我正在尝试从我的管理区域内部进行错误重定向到我的错误视图,这是在所有区域之外共享的。
我在Lobby控制器上创建了一个名为error的方法:
public ViewResult Error()
{
return View("Views/Shared/Error");
}
视图存在于Views / Shared目录中,称为Error。
在管理区域的我的用户控制器中,我正在尝试:
return RedirectToAction("Error", "Lobby", new {area = ""});
但是,应用程序尝试重定向到“/ Admin / Lobby / Error”,尽管我在路由值中有area =“”。当我尝试单步执行代码时,在上一行和浏览器中的404错误之间没有执行任何行。
我在这里缺少什么?
编辑补充:实际上我的路线可能有问题。我尝试在登录后更改默认行为,直接指向不在某个区域的控制器,它会自动尝试将我发送到我的管理区域。
我正在努力实现的目标:我希望将具有区域的路由解释为需要转到该区域,并且希望没有区域的路由使用默认区域。目前我只有一个区域(管理员),但会有更多。
以下是我的路线:
routes.MapRoute("ErrorPage", "Error", new { controller="Error", action="Error" }, new[] { "WebUI.Controllers" }); //Error Route
routes.MapRoute(
"", // Route name
"Admin/{controller}/{action}/{id}", // URL with parameters
new { area ="Admin", controller = "Client", action = "ManageClients", id = UrlParameter.Optional } // Parameter defaults
, new[] { "WebUI.Areas.Admin.Controllers" } //prioritize admin
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Lobby", action = "Index", id = UrlParameter.Optional } // Parameter defaults
, new[] {"WebUI.Controllers"} //prioritize main
);
IIRC当我尝试使用没有“硬编码”“路径”的路由作为区域名称时,路由引擎尝试将没有区域的路由填充到区域路由中,导致控制器被误认为是区域和控制器的动作。
但是我怀疑它现在正在做什么以某种方式将“/ Admin”附加到我的所有路线上! 例如,应用程序在启动时首先进入帐户/登录(不在某个区域)。当我更改登录行为时转到:
return RedirectToAction("Summary", "Logging");
正在形成一个url / Admin / Logging / Summary而不是/ Logging / Summary。 即使我手动将其更改为
return RedirectToAction("Summary", "Logging", new {area=""});
必须从路线中取“默认”管理区域。但是,如果我从路线中删除默认区域,那么我的管理员会链接所有中断。
这是我的区域注册:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new [] { "WebUI.Areas.Admin.Controllers" }
);
}
所以我想我需要将我的问题改为:我如何配置区域和路线以便路线&区域内外的链接是否正常运行?
答案 0 :(得分:0)
我最终通过修改Phil Haack的AreaRouteHelper扩展来解决问题:
public static class AreaRouteHelper
{
public static void MapAreas(this RouteCollection routes, string url, string rootNamespace, string[] areas)
{
Array.ForEach(areas, area =>
{
Route route = new Route("{area}/" + url, new MvcRouteHandler());
route.Constraints = new RouteValueDictionary(new { area });
string areaNamespace = rootNamespace + ".Areas." + area + ".Controllers";
route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { areaNamespace } });
route.Defaults = new RouteValueDictionary(new { action = "Index", controller = "Landing", id = "" });
routes.Add(route);
});
}
public static void MapRootArea(this RouteCollection routes, string url, string rootNamespace, object defaults)
{
Route route = new Route(url, new MvcRouteHandler());
route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { rootNamespace + ".Controllers" } });
route.Defaults = new RouteValueDictionary(new { area = "", action = "Index", controller = "Lobby", id = "" });
routes.Add(route);
}
}
(基本上我必须从默认的RootArea默认值中删除“root”一词,并将默认值更改为“Lobby”和“Landing”,这是我们的标准而不是Home。当我在那里留下默认的“root”时,它将“root”添加到文件夹结构中,但不起作用)
然后我从RegisterRoutes中删除了后两条路线并替换为:
routes.MapAreas("{controller}/{action}/{id}", "WebUI", new[] { "Admin", "Analysis" });
routes.MapRootArea("{controller}/{action}/{id}",
"WebUI",
new { controller = "Lobby", action = "Index", id = "" });
此修复程序需要区域感知视图引擎。 Haack项目中的一个是一个1.0 webform视图引擎,我已经有了一个区域感知的剃刀视图引擎,我从某个地方的另一个帖子中抓取了这个工作。老实说,我不记得我发现它的帖子,或者我直接链接到它以表示作者。但这就是它的样子(如果有人在这里知道是谁写的,我会高兴地将它归于那个人)。请注意,这里的映射与我的项目相匹配,如果没有一些调整,可能与其他人没有匹配!
public class RazorAreaAwareViewEngine :RazorViewEngine
{
private static readonly string[] EmptyLocations = { };
public RazorAreaAwareViewEngine()
{
MasterLocationFormats = new string[]
{
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master"
};
ViewLocationFormats = new string[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/{2}/{0}.cshtml",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
};
PartialViewLocationFormats = ViewLocationFormats;
}
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 string GetArea(ControllerContext controllerContext)
{
object area = null;
if (controllerContext.RouteData.DataTokens.ContainsKey("area"))
{
area = controllerContext.RouteData.DataTokens["area"];
}
if (area == null)
{
controllerContext.RouteData.Values.TryGetValue("area", out area);
}
if(area !=null)
{
return area.ToString();
}
return null;
}
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 static bool IsSpecificPath(string name)
{
char ch = name[0];
if (ch != '~')
{
return (ch == '/');
}
return true;
}
}
进行这些更改后,内部和外部区域的动作链接都生成正确,我可以在内部和外部进行路由。外面的区域。