这篇文章主要为大家详细介绍了轻量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
{
/// <summary>
/// 请求头ajax标记键
/// </summary>
public const string key = "ajaxflag";
/// <summary>
/// 请求头ajax标记值
/// </summary>
public const string value = "xhr";
/// <summary>
/// 请求头ajax方法标记
/// </summary>
public const string methodname = "";
}
意思是如果http 的请求头包含一个 ajaxflag : xhr,就是我们要处理的。另外http header的methodname就表示我们要执行的方法的名称。
ajaxmethodattribute标记属性
标记属性是给反射用的,在这里定义我们需要的一些功能。我们希望有:
1. 可以配置session状态
2. 支持异步handler
3. 支持get缓存
4. 支持服务端缓存
定义如下,用attributeusag标记该标记只能用于方法上。
/// <summary>
/// ajax方法标记属性
/// </summary>
[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;
/// <summary>
/// session状态
/// </summary>
public sessionstate sessionstate
{
get { return _sessionstate; }
set { _sessionstate = value; }
}
/// <summary>
/// 客户端缓存时间,以秒为单位。该标记只对get请求有效
/// </summary>
public int outputcache
{
get { return _outputcache; }
set { _outputcache = value; }
}
/// <summary>
/// 服务端缓存时间,以秒为单位
/// </summary>
public int servercache
{
get { return _servercache; }
set { _servercache = value; }
}
/// <summary>
/// 输出类型(默认为text/plain)
/// </summary>
public contenttype contenttype
{
get { return _contenttype; }
set { _contenttype = value; }
}
/// <summary>
/// 使用启用异步处理
/// </summary>
public bool isasync
{
get { return _isuseasync; }
set { _isuseasync = value; }
}
}
/// <summary>
/// session状态
/// </summary>
public enum sessionstate
{
none,
readonly,
readwrite
}
/// <summary>
/// 输出内容类型
/// </summary>
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<page, httpcontext, cachemethodinfo> action = new action<page, httpcontext, cachemethodinfo>(executor.execute);
iasyncresult result = action.begininvoke(_page, context, _cachemethodinfo, cb, action);
return result;
}
public void endprocessrequest(iasyncresult result)
{
action<page, httpcontext, cachemethodinfo> action = result.asyncstate as action<page, httpcontext, cachemethodinfo>;
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;
}
/// <summary>
/// 获取自定义处理程序
/// </summary>
/// <param name="page">处理页面</param>
/// <param name="methodname">处理方法</param>
/// <param name="context">当前请求</param>
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<object, object[], object>,该委托的返回值为object类型,表示可以返回任意的类型(我们可以在组件内部进行处理,例如如果是引用类型(非string),就将其序列化为json,但这里并没有实现)。该委托接收两个参数,第一个参数是方法所属的对象,如果是静态方法就是null;第二个参数是方法的参数,定义为object[]表示可以接收任意类型的参数。通过委托执行方法,与直接调用方法的效率差别就不是很大(对委托不熟悉的朋友可以参见:委托)。cachemethodinfo的定义如下:
/// <summary>
/// 缓存方法信息
/// </summary>
sealed class cachemethodinfo
{
/// <summary>
/// 方法名称
/// </summary>
public string methodname { get; set; }
/// <summary>
/// 方法委托
/// </summary>
public func<object, object[], object> func { get; set; }
/// <summary>
/// 方法参数
/// </summary>
public parameterinfo[] parameters { get; set; }
/// <summary>
/// ajax标记属性
/// </summary>
public ajaxmethodattribute ajaxmethodattribute { get; set; }
}
核心方法
1. eexcutor.getdelegateinfo 获取方法相关信息
该方法用于遍历页面类,获取所有ajaxmethodattribute标记的方法信息,生成一个cachemethodinfo对象,包括标记信息、方法名称、参数信息,以及最重要的方法委托。该对象会缓存在一个哈希表中,下次获取时,直接从内存获得。
/// <summary>
/// 获取页面标记方法信息
/// </summary>
/// <param name="page">页面对象</param>
/// <param name="methodname">方法名称</param>
internal static cachemethodinfo getdelegateinfo(page page, string methodname)
{
if (page == null)
{
throw new argumentnullexception("page");
}
type type = page.gettype();
//ajaxdelegatetable是一个hashtable
dictionary<string, cachemethodinfo> dic = ajaxdelegatetable[type.assemblyqualifiedname] as dictionary<string, cachemethodinfo>;
if (dic == null)
{
dic = new dictionary<string, cachemethodinfo>();
//遍历页面的所有methodinfo
ienumerable<cachemethodinfo> 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<object,object[],object>委托,为type编译一个func<object>委托,用于创建实例对象。
通过expression优化反射
expression(表达式树)允许我们将代码逻辑以表达式的形式存储在树状结构里,然后在运行时去动态解析,实现动态编辑和执行代码。熟悉orm框架的朋友对expression肯定很熟悉,因为大部分方法都有一个expression<tdelegate>类型的参数。访问关系型数据库的本质还是sql语句,orm的工作就是为开发人员屏蔽这个过程,以面向对象的方式去读写数据库,而不是自己编写sql语句。例如,users.where(u => u.age > 18) 就可查询年龄大于18的用户。这里不对应用在orm的过程进行详解,下面我们介绍如何用expression并利用它来生成委托。
.net定义了许多表达式类型,这些类型都派生自expression,expression是一个抽象类,而且是一个工厂类,所有类型的表达式都通过它来创建。如图:
先看一个 1 * 2 + 2 例子,我们用表达树来描述来描述它:
/*
* a * b + 2
*/
/*
直接操作
int a = 1, b = 2;
int result = a * 2 + 2;
*/
/*
通过委托调用
func<int, int, int> func = new func<int, int, int>((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<func<int, int, int>>(unaryexpression, parametersexpression);
//将委托编译成可执行代码
func<int,int,int> func = lambdaexpression.compile() as func<int,int,int>;
console.writeline(func(1, 2));
可以看到我们最终将其编译为一个具体类型的委托了。下面看我们真正用到的方法是如何实现的,代码如下:
public static func<object, object[], object> getmethoddelegate(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<expression> paramexplist = new list<expression>();
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<action<object, object[]>> lambda = expression.lambda<action<object, object[]>>(methodcall, instanceexp, paramexp);
action<object, object[]> action = lambda.compile();
return (instance, parameters) =>
{
action(instance, parameters);
return null;
};
}
else
{
unaryexpression castmethodcall = expression.convert(methodcall, typeof(object));
expression<func<object, object[], object>> lambda = expression.lambda<func<object, object[], object>>(castmethodcall, instanceexp, paramexp);
return lambda.compile();
}
}
具体代码都有注释解释,最终我们获得了一个func<object,object[],object>类型的委托,它会作为cachemethodinfo的属性进行缓存。有兴趣测试反射性能的朋友,也不妨去测试对比一下这几种方式执行的效率差别:1.直接执行方法 2.emit 3. 缓存+委托 4.delegate.dynamicinvoke。
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
{
/// <summary>
/// 获取实例字段/属性集合
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
public static list<datamember> getdatamember(type type)
{
if (type == null)
{
throw new argumentnullexception("type");
}
ienumerable<propertymember> propertymembers = from property in type.getproperties(bindingflags.instance | bindingflags.public)
select new propertymember(property);
ienumerable<fieldmember> fieldmembers = from field in type.getfields(bindingflags.instance | bindingflags.public)
select new fieldmember(field);
list<datamember> members = new list<datamember>();
foreach(var property in propertymembers)
{
members.add(property);
}
foreach (var field in fieldmembers)
{
members.add(field);
}
return members;
}
}
在前面我们定义的handler的processrequest方法中,我们调用了executor.execute,该方法用于执行委托,实现如下:
/// <summary>
/// 核心函数,执行handler的方法
/// </summary>
/// <param name="page">页面对象</param>
/// <param name="context">请求上下文</param>
/// <param name="cachemethodinfo">缓存方法原数据</param>
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一个实例对象,然后为其字段或属性赋值。实现如下:
/// <summary>
/// 从请求获取参参数
/// </summary>
/// <param name="request">httprequest</param>
///<param name="parameters">参数信息</param>
/// <returns>参数数组</returns>
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
{
/// <summary>
/// 缓存构造函数
/// </summary>
private static hashtable constructortable = hashtable.synchronized(new hashtable());
/// <summary>
/// 根据名称从httprequest获取值
/// </summary>
/// <param name="request">httprequest</param>
/// <param name="name">键名称</param>
/// <param name="type">参数类型</param>
/// <returns></returns>
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);
}
/// <summary>
/// 创建实例对象
/// </summary>
/// <param name="type">实例类型</param>
/// <returns></returns>
public static object createmodel(type type)
{
if (type == null)
{
throw new argumentnullexception("type");
}
func<object> func = constructortable[type.assemblyqualifiedname] as func<object>;
if (func == null)
{
func = reflectionutil.getconstructordelegate(type);
constructortable[type.assemblyqualifiedname] = func;
}
if (func != null)
{
return func();
}
return null;
}
/// <summary>
/// 填充模型
/// </summary>
/// <param name="request">httprequest</param>
/// <param name="name">键名称</param>
/// <param name="prefix">参数类型</param>
/// <parparam name="model">实例对象</parparam>
public static void fillmodelbyrequest(httprequest request, string name, type type, object model)
{
if (model == null)
{
return;
}
ienumerable<datamember> 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<object>类型的委托来优化,它调用了reflectionutil.getconstructordelegate方法。实现如下:
/// <summary>
/// 获取构造函数委托
/// </summary>
/// <param name="type">实例类型</param>
/// <returns></returns>
public static func<object> 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<func<object>> lambda = expression.lambda<func<object>>(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();
}
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
ajax返回object object的快速解决方法
jquery中ajax的4种常用请求方式介绍
使用原生ajax处理json字符串的方法
以上就是编写轻量ajax组件第三篇实现的详细内容。