zoukankan      html  css  js  c++  java
  • 写一个简单的Web框架

      在.Net中有两种常用的Web开发方式,一种是Asp.Net WebForm,另一种是Asp.Net MVC。我先简单的给大家介绍下这两种开发方式的特点,然后再应用自定义脚本映射,反射,json2template.js,htm等技术演示一个纯静态的Web框架。

      Asp.Net WebForm

      在Asp.Net WebForm中,请求大都以.aspx为后缀,那么.Net是如何处理.aspx请求呢? 打开.Net的配置文件,

      .Net4.0配置文件地址(64位):C:WindowsMicrosoft.NETFramework64v4.0.30319Configweb.config;

      .Net4.0配置文件地址(32位):C:WindowsMicrosoft.NETFrameworkv4.0.30319Configweb.config。

      找到HttpHandlers的配置信息如下:

          <httpHandlers>
                <add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
                <add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True" />
                <add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True" />
                <add verb="*" path="*_AppService.axd" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False" />
                <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
                <add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
                <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />       ................................................

    从以上配置信息可以看出所有的*.aspx请求都是交给PageHandlerFactory处理工厂去处理的。PageHandlerFactory定义如下:

      public class PageHandlerFactory : IHttpHandlerFactory2, IHttpHandlerFactory
        {
            public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path);
            private IHttpHandler GetHandlerHelper(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath);
            public virtual void ReleaseHandler(IHttpHandler handler);
            IHttpHandler IHttpHandlerFactory2.GetHandler(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath);
        }

    调用PageHandlerFactory的GetHandler会生成一个Page(IHttpHandler)类,然后调用Page类的ProcessRequest方法,再渲染*.aspx中的控件,最后生成Html给Response。如图:

     

      Asp.Net MVC

        在Asp.Net MVC中,所有的请求都交给UrlRoutingModule处理。通过UrlRoutingModule得到一个MvcRouteHandler。调用MvcRouteHandler的GetHttpHandler方法返回MvcHandler。然后调用MvcHandler的ProcessRequest方法,通过反射创建Controller实例,并执行其方法。如图:

          

         

          在Asp.Net WebForm和Asp.Net Mvc中,其实都是生成一个IHttpHandler的类,并调用其ProcessRequest方法,通过不同的渲染方式,把最终结果返回给用户。

      

      框架

          好了,WebForm和MVC就介绍到这里,下面开始写自己的框架了。我们知道Asp.Net MVC 包括:UrlRoutingModule(Url处理) + View(*.aspx)+Controller+ViewEngine,而我的框架包括:
         WebMethodHttpHandler(处理中心)+View(*.htm)+Controller(业务类)+Js(json2template.js渲染器),呵呵,跟Asp.Net MVC有点像。如图:

      

          框架中,静态页面都是以.htm为后缀,如:login.htm。动态请求都是以mthd为后缀,如:/User/CheckLogin.mthd。动态请求URL地址有一定的含义:如:/User/CheckLogin.mthd中,User代表业务处理类 UserController,CheckLogin就是UserController的一个方法(验证用户登录的方法)。

         我们已经知道,不管是WebForm还是Mvc,最终都需要生成一个IHttpHandler的类去处理请求。在我的框架中,我打算模仿WebForm对于*.aspx的处理方式,定义一个IHttpHandler去处理*.mthd请求。这个IHttpHandler的类定义为 WebMethodHttpHandler。WebMethodHttpHandler定义如下:

      

     1 public class WebMethodHttpHandler : IHttpHandler, IRequiresSessionState
     2     {
     3         public bool IsReusable
     4         {
     5             get { return false; }
     6         }
     7 
     8         public void ProcessRequest(HttpContext context)
     9         {
    10             var request = context.Request;
    11             var arr = request.Path.Split('/');
    12 
    13             string controllerName = arr[arr.Length - 2];
    14             string methodName = Path.GetFileNameWithoutExtension(arr[arr.Length - 1]);
    15 
    16             var factory = ControllerBuilder.Current.GetControllerFactory();
    17             var obj = factory.CreateController(controllerName, methodName);
    18             var result = obj.Execute(request.Params);
    19 
    20             var js = new JavaScriptSerializer();
    21             string json = js.Serialize(result);
    22             context.Response.ContentType = "json/plain";
    23             context.Response.Write(json);
    24         }
    25     }
    View Code

      代码很简单,WebMethodHttpHandler实现了两个接口,分别是IHttpHandler和 IRequiresSessionState。在方法ProcessRequest中把请求的路径URL根据"/"拆分成一个数组,分别获得业务类Controller和它的方法名,再调用DefaultControllerFactory使用反射技术动态生成RemotingObject实例,最后调用RemotingObject的Execute方法返回Json数据。好了,我们看看ControllerBuilder 的定义:

      

     1  public class ControllerBuilder
     2     {
     3         private static ControllerBuilder _instance = null;
     4         private static object syncObj = new object();
     5 
     6         private Func<DefaultControllerFactory> func = null;
     7 
     8         private ControllerBuilder()
     9         {
    10             SetControllerFactory(new DefaultControllerFactory());
    11         }
    12 
    13         public static ControllerBuilder Current
    14         {
    15             get
    16             {
    17                 if (_instance == null)
    18                 {
    19                     lock (syncObj)
    20                     {
    21                         if (_instance == null)
    22                         {
    23                             _instance = new ControllerBuilder();
    24                         }
    25                     }
    26                 }
    27                 return _instance;
    28             }
    29         }
    30 
    31         public void SetControllerFactory(DefaultControllerFactory controllerFactory)
    32         {
    33             if (controllerFactory == null)
    34             {
    35                 throw new ArgumentNullException("controllerFactory");
    36             }
    37 
    38             func = () => controllerFactory;
    39         }
    40 
    41         public DefaultControllerFactory GetControllerFactory()
    42         {
    43             return func();
    44         }
    45     }
    View Code

         ControllerBuilder类定义很简单就是一个单例模式,用于返回DefaultControllerFactory。DefaultControllerFactory定义:

       

     1 public sealed class DefaultControllerFactory
     2     {
     3         private static object _controllerTypeCacheLock = new object();
     4         private static ControllerTypeCache _controllerTypeCache = new ControllerTypeCache();
     5         private readonly string key = "{0}.{1}";
     6 
     7         /// <summary>
     8         /// 创建Controller-Method
     9         /// </summary>
    10         /// <param name="controllerName">Controller名称</param>
    11         /// <param name="methodName">方法名称</param>
    12         /// <returns></returns>
    13         public RemotingObject CreateController(string controllerName, string methodName)
    14         {
    15             if (string.IsNullOrEmpty(controllerName) || string.IsNullOrEmpty(methodName))
    16             {
    17                 throw new Exception("controllerName or methodName is null");
    18             }
    19 
    20             if (!_controllerTypeCache.Initialized)
    21             {
    22                 lock (_controllerTypeCacheLock)
    23                 {
    24                     if (!_controllerTypeCache.Initialized)
    25                     {
    26                         _controllerTypeCache.Initialize();
    27                     }
    28 
    29                     var assemblies = BuildManager.GetReferencedAssemblies();
    30 
    31                     foreach (Assembly asm in assemblies)
    32                     {
    33                         foreach (Type t in asm.GetTypes())
    34                         {
    35                             //类型t是否继承IController
    36                             if (typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
    37                                 && t != typeof(IController))
    38                             {
    39                                 var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.DeclaredOnly);
    40 
    41                                 foreach (var method in methods)
    42                                 {
    43                                     if (!_controllerTypeCache.ContainsController(string.Format(key, t.Name, method.Name)))
    44                                     {
    45                                         _controllerTypeCache.AddControllerType(CreateRemotingObject(t, method.Name));
    46                                     }
    47                                 }
    48                             }
    49                         }
    50                     }
    51                 }
    52             }
    53 
    54             controllerName = controllerName.EndsWith("Controller") ? controllerName : controllerName + "Controller";
    55 
    56             return _controllerTypeCache.GetControllerType(string.Format(key, controllerName, methodName));
    57         }
    58 
    59         public RemotingObject CreateRemotingObject(Type type, string methodName)
    60         {
    61             if (type == null)
    62             {
    63                 throw new Exception(string.Format("类型null不存在!"));
    64             }
    65 
    66             var method = type.GetMethods().ToList().Find(p => p.Name.ToLowerInvariant() == methodName.ToLowerInvariant());
    67 
    68             if (method == null)
    69             {
    70                 throw new Exception(string.Format("类:{0}不存在方法名:{1}", type.FullName, methodName));
    71             }
    72 
    73             return new RemotingObject
    74             {
    75                 Request = string.Format(key, type.Name, methodName),
    76                 ControlObject = (IController)Activator.CreateInstance(type),
    77                 Method = method
    78             };
    79         }
    80     }
    View Code

        RemotingObject定义如下:

     1 public class RemotingObject
     2     {
     3         /// <summary>
     4         /// 请求地址
     5         /// </summary>
     6         public string Request { get; set; }
     7 
     8         /// <summary>
     9         /// control实例
    10         /// </summary>
    11         public IController ControlObject { get; set; }
    12 
    13         /// <summary>
    14         /// 所调用方法
    15         /// </summary>
    16         public MethodInfo Method { get; set; }
    17 
    18         public object Execute(NameValueCollection collection)
    19         {
    20             var parameters = new object[Method.GetParameters().Length];
    21             int i = 0;
    22 
    23             foreach (var parameter in Method.GetParameters())
    24             {
    25                 var item =
    26                     collection.AllKeys.ToList().Find(
    27                         p => string.Equals(parameter.Name, p, StringComparison.OrdinalIgnoreCase));
    28 
    29                 if (item != null)
    30                 {
    31                     parameters[i] = Convert.ChangeType(collection[item], parameter.ParameterType);
    32                     i++;
    33                 }
    34             }
    35 
    36             return Method.Invoke(ControlObject, parameters);
    37         }
    38     }
    View Code

        ControllerTypeCache定义如下:

      

     1  /// <summary>
     2     /// Controller集合缓存
     3     /// </summary>
     4     internal sealed class ControllerTypeCache
     5     {
     6         private Dictionary<string, RemotingObject> _controllerCache = new Dictionary<string, RemotingObject>(StringComparer.OrdinalIgnoreCase);
     7         private bool _initialized;
     8 
     9         /// <summary>
    10         /// RemotingObject个数
    11         /// </summary>
    12         public int Count
    13         {
    14             get
    15             {
    16                 return _controllerCache.Count;
    17             }
    18         }
    19 
    20         /// <summary>
    21         /// 是否已加载
    22         /// </summary>
    23         public bool Initialized
    24         {
    25             get
    26             {
    27                 return _initialized;
    28             }
    29         }
    30 
    31         public void Initialize()
    32         {
    33             _initialized = true;
    34         }
    35 
    36         /// <summary>
    37         /// 添加controllerType
    38         /// </summary>
    39         /// <param name="name"></param>
    40         /// <param name="controllerType"></param>
    41         public void AddControllerType(RemotingObject controllerType)
    42         {
    43             _controllerCache[controllerType.Request] = controllerType;
    44         }
    45 
    46         public bool ContainsController(string name)
    47         {
    48             return _controllerCache.ContainsKey(name);
    49         }
    50 
    51         /// <summary>
    52         /// 根据name获取Controller-Method
    53         /// </summary>
    54         /// <param name="name"></param>
    55         /// <returns></returns>
    56         public RemotingObject GetControllerType(string name)
    57         {
    58             return _controllerCache[name];
    59         }
    60     }
    View Code

        介绍完核心类后,在介绍下Controller,我的Controller结构如图:

      UserController定义如下:

      

     1 /// <summary>
     2     /// /用户Controller
     3     /// </summary>   
     4 
     5     public class UserController : IController
     6     {
     7         public object GetUserInfo()
     8         {
     9             return new
    10                        {
    11                            ID=1,
    12                            Name="喜羊羊",
    13                            Age=31,
    14                            Address="北京"
    15                        };
    16         }
    17     }
    View Code

      UserController定义很简单,跟普通类没什么区别,只是继承了IController,IController只是一个标志接口,定义如下:

      

     public interface IController
        {
        }
    View Code

        好了,介绍完框架的核心类。要让网站运行起来,我们还需要再做两件事情。

      第一步:在web.config的httpHandlers中注册处理mthd的Handler。

           <httpHandlers>
                <add path="*.mthd" verb="*" type="Elong.Sticker.Core.HttpHandlers.WebMethodHttpHandler,Elong.Sticker.Core" />
             </httpHandlers>

      第二步:添加脚本映射。首先打开IIS,找到处理程序映射,双击打开,找到左边菜单“添加脚本映射”,编辑如下:

       

        "确定"完成,会在站点的web.config中添加

        <system.webServer>
          <modules runAllManagedModulesForAllRequests="true" />
            <handlers>
                <add name="aspnet4Method" path="*.mthd" verb="*" modules="IsapiModule" scriptProcessor="C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
            </handlers>
        </system.webServer>

         新建UserInfo.htm文件,内容如下:

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script src="lib/jquery-1.4.1.min.js" type="text/javascript"></script>
        <script src="lib/json2template.js" type="text/javascript"></script>
    </head>
    <body>
    <div id="userlist">
    <div id="template-userinfo">
    <table width="400" align="center">
    <tr><td>编号</td><td>姓名</td><td>年龄</td><td>地址</td></tr>
    <tr>
    <td width="100">{{ID}}</td>
    <td width="100">{{Name}}</td>
    <td width="100">{{Age}}</td>
    <td width="100">{{Address}}</td>
    </tr>
    </table>
    </div>
    </div>
    
    <script type="text/javascript">
        $(document).ready(function () {
            var dataSouce = {};
            $.ajax(
    {
        url: '/User/GetUserInfo.mthd',
        dataType: "json",
        success: function (data) {
            dataSouce.item = data;
            $("#userlist").bindTemplate({ source: dataSouce, template: $("#template-userinfo") });
        }
    });
        });
    </script>
    </body>
    </html>
    View Code

       现在可以预览了,在浏览器中输入UserInfo.htm页面地址,会等到如下结果:

      

      好了,感谢阅读,希望这篇文章能给你带来帮助!

         源代码

  • 相关阅读:
    教你发布Silverlight Bussiness Application(SQL Server 登录,局域网访问,以及使用ArcGIS Server服务需要注意的问题)
    ArcGIS API for Silverlight 使用GeometryService进行河流网格划分(三)
    ArcGIS Server 10.1发布要素服务时遇到的数据库注册问题总结 (二)
    使用ArcGIS API for Silverlight + Visifire绘制地图统计图
    使用Visifire+ArcGIS API for Silverlight实现Graphic信息的动态图表显示
    报个道
    Cgroups
    docker的文件系统
    go实现http服务
    linux调度器原理
  • 原文地址:https://www.cnblogs.com/xiyangyang/p/3381040.html
Copyright © 2011-2022 走看看