mvc模拟实现
.定义httpmodule
<system.webServer>
<modules>
<add name="UrlRoutingModule" type="WebApp.UrlRoutingModule,WebApp"/>
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
.对应的mvc类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Compilation;
using System.Web.UI;
using System.Web.UI.WebControls; namespace WebApp
{
/// <summary>
/// 二次封装的请求上下文:包括原始的HttpContextBase和经过提取的路由数据对象
/// </summary>
public class RequestContext
{
public virtual HttpContextBase HttpContext { get; set; }
public virtual RouteData RouteData { get; set; }
}
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
public abstract class RouteBase
{
public abstract RouteData GetRouteData(HttpContextBase httpContext);
}
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 Route : RouteBase
{
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();
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
IDictionary<string, object> variables;
//如 AppRelativeCurrentExecutionFilePath的值~/home/index,前两个是~/我们从第三位取值,
//所以substring(2)的结果是home/index match返回返回符合路由规则的路由参数这里 字典里controller:"home",action:"index"
if (this.Match(httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(), out variables))
{
RouteData routeData = new RouteData();
foreach (var item in variables)
{
routeData.Values.Add(item.Key, item.Value); }
foreach (var item in DataTokens)
{
routeData.DataTokens.Add(item.Key, item.Value); }
routeData.RouteHandler = this.RouteHandler;
return routeData;
}
return null;
} 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 = ; i < strArray2.Length; i++)
{
if (strArray2[i].StartsWith("{") && strArray2[i].EndsWith("}"))
{
variables.Add(strArray2[i].Trim("{}".ToCharArray()), strArray1[i]);
}
}
return true;
}
} 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)
{
//便利global.asax添加的路由规则
foreach (RouteBase route in this.Values)
{
//比如获取得到其中的某一条路由规则 "{Controller}/{Action}" 比如我们请求地址/home/index 对应的数据层次就像routeData.Value=["Controller":"home","Action":"index"]
//routeData.RouteHandler=MvcHandler
RouteData routeData = route.GetRouteData(httpContext);
if (routeData != null)
{
return routeData;
}
}
return null;
}
}
public class UrlRoutingModule : IHttpModule
{
public void Dispose()
{ } public void Init(HttpApplication context)
{
context.PostResolveRequestCache += onPostResolveRequestCache;
} public virtual void onPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextWrapper httpContext = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);
if (routeData == null)
{
return;
}
RequestContext requestContext = new RequestContext
{ RouteData = routeData,
HttpContext = httpContext
};
IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);//这里返回MvcHandler
httpContext.RemapHandler(handler);//UrlRoutingModule使用MvcHandler处理器处理,调用响应的processrequest方法 }
}
public class MvcRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MvcHandler(requestContext);
}
}
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);
}
}
public interface IController
{
void Execute(RequestContext requestContext);
}
public interface IControllerFactory
{
IController CreateController(RequestContext requestContext, string controllerName);
}
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 DefaultControllerFactry : IControllerFactory
{
private static List<Type> controllerTypes = new List<Type>();
/// <summary>
/// 构造函数加载所有的控制器类的类型放在controllerTypes
/// </summary>
static DefaultControllerFactry()
{
foreach (Assembly assembly in BuildManager.GetReferencedAssemblies())
{
foreach (Type type in assembly.GetTypes().Where(type => typeof(IController).IsAssignableFrom(type)))
{
controllerTypes.Add(type);
}
}
} /// <summary>
/// 通过controllerTypes集合和具体的控制器名称controllerName,反射创建对应控制器
/// </summary>
/// <param name="requestContext"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
public IController CreateController(RequestContext requestContext, string controllerName)
{
string typeName = controllerName + "Controller";
Type controllerType = controllerTypes.FirstOrDefault(c => string.Compare(typeName, c.Name, true) == );
if (controllerType == null)
{
return null;
}
return (IController)Activator.CreateInstance(controllerType);
}
} public 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 interface IActionInvoker
{
void InvokeAction(ControllerContext context, string actionName);
}
/// <summary>
/// 控制器上下文:包含控制器和二次封装过的RequestContext请求上下文
/// </summary>
public class ControllerContext
{
/// <summary>
/// 包含使用的控制器
/// </summary>
public ControllerBase Controller { get; set; }
public RequestContext RequestContext { get; set; }
}
public class ControllerActionInvoker : IActionInvoker
{
public IModelBinder ModelBinder { get; private set; }
public ControllerActionInvoker()
{
this.ModelBinder = new DefaultModelBinder();
}
public void InvokeAction(ControllerContext controllerContext, string actionName)
{
MethodInfo method = controllerContext.Controller.GetType().GetMethods()
.First(m => string.Compare(actionName, m.Name, true) == );
List<object> parameters = new List<object>();
foreach (ParameterInfo parameter in method.GetParameters())
{
//把请求的参数绑定对应方法参数的模型上
parameters.Add(this.ModelBinder.BindModel(controllerContext,
parameter.Name, parameter.ParameterType));
}
ActionResult actionResult = method.Invoke(controllerContext.Controller, parameters.ToArray()) as ActionResult;
actionResult.ExecuteResult(controllerContext);
}
}
public interface IModelBinder
{
object BindModel(ControllerContext controllerContext, string modelName, Type modelType);
}
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)
{
System.Collections.Specialized.NameValueCollection form = HttpContext.Current.Request.Form;
string key;
if (null != form)
{
key = form.AllKeys.FirstOrDefault(k => string.Compare(k, modelName, true) == );
if (key != null)
{
value = Convert.ChangeType(form[key], modelType);
return true;
} }
key = controllerContext.RequestContext.RouteData.Values
.Where(item => string.Compare(item.Key, modelName, true) == )
.Select(item => item.Key).FirstOrDefault();
if (null != key)
{
value = Convert.ChangeType(controllerContext.RequestContext.RouteData.Values[key], modelType);
return true;
}
key = controllerContext.RequestContext.RouteData.DataTokens
.Where(item => string.Compare(item.Key, modelName, true) == )
.Select(item => item.Key).FirstOrDefault(); if (null != key)
{
value = Convert.ChangeType(controllerContext.RequestContext.RouteData.DataTokens[key], modelType);
return true;
}
value = null;
return false;
} }
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
public class RawContentResult : ActionResult
{
public string RawData { get; private set; }
public RawContentResult(string rawData)
{
RawData = rawData;
}
public override void ExecuteResult(ControllerContext context)
{
context.RequestContext.HttpContext.Response.Write(this.RawData);
}
}
public class SimpleModel
{
public string Controller { get; set; }
public string Action { get; set; }
}
public class HomeController : ControllerBase
{
public ActionResult Index(SimpleModel model)
{
string content = string.Format("Controller:{0}<br/>Action:{1}", model.Controller, model.Action);
return new RawContentResult(content);
}
}
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ }
}
}
.global.asax
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Compilation;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState; namespace WebApp
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// 在应用程序启动时运行的代码
//RouteConfig.RegisterRoutes(RouteTable.Routes);
//BundleConfig.RegisterBundles(BundleTable.Bundles); RouteTable.Routes.Add("default",
new Route { Url = "{Controller}/{Action}" }); ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactry());
}
} }
mvc模拟实现的更多相关文章
- asp.net MVC 模拟实现与源码分析
前言 本文流程#1: 从一个空项目->模拟实现一个从/Home/Test形式的URL敲入->后台逻辑处理->传入后台model参数->调用razor引擎->前台展示 涉及 ...
- Spring MVC 模拟
在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...
- asp.net mvc 模拟百度搜索
页面代码: <td><span>*</span>车牌号码:</td> <td> <div id="search"& ...
- Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建
MVC之前的那点事儿系列 解读ASP.NET 5 & MVC6系列 MVC模拟(摘自ASP.NET MVC5框架揭秘) Asp.net中,通过HttpModule的形式定义拦截器,也就是路由表 ...
- ASP.NET MVC 基础
ASP.NET MVC oo1 Mvc准备工作课程安排:ORM->AspNet MVC开发环境:VS2012/VS2013SqlServer2008/2005主讲Asp.Net Mvc4 Raz ...
- Spring Cloud(中文版)
原文链接:Spring Cloud I.云原生应用 Spring Cloud上下文:应用上下文服务 2.1.Bootstrap应用程序上下文 2.2.应用程序上下文层次结构 2.3.更改Bootstr ...
- AuthorizeAttribute示例
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- 一、ASP.NET MVC 路由(一)--- ASP.NET WebForm路由模拟
ASP.NET WebForm 应用,用户请求的是物理文件,其中包括静态页面和动态页面,在Url中的显示都是服务器中一个物理文件的相对路径.但是ASP.NET MVC就不同了,用户请求的是Contro ...
- [转]模拟HttpContext 实现ASP.NET MVC 的单元测试
众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过 ...
随机推荐
- Java调用Bat
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.Input ...
- 0_Simple__simpleMultiCopy
利用 CUDA 的 Overlap 特性同时进行运算和数据拷贝来实现加速. ▶ 源代码.使用 4 个流一共执行 10 次 “数据上传 - 内核计算 - 数据下载” 过程,记录使用时间. #includ ...
- 使用three.js开发3d地图初探
three是图形引擎,而web二维三维地图都是基于图形引擎的,所以拿three来开发需求简单的三维地图应用是没什么问题的. 1.坐标转换 实际地理坐标为经度.纬度.高度,而three.js使用的是右手 ...
- 3.为什么要使用struts2代替struts1.x
转自:https://blog.csdn.net/li15365002374/article/details/9166431?utm_source=blogxgwz1 (1)struts2的execu ...
- 使用AngularJS处理单选框和复选框的简单方法
在复选框中,可以绑定ng-model给false或者true值,即可选中或清除选中状态 如下图 而在单选框里就相对复杂一点,单选框要选中一个,就要给相同的name属性,然后绑定相同的ng-model, ...
- heat 用法 示例
heat.exe dir "./SampleFolder" -cg Files -dr INSTALLDIR -gg -g1 -sf -srd -var "var.Tar ...
- python中带下划线的变量和函数的意义
表示私有属性,只能在自己的实例方法里面访问. self.__name会被编译成self._Bar__name以达到“不被外部访问”的效果 示例如下: 变量: 1. 前带_的变量: 标明是一个私有变 ...
- Status Code:405 Method Not Allowed
场景: 前端调用方法的时候,调不通,并且报错信息为405 因为我们公司前后端分离开发,于是前端就来找我说我写的接口有问题?于是我就在这里的postman中测试发现没问题啊. 然后我好好看了一下报错信息 ...
- 如何将Wav文件做到EXE文件里
1)编写.RC文件 ..RC文件是资源的源文件,编译器也就编译这个文件,生成.RES的资源文件 首先在我们的项目子目录中建立一个纯文本文件,起名叫Sound.rc,文件中 有一行,内容为: SOUND ...
- 2017面向对象程序设计(Java)第三周学习总结
白驹过隙,日月如梭,一转眼,我们已经度过了第三周的学习时光,随着时间的一天天流逝,我么对知识的积累也逐渐增多.当然,我们还有许许多多需要改进的地方.下面,我将对第三周的助教工作进行总结,望老师及同学们 ...