这次给大家带来编写轻量级ajax组件(图文详解),编写轻量级ajax组件的注意事项有哪些,下面就是实战案例,一起来看一下。
通过之前的介绍,我们知道要执行页面对象的方法,核心就是反射,是从请求获取参数并执行指定方法的过程。实际上这和asp.net mvc框架的核心思想很类似,它会解析url,从中获取controller和action名称,然后激活controller对象,从请求获取action参数并执action。在web form平台上,我们把方法写在.aspx.cs中,要实现的就是在页面对象还未生成的情况下,执行指定的方法,然后返回结果。
我们先看实现后几个调用例子,这些功能也可以组合使用:
[AjaxMethod]
public void Test1(int index)
{
//简单调用
}
[AjaxMethod]
public string Test2(Test test)
{
return "参数为一个Test实例";
}
[AjaxMethod(OutputCache = 20)]
public string Test3(int index)
{
return "输出结果缓存20秒";
}
[AjaxMethod(ServerCache = 20)]
public string Test4()
{
return "在服务端缓存20秒";
}
[AjaxMethod(SessionState=SessionState.None)]
public void Test5()
{
//Session未被加载
}
[AjaxMethod(SessionState = SessionState.ReadOnly)]
public void Test6()
{
//Session只能读不能写
}
[AjaxMethod(SessionState = SessionState.ReadWrite)]
public void Test7()
{
//Session可以读写
}
[AjaxMethod(IsAsync = true)]
public void Test8()
{
//异步调用
}前面我们已经熟悉基本的执行流程,现在直接进入主题。
Ajax约定
通常现在主流浏览器在使用ajax发送异步请求时,请求头都会带上一个:X-Requested-With:XMLHttpRequest 的标记。我们也可以直接通过这个标记来判断是不是ajax请求,不过项目中可能有用其它的组件,为了不相互影响,我们加入一个自定义的请求头。这里为:
internal static class AjaxConfig
{
///
/// 请求头Ajax标记键
///
public const string Key = "AjaxFlag";
///
/// 请求头Ajax标记值
///
public const string Value = "XHR";
///
/// 请求头Ajax方法标记
///
public const string MethodName = "";
}意思是如果http 的请求头包含一个 AjaxFlag : XHR,就是我们要处理的。另外http header的MethodName就表示我们要执行的方法的名称。
AjaxMethodAttribute标记属性
标记属性是给反射用的,在这里定义我们需要的一些功能。我们希望有:
1. 可以配置Session状态
2. 支持异步Handler
3. 支持Get缓存
4. 支持服务端缓存
定义如下,用AttributeUsag标记该标记只能用于方法上。
////// ajax方法标记属性 /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class AjaxMethodAttribute : Attribute { public AjaxMethodAttribute() { } private SessionState _sessionState = SessionState.None; private int _outputCache = 0; private int _serverCache = 0; private ContentType _contentType = ContentType.Plain; private bool _isUseAsync = false; ////// session状态 /// public SessionState SessionState { get { return _sessionState; } set { _sessionState = value; } } ////// 客户端缓存时间,以秒为单位。该标记只对get请求有效 /// public int OutputCache { get { return _outputCache; } set { _outputCache = value; } } ////// 服务端缓存时间,以秒为单位 /// public int ServerCache { get { return _serverCache; } set { _serverCache = value; } } ////// 输出类型(默认为text/plain) /// public ContentType ContentType { get { return _contentType; } set { _contentType = value; } } ////// 使用启用异步处理 /// public bool IsAsync { get { return _isUseAsync; } set { _isUseAsync = value; } } } ////// Session状态 /// public enum SessionState { None, ReadOnly, ReadWrite } ////// 输出内容类型 /// public enum ContentType { Plain, Html, XML, Javascript, JSON }
各种处理程序和AjaxHandlerFactory
按照上一篇的说法,具体的Handler主要分为两类,异步和非异步;这两类下,对于Session的状态又有3三种,不支持、只支持读(实现IReadOnlySessionState接口)、支持读写(实现IRequiresSessionState接口)。IReadOnlySessionState和IRequiresSessionState都只是标记接口(无任何方法,其实应该用标记属性实现比较合理)。异步的Handler需要实现IHttpAsyncHandler接口,该接口又实现了IHttpHandler。Handler的ProcessRequest方法(或BeginProcessRequest)就是我们要执行方法的地方。定义如下:
非异步状态的Handler:
//不支持Session
internal class SyncAjaxHandler : IHttpHandler
{
private Page _page;
private CacheMethodInfo _cacheMethodInfo;
internal SyncAjaxHandler(Page page, CacheMethodInfo cacheMethodInfo)
{
_page = page;
_cacheMethodInfo = cacheMethodInfo;
}
public void ProcessRequest(HttpContext context)
{
//执行方法(下面详细介绍)
Executor.Execute(_page, context, _cacheMethodInfo);
}
public bool IsReusable
{
get { return false; }
}
public static SyncAjaxHandler CreateHandler(Page page, CacheMethodInfo cacheMethodInfo, SessionState state)
{
switch (state)
{
case SessionState.ReadOnly:
return new SyncAjaxSessionReadOnlyHandler(page, cacheMethodInfo);
case SessionState.ReadWrite:
return new SyncAjaxSessionHandler(page, cacheMethodInfo);
default:
return new SyncAjaxHandler(page, cacheMethodInfo);
}
}
}
//支持只读Session
internal class SyncAjaxSessionReadOnlyHandler : SyncAjaxHandler, IReadOnlySessionState
{
internal SyncAjaxSessionReadOnlyHandler(Page page, CacheMethodInfo cacheMethodInfo)
: base(page, cacheMethodInfo)
{
}
}
//支持读写Session
internal class SyncAjaxSessionHandler : SyncAjaxHandler, IRequiresSessionState
{
internal SyncAjaxSessionHandler(Page page, CacheMethodInfo cacheMethodInfo)
: base(page, cacheMethodInfo)
{
}
}异步状态的Handler:
//不支持Session
internal class ASyncAjaxHandler : IHttpAsyncHandler, IHttpHandler
{
private Page _page;
private CacheMethodInfo _cacheMethodInfo;
internal ASyncAjaxHandler(Page page, CacheMethodInfo cacheMethodInfo)
{
_page = page;
_cacheMethodInfo = cacheMethodInfo;
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
//执行方法(下面详细介绍)
Action action = new Action(Executor.Execute);
IAsyncResult result = action.BeginInvoke(_page, context, _cacheMethodInfo, cb, action);
return result;
}
public void EndProcessRequest(IAsyncResult result)
{
Action action = result.AsyncState as Action;
action.EndInvoke(result);
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
public bool IsReusable
{
get { return false; }
}
public static ASyncAjaxHandler CreateHandler(Page page, CacheMethodInfo cacheMethodInfo, SessionState state)
{
switch (state)
{
case SessionState.ReadOnly:
return new ASyncAjaxSessionReadOnlyHandler(page, cacheMethodInfo);
case SessionState.ReadWrite:
return new ASyncAjaxSessionHandler(page, cacheMethodInfo);
default:
return new ASyncAjaxHandler(page, cacheMethodInfo);
}
}
}
//支持只读Session
internal class ASyncAjaxSessionReadOnlyHandler : ASyncAjaxHandler, IReadOnlySessionState
{
internal ASyncAjaxSessionReadOnlyHandler(Page page, CacheMethodInfo cacheMethodInfo)
: base(page, cacheMethodInfo)
{
}
}
//支持读写Session
internal class ASyncAjaxSessionHandler : ASyncAjaxHandler, IRequiresSessionState
{
internal ASyncAjaxSessionHandler(Page page, CacheMethodInfo cacheMethodInfo)
: base(page, cacheMethodInfo)
{
}
} AjaxHandlerFactory实现了IHandlerFactory接口,用来根据请求生成具体的Handler,它需要在web.config进行注册使用。AjaxHandlerFactory的GetHandler是我们拦截请求的第一步。通过请求头的AjaxFlag:XHR来判断是否需要我们处理,如果是,则创建一个Handler,否则按照普通的方式进行。由于我们的方法是写在.aspx.cs内的,我们的请求是.aspx后缀的,也就是页面(Page,实现了IHttpHandler)类型,Page是通过PageHandlerFactory创建的,PageHandlerFactory也实现了IHandlerFactory接口,表示它是用来创建处理程序的。所以我们需要用PageHandlerFactory来创建一个IHttpHandler,不过PageHandlerFactory的构造函数是protected internal类型的,我们无法直接new一个,所以需要通过一个CommonPageHandlerFactory继承它来实现。
通过PageHandlerFactory获得Page后,结合方法名称,我们就可以反射获取AjaxMethodAttribute标记属性了。然后根据它的相关属性生成具体的Handler。具体代码如下:
internal class CommonPageHandlerFactory : PageHandlerFactory { }
internal class AjaxHandlerFactory : IHttpHandlerFactory
{
public void ReleaseHandler(IHttpHandler handler)
{
}
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
HttpRequest request = context.Request;
if (string.Compare(request.Headers[AjaxConfig.Key], AjaxConfig.Value, true) == 0)
{
//检查函数标记
string methodName = request.Headers[AjaxConfig.MethodName];
if (methodName.IsNullOrEmpty())
{
Executor.EndCurrentRequest(context, "方法名称未正确指定!");
return null;
}
try
{
CommonPageHandlerFactory ajaxPageHandler = new CommonPageHandlerFactory();
IHttpHandler handler = ajaxPageHandler.GetHandler(context, requestType, url, pathTranslated);
Page page = handler as Page;
if (page == null)
{
Executor.EndCurrentRequest(context, "处理程序类型必须是aspx页面!");
return null;
}
return GetHandler(page, methodName, context);
}
catch
{
Executor.EndCurrentRequest(context, url + " 不存在!");
return null;
}
}
if (url.EndsWith(".aspx", StringComparison.CurrentCultureIgnoreCase))
{
CommonPageHandlerFactory orgPageHandler = new CommonPageHandlerFactory();
return orgPageHandler.GetHandler(context, requestType, url, pathTranslated);
}
return null;
}
///
/// 获取自定义处理程序
///
/// 处理页面
/// 处理方法
/// 当前请求
private IHttpHandler GetHandler(Page page, string methodName, HttpContext context)
{
//根据Page和MethodName进行反射,获取标记属性(下面详细介绍)
CacheMethodInfo methodInfo = Executor.GetDelegateInfo(page, methodName);
if (methodInfo == null)
{
Executor.EndCurrentRequest(context, "找不到指定的Ajax方法!");
return null;
}
AjaxMethodAttribute attribute = methodInfo.AjaxMethodAttribute;
if (attribute.ServerCache > 0)
{
//先查找缓存
object data = CacheHelper.TryGetCache(context);
if (data != null)
{
Executor.EndCurrentRequest(context, data);
return null;
}
}
if (attribute.IsAsync)
{
//异步处理程序
return ASyncAjaxHandler.CreateHandler(page, methodInfo, attribute.SessionState);
}
return SyncAjaxHandler.CreateHandler(page, methodInfo, attribute.SessionState);
}
}上面的CacheMethodInfo是用于缓存调用方法的相关信息的,第一篇我们有提到过优化缓存的一些方法,其中就包括缓存+委托。但这里我们并不直接缓存方法的MethodInfo,因为缓存MethodInfo的话,需要通过Invoke去执行,这样的效率比较低。这里我缓存的是方法的委托,该委托的签名为:Func
////// 缓存方法信息 /// sealed class CacheMethodInfo { ////// 方法名称 /// public string MethodName { get; set; } ////// 方法委托 /// public Func
核心方法
1. Eexcutor.GetDelegateInfo 获取方法相关信息
该方法用于遍历页面类,获取所有AjaxMethodAttribute标记的方法信息,生成一个CacheMethodInfo对象,包括标记信息、方法名称、参数信息,以及最重要的方法委托。该对象会缓存在一个哈希表中,下次获取时,直接从内存获得。
////// 获取页面标记方法信息 /// /// 页面对象 /// 方法名称 internal static CacheMethodInfo GetDelegateInfo(Page page, string methodName) { if (page == null) { throw new ArgumentNullException("page"); } Type type = page.GetType(); //ajaxDelegateTable是一个Hashtable Dictionarydic = ajaxDelegateTable[type.AssemblyQualifiedName] as Dictionary ; if (dic == null) { dic = new Dictionary (); //遍历页面的所有MethodInfo IEnumerable infos = (from m in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) let ca = m.GetCustomAttributes(typeof(AjaxMethodAttribute), false).FirstOrDefault() where ca != null select new CacheMethodInfo { //方法标记属性 AjaxMethodAttribute = ca as AjaxMethodAttribute, //方法名称 MethodName = m.Name, //方法参数信息 Parameters = m.GetParameters() }); if (infos.IsNullOrEmpty()) { return null; } for (int i = 0, length = infos.Count(); i < length; i++) { CacheMethodInfo cacheMethodInfo = infos.ElementAt(i); string name = cacheMethodInfo.MethodName; MethodInfo methodInfo = type.GetMethod(name); if (!dic.ContainsKey(name)) { //根据MethodInfo获取方法委托 cacheMethodInfo.Func = ReflectionUtil.GetMethodDelegate(methodInfo); dic.Add(name, cacheMethodInfo); } } ajaxDelegateTable[type.AssemblyQualifiedName] = dic; } CacheMethodInfo currentMethodInfo = null; dic.TryGetValue(methodName, out currentMethodInfo); return currentMethodInfo; }
获取方法的委托的是通过一个ReflectionUtil获得的,该类主要用来优化反射,它通过Expression,可以将MethodInfo编译成Func
通过Expression优化反射
Expression(表达式树)允许我们将代码逻辑以表达式的形式存储在树状结构里,然后在运行时去动态解析,实现动态编辑和执行代码。熟悉ORM框架的朋友对Expression肯定很熟悉,因为大部分方法都有一个Expression
.net定义了许多表达式类型,这些类型都派生自Expression,Expression是一个抽象类,而且是一个工厂类,所有类型的表达式都通过它来创建。如图:
先看一个 1 * 2 + 2 例子,我们用表达树来描述来描述它:
/*
* a * b + 2
*/
/*
直接操作
int a = 1, b = 2;
int result = a * 2 + 2;
*/
/*
通过委托调用
Func func = new Func((a, b) => { return a * b + 2; });
func(1, 2);
*/
/*通过Expression调用*/
//定义两个参数
ParameterExpression pe1 = Expression.Parameter(typeof(int), "a");
ParameterExpression pe2 = Expression.Parameter(typeof(int), "b");
//定义一个常量
ConstantExpression constExpression = Expression.Constant(2);
//参数数组
ParameterExpression[] parametersExpression = new ParameterExpression[]{pe1,pe2};
//一个乘法运算
BinaryExpression multiplyExpression = Expression.Multiply(pe1, pe2);
//一个加法运算
BinaryExpression unaryExpression = Expression.Add(multiplyExpression, constExpression);
//将上面的表达式转换为一个委托表达式
LambdaExpression lambdaExpression = Expression.Lambda>(unaryExpression, parametersExpression);
//将委托编译成可执行代码
Func func = lambdaExpression.Compile() as Func;
Console.WriteLine(func(1, 2)); 可以看到我们最终将其编译为一个具体类型的委托了。下面看我们真正用到的方法是如何实现的,代码如下:
public static FuncGetMethodDelegate(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } //定义参数表达式,它表示委托的第一个参数 ParameterExpression instanceExp = Expression.Parameter(typeof(object), "instance"); //定义参数表达式,它表示委托的第二个参数 ParameterExpression paramExp = Expression.Parameter(typeof(object[]), "parameters"); //获取方法的参数信息数组 ParameterInfo[] paramInfos = methodInfo.GetParameters(); //参数表达式集合 List paramExpList = new List (); int length = paramInfos.Length; for (int i = 0; i < length; i++) { //获取paramExp参数数组的第i个元素 BinaryExpression valueObj = Expression.ArrayIndex(paramExp, Expression.Constant(i)); //将其转换为与参数类型一致的类型 UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType); //添加到参数集合 paramExpList.Add(valueCast); } //方法所属的实例的表达式,如果为静态则为null UnaryExpression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceExp, methodInfo.ReflectedType); //表示调用方法的表达式 MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, paramExpList); //将表达式目录描述的lambda编译为可执行代码(委托) if (methodCall.Type == typeof(void)) { Expression > lambda = Expression.Lambda >(methodCall, instanceExp, paramExp); Action action = lambda.Compile(); return (instance, parameters) => { action(instance, parameters); return null; }; } else { UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object)); Expression > lambda = Expression.Lambda >(castMethodCall, instanceExp, paramExp); return lambda.Compile(); } }
具体代码都有注释解释,最终我们获得了一个Func
2. Executor.Execute 执行委托
在执行委托前,我们需要先从请求获取参数,映射到方法。参数可以是简单的类型,如 string Test(int i,int j); 也可以是一个对象,如 string Test(User user); 如果是 string Test(User user1, User user2) 也行,提交参数时只需要加上 user1或 user2 前缀即可,例如 user1.Name,user2.Name。这里没有支持更多的匹配方式,像mvc,它还支持嵌套类型等等,这些可以自己去实现。如果参数是一个对象,我们可能需要为它的字段进行赋值,也可能为它的属性进行赋值。这里我们定义一个DataMember,用来表示字段或属性的父类。如:
internal abstract class DataMember
{
public abstract string Name { get; }
public abstract Type MemberType { get; }
public abstract void SetValue(object instance,object value);
public abstract object GetValue(object instance);
}接着定义属性类型PropertyMember和字段类型FieldMember,分别继承了DataMember。
PropertyMember定义:
internal class PropertyMember : DataMember
{
private PropertyInfo property;
public PropertyMember(PropertyInfo property)
{
if (property == null)
{
throw new ArgumentNullException("property");
}
this.property = property;
}
public override void SetValue(object instance, object value)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
this.property.SetValue(instance, value, null);
}
public override object GetValue(object instance)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
return this.property.GetValue(instance,null);
}
public override string Name
{
get { return this.property.Name; }
}
public override Type MemberType
{
get { return this.property.PropertyType; }
}
}FieldMember定义:
internal class FieldMember : DataMember
{
private FieldInfo field;
public FieldMember(FieldInfo field)
{
if (field == null)
{
throw new ArgumentNullException("field");
}
this.field = field;
}
public override void SetValue(object instance, object value)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
this.field.SetValue(instance, value);
}
public override object GetValue(object instance)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
return this.field.GetValue(instance);
}
public override string Name
{
get { return this.field.Name;}
}
public override Type MemberType
{
get { return this.field.FieldType; }
}
}定义一个DataMemberManager,用来遍历Type,获取所有字段和属性的,实现如下:
internal static class DataMemberManager
{
///
/// 获取实例字段/属性集合
///
/// 类型
///
public static List GetDataMember(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
IEnumerable propertyMembers = from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
select new PropertyMember(property);
IEnumerable fieldMembers = from field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)
select new FieldMember(field);
List members = new List();
foreach(var property in propertyMembers)
{
members.Add(property);
}
foreach (var field in fieldMembers)
{
members.Add(field);
}
return members;
}
} 在前面我们定义的Handler的ProcessRequest方法中,我们调用了Executor.Execute,该方法用于执行委托,实现如下:
////// 核心函数,执行Handler的方法 /// /// 页面对象 /// 请求上下文 /// 缓存方法原数据 internal static void Execute(Page page, HttpContext context, CacheMethodInfo methodInfo) { if (page == null) { throw new ArgumentNullException("page"); } try { if (methodInfo != null) { HttpRequest request = context.Request; object[] parameters = GetParametersFromRequest(request, methodInfo.Parameters); object data = methodInfo.Func(page, parameters); int serverCache = methodInfo.AjaxMethodAttribute.ServerCache; if (serverCache > 0) { CacheHelper.Insert(context, methodInfo.AjaxMethodAttribute.ServerCache, data); } EndCurrentRequest(context, data, methodInfo.AjaxMethodAttribute.OutputCache); } else { EndCurrentRequest(context, "找不到合适的Ajax方法!"); } } catch (FormatException) { EndCurrentRequest(context, "调用方法匹配到无效的参数!"); } catch (InvalidCastException) { EndCurrentRequest(context, "参数转换出错!"); } catch (System.Threading.ThreadAbortException) { //do nothing } catch (Exception ex) { EndCurrentRequest(context, ex.Message); } }
CacheMethodInfo我们已经获得了,现在只要获得参数我们就可以执行方法。
GetParameterFromRequest用于从请求获取object[]参数数组。根据上面所说的,如果参数是一个简单类型,那么直接进行转换;如果是实例对象,那么我们先要创建new一个实例对象,然后为其字段或属性赋值。实现如下:
////// 从请求获取参参数 /// /// HttpRequest ///参数信息 ///参数数组 private static object[] GetParametersFromRequest(HttpRequest request, ParameterInfo[] parameters) { if (parameters.IsNullOrEmpty()) { return null; } int length = parameters.Length; object[] realParameters = new object[length]; for (int i = 0; i < length; i++) { ParameterInfo pi = parameters[i]; Type piType = pi.ParameterType.GetRealType(); object value = null; if (piType.IsValueType()) { //值类型 value = ModelUtil.GetValue(request, pi.Name, piType); value = value ?? Activator.CreateInstance(piType); } else if (piType.IsClass) { //引用类型 object model = ModelUtil.CreateModel(piType); ModelUtil.FillModelByRequest(request, pi.Name, piType, model); value = model; } else { throw new NotSupportedException(pi.Name + " 参数不被支持"); } realParameters[i] = value; } return realParameters; }
ModelUtil会从Http Request获取参数,并进行类型转换处理:
internal static class ModelUtil
{
///
/// 缓存构造函数
///
private static Hashtable constructorTable = Hashtable.Synchronized(new Hashtable());
///
/// 根据名称从HttpRequest获取值
///
/// HttpRequest
/// 键名称
/// 参数类型
///
public static object GetValue(HttpRequest request, string name, Type type)
{
string[] values = null;
if (string.Compare(request.RequestType, "POST", true) == 0)
{
values = request.Form.GetValues(name);
}
else
{
values = request.QueryString.GetValues(name);
}
if (values.IsNullOrEmpty())
{
return null;
}
string data = values.Length == 1 ? values[0] : string.Join(",", values);
return Convert.ChangeType(data, type);
}
///
/// 创建实例对象
///
/// 实例类型
///
public static object CreateModel(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
Func func = constructorTable[type.AssemblyQualifiedName] as Func;
if (func == null)
{
func = ReflectionUtil.GetConstructorDelegate(type);
constructorTable[type.AssemblyQualifiedName] = func;
}
if (func != null)
{
return func();
}
return null;
}
///
/// 填充模型
///
/// HttpRequest
/// 键名称
/// 参数类型
/// 实例对象
public static void FillModelByRequest(HttpRequest request, string name, Type type, object model)
{
if (model == null)
{
return;
}
IEnumerable members = DataMemberManager.GetDataMember(type);
if (members.IsNullOrEmpty())
{
return;
}
object value = null;
foreach (DataMember member in members)
{
value = GetValue(request, string.Format("{0}.{1}", name, member.Name), member.MemberType);
value = value ?? GetValue(request, member.Name, member.MemberType);
member.SetValue(model, value);
}
}
} 如果是引用类型,需要通过构造函数创建对象,像前面用于,这里我们也用Expression来构建一个Func
////// 获取构造函数委托 /// /// 实例类型 ///public static Func GetConstructorDelegate(Type type) { if (type == null) { throw new ArgumentNullException("type"); } ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes); if (ci == null) { throw new MissingMemberException("类型必须有一个无参public构造函数!"); } NewExpression newExp = Expression.New(type); Expression > lambda = Expression.Lambda >(newExp); return lambda.Compile(); }
最后再输出结果时,如果是Get请求,并且需要缓存,我们还需要设置一下Response.Cache。如下:
private static void EndRequest(HttpContext context, object data, int outPutCache, ContentType contentType)
{
HttpResponse response = context.Response;
if (outPutCache != 0)
{
if (string.Compare(context.Request.HttpMethod, "GET", true) == 0)
{
if (outPutCache > 0)
{
response.Cache.SetCacheability(HttpCacheability.Public);
response.Cache.SetMaxAge(new TimeSpan(0, 0, outPutCache));
response.Cache.SetExpires(DateTime.Now.AddSeconds(outPutCache));
}
else
{
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.Cache.SetNoStore();
}
}
}
response.ContentType = GetContentType(contentType);
response.ContentEncoding = System.Text.Encoding.UTF8;
if (data != null)
{
response.Write(data);
}
response.End();
}
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:










