如何在MVC中设置默认路由(到区域)


122

好的,以前已经问过了,但是那里没有固定的解决方案。因此,对于我自己和其他可能会觉得有用的人而言。

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

在Global.asax中使用以下路由

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

现在,它的工作方式就像尝试提供正确的页面一样。但是,MVC继续在站点的根目录而不是Area文件夹中查找View。

有办法解决吗?

编辑

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

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

编辑:

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

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

Answers:


98

这让我很感兴趣,我终于有机会对此进行了研究。其他人显然还不了解这是查找视图的问题,而不是路由本身的问题-这可能是因为您的问题标题表明这与路由有关。

无论如何,由于这是与View相关的问题,因此获得所需内容的唯一方法是覆盖默认View Engine。通常,执行此操作时,它只是出于切换视图引擎的简单目的(即,切换到Spark,NHaml等)。在这种情况下,不是我们需要重写的View-creation逻辑,而是类中的FindPartialViewand FindView方法VirtualPathProviderViewEngine

您可以感谢幸运的明星,因为这些方法实际上是虚拟的,因为VirtualPathProviderViewEngine甚至无法访问其中的所有内容-它是私有的,这使重写查找逻辑变得非常烦人,因为您必须基本上重写已经存在的一半代码如果您希望它与位置缓存和位置格式配合使用,请撰写本文。经过对Reflector的深入研究后,我终于设法提出了一个可行的解决方案。

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

下面的代码相当冗长,因此为您简要介绍了它的实际作用:它使您可以将a {2}放入对应于区域名称的位置格式,也对应于{1}对应于控制器名称的方式。而已!那就是我们必须为以下所有代码编写的代码:

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}将映射到area我们放入中的RouteData。我已经离开了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或存在同样的问题。
LiamB'2

1
@Pino:我认为您应该可以ActionLink通过将相同的代码添加area = "AreaZ"到“默认”路由映射中来解决此问题global.asax.cs。我不是很乐观。试试看。
Aaronaught

在MVC4 “默认”路线declaraton从Global.asax中移动到〜/ App_Start / RouteConfig.cs /的RegisterRoutes()
安德烈F.

3
我讨厌投票,但我实在不敢相信@Chris Alderson的以下回答没有获得更多投票。这是一个很多比这更简单的解决方案,似乎解决了边缘的情况下(ActionLinks等)。
jdmcnair 2014年

看来这里有个错误。例如,名为“ Re”的区域的视图将位于〜/ Areas / Re / Views / Ctrlr / blah.aspx中,但是此处的代码使用的是〜/ {2} / {1} / {0},即〜 /Re/Ctrl/blah.aspx,在路径中缺少关键的Areas目录。它应该是“〜/ Areas / {2} / Views / {1} / {0} .aspx”
Chris Moschini 2015年

100

这就是我的方法。我不知道为什么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文件,它可能会覆盖旧的全局配置。
Mert Akcakaya 2014年

56

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

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

6
这对我来说很棒。我在根目录没有任何控制器,仅使用Areas。对于MVC 4,我将其替换为RouteConfig.cs中的默认值。谢谢!
2013年

2
我正在使用MVC4,这对我来说是最简单的解决方案。允许应用程序将特定区域内的索引视图用作站点的“主页”。
JTech 2013年

2
此解决方案以后将无法使用(从Asp.Net MVC6及更高版本开始)。
Patrick Desjardins,2015年

@PatrickDesjardins:是否支持上述解决方案?
Akash KC

@SeriousM您的回答是常绿的。它仍然有帮助。你救了我一晚。
skpaul

16

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

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

在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"); 
} 

作为有效的hack,但这应该是

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

如果您不想遵循该约定,那么,您可能想要采取一条简短的路径,要么派生自WebFormViewEngine(您可以在构造函数中设置查找路径的)(例如,在MvcContrib中完成),要么-a小hacky-通过在以下方式指定您的约定Application_Start

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

当然,应该更加谨慎地执行此操作,但是我认为这表明了这个想法。这些字段publicVirtualPathProviderViewEngine的MVC 2 RC。


值得注意的是,这仅适用于MVC 2 RC-MVC 1 VirtualPathProviderViewEngine不具有此属性,并且不识别区域。尽管确实有人说这个问题是关于MVC 2的,但很多人仍然没有使用它(并且不会使用一段时间)。因此,对于特定问题,您的答案更容易,但是我的答案是唯一适用于偶然发现此问题的MVC1用户的答案。我想提供不依赖于可能会更改的预发布功能的答案。
亚罗诺(Aaronaught)2010年

它也不是“伪视图引擎”-故意使视图引擎类具有可扩展性,以便可以使用各种视图。
Aaronaught

对不起,那并不是要侮辱您。它是“伪”的,因为它不会显着改变视图的处理方式,而只是替换一些值。
mnemosyn

我并没有感到冒犯,我只是想弄清楚派生自定义视图引擎并不是一个特别不寻常的原因,相关方法是可重写的,这一事实证明了这一点。
Aaronaught

2
关于RegisterAreas前进的秘诀RegisterRoutes。想知道为什么我的代码突然停止工作并注意到该重构;)
webnoob 2014年

6

我想您希望用户访问~/AreaZURL后将其重定向到~/URL。我可以通过root内的以下代码来实现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。真的不理想。
LiamB 2010年

2

首先,您使用的是哪个版本的MVC2?从Preview2到RC进行了重大更改。

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

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

上面的代码会向用户发送到MyRouteController我们的ShopArea每默认。

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

当然,您将必须更改默认路由,Global.asax以免干扰此默认路由,例如,通过为主站点使用前缀。

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

希望这可以帮助。


谢谢,但是我不确定这是否可以解决问题中说明的问题。及其MVC RC
LiamB,2010年

2

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

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"
};

1

为了使它起作用,我做了以下工作:

  1. 我在根目录/控制器文件夹中创建了一个默认控制器。我将控制器命名为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


0
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
LiamB 2010年

2
我明白。我将尝试寻找解决方案。+1的问题
Barbaros Alp 2010年

0

在请求生命周期中找到不同的构建基块。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服务器时触发,并注册了路由表。默认路由名为“默认”,它以http://www.example.com/ {controller} / {action} / {id} 的形式响应URL 。{和}之间的变量将使用请求URL中的实际值或默认值填充(如果URL中不存在替代值)。根据默认的路由参数,此默认路由将映射到Home控制器和Index操作方法。我们不会对此路由图采取任何其他措施。

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

routes.MapRoute(

   "EmployeeShow",                    // Route name
   "Employee/{firstname}",            // URL with parameters
    new {                             // Parameter defaults
       controller = "Employee",
       action = "Show", 
       firstname = "" 
   }  

);

现在,让我们为该路线添加必要的组件。首先,在Controllers文件夹中创建一个名为EmployeeController的类。您可以通过在项目中添加一个新项并选择位于Web | Web页面下的MVC Controller Class模板来完成此操作。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; }
   }

} 

1
谢谢,我不太确定这与设置默认区域有什么关系。:-/
LiamB 2010年

0

好了,尽管创建自定义视图引擎可以解决此问题,但是您仍然可以选择以下方法:

  • 确定默认情况下需要显示的内容。
  • 那东西有控制器和动作(和区域),对吗?
  • 打开该区域注册并添加如下内容:
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文件。
nuhusky2003

在这种情况下,您的global.asax定义将知道区域控制器名称空间的存在,我认为这是不对的。区域是一项新增功能,这意味着您必须能够添加/删除一项而无需触及global.asax定义。在解决这个问题时,我希望使用一个区域来“接管”该请求,而不是使用一个“全球”网站来“接管”该请求。
Tengiz

0

对此问题的公认解决方案是,在总结如何创建自定义视图引擎时是正确的,但不能正确回答该问题。这里的问题是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);

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


-1

恩,我不知道为什么要进行所有这些编程,我认为通过指定此默认路由可以轻松解决原始问题...

routes.MapRoute("Default", "{*id}", 
                 new { controller = "Home"
                     , action = "Index"
                     , id = UrlParameter.Optional 
                     }
              );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.