根据控制器动态查看serach位置

时间:2016-09-30 13:08:39

标签: c# asp.net asp.net-mvc razorengine

首先,抱歉很长时间的问题。我知道阅读和回答长期问题是痛苦的,但我必须清楚地解释我的情况。最近,我发现自己在ASP.NET MVC应用程序中复制视图并且不做任何改动或仅改变一些事情,通常是BeginForm("actionName", "controllerName")上的控制器名称(幸运的是,这可以在视图内部解决)。不久,我的主要目的是消除重复的观点。

原因

原因是我有不同的控制器具有类似的功能。它们看起来与用户相同,但控制器的计算结果非常不同。更具体地说,我有四个名为 InitialReport,CorrectionReport,InitialReportReview,CorrectionReportReview 的控制器。 InitialReport CorrectionReport InitialReportReview,CorrectionReportReview 的视图几乎完全相同。所以我想做的是消除重复的视图并为夫妻创建共享视图。

问题

我的问题是,我不想将所有视图都放到 Shared 视图文件夹中,因为它们太多而无法放入此文件夹。此外,控制器中的操作名称重叠。假设我在所有四个控制器中都有ReportPayments动作方法,因此视图名称也会重叠。但是,InitialReportInitialReportReview的视图必须不同。所以我在共享视图文件夹中添加了两个文件夹,名为 Report (对于 InitialReport,CorrectionReport )和 ReportReview (对于 InitialReportReview,CorrectionReportReview )。我计划将所有共享视图分别添加到 Report ReportReview 子文件夹。现在的问题是,查看查找位置必须动态更改以适应&#34;控制器类型&#34;。例如,如果我在InitialReport控制器中并且我导航到ReportPayments操作,则必须从〜/ Views / Shared / Report / ReportPayments.cshtml <加载视图/ em>,但如果我在InitialReportReview控制器中,那么视图应该从〜/ Views / Shared / ReportReview / ReportPayments.cshtml 加载。

解决方案

作为我创建自定义视图引擎的解决方案,我覆盖FindView方法并根据控制器名称设置ViewLocationFormats

public class ExtendedRazorViewEngine
    : RazorViewEngine
{
    string[] DefaultViewLocations { get; set; }
    string[] ReportViewLocations { get; set; }
    string[] ReportReviewViewLocations { get; set; }

    public ExtendedRazorViewEngine()
    {
        // Get the copy of default view locations
        DefaultViewLocations = new string[ViewLocationFormats.Length];
        ViewLocationFormats.CopyTo(DefaultViewLocations, 0);

        // Initialize ReportViewLocations
        List<string> customReportViewLocations = new List<string>
        {
            "~/Views/Shared/Report/{0}.cshtml"
        };
        ReportViewLocations = DefaultViewLocations
            .Union(customReportViewLocations)
            .ToArray();

        // Initialize ReportReviewViewLocations
        List<string> customReportReviewViewLocations = new List<string>
        {
            "~/Views/Shared/ReportReview/{0}.cshtml"
        };
        ReportReviewViewLocations = DefaultViewLocations
            .Union(customReportReviewViewLocations)
            .ToArray();
    }

    public override ViewEngineResult FindView(
        ControllerContext controllerContext, 
        string viewName, 
        string masterName, 
        bool useCache)
    {
        // Get controller name
        string controllerName = controllerContext.RouteData.GetRequiredString("controller");

        // Set view search locations
        if (controllerName.EndsWith("ReportReview"))
            ViewLocationFormats = ReportReviewViewLocations;
        else if (controllerName.EndsWith("Report"))
            ViewLocationFormats = ReportViewLocations;
        else
            ViewLocationFormats = DefaultViewLocations;

        return base.FindView(controllerContext, viewName, masterName, useCache);
    }
}

我已将ExtendedRazorViewEngine注册为默认视图引擎,似乎工作正常。但我几乎没有问题。有一个questionanswer与我的相似(不完全相同),确实非常有用,但它没有回答我的问题。

问题

  1. 这是正确的方法吗?此方法是否有任何缺点,例如视图未缓存或任何其他性能问题?我可以更好地使用这种方法吗?
  2. 有没有更好的方法来实现我的目标?
  3. 当我测试时,我意识到FindView方法被击中两次。为什么?我复制了视图引擎并在一个几乎空的MVC应用程序中进行了测试,同样的事情也发生在那里,所以我认为它与我的应用程序无关。

1 个答案:

答案 0 :(得分:1)

我认为你正在努力实现这一目标。将View放在Shared文件夹中似乎要简单得多。但是如果您不想这样做,即使它不在共享文件夹中,您仍然可以调用View。

从视图:

@Html.Partial("~/Views/ReportReview/InitialReport.cshtml")

或来自控制器:

return this.View("~/Views/ReportReview/InitialReport.cshtml");

所以如果我是你,我会创建一次这些视图,然后从其他视图或控制器中调用它。这样您就不必重复代码,也不必创建自定义视图引擎(我想这将是多年来保持的熊)。