在ASP.Net MVC中将子目录添加到“View/Shared”文件夹并调用视图

55

我目前正在使用ASP.Net MVC3和Razor开发网站。在“View/Shared”文件夹中,我想添加一个名为“Partials”的子文件夹,以便更好地组织我的部分视图。

只要在调用视图时始终引用“Partials”文件夹(使用Razor),我就可以轻松实现这一点:

@Html.Partial("Partials/{ViewName}")

我想知道是否有办法将“Partials”文件夹添加到.NET在搜索视图时经过的列表中,这样我就可以调用我的视图而无需引用“Partials”文件夹,像这样:

@Html.Partial("{ViewName}")

感谢您的帮助!

7个回答

70

问题已解决。要将我创建的“Shared/Partials”子目录添加到在尝试查找Razor中的Partial View时搜索的位置列表中,可以使用以下代码:

@Html.Partial("{NameOfView}")

首先创建一个 RazorViewEngine 作为基类的视图引擎,然后按照以下方式添加您的视图位置。同样,我想把所有的局部视图都存储在我在 MVC 中创建的默认 "Views/Shared" 目录下的 "Partials" 子目录中。

public class RDDBViewEngine : RazorViewEngine
{
    private static readonly string[] NewPartialViewFormats = 
    { 
        "~/Views/{1}/Partials/{0}.cshtml",
        "~/Views/Shared/Partials/{0}.cshtml"
    };

    public RDDBViewEngine()
    {
        base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NewPartialViewFormats).ToArray();
    }       

}

注意:在位置格式中 {1} 是控制器名称,{0} 是视图名称。

然后,在 global.asax 的 Application_Start() 方法中,将该视图引擎添加到 MVC ViewEngines.Engines 集合中:

ViewEngines.Engines.Add(new RDDBViewEngine()); 

在哪里添加你在第二步中创建的“RDDBViewEngine”类? - Zapnologica
我创建了一个新的.cs文件,然后将该类添加到我的主{Project}.Models命名空间中。在VS中,只需右键单击Models目录,点击Add->Class并将类命名为FooViewEngine。您将获得一个存根类,可以将上面的代码复制到其中。 - lamarant
4
PartialViewLocationFormats 中不仅可以使用 {2},还可以使用区域信息。 - Alex
@lamarant,请看下面我的答案,关于Areas的问题。 - mcfea
对于MVC 5,只需放置@Html.Partial("Partial/myPartial.cshtml")即可。 - Santosh
显示剩余2条评论

31

感谢你的回答。这已经整理了我的共享文件夹,但是为什么要创建一种新的视图引擎?我只是创建了一个新的RazorViewEngine,设置了它的PartialViewLocationFormats并将其添加到ViewEngines列表中。

ViewEngines.Engines.Add(new RazorViewEngine
{
    PartialViewLocationFormats = new string[]
    {
        "~/Views/{1}/Partials/{0}.cshtml",
        "~/Views/Shared/Partials/{0}.cshtml"
    }
});

3
创建你自己的类会让你在未来重复使用它,而不是每次都记得手写那些字符串字面值。 - Jim D'Angelo
两种方法都可以,我想每种方法都有其优缺点。对我来说,这是更好的答案,因为我们没有改变RazorViewEngine中已经存在的行为。 - Jaans
请注意,您可以轻松地从 Helper 方法中运行此答案中的代码,该方法捕获了这个细节,而不是构建一个仅包含此细节的额外类。 - Chris Moschini

20

自定义视图引擎很好,但如果你只想拥有一个子文件夹或局部文件,则不需要那么多...

只需像 Layout View 一样使用部分视图的完整路径即可:

@Html.Partial("/Views/Shared/Partial/myPartial.cshtml")

希望它能帮助到某些人...


谢谢,真的是一个简单而有效的解决方案! - Dzianis Yafimau
8
对于 MVC 5,只需添加 @Html.Partial("Partial/myPartial.cshtml")。 - Santosh

14
如果您在ASP.NET Core中进行此操作,请简单地转到Startup类,在ConfigureServices方法下放置。
services.AddMvc()
    .AddRazorOptions(opt => {
        opt.ViewLocationFormats.Add("/Views/{1}/Partials/{0}.cshtml");
        opt.ViewLocationFormats.Add("/Views/Shared/Partials/{0}.cshtml");
    });

对于那些不确定 {0} 和 {1} 占位符代表什么的人来说,{1} 将是控制器名称,而 {0} 将是视图名称。我想补充一点,你可以使用 ViewLocationFormats.ViewExtension 属性,而不是硬编码 '.cshtml' 扩展名。 - Christopher King

7

我更新了lamarant的优秀答案,加入了Areas:

public class RDDBViewEngine : RazorViewEngine
{
    private static readonly string[] NewPartialViewFormats =
    {
        "~/Views/{1}/Partials/{0}.cshtml",
        "~/Views/Shared/Partials/{0}.cshtml"
    };

    private static List<string> AreaRegistrations;

    public RDDBViewEngine()
    {
        AreaRegistrations = new List<string>();

        BuildAreaRegistrations();

        base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NewPartialViewFormats).ToArray();
        base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(areaRegistrations).ToArray();
    }

    private static void BuildAreaRegistrations()
    {
        string[] areaNames = RouteTable.Routes.OfType<Route>()
            .Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area"))
            .Select(r => r.DataTokens["area"].ToString()).ToArray();

        foreach (string areaName in areaNames)
        {
            AreaRegistrations.Add("~/Areas/" + areaName + "/Views/Shared/Partials/{0}.cshtml");
            AreaRegistrations.Add("~/Areas/" + areaName + "/Views/{1}/Partials/{0}.cshtml");
        }
    }
}

那么在你的应用程序启动时不要忘记包含以下内容:
public class MvcApplication : System.Web.HttpApplication
{

    protected void Application_Start()
    {
        ...

        ViewEngines.Engines.Add(new RDDBViewEngine()); 
    }
}

我已经这样做了,但是在virtualPath上出现了ArgumentNullException,我错在哪里了? - Phate01

5
您还可以更新已注册的RazorViewEngine的partialview-location-formats。 请将以下代码放置于Global.asax中的Application_Start方法中。
 RazorViewEngine razorEngine = ViewEngines.Engines.OfType<RazorViewEngine>().FirstOrDefault();
        if (razorEngine != null)
        {
            string[] newPartialViewFormats = new[] { 
                    "~/Views/{1}/Partials/{0}.cshtml",
                    "~/Views/Shared/Partials/{0}.cshtml"
            };
            razorEngine.PartialViewLocationFormats =
                razorEngine.PartialViewLocationFormats.Union(newPartialViewFormats).ToArray();
        }

1

你可以创建自己的视图引擎,它派生于你正在使用的任何视图引擎(Webforms/Razor),并在构造函数中指定任何位置,或者将它们添加到已存在位置的列表中:

this.PartialViewLocationFormats = viewLocations;

然后在应用程序启动时,您可以像这样添加您的视图引擎:

ViewEngines.Engines.Add(new MyViewEngineWithPartialPath());

你不需要继承该类。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接