ASP.NET MVC-Grouping Controllers
好久没有写文章了,有时候想写点东西但是又不知该写点什么。总觉得微软的技术不错,但是就是更新的太快,也许我们也老了。很多人还在用VS2003写东西,因为他们觉得够用了,而且升级到VS2008上,大家也都不能确定会有多少Code需要重构,所以还沿用至今。最近一直在关注ASP.NET MVC的东西,感觉微软有后发制人的想法,虽然明年才能发布(也不知道会不会跳票,估计是等VS一起发布)但是现在但是可以用这个东西做点事情了,毕竟ASP.NET MVC中很多思想和模式都已经渐渐成熟了,个人觉得这是个好东东,但是需要更多的指导手册。在ASP.net站点上有一套screencast不错,将一个完整的MVC应用的设计开发过程都展示出来,而且有Code可以下载学习。
很多初学者会发现Route是一个不好搞定的东东,默认情况下新建的ASP.NET MVC项目会建立Controller/Views/Models目录,但是大多数情况下,我们的应用结构肯定不是这个样子的例如
WebApp/
WebApp/Areas/
WebApp/Areas/HR
WebApp/Areas/HR/Controller
WebApp/Areas/HR/Views
WebApp/Areas/HR/Models
WebApp/Controller
WebApp/Views
WebApp/Models
这样规划开起来更清晰,但是需要我们对于Route做一些特殊的处理,我们需要对于Controller和View做相应的扩展,因为我们的View中页面和空间的位置以及Controller的名称空间都发生了变化。我们需要做一个自定义的WebFormViewEngine并扩展RouteCollection对于Controller映射方法
在WebFormViewEngine中我们需要重载FindPartialView和FindView方法,以便于MVC在Render的时候可以找到相应的.ascx和aspx。在扩展RouteCollection是主要是需要重新映射Controller的名称空间。
接下来只需要在Global.asax.cs中使用MapAreas和MapRootAreas注册你的Route,并ViewEngines.Engines中添加我们的的WebFormViewEngine 就可以了。
下面是相应的代码片段
public class AreaViewEngine : WebFormViewEngine {
public AreaViewEngine() : base() {
ViewLocationFormats = new[] {
"~/{0}.aspx",
"~/{0}.ascx",
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
};
MasterLocationFormats = new[] {
"~/{0}.master",
"~/Shared/{0}.master",
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master",
};
PartialViewLocationFormats = ViewLocationFormats;
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaPartialName = FormatViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, areaPartialName);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindPartialView(controllerContext, partialViewName);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaViewName = FormatViewName(controllerContext, viewName);
areaResult = base.FindView(controllerContext, areaViewName, masterName);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindView(controllerContext, viewName, masterName);
}
private static string FormatViewName(ControllerContext controllerContext, string viewName) {
string controllerName = controllerContext.RouteData.GetRequiredString("controller");
string area = controllerContext.RouteData.Values["area"].ToString();
return "Areas/" + area + "/Views/" + controllerName + "/" + viewName;
}
private static string FormatSharedViewName(ControllerContext controllerContext, string viewName) {
string area = controllerContext.RouteData.Values["area"].ToString();
return "Areas/" + area + "/Views/Shared/" + viewName;
}
}
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 = "Home", 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="root", action = "Index", controller = "Home", id = "" });
routes.Add(route);
}
}
具体的可以参考 http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx
posted on 2008-11-11 14:24:52 by Sun.wei 评论(0) 阅读(3960)