- MVC之前的那点事儿系列
- http://www.projky.com/asp.netmvc/5.0/
- http://www.cnblogs.com/greatandforever/archive/2010/04/20/1715914.html
MVC模拟(摘自ASP.NET MVC5框架揭秘)
Asp.net中,通过HttpModule的形式定义拦截器,也就是路由表的调用。路由表解析出相应的Controller类型和Action方法的名称及必要参数。然后依据路由数据和请求上下文,选择特定的HttpHandler,采用反射的机制激活目标Controller,执行相应的方法。
实现IHttpModule创建自定义的拦截器
public class UrlRoutingModule : IHttpModule
{
public void Dispose()
{ }
public void Init(HttpApplication context)
{
context.PostResolveRequestCache += OnPostResolveRequestCache;
}
//调用路由表,依据路由数据切换Handler
protected virtual void OnPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextWrapper httpContext = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);
if (null == routeData)
{
return;
}
RequestContext requestContext = new RequestContext
{
RouteData = routeData,
HttpContext = httpContext
};
IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);
httpContext.RemapHandler(handler);
}
}
实现IHttpHandler创建自定义的处理程序
public class MvcHandler : IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public RequestContext RequestContext { get; private set; }
public MvcHandler(RequestContext requestContext)
{
this.RequestContext = requestContext;
}
public void ProcessRequest(HttpContext context)
{
string controllerName = this.RequestContext.RouteData.Controller;
IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();
IController controller = controllerFactory.CreateController(this.RequestContext, controllerName);
controller.Execute(this.RequestContext);
}
}
路由表解析URL
public class RouteTable
{
public static RouteDictionary Routes { get; private set; }
static RouteTable()
{
Routes = new RouteDictionary();
}
}
public class RouteDictionary : Dictionary<string, RouteBase>
{
//路由对象集合,自带遍历匹配路由的方法
public RouteData GetRouteData(HttpContextBase httpContext)
{
foreach (var route in this.Values)
{
RouteData routeData = route.GetRouteData(httpContext);
if (null != routeData)
{
return routeData;
}
}
return null;
}
}
继承RouteBase创建自定义的Route类型
//路由
public class Route : RouteBase
{
//匹配相应的IHttpHandler
public IRouteHandler RouteHandler { get; set; }
//路由模版
public string Url { get; set; }
//限定的命名空间集合
public IDictionary<string, object> DataTokens { get; set; }
public Route()
{
this.DataTokens = new Dictionary<string, object>();
this.RouteHandler = new MvcRouteHandler();
}
//获取路由数据,不匹配则返回null.
public override RouteData GetRouteData(HttpContextBase httpContext)
{
IDictionary<string, object> variables;
if (this.Match(httpContext.Request
.AppRelativeCurrentExecutionFilePath.Substring(2), out variables))
{
//匹配成功
RouteData routeData = new RouteData();
//Controller和Action名称
foreach (var item in variables)
{
routeData.Values.Add(item.Key, item.Value);
}
//模版中限定的命名空间集合
foreach (var item in DataTokens)
{
routeData.DataTokens.Add(item.Key, item.Value);
}
//IHttpHandler路由
routeData.RouteHandler = this.RouteHandler;
return routeData;
}
return null;
}
//判别当前路由对象(this)是否匹配,匹配则找到对应的Controller和Action名称
protected bool Match(string requestUrl, out IDictionary<string, object> variables)
{
variables = new Dictionary<string, object>();
string[] strArray1 = requestUrl.Split('/');
string[] strArray2 = this.Url.Split('/');
if (strArray1.Length != strArray2.Length)
{
return false;
}
for (int i = 0; i < strArray2.Length; i++)
{
if (strArray2[i].StartsWith("{") && strArray2[i].EndsWith("}"))
{
variables.Add(strArray2[i].Trim("{}".ToCharArray()), strArray1[i]);
}
}
return true;
}
}
路由数据
//由路由解析得到的路由数据
public class RouteData
{
public IDictionary<string, object> Values { get; private set; }
public IDictionary<string, object> DataTokens { get; private set; }
public IRouteHandler RouteHandler { get; set; }
public RouteBase Route { get; set; }
public RouteData()
{
this.Values = new Dictionary<string, object>();
this.DataTokens = new Dictionary<string, object>();
this.DataTokens.Add("namespaces", new List<string>());
}
public string Controller
{
get
{
object controllerName = string.Empty;
this.Values.TryGetValue("controller", out controllerName);
return controllerName.ToString();
}
}
public string ActionName
{
get
{
object actionName = string.Empty;
this.Values.TryGetValue("action", out actionName);
return actionName.ToString();
}
}
}
初始化(将自定义的路由对象加入路由表)
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("default", new Route { Url = "{controller}/{action}" });
}
}
实现IRouteHandler自定义HttpHandler提供机制
public class MvcRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MvcHandler(requestContext);
}
}
Controller实例的获取
public class ControllerBuilder
{
private Func<IControllerFactory> factoryThunk;
public static ControllerBuilder Current { get; private set; }
static ControllerBuilder()
{
Current = new ControllerBuilder();
}
public IControllerFactory GetControllerFactory()
{
return factoryThunk();
}
public void SetControllerFactory(IControllerFactory controllerFactory)
{
factoryThunk = () => controllerFactory;
}
}
public class DefaultControllerFactory : IControllerFactory
{
private static List<Type> controllerTypes = new List<Type>();
static DefaultControllerFactory()
{
//查找包内所有IController
foreach (Assembly assembly in BuildManager.GetReferencedAssemblies())
{
foreach (Type type in assembly.GetTypes().Where(type => typeof(IController).IsAssignableFrom(type)))
{
controllerTypes.Add(type);
}
}
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
string typeName = controllerName + "Controller";
Type controllerType = controllerTypes.FirstOrDefault(c => string.Compare(typeName, c.Name, true) == 0);
if (null == controllerType)
{
return null;
}
return (IController)Activator.CreateInstance(controllerType);
}
}
初始化(添加Controller工厂实例)
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory());
}
}
Action方法的执行
public abstract class ControllerBase : IController
{
protected IActionInvoker ActionInvoker { get; set; }
public ControllerBase()
{
this.ActionInvoker = new ControllerActionInvoker();
}
public void Execute(RequestContext requestContext)
{
ControllerContext context = new ControllerContext
{
RequestContext = requestContext,
Controller = this
};
string actionName = requestContext.RouteData.ActionName;
this.ActionInvoker.InvokeAction(context, actionName);
}
}
public class ControllerActionInvoker : IActionInvoker
{
public IModelBinder ModelBinder { get; private set; }
public ControllerActionInvoker()
{
this.ModelBinder = new DefaultModelBinder();
}
public void InvokeAction(ControllerContext controllerContext, string actionName)
{
MethodInfo methodInfo = controllerContext.Controller.GetType().GetMethods().First(m => string.Compare(actionName, m.Name, true) == 0);
List<object> parameters = new List<object>();
foreach (ParameterInfo parameter in methodInfo.GetParameters())
{
parameters.Add(this.ModelBinder.BindModel(controllerContext, parameter.Name, parameter.ParameterType));
}
ActionExecutor executor = new ActionExecutor(methodInfo);
ActionResult actionResult = (ActionResult)executor.Execute(controllerContext.Controller, parameters.ToArray());
actionResult.ExecuteResult(controllerContext);
}
}
internal class ActionExecutor
{
private static Dictionary<MethodInfo, Func<object, object[], object>> executors = new Dictionary<MethodInfo, Func<object, object[], object>>();
private static object syncHelper = new object();
public MethodInfo MethodInfo { get; private set; }
public ActionExecutor(MethodInfo methodInfo)
{
this.MethodInfo = methodInfo;
}
public object Execute(object target, object[] arguments)
{
Func<object, object[], object> executor;
if (!executors.TryGetValue(this.MethodInfo, out executor))
{
lock (syncHelper)
{
if (!executors.TryGetValue(this.MethodInfo, out executor))
{
executor = CreateExecutor(this.MethodInfo);
executors[this.MethodInfo] = executor;
}
}
}
return executor(target, arguments);
}
private static Func<object, object[], object> CreateExecutor(MethodInfo methodInfo)
{
ParameterExpression target = Expression.Parameter(typeof(object), "target");
ParameterExpression arguments = Expression.Parameter(typeof(object[]), "arguments");
List<Expression> parameters = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = 0; i < paramInfos.Length; i++)
{
ParameterInfo paramInfo = paramInfos[i];
BinaryExpression getElementByIndex = Expression.ArrayIndex(arguments, Expression.Constant(i));
UnaryExpression convertToParameterType = Expression.Convert(getElementByIndex, paramInfo.ParameterType);
parameters.Add(convertToParameterType);
}
UnaryExpression instanceCast = Expression.Convert(target, methodInfo.ReflectedType);
MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameters);
UnaryExpression convertToObjectType = Expression.Convert(methodCall, typeof(object));
return Expression.Lambda<Func<object, object[], object>>(convertToObjectType, target, arguments).Compile();
}
}
public class RawContentResult : ActionResult
{
private Action<TextWriter> Callback { get; set; }
public RawContentResult(Action<TextWriter> action)
{
this.Callback = action;
}
public override void ExecuteResult(ControllerContext context)
{
this.Callback(context.RequestContext.HttpContext.Response.Output);
}
}
解析Action的参数
public class DefaultModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, string modelName, Type modelType)
{
if (modelType.IsValueType || typeof(string) == modelType)
{
object instance;
if (GetValueTypeInstance(controllerContext, modelName, modelType, out instance))
{
return instance;
};
return Activator.CreateInstance(modelType);
}
object modelInstance = Activator.CreateInstance(modelType);
foreach (PropertyInfo property in modelType.GetProperties())
{
if (!property.CanWrite || (!property.PropertyType.IsValueType && property.PropertyType != typeof(string)))
{
continue;
}
object propertyValue;
if (GetValueTypeInstance(controllerContext, property.Name,
property.PropertyType, out propertyValue))
{
property.SetValue(modelInstance, propertyValue, null);
}
}
return modelInstance;
}
private bool GetValueTypeInstance(ControllerContext controllerContext, string modelName, Type modelType, out object value)
{
Dictionary<string, object> dataSource = new Dictionary<string, object>();
//数据来源一:HttpContext.Current.Request.Form
foreach (string key in HttpContext.Current.Request.Form)
{
if (dataSource.ContainsKey(key.ToLower()))
{
continue;
}
dataSource.Add(key.ToLower(), HttpContext.Current.Request.Form[key]);
}
//数据来源二:HttpContext.Current.Request.QueryString
foreach (string key in HttpContext.Current.Request.QueryString)
{
if (dataSource.ContainsKey(key.ToLower()))
{
continue;
}
dataSource.Add(key.ToLower(), HttpContext.Current.Request.QueryString[key]);
}
//数据来源三:ControllerContext.RequestContext.RouteData.Values
foreach (var item in controllerContext.RequestContext.RouteData.Values)
{
if (dataSource.ContainsKey(item.Key.ToLower()))
{
continue;
}
dataSource.Add(item.Key.ToLower(), controllerContext.RequestContext.RouteData.Values[item.Key]);
}
//数据来源四:ControllerContext.RequestContext.RouteData.DataTokens
foreach (var item in controllerContext.RequestContext.RouteData.DataTokens)
{
if (dataSource.ContainsKey(item.Key.ToLower()))
{
continue;
}
dataSource.Add(item.Key.ToLower(), controllerContext.RequestContext.RouteData.DataTokens[item.Key]);
}
if (dataSource.TryGetValue(modelName.ToLower(), out value))
{
value = Convert.ChangeType(value, modelType);
return true;
}
return false;
}
}
ActionResult
public class HomeController : ControllerBase
{
public ActionResult Index(SimpleModel model)
{
Action<TextWriter> callback = writer =>
{
writer.Write(string.Format("Controller: {0}<br/>Action: {1}<br/><br/>", model.Controller, model.Action));
writer.Write(string.Format("Foo: {0}<br/>Bar: {1}<br/>Baz: {2}", model.Foo, model.Bar, model.Baz));
};
return new RawContentResult(callback);
}
}
MVC项目搭建
MVC5中只有一种ASP.NET Web Application项目类型。通过NuGet可以在开发过程中可以随时添加对其他框架的支持。
首先可以新建一个空站
可以向其中添加aspx文件做web Form开发。也可以随时引入MVC框架。
添加单元测试