gpt4 book ai didi

asp.net-mvc - 如何在 MVC 中设置默认路由(到某个区域)

转载 作者:行者123 更新时间:2023-12-03 04:36:20 25 4
gpt4 key购买 nike

好的,这个问题之前已经被问过,但没有可靠的解决方案。因此,为了我自己和其他可能发现这有用的人的目的。

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

在 Global.asax 中使用以下路由

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

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

有办法解决这个问题吗?

编辑

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

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

编辑:

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

这一切是设计使然还是缺陷?

最佳答案

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

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

您可以感谢您的幸运星,这些方法实际上是虚拟的,因为 VirtualPathProviderViewEngine 中的其他所有内容甚至无法访问 - 它是私有(private)的,这使得重写查找逻辑非常很烦人,因为如果您愿意,您基本上必须重写已经编写的代码的一半它可以与位置缓存和位置格式很好地配合。经过对 Reflector 的一番研究,我终于想出了一个可行的解决方案。

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

下面的代码相当冗长,因此可以快速总结一下它的实际用途:它可以让您输入 {2}转化为位置格式,对应区域名称,同理{1}对应 Controller 名称。就是这样!这就是我们必须编写所有这些代码的目的:

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

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

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注册此 View 引擎:

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

显然我们需要目录结构和 View 来配合它 - 我们将保持这个 super 简单:

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 中编辑几行即可。并创建您的网站结构。

关于asp.net-mvc - 如何在 MVC 中设置默认路由(到某个区域),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2140208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com