Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

时间:2022-09-10 08:40:28

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可以在开发过程中可以随时添加对其他框架的支持。

首先可以新建一个空站

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

可以向其中添加aspx文件做web Form开发。也可以随时引入MVC框架。

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

添加单元测试

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

使用模版

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

简洁版创建

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建的更多相关文章

  1. 七天学会ASP&period;NET MVC &lpar;三&rpar;——ASP&period;Net MVC 数据处理

    第三天我们将学习Asp.Net中数据处理功能,了解数据访问层,EF,以及EF中常用的代码实现方式,创建数据访问层和数据入口,处理Post数据,以及数据验证等功能. 系列文章 七天学会ASP.NET M ...

  2. 七天学会ASP&period;NET MVC &lpar;三&rpar;——ASP&period;Net MVC 数据处理 【转】

    http://www.cnblogs.com/powertoolsteam/p/MVC_three.html 第三天我们将学习Asp.Net中数据处理功能,了解数据访问层,EF,以及EF中常用的代码实 ...

  3. 七天学会ASP&period;NET MVC &lpar;二&rpar;——ASP&period;NET MVC 数据传递

    通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上,因此需要确保您是否掌握了上一节的内容.本章的目标是在今天学习结束时利用最佳实践解决方案创建一个小型的MV ...

  4. 七天来学习ASP&period;NET MVC &lpar;两&rpar;——ASP&period;NET MVC 数据传输

    通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上.因此须要确保您是否掌握了上一节的内容. 本章的目标是在今天学习结束时利用最佳实践解决方式创建一个小型的M ...

  5. 七天学会ASP&period;NET MVC &lpar;二&rpar;——ASP&period;NET MVC 数据传递 【转】

    http://www.cnblogs.com/powertoolsteam/p/MVC_two.html 通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上 ...

  6. 【MVC】ASP&period;NET MVC Forms验证机制

    http://www.cnblogs.com/bomo/p/3309766.html 随笔 - 121  文章 - 0  评论 - 92 [MVC]ASP.NET MVC Forms验证机制 ASP. ...

  7. Pro ASP&period;NET MVC –第六章 MVC的基本工具

    在本章,我们将介绍每个MVC程序员"武器库"的三个重要工具:依赖注入容器.单元测试框架和mock工具.在本书,对于三个工具分别都只用了一种方式实现,但每个工具都还有其他的实现方式. ...

  8. Asp&period;Net MVC 路由 - Asp&period;Net 编程 - 张子阳

    http://cache.baiducontent.com/c?m=9d78d513d98316fa03acd2294d01d6165909c7256b96c4523f8a9c12d522195646 ...

  9. Asp &period;Net MVC4笔记之走进MVC

    一.MVC三层架构: mvc三层架构,大家都比较熟悉了,这里再介绍一下.Mvc将应用程序分离为三个部分: Model:是一组类,用来描述被处理的数据,同时也定义这些数据如何被变更和操作的业务规则.与数 ...

随机推荐

  1. LeetCode - 413&period; Arithmetic Slices - 含中文题意解释 - O&lpar;n&rpar; - &lpar; C&plus;&plus; &rpar; - 解题报告

    1.题目大意 A sequence of number is called arithmetic if it consists of at least three elements and if th ...

  2. web config数据库连接字符串加密

    ASP.NET web.config中,数据库连接字符串的加密与解密 ASP.NET web.config中,数据库连接字符串的加密与解密. 开始--->运行,输入cmd,接着输入以下内容 加密 ...

  3. centOS7虚拟环境搭建

    今天来记录一下使用WMware虚拟机来搭建centOS虚拟机的过程. 本次使用工具为VMware Workstation 14 Pro,可以从https://www.vmware.com/来获取所需工 ...

  4. 火狐浏览器无故卡死,未响应或者占大量cpu资源解决方案

    这是火狐社区的文章,对火狐浏览器无故卡死,未响应或者占大量cpu资源有详细的说明和解决,记录下!!! ++++++++++++++++++++++++++++++++ Firefox 挂起 如果您的 ...

  5. 必读:Spark与kafka010整合

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/rlnLo2pNEfx9c/article/details/79648890 SparkStreami ...

  6. MapReduce调度与执行原理系列文章

    转自:http://blog.csdn.net/jaytalent?viewmode=contents MapReduce调度与执行原理系列文章 一.MapReduce调度与执行原理之作业提交 二.M ...

  7. 将Gridview中的数据出到excel或word中

    在以下按钮单击事件中实现:private void btnMIME_Click(object sender, System.EventArgs e){dgShow.AllowPaging = fals ...

  8. 用IntelliJ IDEA 配置Maven并部署Maven工程到Tomcat(Windows中)

    近几天做一个新项目才接触Intellij IDEA 1.在官网下载了maven 解压并新建一个本地仓库文件夹 2.配置本地仓库路径 3.配置maven环境变量 4.在IntelliJ IDEA中配置m ...

  9. linux——制作本地yum源

    1. 将windows系统中的linux镜像插入到linux系统的光驱中 2. 将光驱挂载到一个挂载点 3. 清缓存:yum clean all 4. 修改配置文件 /etc/yum.repos.d/ ...

  10. python资料汇总

    http://www.cnblogs.com/vamei/archive/2012/09/13/2682778.html