You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC共享视图报错:找不到SummaryReport视图的解决咨询

问题描述

我的解决方案包含3个项目:

  • Library -> 控制台应用
  • Project1 -> MVC项目
  • Project2 -> MVC项目

Project1和Project2的视图结构相似,都在Views/Monthly目录下有SummaryReport.cshtml:

- Project1/Project2
  \--Views
  \---Monthly
  \----SummaryReport.cshtml

两个项目中都有Monthly.cs控制器。我已经把Monthly.cs控制器迁移到Library项目,通过复制为链接的方式实现了控制器在两个MVC项目间的共享。

接下来想复用SummaryReport.cshtml视图:将文件放到Library项目的Views/Monthly目录下,再用同样的复制为链接方式关联到Project1和Project2,但运行时报错:

[InvalidOperationException: The view 'SummaryReport' or its master was not found or no view engine supports the searched locations. The following locations were searched:

~/Views/Monthly/SummaryReport.cshtml

~/Views/Monthly/SummaryReport.vbhtml

~/Views/Shared/SummaryReport.cshtml

~/Views/Shared/SummaryReport.vbhtml]

System.Web.Mvc.ViewResult.FindView(ControllerContext context) +511

System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +143

System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +91<br /> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +795

System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +795<br /> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList1 filters, ActionResult actionResult) +81

System.Web.Mvc.Async.<>c__DisplayClass21.b__1e(IAsyncResult asyncResult) +188

System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +38

System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +32

System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +73<br /> System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +52<br /> System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +39

System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38

System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +46

System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +73

System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38

System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +426

System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +172

System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +158

我已经给Project1添加了Library项目的引用并配置了依赖关系,请问:

  1. 报错原因是什么?
  2. 如何修复?
  3. 跨项目复用视图的最佳方式是什么?

附MonthlyController中的SummaryReport方法代码:

public ActionResult SummaryReport()
{
    var model = db.Database.SqlQuery<MontlhySummary>("SELECT * FROM monthlySummary").ToList();

    ViewBag.Title = "Monthly Report";

    return View(model);
}
问题解答

一、报错原因

MVC视图引擎默认仅在当前Web项目的Views目录下查找视图文件,复制为链接只是在项目中创建了文件引用,编译时这些链接文件不会被复制到Web项目的输出目录,运行时视图引擎找不到实际的视图文件,因此抛出异常。另外,你的Library是控制台应用项目,输出类型与Web项目不同,即便视图文件被复制到输出目录,视图引擎也不会去搜索类库的输出路径。

二、修复方法

临时修复(适配复制为链接方式)

  1. 选中Project1/Project2中通过复制为链接添加的SummaryReport.cshtml文件,在属性窗口设置:
    • 复制到输出目录:选择「如果较新则复制」或「始终复制」
    • 生成操作:设置为「内容」
  2. 同时确保Library项目中的视图文件属性也设置为「内容」,且配置复制到输出目录。

这种方式仅能临时解决问题,后续维护容易出现路径或文件同步问题,不推荐长期使用。

可靠修复方案

  1. 将Library改为类库项目:控制台应用不适合作为MVC控制器和视图的共享载体,改为类库(.NET Framework)或ASP.NET Web Application(空)项目。
  2. 自定义视图引擎,添加类库视图搜索路径:
    创建自定义视图引擎,让它能定位到Library项目中的视图目录:
    public class SharedViewEngine : RazorViewEngine
    {
        public SharedViewEngine()
        {
            // 根据实际项目结构调整路径
            var sharedViewsPath = @"~/../Library/Views/{1}/{0}.cshtml";
            ViewLocationFormats = ViewLocationFormats.Concat(new[] { sharedViewsPath }).ToArray();
            PartialViewLocationFormats = PartialViewLocationFormats.Concat(new[] { sharedViewsPath }).ToArray();
        }
    }
    
    在Global.asax的Application_Start方法中注册:
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new SharedViewEngine());
    

三、跨项目复用视图的最佳方式

1. 类库封装+自定义视图引擎

将共享的控制器、视图、模型统一放到ASP.NET MVC类库项目中,保持标准的Views目录结构。Web项目引用该类库后,通过自定义视图引擎指定类库的视图搜索路径,实现视图复用。

2. 嵌入资源方式(推荐长期维护)

将类库中的视图文件设置为嵌入的资源,编写自定义视图引擎从程序集中读取嵌入的视图内容:

public class EmbeddedViewEngine : RazorViewEngine
{
    private readonly Assembly _sharedAssembly;

    public EmbeddedViewEngine(Assembly sharedAssembly)
    {
        _sharedAssembly = sharedAssembly;
        // 对应嵌入资源的命名空间格式
        ViewLocationFormats = new[]
        {
            "Library.Views.{1}.{0}.cshtml"
        };
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var resourceName = viewPath.Replace(".", "/");
        return new EmbeddedResourceView(_sharedAssembly, resourceName);
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var resourceName = partialPath.Replace(".", "/");
        return new EmbeddedResourceView(_sharedAssembly, resourceName);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var resourceName = virtualPath.Replace(".", "/");
        return _sharedAssembly.GetManifestResourceInfo(resourceName) != null;
    }
}

public class EmbeddedResourceView : IView
{
    private readonly Assembly _assembly;
    private readonly string _resourceName;

    public EmbeddedResourceView(Assembly assembly, string resourceName)
    {
        _assembly = assembly;
        _resourceName = resourceName;
    }

    public void Render(ViewContext viewContext, TextWriter writer)
    {
        using (var stream = _assembly.GetManifestResourceStream(_resourceName))
        {
            using (var reader = new StreamReader(stream))
            {
                var html = reader.ReadToEnd();
                writer.Write(html);
            }
        }
    }
}

在Global.asax注册:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new EmbeddedViewEngine(typeof(MonthlyController).Assembly));

这种方式无需复制文件,视图嵌入在类库中,避免了路径问题,适合长期维护。

3. Razor类库(ASP.NET Core适用)

如果是ASP.NET Core项目,直接使用官方提供的Razor类库项目类型,专门用于封装可复用的Razor视图、页面和控制器,Web项目引用后可直接使用,无需自定义视图引擎,是官方推荐的方案。


内容的提问来源于stack exchange,提问作者Adam Suchi Hafizullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:47:17