zoukankan      html  css  js  c++  java
  • Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

    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框架。

    添加单元测试

    使用模版

    简洁版创建

  • 相关阅读:
    在 MVC 控制器中使用 构造函数时行依赖注入 (IoC)
    跟我学 NHibernate (三)
    跟我学 NHibernate (二)
    跟我学 NHibernate (一)
    使用PetaPoco ORM 框架分页查询
    ASP.NET MVC 中使用 AjaxFileUpload 插件时,上传图片后不能显示(预览)
    在 mvc 中使用下拉列表
    String.Join() 方法 的用法
    动态为页面添加CSS样式文件引用
    禁止页面内按F5键进行刷新(扩展知识:禁止复制信息内容)
  • 原文地址:https://www.cnblogs.com/wj033/p/5866591.html
Copyright © 2011-2022 走看看