写一个简单的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:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config;
.Net4.0配置文件地址(32位):C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.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定义如下:
public class WebMethodHttpHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable
{
get { return false; }
} public void ProcessRequest(HttpContext context)
{
var request = context.Request;
var arr = request.Path.Split('/'); string controllerName = arr[arr.Length - ];
string methodName = Path.GetFileNameWithoutExtension(arr[arr.Length - ]); var factory = ControllerBuilder.Current.GetControllerFactory();
var obj = factory.CreateController(controllerName, methodName);
var result = obj.Execute(request.Params); var js = new JavaScriptSerializer();
string json = js.Serialize(result);
context.Response.ContentType = "json/plain";
context.Response.Write(json);
}
}
代码很简单,WebMethodHttpHandler实现了两个接口,分别是IHttpHandler和 IRequiresSessionState。在方法ProcessRequest中把请求的路径URL根据"/"拆分成一个数组,分别获得业务类Controller和它的方法名,再调用DefaultControllerFactory使用反射技术动态生成RemotingObject实例,最后调用RemotingObject的Execute方法返回Json数据。好了,我们看看ControllerBuilder 的定义:
public class ControllerBuilder
{
private static ControllerBuilder _instance = null;
private static object syncObj = new object(); private Func<DefaultControllerFactory> func = null; private ControllerBuilder()
{
SetControllerFactory(new DefaultControllerFactory());
} public static ControllerBuilder Current
{
get
{
if (_instance == null)
{
lock (syncObj)
{
if (_instance == null)
{
_instance = new ControllerBuilder();
}
}
}
return _instance;
}
} public void SetControllerFactory(DefaultControllerFactory controllerFactory)
{
if (controllerFactory == null)
{
throw new ArgumentNullException("controllerFactory");
} func = () => controllerFactory;
} public DefaultControllerFactory GetControllerFactory()
{
return func();
}
}
ControllerBuilder类定义很简单就是一个单例模式,用于返回DefaultControllerFactory。DefaultControllerFactory定义:
public sealed class DefaultControllerFactory
{
private static object _controllerTypeCacheLock = new object();
private static ControllerTypeCache _controllerTypeCache = new ControllerTypeCache();
private readonly string key = "{0}.{1}"; /// <summary>
/// 创建Controller-Method
/// </summary>
/// <param name="controllerName">Controller名称</param>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
public RemotingObject CreateController(string controllerName, string methodName)
{
if (string.IsNullOrEmpty(controllerName) || string.IsNullOrEmpty(methodName))
{
throw new Exception("controllerName or methodName is null");
} if (!_controllerTypeCache.Initialized)
{
lock (_controllerTypeCacheLock)
{
if (!_controllerTypeCache.Initialized)
{
_controllerTypeCache.Initialize();
} var assemblies = BuildManager.GetReferencedAssemblies(); foreach (Assembly asm in assemblies)
{
foreach (Type t in asm.GetTypes())
{
//类型t是否继承IController
if (typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
&& t != typeof(IController))
{
var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.DeclaredOnly); foreach (var method in methods)
{
if (!_controllerTypeCache.ContainsController(string.Format(key, t.Name, method.Name)))
{
_controllerTypeCache.AddControllerType(CreateRemotingObject(t, method.Name));
}
}
}
}
}
}
} controllerName = controllerName.EndsWith("Controller") ? controllerName : controllerName + "Controller"; return _controllerTypeCache.GetControllerType(string.Format(key, controllerName, methodName));
} public RemotingObject CreateRemotingObject(Type type, string methodName)
{
if (type == null)
{
throw new Exception(string.Format("类型null不存在!"));
} var method = type.GetMethods().ToList().Find(p => p.Name.ToLowerInvariant() == methodName.ToLowerInvariant()); if (method == null)
{
throw new Exception(string.Format("类:{0}不存在方法名:{1}", type.FullName, methodName));
} return new RemotingObject
{
Request = string.Format(key, type.Name, methodName),
ControlObject = (IController)Activator.CreateInstance(type),
Method = method
};
}
}
RemotingObject定义如下:
public class RemotingObject
{
/// <summary>
/// 请求地址
/// </summary>
public string Request { get; set; } /// <summary>
/// control实例
/// </summary>
public IController ControlObject { get; set; } /// <summary>
/// 所调用方法
/// </summary>
public MethodInfo Method { get; set; } public object Execute(NameValueCollection collection)
{
var parameters = new object[Method.GetParameters().Length];
int i = ; foreach (var parameter in Method.GetParameters())
{
var item =
collection.AllKeys.ToList().Find(
p => string.Equals(parameter.Name, p, StringComparison.OrdinalIgnoreCase)); if (item != null)
{
parameters[i] = Convert.ChangeType(collection[item], parameter.ParameterType);
i++;
}
} return Method.Invoke(ControlObject, parameters);
}
}
ControllerTypeCache定义如下:
/// <summary>
/// Controller集合缓存
/// </summary>
internal sealed class ControllerTypeCache
{
private Dictionary<string, RemotingObject> _controllerCache = new Dictionary<string, RemotingObject>(StringComparer.OrdinalIgnoreCase);
private bool _initialized; /// <summary>
/// RemotingObject个数
/// </summary>
public int Count
{
get
{
return _controllerCache.Count;
}
} /// <summary>
/// 是否已加载
/// </summary>
public bool Initialized
{
get
{
return _initialized;
}
} public void Initialize()
{
_initialized = true;
} /// <summary>
/// 添加controllerType
/// </summary>
/// <param name="name"></param>
/// <param name="controllerType"></param>
public void AddControllerType(RemotingObject controllerType)
{
_controllerCache[controllerType.Request] = controllerType;
} public bool ContainsController(string name)
{
return _controllerCache.ContainsKey(name);
} /// <summary>
/// 根据name获取Controller-Method
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public RemotingObject GetControllerType(string name)
{
return _controllerCache[name];
}
}
介绍完核心类后,在介绍下Controller,我的Controller结构如图:
UserController定义如下:
/// <summary>
/// /用户Controller
/// </summary> public class UserController : IController
{
public object GetUserInfo()
{
return new
{
ID=,
Name="喜羊羊",
Age=,
Address="北京"
};
}
}
UserController定义很简单,跟普通类没什么区别,只是继承了IController,IController只是一个标志接口,定义如下:
public interface IController
{
}
好了,介绍完框架的核心类。要让网站运行起来,我们还需要再做两件事情。
第一步:在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:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_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>
现在可以预览了,在浏览器中输入UserInfo.htm页面地址,会等到如下结果:
好了,感谢阅读,希望这篇文章能给你带来帮助!
写一个简单的Web框架的更多相关文章
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
- 一个简单的web框架实现
一个简单的web框架实现 #!/usr/bin/env python # -- coding: utf-8 -- __author__ = 'EchoRep' from wsgiref.simple_ ...
- 如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...
- Python学习 - 编写一个简单的web框架(二)
在上一篇日志中已经讨论和实现了根据url执行相应应用,在我阅读了bottle.py官方文档后,按照bottle的设计重写一遍,主要借鉴大牛们的设计思想. 一个bottle.py的简单实例 来看看bot ...
- 【Java学习笔记】如何写一个简单的Web Service
本Guide利用Eclipse以及Ant建立一个简单的Web Service,以演示Web Service的基本开发过程: 1.系统条件: Eclipse Java EE IDE for Web De ...
- express 写一个简单的web app
之前写过一个简单的web app, 能够完成注册登录,展示列表,CURD 但是版本好像旧了,今天想写一个简单的API 供移动端调用 1.下载最新的node https://nodejs.org/zh- ...
随机推荐
- Win7搭建NodeJs开发环境
Win7搭建NodeJs开发环境以及HelloWorld展示—图解 Windows 7系统下搭建NodeJs开发环境(NodeJs+WebStrom)以及Hello World!展示,大体思路如下:第 ...
- 在windows下用C语言写socket通讯实例
原文:在windows下用C语言写socket通讯实例 From:Microsoft Dev Center #undef UNICODE #define WIN32_LEAN_AND_MEAN #in ...
- 安卓CTS官方文档之兼容性方案概览
兼容性方案概览 安卓的兼容性方案让安卓手机生产商能够很容易就开发中可兼容的安卓设备(天地会珠海分舵注:可兼容什么呢?就是可以兼容标准google提供的安卓系统可以支持的功能,以防手机生产商把开源的安卓 ...
- DDD实践2
DDD实践切入点(二) 承前:大型系统的支撑,应用系统开发思想的变迁,DDD实践切入点(一) 从大比例结构入手已经开始了系统的建设,大家都知道需求是会不断变化不断深入的,刚开始自然是模糊的大比例结构对 ...
- [转]Android与电脑局域网共享之:Samba Server
大家都有这样的经历,通过我的电脑或网上邻居访问另一台计算机上的共享资源,虽然电脑和手机之间可以有多种数据传输方式,但通过Windows SMB方式进行共享估计使用的人并不是太多,下面我就简单介绍一下, ...
- win7 64位系统装oracle11 提示环境变量path 值超过1023字符
win7 64位系统装oracle10 提示环境变量path 值超过1023字符 1.提示环境变量path 值超过1023字符. 方案: 1.oracle安装文件,右键属性--设置兼容性--兼容XP ...
- Printk 标志优先级别
#define KERN_EMERG "<0>" /* 致命级:紧急事件消息,系统崩溃之前提示,表示系统不可用 */# ...
- KMP 代码 暂存
#include <stdio.h> #include <string.h> ],B[]; ]; int n, m; void _next(){ ; ; next[] = ; ...
- IIS发布网站,浏览网站时候,出现 试图加载格式不正确的程序。
异常来自HRESULT:0x8007000B 缘由:在64位操作系统下IIS发布32位的项目,报“项目依赖的dll无法读取,试图加载格式不正确的程序”错误. 原因:程序集之间的通讯要么全是64位环境下 ...
- CHD4 impala安装配置
impala基于CHD,提供针对HDFS,hbase的实时查询,查询语句类似于hive 包括几个组件 Clients:提供Hue, ODBC clients, JDBC clients, and th ...