경 량 ajax 구성 요소 세 번 째 편 작성 실현

37228 단어 ajax구성 요소
이전 소 개 를 통 해 우 리 는 페이지 대상 을 실행 하 는 방법 을 알 고 있 습 니 다.핵심 은 반사 입 니 다.요청 에서 파 라 메 터 를 얻 고 지정 한 방법 을 실행 하 는 과정 입 니 다.실제로 이것 은 asp.net 뮤 직 비디오 프레임 워 크 의 핵심 사상 과 유사 합 니 다.url 을 분석 하여 contrller 와 action 이름 을 가 져 온 다음 에 contrller 대상 을 활성화 시 켜 action 파 라 메 터 를 요청 하고 action 을 집 니 다.웹 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 를 사용 하여 비동기 요청 을 보 낼 때 요청 헤더 에 X-Requested-With:XML HttpRequest 라 는 표 시 를 가 져 옵 니 다.이 표 시 를 통 해 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 의 요청 헤더 에 Ajax Flag:XHR 가 포함 되 어 있다 면 우리 가 처리 해 야 한 다 는 뜻 입 니 다.또한 http header 의 MethodName 은 우리 가 실행 할 방법의 이름 을 표시 합 니 다.
AjaxMethodAttribute 태그 속성
태그 속성 은 반사 용 입 니 다.여기 서 우리 가 필요 로 하 는 기능 을 정의 합 니 다.우 리 는 있 기 를 바란다.
1.세 션 상 태 를 설정 할 수 있 습 니 다.
2.비동기 핸들 러 지원
3.캐 시 받 기 지원
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
  }

각종 처리 프로그램 과 Ajax Handler Factory
전편 에 따 르 면 구체 적 인 Handler 는 주로 두 가지 로 나 뉘 는데 비동기 와 비 비동기 이다.이 두 가지 유형 에서 Session 의 상태 에 대해 서 는 세 가지 가 있 습 니 다.지원 하지 않 고 읽 기 만 지원 합 니 다(IReadOnly Session State 인터페이스 실현).읽 기 쓰기 지원(IRequiresSession State 인터페이스 실현).IReadOnly Session State 와 IRequiresSession State 는 모두 인터페이스 만 표시 합 니 다(아무런 방법 이 없 으 며,사실은 태그 속성 으로 합 리 적 으로 이 루어 져 야 합 니 다).비동기 적 인 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)
    {
    }
  }  

Ajax Handler Factory 는 요청 에 따라 구체 적 인 Handler 를 생 성 하 는 IHandler Factory 인 터 페 이 스 를 실현 하 였 으 며,웹.config 에 등록 하여 사용 해 야 합 니 다.Ajax Handler Factory 의 GetHandler 는 우리 가 요청 을 차단 하 는 첫걸음 이다.요청 헤더 의 AjaxFlag:XHR 를 통 해 우리 가 처리 해 야 할 지 여 부 를 판단 합 니 다.만약 그렇다면 Handler 를 만 듭 니 다.그렇지 않 으 면 일반적인 방식 으로 진행 합 니 다.우리 의 방법 은.aspx.cs 에 쓰 여 있 기 때문에 우리 의 요청 은.aspx 접미사,즉 페이지(Page,IHttpHandler)형식 입 니 다.Page 는 PageHandler Factory 를 통 해 만 들 어 졌 고 PageHandler Factory 도 IHandler Factory 인 터 페 이 스 를 실현 하여 처리 프로그램 을 만 드 는 데 사용 되 었 음 을 표시 합 니 다.그래서 우 리 는 PageHandler Factory 로 IHttpHandler 를 만들어 야 합 니 다.그러나 PageHandler Factory 의 구조 함 수 는 proctected internal 형식 입 니 다.우 리 는 직접 new 를 만 들 수 없 기 때문에 CommonPageHandler Factory 를 통 해 이 를 계승 해 야 합 니 다.
PageHandler Factory 를 통 해 Page 를 획득 한 후 방법 명 을 결합 하면 Ajax MethodAttribute 태그 속성 을 반사 적 으로 얻 을 수 있 습 니 다.그리고 그 속성 에 따라 구체 적 인 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 형식 으로 임의의 형식 으로 되 돌아 갈 수 있 음 을 표시 합 니 다.(예 를 들 어 참조 형식(비 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의뢰 로 컴 파일 하여 Type 에 Func의뢰 를 컴 파일 하여 인 스 턴 스 대상 을 만 드 는 데 사용 할 수 있 습 니 다.
Expression 을 통 해 반사 최적화
Expression(표현 식 트 리)은 코드 논 리 를 표현 식 으로 트 리 구조 에 저장 한 다음 실행 할 때 동적 으로 해석 하여 동적 편집 과 실행 코드 를 실현 할 수 있 도록 합 니 다.ORM 프레임 워 크 에 익숙 한 친 구 는 Expression 에 익숙 할 것 입 니 다.대부분의 방법 은 Expression형식의 매개 변 수 를 가지 고 있 기 때 문 입 니 다.관계 형 데이터 베 이 스 를 방문 하 는 본질은 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형식의 의뢰 를 받 았 습 니 다.이것 은 CacheMethodInfo 의 속성 으로 캐 시 됩 니 다.반사 성능 테스트 에 관심 이 있 는 친구 도 이 몇 가지 방식 의 실행 효율 차 이 를 비교 해 보 는 것 이 좋 습 니 다.1.직접 실행 방법 2.Emit 3.캐 시+의뢰 4.Delegate.Dynamic Invoke.
2.실행 자.실행 의뢰
의뢰 를 수행 하기 전에,우 리 는 먼저 요청 에서 파 라미 터 를 얻어 방법 에 비 추어 야 한다.매개 변 수 는 string Test(int i,int j)와 같은 간단 한 유형 일 수 있 습 니 다.string Test(User user)와 같은 대상 일 수도 있 습 니 다.string Test(User user 1,User user 2)도 괜 찮 습 니 다.인 자 를 제출 할 때 user 1 이나 user 2 접 두 사 를 추가 하면 됩 니 다.예 를 들 어 user1.Name,user2.Name.여 기 는 mvc 와 같은 더 많은 일치 방식 을 지원 하지 않 습 니 다.끼 워 넣 기 형식 도 지원 합 니 다.이것 은 스스로 실현 할 수 있 습 니 다.매개 변수 가 대상 이 라면 필드 에 값 을 부여 해 야 할 수도 있 고 속성 에 값 을 부여 할 수도 있 습 니 다.필드 나 속성 을 나타 내 는 부모 클래스 를 정의 합 니 다.예:

  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; }
    }
  }

Type 을 옮 겨 다 니 며 모든 필드 와 속성 을 가 져 오 는 DataMemberManager 를 정의 합 니 다.다음 과 같 습 니 다.
   

 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형식의 의뢰 를 구축 하여 최적화 시 켜 야 합 니 다.ReflectionUtil.GetConstructor Delegate 방법 을 호출 했 습 니 다.다음 과 같이 구현:

  /// <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();
    }
총결산
지금 은 우리 프론트 데스크 톱 이 어떤 스 크 립 트 라 이브 러 리 를 사용 하 든 약속 에 따라 태그 방법 을 호출 할 수 있 습 니 다.위 에서 이미 구성 요소 의 핵심 부분 을 소 개 했 습 니 다.당신 도 자신의 생각 에 따라 확장 할 수 있 고 공동 학습 과 교 류 를 환영 합 니 다.

좋은 웹페이지 즐겨찾기