这篇我来讲如何实现自定义特性ajax,以及如何自动生成客户端js。
第一:所谓的自定义特性,就是我们自己定义的一个特性标签,在.net中,就有一些这样的特性,例如 .net内置的System.ObsoleteAttribute 。示例代码如下:
public void testObsolete()
{ }
public void testObsolete( int j)
{ }
public void testA()
{
this .testObsolete();
}
如果存在一个方法的多个重载,又不能删除某些重载,可以给它加上Obsolete,当用户调用这个方法时,编译器就会给出警告提示用户。这个类继承自Attribute,特性是一个对象,可以加载到程序集及程序集的对象中,包括程序集本身、模块、类、接口、结构、构造函数、方法、方法参数等,加载了特性的对象称作特性的目标。特性为程序添加元数据(描述数据的数据)的一种机制,它可以给编译器提供指示或者提供对数据的说明。
特性有以下三个非常实用的参数以及属性:[AttributeUsage(AttributeTargets.Class, AllowMutiple=true, Inherited=false)]
1:AttributeTargets代表特性应用的对象,类,接口,方法等。
2:AllowMutiple,是否允许用户在一个对象上多次使用特性标签。
3:Inherited:对于子类是否有效。
这里我们创建一个AjaxAttribute.cs类,包含三个简单属性。
public class AjaxAttribute:Attribute
{
public string Name { get ; set ; }
public bool Inherited{ get ; set ;}
public AjaxReturnType ReturnType { get ; set ; }
}
第二:上篇文章(asp.net mvc(八))我们提到,MVC中实现ajax,可以返回JsonResult类型的值供客户端调用,但它返回的是查询出来的直接对象,如果对象为空,则不会有实际内容返回。这个对象提供的信息可以扩充下,创建一个AjaxResult对象,继承自JsonResult,有三个构造函数。 客户端在调用回调方法时可以根据这些新增加的值来处理。
1:可以在返回结果对象中增加一个操作状态值,一般可以是成功或者是失败(success)。
2:可以在返回结果对象中增加一些提示信息,例如失败的原因之类信息(message)。
3: 可以在返回结果对象中增加一个类型为object的属性,用来保存程序返回的数据(object value)。
{
public AjaxResult( bool isSuccess)
{
AjaxInfo info = new AjaxInfo();
info.success = isSuccess;
this .Data = info;
}
public AjaxResult( bool isSuccess, object data)
{
AjaxInfo info = new AjaxInfo();
info.success = isSuccess;
info.value = data;
this .Data = info;
}
public AjaxResult( bool isSuccess, object data, string messsage)
{
AjaxInfo info = new AjaxInfo();
info.success = isSuccess;
info.value = data;
info.message = messsage;
this .Data = info;
}
}
public class AjaxInfo
{
public bool success { get ; set ; }
public string message { get ; set ; }
public object value { get ; set ; }
}
第三:提供多种返回类型,之前的示例返回json格式,显然有局限性,为此可以创建一个返回值类型的枚举,以支持多种格式的数据。当返回类型不同时,异常调用方法的返回类型也需要跟着变化。
/// Ajax方法的返回类型
/// </summary>
public enum AjaxReturnType
{
/// <summary>
/// 返回一个可以由jQuery对象处理的XML文档
/// </summary>
Xml,
/// <summary>
/// 返回纯文本格式的HTML,包括求值后的脚本标记
/// </summary>
Html,
/// <summary>
/// 将响应作为JSON求值,并返回一个Javascript对象
/// </summary>
Json,
/// <summary>
/// 将响应作为Javascript语句求值,并返回纯文本
/// </summary>
Script
}
第四:利用反射以及结合我们创建的自定义特性AjaxAttribute,完成js代码的输出。这段代码比较多,大家可以自己去试试。
{
private string _Script;
private Dictionary < string , AjaxMethodInfo > _AjaxMethods;
private List < PropertyInfo > _AjaxProperties;
/// <summary>
/// 利用反射,创建js脚本
/// </summary>
/// <param name="type"></param>
public AjaxClass(Type type)
{
List < string > scripts = new List < string > ();
Dictionary < string , AjaxMethodInfo > methodList = new Dictionary < string , AjaxMethodInfo > ();
List < PropertyInfo > propertyList = new List < PropertyInfo > ();
MethodInfo[] methods;
PropertyInfo[] properties;
string clientName;
object [] attrs = type.GetCustomAttributes( typeof (AjaxAttribute), false );
if (attrs.Length > 0 )
{
AjaxAttribute attr = attrs[ 0 ] as AjaxAttribute;
clientName = string .IsNullOrEmpty(attr.Name) ? type.Name : attr.Name;
if (attr.Inherited)
{
methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);
}
else
{
methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.DeclaredOnly);
}
}
else
{
clientName = type.Name;
methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.DeclaredOnly);
}
foreach (MethodInfo mi in methods)
{
attrs = mi.GetCustomAttributes( typeof (AjaxAttribute), false );
if (attrs.Length > 0 )
{
AjaxReturnType returnType = AjaxReturnType.Html;
if (mi.ReturnType == typeof ( int ) || mi.ReturnType == typeof (System.Web.Mvc.JsonResult))
returnType = AjaxReturnType.Json;
// AjaxReturnType returnType = (attrs[0] as AjaxAttribute).ReturnType;
AjaxMethodInfo ami = new AjaxMethodInfo(mi, returnType);
methodList.Add(mi.Name, ami);
scripts.Add(BuildAjaxRequest(ami));
}
}
foreach (PropertyInfo pi in properties)
{
attrs = pi.GetCustomAttributes( typeof (AjaxAttribute), false );
if (attrs != null && attrs.Length > 0 ) propertyList.Add(pi);
}
if (methodList.Count > 0 ) _AjaxMethods = methodList;
if (propertyList.Count > 0 ) _AjaxProperties = propertyList;
BuildScript(clientName, scripts, propertyList);
}
/// <summary>
/// 输入所有属性的js脚本
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public string GetScript( object obj)
{
if (_AjaxProperties == null ) return _Script;
string script = string .Empty;
foreach (PropertyInfo pi in _AjaxProperties)
{
if (script == string .Empty) script = BuildAjaxObject(obj, pi);
else script += " ,\r\n " + BuildAjaxObject(obj, pi);
}
return _Script.Replace( " {property} " , script);
}
/// <summary>
/// 创建最终的js脚本
/// </summary>
/// <param name="typeName"></param>
/// <param name="scripts"></param>
/// <param name="propertyList"></param>
private void BuildScript( string typeName, List < string > scripts, List < PropertyInfo > propertyList)
{
if (scripts.Count > 0 || propertyList.Count > 0 )
{
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine( " <script type=\ " text / javascript\ " > " );
sb.AppendFormat( " var {0} = {{ " , typeName);
if (propertyList.Count > 0 )
{
sb.AppendLine();
sb.Append( " {property} " );
}
for ( int i = 0 ; i < scripts.Count; i ++ )
{
if (i == 0 && propertyList.Count == 0 ) sb.AppendLine();
else sb.AppendLine( " , " );
sb.Append( " " + scripts[i]);
}
sb.AppendLine();
sb.AppendLine( " } " );
sb.AppendLine( " </script> " );
_Script = sb.ToString();
}
}
/// <summary>
/// jquery相关ajax方法的脚本构建
/// </summary>
/// <param name="ami"></param>
/// <returns></returns>
private string BuildAjaxRequest(AjaxMethodInfo ami)
{
string methodName = ami.MethodInfo.Name;
string url = " {url} " + methodName + " {querystring} " ;
ParameterInfo[] parameters = ami.MethodInfo.GetParameters();
AjaxReturnType returnType = ami.ReturnType;
string param, data;
if (parameters == null || parameters.Length == 0 )
{
param = " callback " ;
data = string .Empty;
}
if (parameters.Length == 0 )
{
return string .Format( @" {0}: function(callback)
{{
$.getJSON('{1}', callback);
}} " ,
methodName, url);
}
else
{
string [] paramArray = new string [parameters.Length + 1 ];
string [] dataArray = new string [parameters.Length];
for ( int i = 0 ; i < parameters.Length; i ++ )
{
paramArray[i] = parameters[i].Name;
dataArray[i] = string .Format( " {0}:{0} " , parameters[i].Name);
}
// paramArray[parameters.Length] = "callback";
param = string .Join( " , " , paramArray);
param = param.Trim ().TrimEnd( ' , ' );
data = string .Join( " , " , dataArray);
}
return string .Format( @" {0}: function({1},callback)
{{
$.getJSON('{2}',{{{3}}}, callback);
}} " ,
methodName,param, url,data);
}
private string BuildAjaxObject( object obj, PropertyInfo pi)
{
object value = pi.GetValue(obj, null );
object [] attrs = pi.GetCustomAttributes( typeof (AjaxAttribute), false );
if (attrs.Length > 0 )
{
AjaxAttribute attr = attrs[ 0 ] as AjaxAttribute;
if (attr.ReturnType == AjaxReturnType.Json && value is string )
return string .Format( @" {0}: {1} " , pi.Name, value);
}
StringBuilder sb = new StringBuilder();
JsonWriter jw = new JsonWriter(sb);
jw.Write(value);
return string .Format( @" {0}: {1} " , pi.Name, sb.ToString());
}
}
第五:为了让所有页面都能利用js自动代码生成,我为所有Controller创建一个基类,在它的Initialize中初始化js脚本。
{
protected override void Initialize(RequestContext requestContext)
{
base .Initialize(requestContext);
InitJavaScript();
}
/// <summary>
/// 初始化Ajax使用的JavaScript
/// </summary>
private void InitJavaScript()
{
string jsb = AjaxManager.GetAjaxScript( this );
string controller = Convert.ToString( this .RouteData.Values[ " controller " ]);
if ( ! string .IsNullOrEmpty(jsb) && ! string .IsNullOrEmpty(controller))
{
string str = System.Web.HttpContext.Current.Request.ApplicationPath;
str = str.Length > 1 ? str : string .Empty;
jsb = jsb.Replace( " {url} " , string .Format( " {0}/{1}/ " , str, controller));
jsb = jsb.Replace( " {querystring} " , GetHttpQueryString());
}
ViewData[ " m_javablock " ] = jsb;
}
private string GetHttpQueryString()
{
StringBuilder sb = new StringBuilder( " ? " );
foreach (KeyValuePair < string , object > pair in this .RouteData.Values)
{
if (pair.Key != " controller " && pair.Key != " action " )
sb.AppendFormat( " {0}={1}& " , pair.Key, (pair.Value != null ) ? pair.Value.ToString(): "" );
}
sb.Append(System.Web.HttpContext.Current.Request.QueryString.ToString());
return sb.ToString();
}
}
public class AjaxManager
{
public static string GetAjaxScript( object obj)
{
AjaxClass ajaxClass = new AjaxClass(obj.GetType());
return ajaxClass.GetScript(obj);
}
}
第六:在HomeController类中,增加如下用于异步请求的代码。同时在方法上面增加特性标签Ajax。
public AjaxResult TestMVC( int i, int j)
{
int I = 0 ;
List < student > list = new List < student > ();
for ( int k = 0 ; k < 10 ; k ++ )
{
student sd = new student() { sname = " aaa " + k.ToString() + j.ToString(), ID = k, Grade = k * 10 };
list.Add(sd);
}
var stu = (from m in list
where m.ID == i
select m
).FirstOrDefault();
return new AjaxResult( true , stu);
}
第七:最终生成的客户端js如下:
var HomeController = {
TestMVC: function(i, j,callback)
{
$.getJSON( ' /Home/TestMVC?id=& ' ,{i:i, j:j}, callback);
}
}
</ script >
总结:上面的代码可能写的比较乱,但大概思路应该有了,这样我们可以在后台代码中为需要异步调用的方法增加Ajax特性标签,然后在客户端通过类型C#命令空间的方式调用。例如:
$( " #divStudent " ).html(data.value.sname);
});
作者:姜敏
出处:http://www.cnblogs.com/aspnet2008/