熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

.NET的動態編譯與WS服務調用詳解

2013-11-13 10:43:38  來源: .NET編程 
這篇文章介紹了NET的動態編譯與WS服務調用詳解有需要的朋友可以參考一下希望對你有所幫助  

  動態編譯與WS服務有關系麼?今天就亂彈一番如何使用動態編譯動態生成WS服務調用的代理類然後通過這個代理類調用WS服務
    首先動態編譯這玩意在NET裡面是非常簡單的實際上只涉及到兩個類型CodeDomProvider以及CompilerParameters他們都位於SystemCodeDomCompiler命名空間
    以下代碼可將源碼動態編譯為一個程序集
動態編譯

復制代碼 代碼如下:
CodeDomProvider provider = CodeDomProviderCreateProvider("CSharp");
CompilerParameters codeParameters = new CompilerParameters();
codeParametersGenerateExecutable = false; //編譯為dll如果為true則編譯為exe
codeParametersGenerateInMemory = true; //編譯後的程序集保存到內存中
StringBuilder code = new StringBuilder();
//此處構造源代碼
CompilerResults results = providerCompileAssemblyFromSource(codeParameters codeToString());
Assembly assembly = null; //動態編譯生成的程序集
if (!resultsErrorsHasErrors)
{
    assembly = resultsCompiledAssembly;
}

  
    獲得assembly後隨後我們即可以通過反射獲取程序集裡面的類型然後實例化調用類型方法…
    不過在此之前我們得構造WS服務的代理類它是什麼樣子的呢?我們使用WCF框架創建服務代理類也是十分簡單的常見的代理類結構如下
服務調用代理類

復制代碼 代碼如下:
[ServiceContract(Namespace="]
public interface TestService
{
    [OperationContract(Action = " ReplyAction = "]
    string HelloWorld();
}
public class TestServiceClient : ClientBase<TestService> TestService
{
    public TestServiceClient(Binding binding EndpointAddress address) :
        base(binding address)
    {
    }
    public string HelloWorld()
    {
        return baseChannelHelloWorld();
    }
}

  
    所以我們要動態構造出代理類源碼應該知道服務的命名空間服務方法的Action地址ReplyAction地址當然還有服務方法的名稱返回類 型參數列表這裡我們省略掉服務方法的參數列表構造代理類實際上就是一個字符串組裝的問題先創建一個類型用於保存構造代理類所要用到的參數

  服務代理類構造參數

復制代碼 代碼如下:
public class WebServiceParamaters
{
    public string address;
    public string Address
    {
        get { return address; }
        set
        {
            address = value;
        }
    }
    private string serviceNamespace;
    public string ServiceNamespace
    {
        get { return serviceNamespace; }
        set
        {
            serviceNamespace = value;
        }
    }
   private string methodAction;
    public string MethodAction
    {
        get { return methodAction; }
        set
        {
            methodAction = value;
        }
    }
    private string methodReplyAction;
    public string MethodReplyAction
    {
        get { return methodReplyAction; }
        set
        {
            methodReplyAction = value;
        }
    }
    private string methodName;
    public string MethodName
    {
        get { return methodName; }
        set
        {
            methodName = value;
        }
    }
    private string returnType;
    public string ReturnType
    {
        get { return returnType; }
        set
        {
            returnType = value;
        }
    }
}

  
 好現在我們只需要構造出代理類源碼然後動態編譯出代理類的程序集最後通過反射調用服務方法
WebServiceProxyCreator

復制代碼 代碼如下:
public class WebServiceProxyCreator
{
    public Object WebServiceCaller(WebServiceParamaters parameters)
    {
        CodeDomProvider provider = CodeDomProviderCreateProvider("CSharp");
        CompilerParameters codeParameters = new CompilerParameters();
        codeParametersGenerateExecutable = false;
        codeParametersGenerateInMemory = true;
        StringBuilder code = new StringBuilder();
        CreateProxyCode(code parameters);
codeParametersReferencedAssembliesAdd("Systemdll");
codeParametersReferencedAssembliesAdd("SystemServiceModeldll");
        CompilerResults results = providerCompileAssemblyFromSource(codeParameters codeToString());
        Assembly assembly = null;
        if (!resultsErrorsHasErrors)
        {
            assembly = resultsCompiledAssembly;
        }
        Type clientType = assemblyGetType("RuntimeServiceClient");
       ConstructorInfo ci = clientTypeGetConstructor(new Type[] { typeof(Binding) typeof(EndpointAddress) });
        BasicHttpBinding binding = new BasicHttpBinding(); //只演示傳統的WebService調用
        EndpointAddress address = new EndpointAddress(parametersaddress);
        Object client = ciInvoke(new object[] { binding address });
        MethodInfo mi = clientTypeGetMethod(parametersMethodName);
        Object result = miInvoke(client null);
        mi = clientTypeGetMethod("Close"); //關閉代理
        miInvoke(client null);
        return result;
   }
    public static void CreateProxyCode(StringBuilder code WebServiceParamaters parameters)
    {
        codeAppendLine("using System;");
        codeAppendLine("using SystemServiceModel;");
        codeAppendLine("using SystemServiceModelChannels;");
        codeAppend(@"[ServiceContract(");
        if (!StringIsNullOrEmpty(parametersServiceNamespace))
        {
            codeAppend("Namespace="")Append(parametersServiceNamespace)Append(""");
        }
        codeAppendLine(")]");
        codeAppendLine("public interface IRuntimeService");
        codeAppendLine("{");
        codeAppend("[OperationContract(");
        if (!StringIsNullOrEmpty(parametersMethodAction))
        {
            codeAppend("Action="")Append(parametersMethodAction)Append(""");
            if (!StringIsNullOrEmpty(parametersMethodReplyAction))
            {
                codeAppend(" ");
            }
        }
        if (!StringIsNullOrEmpty(parametersMethodReplyAction))
        {
            codeAppend("ReplyAction="")Append(parametersMethodReplyAction)Append(""");
        }
        codeAppendLine(")]");
        codeAppend(parametersReturnType)Append(" ");
        codeAppend(parametersMethodName)AppendLine("();");
        codeAppendLine("}");
        codeAppendLine();
        codeAppendLine("public class RuntimeServiceClient : ClientBase<IRuntimeService> IRuntimeService");
        codeAppendLine("{");
        codeAppendLine("public RuntimeServiceClient(Binding binding EndpointAddress address) :base(binding address)");
        codeAppendLine("{");
        codeAppendLine("}");
        codeAppend("public ")Append(parametersReturnType)Append(" ");
        codeAppend(parametersMethodName)AppendLine("()");
        codeAppendLine("{");
        codeAppend("return baseChannel")Append(parametersMethodName)AppendLine("();");
        codeAppendLine("}");
        codeAppendLine("}");
    }
}

  
  注意紅色部分由於代理類使用了WCF框架所以編譯時我們需要添加SystemServiceModel的引用當然Systemdll肯定是必 須的這裡要注意SystemServiceModeldll應該保存到應用程序目錄否則動態編譯時會引發異常很簡單在工程引用中添加 SystemServiceModel的引用然後在屬性中將拷貝到本地屬性設置為true
   到此我們就可以直接通過傳入的服務地址服務方法名稱以及相關的命名空間即可調用服務(盡管我們只能調用無參服務並且盡管我們也只能調用使用 BasicHttpBinding綁定的服務這些限制的原因是…我懶好吧相信只要經過一點改動即可去掉這些限制)
   可惜我們的程序還很傻每次調用服務都需要去生成代碼編譯創建代理實例最後再調用嗯…那就緩存吧
  在WebServiceParameters類中重寫GetHashCode方法

復制代碼 代碼如下:
 public override int GetHashCode()
  {
      return StringConcat(serviceNamespace methodAction methodReplyAction methodName returnType)GetHashCode();
  }
 

  
然後在WebServiceProxyCreator中加入緩存機制

復制代碼 代碼如下:

  
  public class WebServiceProxyCreator
   {
       private static Dictionary<int Type> proxyTypeCatch = new Dictionary<int Type>();

       public Object WebServiceCaller(WebServiceParamaters parameters)
       {
           int key = parametersGetHashCode();
           Type clientType = null;
           if (proxyTypeCatchContainsKey(key))
          {
              clientType = proxyTypeCatch[key];
              DebugWriteLine("使用緩存");
          }
          else
          {

              CodeDomProvider provider = CodeDomProviderCreateProvider("CSharp");
              CompilerParameters codeParameters = new CompilerParameters();
              codeParametersGenerateExecutable = false;
              codeParametersGenerateInMemory = true;

              StringBuilder code = new StringBuilder();
              CreateProxyCode(code parameters);

              codeParametersReferencedAssembliesAdd("Systemdll");
              codeParametersReferencedAssembliesAdd("SystemServiceModeldll");

              CompilerResults results = providerCompileAssemblyFromSource(codeParameters codeToString());
              Assembly assembly = null;
              if (!resultsErrorsHasErrors)
              {
                  assembly = resultsCompiledAssembly;
              }

              clientType = assemblyGetType("RuntimeServiceClient");

              proxyTypeCatchAdd(key clientType);
          }
          ConstructorInfo ci = clientTypeGetConstructor(new Type[] { typeof(Binding) typeof(EndpointAddress) });
          BasicHttpBinding binding = new BasicHttpBinding(); //只演示傳統的WebService調用
          EndpointAddress address = new EndpointAddress(parametersaddress);
          Object client = ciInvoke(new object[] { binding address });

          MethodInfo mi = clientTypeGetMethod(parametersMethodName);
          Object result = miInvoke(client null);
          mi = clientTypeGetMethod("Close"); //關閉代理
          miInvoke(client null);
          return result;
      }

 }


From:http://tw.wingwit.com/Article/program/net/201311/14381.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.