今天闲逛时看到MVC 2.0的一些新特性,其中一样就是:提供域划分功能(Areas)。MVC 1.0刚发布的时候,我就为这个东西纠结过一段时间,后来在老外的Blog上看到了一个简单的解决方案,一直都在用,现整理出来,给有需要的同学做个参考。
园子里对这个功能关注的人好象不是很多,所以对此功能稍做一下解释。域划分简单的说就是按功能来划分模块。如用户模块(User)及文章模块(Article),每个模块都有好几个Controller,也许我们需要把模块分别放在独立的命名空间下。在Url上,模块划分体现为:/{Area}/{Controller}/{Action}。(可能我说的不大清楚,尚不明白的请自行到网上搜索)
以下为步骤:
1.把Controller按模块分类。
2.为模块设计路由
3.更换模板引擎(见上图)
4.将视图移至Area文件夹(路径为/{Area}/{Controller}/{Action})
以下为实现
1.为路由添加area
代码
using System.Web.Routing;
namespace Madnet.DevMvc
{
public static class RouteHelper
{
public static void CreateArea(this RouteCollection routes, string areaName, string[] controllersNamespace, params Route[] routeEntries)
{
foreach (var route in routeEntries)
{
if (route.Constraints == null) route.Constraints = new RouteValueDictionary();
if (route.Defaults == null) route.Defaults = new RouteValueDictionary();
if (route.DataTokens == null) route.DataTokens = new RouteValueDictionary();
route.Constraints.Add("area", areaName);
route.Defaults.Add("area", areaName);
route.DataTokens.Add("namespaces", controllersNamespace);
if (!routes.Contains(route)) // To support "new Route()" in addition to "routes.MapRoute()"
routes.Add(route);
}
}
}
}
namespace Madnet.DevMvc
{
public static class RouteHelper
{
public static void CreateArea(this RouteCollection routes, string areaName, string[] controllersNamespace, params Route[] routeEntries)
{
foreach (var route in routeEntries)
{
if (route.Constraints == null) route.Constraints = new RouteValueDictionary();
if (route.Defaults == null) route.Defaults = new RouteValueDictionary();
if (route.DataTokens == null) route.DataTokens = new RouteValueDictionary();
route.Constraints.Add("area", areaName);
route.Defaults.Add("area", areaName);
route.DataTokens.Add("namespaces", controllersNamespace);
if (!routes.Contains(route)) // To support "new Route()" in addition to "routes.MapRoute()"
routes.Add(route);
}
}
}
}
2.改造模板引擎,以满足基于area的模板路径搜索
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace Madnet.DevMvc
{
public class DefaultViewEngine: WebFormViewEngine
{
public DefaultViewEngine()
: 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;
}
#region IViewEngine Members
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaPartialName = FormatViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, areaPartialName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaViewName = FormatViewName(controllerContext, viewName);
string masterAreaViewName = FormatMasterViewName(controllerContext, masterName);
areaResult = base.FindView(controllerContext, areaViewName, masterAreaViewName, useCache);
if (areaResult != null && areaResult.View != null)
{
return areaResult;
}
areaResult = base.FindView(controllerContext, areaViewName, masterName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
areaResult = base.FindView(controllerContext, sharedAreaViewName, masterAreaViewName, useCache);
if (areaResult != null && areaResult.View != null)
{
return areaResult;
}
areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindView(controllerContext, viewName, masterName, useCache);
}
#endregion IViewEngine Members
private static string FormatViewName(ControllerContext controllerContext, string viewName)
{
string controllerName = controllerContext.RouteData.GetRequiredString("controller");
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/" + controllerName + "/" + viewName;
}
private static string FormatSharedViewName(ControllerContext controllerContext, string viewName)
{
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/Shared/" + viewName;
}
private static string FormatMasterViewName(ControllerContext controllerContext, string masterName)
{
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/Masters/" + masterName;
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace Madnet.DevMvc
{
public class DefaultViewEngine: WebFormViewEngine
{
public DefaultViewEngine()
: 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;
}
#region IViewEngine Members
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaPartialName = FormatViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, areaPartialName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
ViewEngineResult areaResult = null;
if (controllerContext.RouteData.Values.ContainsKey("area")) {
string areaViewName = FormatViewName(controllerContext, viewName);
string masterAreaViewName = FormatMasterViewName(controllerContext, masterName);
areaResult = base.FindView(controllerContext, areaViewName, masterAreaViewName, useCache);
if (areaResult != null && areaResult.View != null)
{
return areaResult;
}
areaResult = base.FindView(controllerContext, areaViewName, masterName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
areaResult = base.FindView(controllerContext, sharedAreaViewName, masterAreaViewName, useCache);
if (areaResult != null && areaResult.View != null)
{
return areaResult;
}
areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName, useCache);
if (areaResult != null && areaResult.View != null) {
return areaResult;
}
}
return base.FindView(controllerContext, viewName, masterName, useCache);
}
#endregion IViewEngine Members
private static string FormatViewName(ControllerContext controllerContext, string viewName)
{
string controllerName = controllerContext.RouteData.GetRequiredString("controller");
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/" + controllerName + "/" + viewName;
}
private static string FormatSharedViewName(ControllerContext controllerContext, string viewName)
{
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/Shared/" + viewName;
}
private static string FormatMasterViewName(ControllerContext controllerContext, string masterName)
{
string area = controllerContext.RouteData.Values["area"].ToString();
return "Views/" + (string.IsNullOrEmpty(area) ? "" : (area + "/")) + "/Masters/" + masterName;
}
}
}
--------------------------------------
http://www.qwolf.com/