【问题标题】:How to set a Default Route (To an Area) in MVC如何在 MVC 中设置默认路由(到某个区域)
【发布时间】:2011-01-09 13:24:29
【问题描述】:

好的,之前有人问过这个问题,但是没有可靠的解决方案。所以为了我自己和其他可能觉得这很有用的人。

在 MVC2 (ASP.NET) 中,我想要它,因此当有人导航到该网站时,会指定一个默认区域。因此,导航到我的网站应该会将您发送到 AreaZ 中的 ControllerX ActionY。

在 Global.asax 中使用以下路由

routes.MapRoute(
                "Area",
                "",
                new { area = "AreaZ", controller = "ControllerX ", action = "ActionY " }
            );

现在这可以正常工作,因为它会尝试提供正确的页面。但是 MVC 继续在站点的根目录中而不是在区域文件夹中查找视图。

有没有办法解决这个问题?

编辑

有一个“解决方案”,在 ControllerX 中,ActionY 返回视图的完整路径。有点破解,但它确实有效。不过我希望有更好的解决方案。

         public ActionResult ActionY()
        {
            return View("~/Areas/AreaZ/views/ActionY.aspx");
        }

编辑:

当有页面的 HTML ActionLink 时,这也会成为一个问题。如果未设置区域,则操作链接输出为空白。

所有这些都是设计的还是缺陷?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-2


    【解决方案1】:

    这个我很感兴趣,我终于有机会研究它了。其他人显然不明白这是 finding view 的问题,而不是 routing 本身的问题 - 这可能是因为您的问题标题表明它是关于路由。

    在任何情况下,由于这是一个与视图相关的问题,因此获得所需内容的唯一方法是覆盖默认视图引擎。通常,当您这样做时,只是为了切换视图引擎(即切换到 Spark、NHaml 等)。在这种情况下,我们需要重写的不是视图创建逻辑,而是VirtualPathProviderViewEngine 类中的FindPartialViewFindView 方法。

    感谢你的幸运星,这些方法实际上是虚拟的,因为 VirtualPathProviderViewEngine 中的其他所有内容甚至都可访问 - 它是私有的,这使得它非常 em> 重写查找逻辑很烦人,因为如果您希望它与位置缓存和位置格式很好地配合,您基本上必须重写一半已经编写的代码。在对 Reflector 进行了一些挖掘之后,我终于想出了一个可行的解决方案。

    我在这里所做的是首先创建一个抽象的AreaAwareViewEngine,它直接派生自VirtualPathProviderViewEngine,而不是WebFormViewEngine。我这样做是为了如果你想创建 Spark 视图(或其他),你仍然可以使用这个类作为基类型。

    下面的代码相当冗长,所以给你一个快速总结它的实际作用:它可以让你将{2} 放入位置格式,它对应于区域名称,同样的方式@987654329 @ 对应于控制器名称。而已!这就是我们必须编写所有这些代码的目的:

    BaseAreaAwareViewEngine.cs

    public abstract class BaseAreaAwareViewEngine : VirtualPathProviderViewEngine
    {
        private static readonly string[] EmptyLocations = { };
    
        public override ViewEngineResult FindView(
            ControllerContext controllerContext, string viewName,
            string masterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(viewName))
            {
                throw new ArgumentNullException(viewName,
                    "Value cannot be null or empty.");
            }
    
            string area = getArea(controllerContext);
            return FindAreaView(controllerContext, area, viewName,
                masterName, useCache);
        }
    
        public override ViewEngineResult FindPartialView(
            ControllerContext controllerContext, string partialViewName,
            bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(partialViewName))
            {
                throw new ArgumentNullException(partialViewName,
                    "Value cannot be null or empty.");
            }
    
            string area = getArea(controllerContext);
            return FindAreaPartialView(controllerContext, area,
                partialViewName, useCache);
        }
    
        protected virtual ViewEngineResult FindAreaView(
            ControllerContext controllerContext, string areaName, string viewName,
            string masterName, bool useCache)
        {
            string controllerName =
                controllerContext.RouteData.GetRequiredString("controller");
            string[] searchedViewPaths;
            string viewPath = GetPath(controllerContext, ViewLocationFormats,
                "ViewLocationFormats", viewName, controllerName, areaName, "View",
                useCache, out searchedViewPaths);
            string[] searchedMasterPaths;
            string masterPath = GetPath(controllerContext, MasterLocationFormats,
                "MasterLocationFormats", masterName, controllerName, areaName,
                "Master", useCache, out searchedMasterPaths);
            if (!string.IsNullOrEmpty(viewPath) &&
                (!string.IsNullOrEmpty(masterPath) || 
                  string.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(CreateView(controllerContext, viewPath,
                    masterPath), this);
            }
            return new ViewEngineResult(
                searchedViewPaths.Union<string>(searchedMasterPaths));
        }
    
        protected virtual ViewEngineResult FindAreaPartialView(
            ControllerContext controllerContext, string areaName,
            string viewName, bool useCache)
        {
            string controllerName =
                controllerContext.RouteData.GetRequiredString("controller");
            string[] searchedViewPaths;
            string partialViewPath = GetPath(controllerContext,
                ViewLocationFormats, "PartialViewLocationFormats", viewName,
                controllerName, areaName, "Partial", useCache,
                out searchedViewPaths);
            if (!string.IsNullOrEmpty(partialViewPath))
            {
                return new ViewEngineResult(CreatePartialView(controllerContext,
                    partialViewPath), this);
            }
            return new ViewEngineResult(searchedViewPaths);
        }
    
        protected string CreateCacheKey(string prefix, string name,
            string controller, string area)
        {
            return string.Format(CultureInfo.InvariantCulture,
                ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:",
                base.GetType().AssemblyQualifiedName,
                prefix, name, controller, area);
        }
    
        protected string GetPath(ControllerContext controllerContext,
            string[] locations, string locationsPropertyName, string name,
            string controllerName, string areaName, string cacheKeyPrefix,
            bool useCache, out string[] searchedLocations)
        {
            searchedLocations = EmptyLocations;
            if (string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }
            if ((locations == null) || (locations.Length == 0))
            {
                throw new InvalidOperationException(string.Format("The property " +
                    "'{0}' cannot be null or empty.", locationsPropertyName));
            }
            bool isSpecificPath = IsSpecificPath(name);
            string key = CreateCacheKey(cacheKeyPrefix, name,
                isSpecificPath ? string.Empty : controllerName,
                isSpecificPath ? string.Empty : areaName);
            if (useCache)
            {
                string viewLocation = ViewLocationCache.GetViewLocation(
                    controllerContext.HttpContext, key);
                if (viewLocation != null)
                {
                    return viewLocation;
                }
            }
            if (!isSpecificPath)
            {
                return GetPathFromGeneralName(controllerContext, locations, name,
                    controllerName, areaName, key, ref searchedLocations);
            }
            return GetPathFromSpecificName(controllerContext, name, key,
                ref searchedLocations);
        }
    
        protected string GetPathFromGeneralName(ControllerContext controllerContext,
            string[] locations, string name, string controllerName,
            string areaName, string cacheKey, ref string[] searchedLocations)
        {
            string virtualPath = string.Empty;
            searchedLocations = new string[locations.Length];
            for (int i = 0; i < locations.Length; i++)
            {
                if (string.IsNullOrEmpty(areaName) && locations[i].Contains("{2}"))
                {
                    continue;
                }
                string testPath = string.Format(CultureInfo.InvariantCulture,
                    locations[i], name, controllerName, areaName);
                if (FileExists(controllerContext, testPath))
                {
                    searchedLocations = EmptyLocations;
                    virtualPath = testPath;
                    ViewLocationCache.InsertViewLocation(
                        controllerContext.HttpContext, cacheKey, virtualPath);
                    return virtualPath;
                }
                searchedLocations[i] = testPath;
            }
            return virtualPath;
        }
    
        protected string GetPathFromSpecificName(
            ControllerContext controllerContext, string name, string cacheKey,
            ref string[] searchedLocations)
        {
            string virtualPath = name;
            if (!FileExists(controllerContext, name))
            {
                virtualPath = string.Empty;
                searchedLocations = new string[] { name };
            }
            ViewLocationCache.InsertViewLocation(controllerContext.HttpContext,
                cacheKey, virtualPath);
            return virtualPath;
        }
    
    
        protected string getArea(ControllerContext controllerContext)
        {
            // First try to get area from a RouteValue override, like one specified in the Defaults arg to a Route.
            object areaO;
            controllerContext.RouteData.Values.TryGetValue("area", out areaO);
    
            // If not specified, try to get it from the Controller's namespace
            if (areaO != null)
                return (string)areaO;
    
            string namespa = controllerContext.Controller.GetType().Namespace;
            int areaStart = namespa.IndexOf("Areas.");
            if (areaStart == -1)
                return null;
    
            areaStart += 6;
            int areaEnd = namespa.IndexOf('.', areaStart + 1);
            string area = namespa.Substring(areaStart, areaEnd - areaStart);
            return area;
        }
    
        protected static bool IsSpecificPath(string name)
        {
            char ch = name[0];
            if (ch != '~')
            {
                return (ch == '/');
            }
            return true;
        }
    }
    

    现在如上所述,这不是一个具体的引擎,因此您也必须创建它。幸运的是,这部分要容易得多,我们需要做的就是设置默认格式并实际创建视图:

    AreaAwareViewEngine.cs

    public class AreaAwareViewEngine : BaseAreaAwareViewEngine
    {
        public AreaAwareViewEngine()
        {
            MasterLocationFormats = new string[]
            {
                "~/Areas/{2}/Views/{1}/{0}.master",
                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.master",
                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                "~/Views/{1}/{0}.master",
                "~/Views/{1}/{0}.cshtml",
                "~/Views/Shared/{0}.master"
                "~/Views/Shared/{0}.cshtml"
            };
            ViewLocationFormats = new string[]
            {
                "~/Areas/{2}/Views/{1}/{0}.aspx",
                "~/Areas/{2}/Views/{1}/{0}.ascx",
                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.aspx",
                "~/Areas/{2}/Views/Shared/{0}.ascx",
                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx",
                "~/Views/{1}/{0}.cshtml",
                "~/Views/Shared/{0}.aspx"
                "~/Views/Shared/{0}.ascx"
                "~/Views/Shared/{0}.cshtml"
            };
            PartialViewLocationFormats = ViewLocationFormats;
        }
    
        protected override IView CreatePartialView(
            ControllerContext controllerContext, string partialPath)
        {
            if (partialPath.EndsWith(".cshtml"))
                return new System.Web.Mvc.RazorView(controllerContext, partialPath, null, false, null);
            else
                return new WebFormView(controllerContext, partialPath);
        }
    
        protected override IView CreateView(ControllerContext controllerContext,
            string viewPath, string masterPath)
        {
            if (viewPath.EndsWith(".cshtml"))
                return new RazorView(controllerContext, viewPath, masterPath, false, null);
            else
                return new WebFormView(controllerContext, viewPath, masterPath);
        }
    }
    

    请注意,我们在标准 ViewLocationFormats 中添加了一些条目。这些是新的{2} 条目,其中{2} 将映射到我们放入RouteDataarea。我已经单独留下了MasterLocationFormats,但显然你可以根据需要更改它。

    现在修改您的global.asax 以注册此视图引擎:

    Global.asax.cs

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new AreaAwareViewEngine());
    }
    

    ...并注册默认路由:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapRoute(
            "Area",
            "",
            new { area = "AreaZ", controller = "Default", action = "ActionY" }
        );
        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = "" }
        );
    }
    

    现在创建我们刚刚引用的AreaController

    DefaultController.cs(在 ~/Controllers/ 中)

    public class DefaultController : Controller
    {
        public ActionResult ActionY()
        {
            return View("TestView");
        }
    }
    

    显然我们需要目录结构和视图来配合它——我们将保持这个超级简单:

    TestView.aspx(在 ~/Areas/AreaZ/Views/Default/ 或 ~/Areas/AreaZ/Views/Shared/ 中)

    <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
    <h2>TestView</h2>
    This is a test view in AreaZ.
    

    就是这样。 终于,我们完成了

    在大多数情况下,您应该能够将 BaseAreaAwareViewEngineAreaAwareViewEngine 放入任何 MVC 项目中,因此即使完成此操作需要大量代码,您只需编写一次。之后,只需在global.asax.cs 中编辑几行并创建您的站点结构即可。

    【讨论】:

    • 这很可能是当前最好的解决方案,但远非理想。如上所述,一旦添加 Actionlink 或存在相同的问题。
    • @Pino:我认为您应该能够通过将相同的area = "AreaZ" 添加到global.asax.cs 中的“默认”路由映射来解决ActionLink 问题。不过我并不积极;试试看。
    • 在 MVC4 中“默认”路由声明从 Global.asax 移动到 ~/App_Start/RouteConfig.cs/RegisterRoutes()
    • 我讨厌投反对票,但我真的不敢相信@Chris Alderson 的以下回答没有获得更多选票。这是一个比这个更简单的解决方案,并且似乎解决了边缘情况(ActionLinks 等)。
    • 这里似乎有一个错误。例如,名为“Re”的区域的视图将位于 ~/Areas/Re/Views/Ctrlr/blah.aspx,但此处的代码使用 ~/{2}/{1}/{0},即 ~ /Re/Ctrl/blah.aspx,路径中缺少关键区域目录。它应该是“~/Areas/{2}/Views/{1}/{0}.aspx”
    【解决方案2】:

    我就是这样做的。我不知道为什么 MapRoute() 不允许您设置区域,但它确实返回了路线对象,因此您可以继续进行任何您想要的其他更改。我使用它是因为我有一个模块化 MVC 站点,该站点出售给企业客户,他们需要能够将 dll 放入 bin 文件夹以添加新模块。我允许他们在 AppSettings 配置中更改“HomeArea”。

    var route = routes.MapRoute(
                    "Home_Default", 
                    "", 
                    new {controller = "Home", action = "index" },
                    new[] { "IPC.Web.Core.Controllers" }
                   );
    route.DataTokens["area"] = area;
    

    编辑:您也可以在 AreaRegistration.RegisterArea 中尝试让用户默认进入的区域。我还没有测试过,但是 AreaRegistrationContext.MapRoute 确实为你设置了route.DataTokens["area"] = this.AreaName;

    context.MapRoute(
                        "Home_Default", 
                        "", 
                        new {controller = "Home", action = "index" },
                        new[] { "IPC.Web.Core.Controllers" }
                       );
    

    【讨论】:

    • 它有效。注意新的 web.config 文件,它可能会覆盖旧的全局配置。
    【解决方案3】:

    即使它已经被回答 - 这是简短的语法(ASP.net 3、4、5):

    routes.MapRoute("redirect all other requests", "{*url}",
        new {
            controller = "UnderConstruction",
            action = "Index"
            }).DataTokens = new RouteValueDictionary(new { area = "Shop" });
    

    【讨论】:

    • 这对我很有用。我在根目录没有任何控制器,只使用区域。对于 MVC 4,我将其替换为 RouteConfig.cs 中的默认值。谢谢!
    • 我正在使用 MVC4,这对我来说是最简单的解决方案。允许应用程序将特定区域内的索引视图用作站点的“主页”。
    • 此解决方案在未来将不再适用(来自 Asp.Net MVC6 及更高版本)。
    • @PatrickDesjardins : 有什么理由不支持上述解决方案?
    • @SeriousM 你的回答是常青树。它仍然有帮助。你救了我一个晚上。
    【解决方案4】:

    感谢 Aaron 指出这是关于定位视图,我误解了这一点。

    [更新] 我刚刚创建了一个项目,默认情况下将用户发送到一个区域,而不会弄乱任何代码或查找路径:

    在 global.asax 中,照常注册:

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = ""}  // Parameter defaults,
            );
        }
    

    Application_Start()中,请务必使用以下顺序;

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }
    

    在您所在地区注册,使用

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "ShopArea_default",
                "{controller}/{action}/{id}",
                new { action = "Index", id = "", controller = "MyRoute" },
                new { controller = "MyRoute" }
            );
        }
    

    可以在以下位置找到一个示例 http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/

    我真的希望这是你所要求的......

    ////

    我不认为在这种情况下写一个伪ViewEngine 是最好的解决方案。 (缺乏声誉,我无法评论)。 WebFormsViewEngine 是区域感知的,包含 AreaViewLocationFormats,默认情况下定义为

    AreaViewLocationFormats = new[] {
            "~/Areas/{2}/Views/{1}/{0}.aspx",
            "~/Areas/{2}/Views/{1}/{0}.ascx",
            "~/Areas/{2}/Views/Shared/{0}.aspx",
            "~/Areas/{2}/Views/Shared/{0}.ascx",
        };
    

    我相信你不遵守这个约定。你发了

    public ActionResult ActionY() 
    { 
        return View("~/Areas/AreaZ/views/ActionY.aspx"); 
    } 
    

    作为一个有效的黑客,但这应该是

       return View("~/Areas/AreaZ/views/ControllerX/ActionY.aspx"); 
    

    如果您不想遵循约定,但是,您可能希望通过从 WebFormViewEngine 派生(例如,在 MvcContrib 中完成)采取一条短路径,您可以在其中设置查找路径构造函数,或者-有点hacky-通过在Application_Start上指定这样的约定:

    ((VirtualPathProviderViewEngine)ViewEngines.Engines[0]).AreaViewLocationFormats = ...;
    

    当然,这应该更加小心,但我认为它表明了这个想法。这些字段是 MVC 2 RC 中 VirtualPathProviderViewEngine 中的 public

    【讨论】:

    • 值得注意的是,这仅适用于 MVC 2 RC - MVC 1 VirtualPathProviderViewEngine 没有此属性,也不是区域感知的。虽然这个问题确实是关于 MVC 2 的,但很多人仍然没有使用它(并且在一段时间内不会使用它)。因此,对于特定问题,您的答案更容易,但我的答案是唯一适用于偶然发现此问题的 MVC1 用户的答案。我喜欢提供不依赖于可能会发生变化的预发布功能的答案。
    • 另外,它不是一个“伪视图引擎”——视图引擎类被故意设计成可扩展的,以便可以使用不同类型的视图。
    • 这不是要侮辱你,对不起。它是“伪”的,因为它不会显着改变视图的处理方式,而只是替换了一些值。
    • 我没有被冒犯,我只是想澄清一个事实,即派生自定义视图引擎并不是一个特别不寻常的原因,相关方法是可覆盖的事实证明了这一点。跨度>
    • 关于RegisterAreasRegisterRoutes 之前的重要提示。想知道为什么我的代码突然停止工作并注意到重构;)
    【解决方案5】:

    我猜您希望用户在访问过~/ URL 后被重定向到~/AreaZ URL。 我将通过您的根目录HomeController 中的以下代码来实现。

    public class HomeController
    {
        public ActionResult Index()
        {
            return RedirectToAction("ActionY", "ControllerX", new { Area = "AreaZ" });
        }
    }
    

    以及Global.asax中的以下路线。

    routes.MapRoute(
        "Redirection to AreaZ",
        String.Empty,
        new { controller = "Home ", action = "Index" }
    );
    

    【讨论】:

    • 这可行,但它会更改为用户浏览器上的 URL。真的不理想。
    【解决方案6】:

    首先,您使用的是哪个版本的 MVC2?从 preview2 到 RC 发生了重大变化。

    假设您使用 RC,我认为您的路线映射应该看起来不同。在您所在地区的AreaRegistration.cs,您可以注册某种默认路由,例如

            context.MapRoute(
                "ShopArea_default",
                "{controller}/{action}/{id}",
                new { action = "Index", id = "", controller="MyRoute" }
            );
    

    默认情况下,上面的代码会将用户发送到我们ShopArea 中的MyRouteController

    使用空字符串作为第二个参数会引发异常,因为必须指定控制器。

    当然,您必须更改 Global.asax 中的默认路由,这样它就不会干扰此默认路由,例如通过使用主站点的前缀。

    另请参阅此线程和 Haack 的回答:MVC 2 AreaRegistration Routes Order

    希望这会有所帮助。

    【讨论】:

    • 谢谢,但我不确定这是否能解决问题中解释的问题。以及它的 MVC RC
    【解决方案7】:

    将以下内容添加到我的 Application_Start 对我有用,但我不确定您在 RC 中是否有此设置:

    var engine = (WebFormViewEngine)ViewEngines.Engines.First();
    
    // These additions allow me to route default requests for "/" to the home area
    engine.ViewLocationFormats = new string[] { 
        "~/Views/{1}/{0}.aspx",
        "~/Views/{1}/{0}.ascx",
        "~/Areas/{1}/Views/{1}/{0}.aspx", // new
        "~/Areas/{1}/Views/{1}/{0}.ascx", // new
        "~/Areas/{1}/Views/{0}.aspx", // new
        "~/Areas/{1}/Views/{0}.ascx", // new
        "~/Views/{1}/{0}.ascx",
        "~/Views/Shared/{0}.aspx",
        "~/Views/Shared/{0}.ascx"
    };
    

    【讨论】:

      【解决方案8】:

      我为使其正常工作所做的工作如下:

      1. 我在根/Controllers 文件夹中创建了一个默认控制器。我将控制器命名为 DefaultController。
      2. 在控制器中我添加了以下代码:

        namespace MyNameSpace.Controllers {
        public class DefaultController : Controller {
            // GET: Default
            public ActionResult Index() {
                return RedirectToAction("Index", "ControllerName", new {area = "FolderName"});
            }
        } }
        
      3. 在我的 RouterConfig.cs 中,我添加了以下内容:

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

      这一切背后的诀窍是我创建了一个默认构造函数,每次我的应用程序启动时它始终是启动控制器。当它点击该默认控制器时,它将重定向到我在默认索引操作中指定的任何控制器。在我的情况下是

      www.myurl.com/FolderName/ControllerName

      .

      【讨论】:

        【解决方案9】:
        routes.MapRoute(
                        "Area",
                        "{area}/",
                        new { area = "AreaZ", controller = "ControlerX ", action = "ActionY " }
                    );
        

        你试过了吗?

        【讨论】:

        • 是的,问题在于现在该站点在根目录中查找视图。未找到视图“ActionY”或其主视图。搜索了以下位置:~/Views/ActionY/ActionY.aspx ~/Views/ActionY/ActionY.ascx ~/Views/Shared/ActionY.aspx ~/Views/Shared/ActionY.ascx
        • 我明白了。我将尝试找到解决方案。为问题 +1
        【解决方案10】:

        定位不同的构建块是在请求生命周期中完成的。 ASP.NET MVC 请求生命周期中的第一步是将请求的 URL 映射到正确的控制器操作方法。这个过程称为路由。默认路由在 Global.asax 文件中初始化,并向 ASP.NET MVC 框架描述如何处理请求。双击MvcApplication1项目中的Global.asax文件会显示如下代码:

        using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing;
        
        namespace MvcApplication1 {
        
           public class GlobalApplication : System.Web.HttpApplication
           {
               public static void RegisterRoutes(RouteCollection routes)
               {
                   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        
                   routes.MapRoute(
                       "Default",                                          // Route name
                       "{controller}/{action}/{id}",                       // URL with parameters
                       new { controller = "Home", action = "Index",
                             id = "" }  // Parameter defaults
                   );
        
               }
        
               protected void Application_Start()
               {
                   RegisterRoutes(RouteTable.Routes);
               }
           }
        
        }
        

        在 Application_Start() 事件处理程序中,每当编译应用程序或重新启动 Web 服务器时都会触发该事件处理程序,它会注册一个路由表。默认路由名为 Default,并以 http://www.example.com/{controller}/{action}/{id} 的形式响应 URL。 { 和 } 之间的变量使用请求 URL 中的实际值填充,如果 URL 中没有覆盖,则使用默认值填充。此默认路由将根据默认路由参数映射到 Home 控制器和 Index 操作方法。我们不会对这个路由图进行任何其他操作。

        默认情况下,所有可能的 URL 都可以通过此默认路由进行映射。也可以创建我们自己的路线。例如,让我们将 URL http://www.example.com/Employee/Maarten 映射到 Employee 控制器、Show 操作和 firstname 参数。下面的代码 sn -p 可以插入到我们刚刚打开的 Global.asax 文件中。因为ASP.NET MVC框架使用的是第一个匹配路由,所以这段代码sn -p应该插入到默认路由上面;否则该路由将永远不会被使用。

        routes.MapRoute(
        
           "EmployeeShow",                    // Route name
           "Employee/{firstname}",            // URL with parameters
            new {                             // Parameter defaults
               controller = "Employee",
               action = "Show", 
               firstname = "" 
           }  
        
        );
        

        现在,让我们为这条路线添加必要的组件。首先,在 Controllers 文件夹中创建一个名为 EmployeeController 的类。您可以通过向项目中添加一个新项目并选择位于 Web | 下的 MVC 控制器类模板来完成此操作。 MVC 类别。删除 Index 操作方法,并将其替换为名为 Show 的方法或操作。此方法接受 firstname 参数并将数据传递到 ViewData 字典。视图将使用该字典来显示数据。

        EmployeeController 类会将一个 Employee 对象传递给视图。这个 Employee 类应该被添加到 Models 文件夹中(右键单击这个文件夹,然后从上下文菜单中选择 Add | Class)。这是 Employee 类的代码:

        namespace MvcApplication1.Models {
        
           public class Employee
           {
               public string FirstName { get; set; }
               public string LastName { get; set; }
               public string Email { get; set; }
           }
        
        } 
        

        【讨论】:

        • 谢谢,不过我不太确定这与设置默认区域有何关系。 :-/
        【解决方案11】:

        好吧,虽然创建自定义视图引擎可以解决这个问题,但您仍然可以有其他选择:

        • 决定您需要默认显示的内容。
        • 那个东西有控制器和动作(和区域),对吧?
        • 打开该区域注册并添加如下内容:
        public override void RegisterArea(AreaRegistrationContext context)
        {
            //this makes it work for the empty url (just domain) to act as current Area.
            context.MapRoute(
                "Area_empty",
                "",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces: new string[] { "Area controller namespace" }
            );
                //other routes of the area
        }
        

        干杯!

        【讨论】:

        • 同意。虽然我认为这个路由定义更合适的地方是在 Global.asax 文件中。
        • 在这种情况下,您的 global.asax 定义会知道区域控制器命名空间的存在,我认为这是不对的。区域是一项附加功能,这意味着您必须能够在不触及 global.asax 定义的情况下添加/删除一个。在我解决这个问题的方法中,我更喜欢一个区域来“接管”请求,而不是一个 [全球] 网站来“移交”请求。
        【解决方案12】:

        这个问题的公认解决方案是,虽然在总结如何创建自定义视图引擎方面是正确的,但没有正确回答这个问题。这里的问题是 Pino 错误地指定了他的默认路线。特别是他的“区域”定义是不正确的。 “区域”是通过 DataTokens 集合检查的,应该这样添加:

        var defaultRoute = new Route("",new RouteValueDictionary(){{"controller","Default"},{"action","Index"}},null/*constraints*/,new RouteValueDictionary(){{"area","Admin"}},new MvcRouteHandler());
        defaultRoute.DataTokens.Add("Namespaces","MyProject.Web.Admin.Controller"); 
        routes.Add(defaultRoute);
        

        默认对象中指定的“区域”将被忽略。上面的代码创建了一个默认路由,它捕获对您站点根目录的请求,然后调用默认控制器,管理区域中的索引操作。另请注意将“命名空间”键添加到 DataTokens,仅当您有多个具有相同名称的控制器时才需要。此解决方案已通过 Mvc2 和 Mvc3 .NET 3.5/4.0 验证

        【讨论】:

          【解决方案13】:

          ummm,我不知道为什么要这么编程,我认为通过指定这个默认路由很容易解决原来的问题......

          routes.MapRoute("Default", "{*id}", 
                           new { controller = "Home"
                               , action = "Index"
                               , id = UrlParameter.Optional 
                               }
                        );
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-01-22
            • 1970-01-01
            相关资源
            最近更新 更多