为什么要这样做?对比其它实现方式的优势?
有不少朋友问到这些问题,所以这篇先把这两个问题先解释一下。后台处理Ajax请求无论使用aspx、asmx、ashx、还是IHttpHandler来处理,情况都跟下面差不多:
也就是说,无论我们使用哪种实现,基本上都是一个转接,将接收到的请求转接到对应的业务类中处理(除非您的项目不介意业务代码分散在aspx、asmx、ashx、IHttpHandler等各个角落)。
而文章中提出的这种方法,就是希望能够创建一个中间代理将请求直接转接到业务类的方法上,只需要在业务类中定义好方法,前端就可以直接通过指定的链接调用,不需要再去定义一个aspx或ashx。
接下来再来介绍这篇文章我们要实现的内容。
//aspx、asmx、ashx、IHttpHandler中的方法
public string GetMemberName(int id){
return new Member().GetMemberName(id);
}
public class Member{
public string GetMemberName(int id){
//do something with id;
return memberName;
}
}
而文章中提出的这种方法,就是希望能够创建一个中间代理将请求直接转接到业务类的方法上,只需要在业务类中定义好方法,前端就可以直接通过指定的链接调用,不需要再去定义一个aspx或ashx。
接下来再来介绍这篇文章我们要实现的内容。
为什么要这使用特性Attribute?
上篇文章中有朋友回复说接收的参数只支持Form提交的数据,能不能加上QueryString?当然是可以的,所以我们在这里引入了特性Attribute,用来解决传入参数的取值问题。
为了方便以后的扩展,我们首先定义了一个抽象类ParameterAttribute。
为了方便以后的扩展,我们首先定义了一个抽象类ParameterAttribute。
定义ParameterAttribute:
[AttributeUsage(AttributeTargets.Parameter)]
public abstract class ParameterAttribute : Attribute {
public object DefaultValue { get; set; }
public string Name { get; set; }
public ParameterAttribute() { }
public ParameterAttribute(string name, object defaultValue) {
Name = name;
DefaultValue = defaultValue;
}
public virtual object GetValue(System.Web.HttpContext context, Type parameterType) {
object value = GetParameterValue(context) ?? DefaultValue;
if (parameterType.FullName == "System.String") {
return value;
}
if (value.GetType().FullName == "System.String") {
if (string.IsNullOrEmpty((string)value)) {
value = DefaultValue;
}
}
return Convert.ChangeType(value, parameterType);
}
public abstract object GetParameterValue(System.Web.HttpContext context);
}
ParameterAttribute类继承自Attribute,并且限定了该类只能应用到参数上。同时还定义了一个属性DefaultValue,一个抽象方法GetParameterValue,有的朋友可能会问为什么DefaultValue不用泛型实现,原因是继承自Attribute的类不能使用泛型。
下面我们再定义一个FormAttribute来处理通过Form方式提交的参数。
下面我们再定义一个FormAttribute来处理通过Form方式提交的参数。
定义FormAttribute:
public class FormAttribute : ParameterAttribute {
public FormAttribute() { }
public FormAttribute(string name) : base(name, null) { }
public FormAttribute(string name, object defaultValue) : base(name, defaultValue) { }
public override object GetParameterValue(System.Web.HttpContext context) {
return context.Request.Form[Name];
}
}
实际上这个类的定义很简单,仅仅是返回一个Request.Form中的值而已,既然如此,那QueryString实现起来也是一件很简单的事情了,复制代码改改名称得到QueryStringAttribute:
定义QueryStringAttribute:
public class QueryStringAttribute : ParameterAttribute {
public QueryStringAttribute() { }
public QueryStringAttribute(string name) : base(name, null) { }
public QueryStringAttribute(string name, object defaultValue) : base(name, defaultValue) { }
public override object GetParameterValue(System.Web.HttpContext context) {
return context.Request.QueryString[Name];
}
}
修改后的Factory.Execute方法:
void Execute(HttpContext context) {
//根据请求的Url,通过反射取得处理该请求的类
string url = context.Request.Url.AbsolutePath;
string[] array = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string typename = "Biz";
for (int x = 1; x < array.Length - 1; x++) {
typename += "." + array[x];
}
Type type = this.GetType().Assembly.GetType(typename, false, true);
if (type != null) {
//取得类的无参数构造函数
var constructor = type.GetConstructor(new Type[0]);
//调用构造函数取得类的实例
var obj = constructor.Invoke(null);
//查找请求的方法
var method = type.GetMethod(System.IO.Path.GetFileNameWithoutExtension(url));
if (method != null) {
var parameters = method.GetParameters();
object[] args = null;
if (parameters.Length > 0) {
args = new object[parameters.Length];
for (int x = 0; x < parameters.Length; x++) {
var parameterAttr = (Attribute.GetCustomAttribute(parameters[x], typeof(ParameterAttribute)) as ParameterAttribute) ?? new FormAttribute();
parameterAttr.Name = parameterAttr.Name ?? parameters[x].Name;
args[x] = parameterAttr.GetValue(context, parameters[x].ParameterType);
}
}
//执行方法并输出响应结果
context.Response.Write(method.Invoke(obj, args));
}
}
}
仅仅是比上次示例的代码多了两行而已。在没有定义ParameterAttribute的情况下默认使用FormAttribute。
为了方便演示代码,我们修改了Javascript代码。
为了方便演示代码,我们修改了Javascript代码。
修改后的前端Javascript代码:
$(function () {
//绑定按钮点击事件
$("#btnAction").click(function () {
$.post("/Ajax/News/Plus.aspx?y=" + $("input[name='y']").val() + "&num3=" + $("input[name='z']").val(), { x: $("input[name='x']").val() }, function (txt) {
$("#result").val(txt);
}, "text");
});
});
上面可以看到,我们为了演示参数可以取别名,将参数z修改成了num3,Html代码也稍作修改。
修改后的前端Html代码:
<input type="text" name="x" value="1" class="txt" />
<input type="button" disabled="disabled" value="+" class="txt btn" />
<input type="text" name="y" value="2" class="txt" />
<input type="button" disabled="disabled" value="+" class="txt btn" />
<input type="text" name="z" value="" class="txt" />
<input id="btnAction" type="button" value="=" class="txt btn" />
<input type="text" readonly="readonly" id="result" class="txt" />
运行示例后,即可看到我们想要的效果了。至此,我们就已经解决了支持参数从QueryString取值的问题,同时还可以实现扩展从其它方式取值,比如:Cookie、Session、Application、甚至Database,这里我就不再一一实现了,有兴趣的朋友不妨自已动手试试?
示例项目源代码:
几天篇文章都是半夜整理的,还要附带写示例代码,觉得有帮助的朋友不妨点下推荐给点鼓励,谢谢!
未完待续...
未完待续...