编写轻量ajax组件第三篇实现

2019-09-14 07:00:14王旭

通过之前的介绍,我们知道要执行页面对象的方法,核心就是反射,是从请求获取参数并执行指定方法的过程。实际上这和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
  }