asp.net mvc(九)

      这篇我来讲如何实现自定义特性ajax,以及如何自动生成客户端js。
     
      第一:所谓的自定义特性,就是我们自己定义的一个特性标签,在.net中,就有一些这样的特性,例如 .net内置的System.ObsoleteAttribute 。示例代码如下:
        

代码
       [Obsolete("此方法已经过时")]
        
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类,包含三个简单属性。

代码
   [AttributeUsage(AttributeTargets.All,AllowMultiple=true )]
   
public  class AjaxAttribute:Attribute
    {
        
public string Name { getset; }
        
public bool Inherited{get;set;}
        
public AjaxReturnType ReturnType { getset; }
    }

 
       第二:上篇文章(asp.net mvc(八))我们提到,MVC中实现ajax,可以返回JsonResult类型的值供客户端调用,但它返回的是查询出来的直接对象,如果对象为空,则不会有实际内容返回。这个对象提供的信息可以扩充下,创建一个AjaxResult对象,继承自JsonResult,有三个构造函数。 客户端在调用回调方法时可以根据这些新增加的值来处理。


          1:可以在返回结果对象中增加一个操作状态值,一般可以是成功或者是失败(success)。
          2:可以在返回结果对象中增加一些提示信息,例如失败的原因之类信息(message)。
          3: 可以在返回结果对象中增加一个类型为object的属性,用来保存程序返回的数据(object value)。
       

代码
public class AjaxResult : JsonResult
    {
        
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 { getset; }

        
public string message { getset; }

        
public object value { getset; }
    }
    

  

      第三:提供多种返回类型,之前的示例返回json格式,显然有局限性,为此可以创建一个返回值类型的枚举,以支持多种格式的数据。当返回类型不同时,异常调用方法的返回类型也需要跟着变化。
    

代码
 /// <summary>
    
/// 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代码的输出。这段代码比较多,大家可以自己去试试。
    

代码
public  class AjaxClass
    {
        
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[0as 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 == nullreturn _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[0as 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脚本。
    

代码
public  class BaseController: System.Web.Mvc.Controller
    {
       
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<stringobject> 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。
  

代码
        [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如下:

代码
    <script type="text/javascript">
        var HomeController 
= {
            TestMVC: function(i, j,callback)
                                                {
                                                     $.getJSON(
'/Home/TestMVC?id=&',{i:i, j:j}, callback);
                                                }
        }
     
</script>

 

       总结:上面的代码可能写的比较乱,但大概思路应该有了,这样我们可以在后台代码中为需要异步调用的方法增加Ajax特性标签,然后在客户端通过类型C#命令空间的方式调用。例如:
     

HomeController.TestMVC(j,j+1, function(data) {
             $(
"#divStudent").html(data.value.sname);
             });

 

 


作者:姜敏
出处:http://www.cnblogs.com/aspnet2008/

 

posted on 2010-03-07 09:59  min.jiang  阅读(2714)  评论(10编辑  收藏  举报