ASP.NET MVC自定义视图路由 [英] ASP.NET MVC Custom View Routing

查看:208
本文介绍了ASP.NET MVC自定义视图路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的解决方案层次结构如下:

控制器\\目录\\查看

例如:
控制器\\ DataAnalysis \\ DataRetrieve

现在我想映射的路由,这样,当用户只需类型的URL视图的名字,它会自动将URL映射到相应的控制器

即:本地主机:1234 \\ DataAnalysis \\ DataRetrieve

应该映射到

查看\\ DataAnalysis \\ DataRetrieve \\ Index.cshtml

同样,任何URL请求,包括动作要获取相应的视图

即:本地主机:1234 \\ DataAnalysis \\ DataRetrieve \\ TestAction

应该映射到

查看\\ DataAnalysis \\ DataRetrieve \\ TestAction.cshtml

目前,我们使用默认的路由

 公共静态无效的RegisterRoutes(RouteCollection路线)
    {
        routes.IgnoreRoute({}资源个.axd / {*} PATHINFO);        routes.MapRoute(
            名称:默认,
            网址:{控制器} / {行动} / {ID}
            默认:新{控制器=登录,行动=索引,ID = UrlParameter.Optional}
        );
    }

这意味着,如果我输入上面显示的URL,它忽略了类别,未能返回的看法。

有没有一种方法可以自定义路由以获得上述的行为?

- 编辑

要基于的评论澄清我的问题,这是我的解决方案资源管理器的截图

现在如果我叫本地主机:12346 / DataAnalysis / DataRetrieve,这应该带我到索引中。路由这不是我可以做一些这样的问题:

  routes.MapRoute(
            名称:ExampleRouting
            网址:{类别} / {控制器} / {行动}
        );

但这里的问题。我也想安排我的文件结构是这样的:

在默认情况下,当我尝试检索dataretrieve的指数,它看起来在查看\\ DataRetrieve \\指数不查看\\ DataAnalysis \\ DataRetrieve \\目录。

我怎样才能改变这种行为?

EDIT2 ------------------------

根据答案,我添加了一个自定义视图引擎中的Application_Start其注册,更新了我的路由。仍然有一个相同的问题。

Global.asax中

 公共类MvcApplication:System.Web.HttpApplication
{
    保护无效的Application_Start()
    {
        AreaRegistration.RegisterAllAreas();        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ViewEngines.Engines.Add(新SPCViewEngine());        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

RouteConfig.cs

 公共静态无效的RegisterRoutes(RouteCollection路线)
    {
        routes.IgnoreRoute({}资源个.axd / {*} PATHINFO);
        routes.MapRoute(
           名称:默认,
           网址:{控制器} / {类别} / {行动} / {ID}
           默认:新{控制器=登录,行动=索引,类别=登录,ID = UrlParameter.Optional}
        );
    }

SPCViewEngine(自定义视图引擎)

 公共类SPCViewEngine:RazorViewEngine
{
    公共SPCViewEngine()
        :基地()
    {
        ViewLocationFormats =新[] {
            〜/查看/ {1} /%1 / {0} .cshtml
            〜/查看/ {1} /%1 / {0} .vbhtml
            〜/查看/共享/ {0} .cshtml
            〜/查看/共享/ {0} .vbhtml
        };         PartialViewLocationFormats =新[] {
            〜/查看/%1 / {1} / {0} .cshtml
            〜/查看/%1 / {1} / {0} .vbhtml
            〜/查看/共享/ {0} .cshtml
            〜/查看/共享/ {0} .vbhtml
        };
    }    保护覆盖IVIEW CreatePartialView(ControllerContext controllerContext,串partialPath)
    {
        。VAR类别名称= controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.CreatePartialView(controllerContext,partialPath.Replace(%1,类别名称));
    }    保护覆盖IVIEW CreateView的(ControllerContext controllerContext,串viewPath,串masterPath)
    {
        。VAR类别名称= controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.CreateView(controllerContext,viewPath.Replace(%1,类别名称),masterPath);
    }    保护覆盖布尔FILEEXISTS(ControllerContext controllerContext,字符串virtualPath)
    {
        。VAR类别名称= controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.FileExists(controllerContext,virtualPath.Replace(%1,类别名称));
    }
}


解决方案

如果我正确理解你的问题,你可以创建在运行时解析视图位置你自己的视图引擎,并插入到你的应用程序。

创建自己的自定义视图引擎。

 公共类MyViewEngine:RazorViewEngine
{
    公共MyViewEngine()
        :基地()
    {
        ViewLocationFormats =新[] {
        〜/查看/ {1} /%1 / {0} .cshtml
        〜/查看/ {1} /%1 / {0} .vbhtml
        〜/查看/共享/ {0} .cshtml
        〜/查看/共享/ {0} .vbhtml
    };    PartialViewLocationFormats =新[] {
        〜/查看/%1 / {1} / {0} .cshtml
        〜/查看/%1 / {1} / {0} .vbhtml
        〜/查看/共享/ {0} .cshtml
        〜/查看/共享/ {0} .vbhtml
    };
    }    保护覆盖IVIEW CreatePartialView(ControllerContext controllerContext,串partialPath)
    {
        。VAR catagoryName = controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.CreatePartialView(controllerContext,partialPath.Replace(%1,catagoryName));
    }    保护覆盖IVIEW CreateView的(ControllerContext controllerContext,串viewPath,串masterPath)
    {
        。VAR catagoryName = controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.CreateView(controllerContext,viewPath.Replace(%1,catagoryName),masterPath);
    }    保护覆盖布尔FILEEXISTS(ControllerContext controllerContext,字符串virtualPath)
    {
        。VAR catagoryName = controllerContext.RouteData.Values​​ [类别]的ToString();
        返回base.FileExists(controllerContext,virtualPath.Replace(%1,catagoryName));
    }}

在这里进行注册。

 保护无效的Application_Start()
{
   AreaRegistration.RegisterAllAreas();   RegisterGlobalFilters(GlobalFilters.Filters);
   的RegisterRoutes(RouteTable.Routes);
   //注册您的视图引擎这里。
   ViewEngines.Engines.Add(新MyViewEngine());
}

更新的路由配置,默认的应该是

  routes.MapRoute(
            名称:默认,
            网址:{控制器} / {类别} / {行动} / {ID}
            默认:新{控制器=家,行动=索引,类别=DefaultCategoryName,ID = UrlParameter.Optional}
        );

Our solution hierarchy is as follows:

Controller\Category\View

Ex: Controllers\DataAnalysis\DataRetrieve

Now I'd like to map the routing so that when the user just types the name of the view in the url, it automatically maps the url to the corresponding controller

I.E: localhost:1234\DataAnalysis\DataRetrieve

Should map to

View\DataAnalysis\DataRetrieve\Index.cshtml

Similarly, any url requests including the action should retrieve the corresponding view

I.E: localhost:1234\DataAnalysis\DataRetrieve\TestAction

Should map to

View\DataAnalysis\DataRetrieve\TestAction.cshtml

Currently, we're using the default routing

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional }
        );
    }

Which means if I type the URL shown above, it ignores the category and fails to return the view.

Is there a way to customize routing to get the behavior above?

--Edit

To clarify my question based on the comments, here's a screenshot of my solution explorer

Now if I call localhost:12346/DataAnalysis/DataRetrieve, this should take me to the index. Routing this isn't a problem as I can do something like this:

        routes.MapRoute(
            name: "ExampleRouting",
            url: "{category}/{controller}/{action}"
        );

But here's the issue. I'd also like to organize my file structure like this:

By default, when I try to retrieve the index of dataretrieve, it looks under Views\DataRetrieve\Index not Views\DataAnalysis\DataRetrieve\Index.

How can I change this behavior?

Edit2------------------------

Based on the answer, I've added a custom view engine, registered it in Application_Start, updated my routing. Still having an identical issue.

Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ViewEngines.Engines.Add(new SPCViewEngine());

        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

RouteConfig.cs

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


        routes.MapRoute(
           name: "Default",
           url: "{controller}/{category}/{action}/{id}",
           defaults: new { controller = "Login", action = "Index", category = "Login", id = UrlParameter.Optional }
        );
    }

SPCViewEngine (Custom View Engine)

public class SPCViewEngine : RazorViewEngine
{
    public SPCViewEngine()
        : base()
    {
        ViewLocationFormats = new[] {
            "~/Views/{1}/%1/{0}.cshtml",
            "~/Views/{1}/%1/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };

         PartialViewLocationFormats = new[] {
            "~/Views/%1/{1}/{0}.cshtml",
            "~/Views/%1/{1}/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreatePartialView(controllerContext, partialPath.Replace("%1", categoryName));
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreateView(controllerContext, viewPath.Replace("%1", categoryName), masterPath);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.FileExists(controllerContext, virtualPath.Replace("%1", categoryName));
    }
}

解决方案

If I understood your question correctly, you can create your own view engine which resolves view location at runtime and plug into your application.

Create your own custom view engine.

    public class MyViewEngine : RazorViewEngine
{
    public MyViewEngine()
        : base()
    {
        ViewLocationFormats = new[] {
        "~/Views/{1}/%1/{0}.cshtml",
        "~/Views/{1}/%1/{0}.vbhtml",
        "~/Views/Shared/{0}.cshtml",
        "~/Views/Shared/{0}.vbhtml"
    };

    PartialViewLocationFormats = new[] {
        "~/Views/%1/{1}/{0}.cshtml",
        "~/Views/%1/{1}/{0}.vbhtml",
        "~/Views/Shared/{0}.cshtml",
        "~/Views/Shared/{0}.vbhtml"
    };
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreatePartialView(controllerContext, partialPath.Replace("%1", catagoryName));
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreateView(controllerContext, viewPath.Replace("%1", catagoryName),masterPath);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.FileExists(controllerContext, virtualPath.Replace("%1", catagoryName));
    }

}

And register it here

protected void Application_Start()
{   
   AreaRegistration.RegisterAllAreas();

   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes);


   //Register your View Engine Here.
   ViewEngines.Engines.Add(new MyViewEngine());
}

Update route config, default should be

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{category}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", category = "DefaultCategoryName", id = UrlParameter.Optional }
        );

这篇关于ASP.NET MVC自定义视图路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆