一般我们在MVC开发过程中,都会碰到这样的问题。页面总是写在Views文件夹下,而且还只能一个Controller的页面只能写在相应的以Controller名命名的文件夹下。如果我们写到别处呢?那么肯定会报错。这是MVC中的一个规定,必须这样写。
- i' G$ q3 R8 p% x1、正常项目目录规则要求标准如下(图一)。我们要访问Index页面,只需要输入http://域名:端口号/Home/Index(本项目示例访问地址为http://localhost:64968/Home/Index)就可以访问了。我们之所以能够这样访问,是因为我们在项目创建之初系统就默认配置了一个默认的路由。我们可以按照这个默认的路由规则进行访问。默认的路由规则代码(路由目录:项目/App_Start/RouteConfig.cs)如下(代码一)。
图一
- public class RouteConfig1 p; G M* ]7 c0 |3 b
- {
- public static void RegisterRoutes(RouteCollection routes)+ ]8 z/ J3 w7 c9 g
- {/ d8 B% ~' J* Z/ y& m
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");2 s, X& o# K, Z& E* {0 q
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
- );# `- f2 }3 I9 m$ ^6 ~6 ~3 V
- }/ l; e) x* [- w$ z2 z+ k
- }
2、那么我们要求的MVC多级目录规则如何呢?如下(图二)。如果我们要访问Admin下的DemoController里面的Index页面,那么我们输入http://域名:端口号/Demo/Index(本项目示例访问地址为http://localhost:64968/Demo/Index),通过这肯定是访问不了的(无法找到资源。)。因为DemoController根本就不在Controllers的根目录下,而是在Controllers/Admin下,这样我们根本就找不到DemoController。那么我们输入http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)现在也是访问不了的(无法找到资源。),那么我们就需要添加一个路由配置了,因为以前的默认路由只能通过{Controller}/{Action}/{Id}这种方式访问,就是必须以Controller开头。我们重新配置的路由(路由目录:项目/App_Start/RouteConfig.cs)添加一条规则如下(代码二)。
图二
- public class RouteConfig: r' h. `/ p3 _$ W
- {% i$ d8 D6 O4 \+ s% [0 x
- public static void RegisterRoutes(RouteCollection routes)6 `$ g7 r# Q2 C5 t
- {& U) d( N: f3 n
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- //路由规则匹配是从上到下的,优先匹配的路由一定要写在最上面。路由匹配成功以后,不会继续匹配下去。3 S0 M; d& ?0 e1 |+ s. Y
- routes.MapRoute(
- name: "Admin",
- url: "Admin/{controller}/{action}/{id}",, f+ U1 ~/ o) ~% l5 a/ I! \+ ^$ c
- defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
- );
- routes.MapRoute(
- name: "Default",8 s/ l1 m0 R) p* V5 L6 Y0 ?
- url: "{controller}/{action}/{id}",* z% S. E7 ?/ ~$ }; [# J
- defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
- );
- }1 B! @9 G* l3 h# F" R
- }
3、那么现在我们再次输入http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index),能找到Views/Admin/Demo/Index.cshtml这个页面吗?显然是不能的(未找到视图。),因为除了路由配置怎么访问Controller外,寻找Views里面的页面也有自己的规则。测试结果肯定是找不到页面,我们看看错误信息(图三)就知道他是怎么寻找cshtml页面了。
据错误信息搜索位置只搜索这些地址,这里我只写Razor视图的地址,写成通配符就是:
Views/{1}/{0}.cshtmlViews/Shared/{0}.cshtml6 v$ k* t# @" J: g
{1}表示Controller的名称,{0}表示视图名称,Shared是存放模板页的文件夹。一看就很清楚了。这个就是寻找视图的规则,所以我们存放在Admin/Demo/Index.cshtml的存放规则就不满足。所以不能正常访问。按照此规则我们创建Views/Demo文件夹,并创建文件Views/Demo/Index.cshtml(图四)。至此http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)则可以访问(图五),但是不是我们所要求的,既然我们Controller区分存放了,我们肯定也希望Views也能够这样存放的。
# x" t6 P7 Q8 W6 ]* r+ {
图五
4、Views存放规则如何修改呢?现在就开始修改寻找规则。第一先创建一个RouteViewEngine.cs类。类代码(代码三),规则重新定义好后将这个规则注册到系统中,将在Global.asax中注册一下,这样我们就可以通过自己的方式来访问了。
- using System;
- using System.Collections.Generic;4 a o9 Q/ b2 f h) ]6 |& w
- using System.Linq;& d4 F0 P' N1 X' z& U {1 W+ Y
- using System.Web;
- using System.Web.Mvc;
- namespace MvcRouteDemo
- {; K3 f& k% `2 @7 C# @/ Z, e
- public sealed class RouteViewEngine : RazorViewEngine$ l- K( l, S' N. T! a0 S
- {
- public RouteViewEngine()
- {
- ViewLocationFormats = new[]
- {5 n, v: K* O, X+ K- ?
- "~/Views/{1}/{0}.cshtml"," D% a+ j, X, L+ p& @
- "~/Views/Shared/{0}.cshtml",& u# D, V" n D" n
- "~/Views/Admin/{1}/{0}.cshtml"//这是我们添加的规则
- };
- }3 T% L. \: I5 E; V
- public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
- {
- return base.FindView(controllerContext, viewName, masterName, useCache);9 f$ s2 D$ ?5 y' i `* F
- }- ?$ u' f6 U1 D% t# A' r& ^7 b1 }
- }' X0 o4 S2 S* P( n8 d# H) s0 C5 k T
- }
5、Global.asax注册操作(代码四)。
- public class MvcApplication : System.Web.HttpApplication
- {
- protected void Application_Start() ~5 g: l8 _- g* b- f/ Y
- {$ q( n. ?3 B( a- n
- AreaRegistration.RegisterAllAreas();
- + A& i2 H& s, o9 d
- WebApiConfig.Register(GlobalConfiguration.Configuration);( l' X+ Q; [: t. t+ B; @
- FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
- RouteConfig.RegisterRoutes(RouteTable.Routes);
- BundleConfig.RegisterBundles(BundleTable.Bundles);
- * G* P7 B* `% f6 m% i
- RegisterView();//注册视图访问规则到系统中
- }/ r8 o% v5 I( v- g3 B
- protected void RegisterView()0 U" B" }5 |9 ]. {: O! b
- {
- ViewEngines.Engines.Clear();
- ViewEngines.Engines.Add(new RouteViewEngine());
- }9 a$ ?! {: `2 `# s8 y- d
- }
5、最后删除(图四)之前所修改路由表测试的文件夹删除,再次访问http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)就可以实现我们的目的(图六)。
最终送上本次示例项目。