頁面導航: 首頁網絡編程ASP.NET實用技巧 → 正文內容 .NET的動態編譯與WS服務調用

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

發布:shangke 字體:[增加 減小] 類型:轉載
這篇文章介紹了.NET的動態編譯與WS服務調用詳解,有需要的朋友可以參考一下,希望對你有所幫助

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

復制代碼 代碼如下:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters codeParameters = new CompilerParameters();
codeParameters.GenerateExecutable = false; //編譯為dll,如果為true則編譯為exe
codeParameters.GenerateInMemory = true; //編譯后的程序集保存到內存中
StringBuilder code = new StringBuilder();
//此處構造源代碼
CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
Assembly assembly = null; //動態編譯生成的程序集
if (!results.Errors.HasErrors)
{
    assembly = results.CompiledAssembly;
}

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

[ServiceContract(Namespace="http://www.www8u888.com/")]
public interface TestService
{
    [OperationContract(Action = "http://www.www8u888.com/HelloWorld", ReplyAction = "http://www.www8u888.com/HelloWorldResponse")]
    string HelloWorld();
}
public class TestServiceClient : ClientBase<TestService>, TestService
{
    public TestServiceClient(Binding binding, EndpointAddress address) :
        base(binding, address)
    {
    }
    public string HelloWorld()
    {
        return base.Channel.HelloWorld();
    }
}

    所以,我們要動態構造出代理類源碼,應該知道服務的命名空間、服務方法的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 = CodeDomProvider.CreateProvider("CSharp");
        CompilerParameters codeParameters = new CompilerParameters();
        codeParameters.GenerateExecutable = false;
        codeParameters.GenerateInMemory = true;
        StringBuilder code = new StringBuilder();
        CreateProxyCode(code, parameters);
codeParameters.ReferencedAssemblies.Add("System.dll");
codeParameters.ReferencedAssemblies.Add("System.ServiceModel.dll");
        CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
        Assembly assembly = null;
        if (!results.Errors.HasErrors)
        {
            assembly = results.CompiledAssembly;
        }
        Type clientType = assembly.GetType("RuntimeServiceClient");
       ConstructorInfo ci = clientType.GetConstructor(new Type[] { typeof(Binding), typeof(EndpointAddress) });
        BasicHttpBinding binding = new BasicHttpBinding(); //只演示傳統的WebService調用
        EndpointAddress address = new EndpointAddress(parameters.address);
        Object client = ci.Invoke(new object[] { binding, address });
        MethodInfo mi = clientType.GetMethod(parameters.MethodName);
        Object result = mi.Invoke(client, null);
        mi = clientType.GetMethod("Close"); //關閉代理
        mi.Invoke(client, null);
        return result;
   }
    public static void CreateProxyCode(StringBuilder code, WebServiceParamaters parameters)
    {
        code.AppendLine("using System;");
        code.AppendLine("using System.ServiceModel;");
        code.AppendLine("using System.ServiceModel.Channels;");
        code.Append(@"[ServiceContract(");
        if (!String.IsNullOrEmpty(parameters.ServiceNamespace))
        {
            code.Append("Namespace=\"").Append(parameters.ServiceNamespace).Append("\"");
        }
        code.AppendLine(")]");
        code.AppendLine("public interface IRuntimeService");
        code.AppendLine("{");
        code.Append("[OperationContract(");
        if (!String.IsNullOrEmpty(parameters.MethodAction))
        {
            code.Append("Action=\"").Append(parameters.MethodAction).Append("\"");
            if (!String.IsNullOrEmpty(parameters.MethodReplyAction))
            {
                code.Append(", ");
            }
        }
        if (!String.IsNullOrEmpty(parameters.MethodReplyAction))
        {
            code.Append("ReplyAction=\"").Append(parameters.MethodReplyAction).Append("\"");
        }
        code.AppendLine(")]");
        code.Append(parameters.ReturnType).Append(" ");
        code.Append(parameters.MethodName).AppendLine("();");
        code.AppendLine("}");
        code.AppendLine();
        code.AppendLine("public class RuntimeServiceClient : ClientBase<IRuntimeService>, IRuntimeService");
        code.AppendLine("{");
        code.AppendLine("public RuntimeServiceClient(Binding binding, EndpointAddress address) :base(binding, address)");
        code.AppendLine("{");
        code.AppendLine("}");
        code.Append("public ").Append(parameters.ReturnType).Append(" ");
        code.Append(parameters.MethodName).AppendLine("()");
        code.AppendLine("{");
        code.Append("return base.Channel.").Append(parameters.MethodName).AppendLine("();");
        code.AppendLine("}");
        code.AppendLine("}");
    }
}

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

 public override int GetHashCode()
  {
      return String.Concat(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 = parameters.GetHashCode();
           Type clientType = null;
           if (proxyTypeCatch.ContainsKey(key))
          {
              clientType = proxyTypeCatch[key];
              Debug.WriteLine("使用緩存");
          }
          else
          {

              CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
              CompilerParameters codeParameters = new CompilerParameters();
              codeParameters.GenerateExecutable = false;
              codeParameters.GenerateInMemory = true;

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

              codeParameters.ReferencedAssemblies.Add("System.dll");
              codeParameters.ReferencedAssemblies.Add("System.ServiceModel.dll");

              CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
              Assembly assembly = null;
              if (!results.Errors.HasErrors)
              {
                  assembly = results.CompiledAssembly;
              }

              clientType = assembly.GetType("RuntimeServiceClient");

              proxyTypeCatch.Add(key, clientType);
          }
          ConstructorInfo ci = clientType.GetConstructor(new Type[] { typeof(Binding), typeof(EndpointAddress) });
          BasicHttpBinding binding = new BasicHttpBinding(); //只演示傳統的WebService調用
          EndpointAddress address = new EndpointAddress(parameters.address);
          Object client = ci.Invoke(new object[] { binding, address });

          MethodInfo mi = clientType.GetMethod(parameters.MethodName);
          Object result = mi.Invoke(client, null);
          mi = clientType.GetMethod("Close"); //關閉代理
          mi.Invoke(client, null);
          return result;
      }

 }

文章評論

最 近 更 新
熱 點 排 行
乐盈在线彩票 阜康市 | 湘潭市 | 巍山 | 沙湾县 | 沙洋县 | 芮城县 | 松溪县 | 会东县 | 富平县 | 长岭县 | 依安县 | 集安市 | 蛟河市 | 和林格尔县 | 泰州市 | 汽车 | 大同市 | 从江县 | 临安市 | 尼玛县 | 东台市 | 怀集县 | 牟定县 | 甘孜 | 广东省 | 安福县 | 淅川县 | 沐川县 | 黄骅市 | 伊宁县 | 重庆市 | 得荣县 | 长汀县 | 读书 | 北京市 | 武鸣县 | 育儿 | 沙湾县 | 浦城县 | 桃园县 | 湖州市 | 周口市 | 当阳市 | 玉溪市 | 甘孜县 | 清远市 | 连州市 | 遂溪县 | 奉贤区 | 石泉县 | 邛崃市 | 丰城市 | 西乌 | 玉门市 | 霞浦县 | 温泉县 | 陵水 | 湘乡市 | 盐源县 | 子洲县 | 绥江县 | 修文县 | 喜德县 | 子长县 | 长寿区 | 邵武市 | 长子县 | 庆城县 | 来安县 | 勐海县 | 利辛县 | 尖扎县 | 酉阳 | 迭部县 | 磐石市 | 清水河县 | 大方县 | 婺源县 | 葵青区 | 江油市 | 武乡县 | 驻马店市 | 普宁市 | 铁岭市 | 扬州市 | 万盛区 | 伊吾县 | 昌图县 | 白城市 | 肇州县 | 宽甸 | 理塘县 | 自治县 | 琼海市 | 浮山县 | 新津县 | 鄂托克旗 | 垦利县 | 澳门 | 赫章县 | 林州市 | 景洪市 | 嘉峪关市 | 定兴县 | 瑞昌市 | 寿宁县 | 滨海县 | 黑河市 | 锡林浩特市 | 铜陵市 | 太仆寺旗 | 汉阴县 | 资源县 | 界首市 | 肃宁县 | 林芝县 | 德州市 | 临汾市 | 宁陵县 | 观塘区 | 蒙城县 | 舞钢市 | 荃湾区 | 吴堡县 | 驻马店市 | 兴化市 | 贵溪市 | 柘荣县 | 广丰县 | 玛曲县 | 逊克县 | 正宁县 | 池州市 | 略阳县 | 响水县 | 扶绥县 | 玉龙 | 都江堰市 | 江口县 | 金寨县 | 舟山市 | 胶州市 | 祁东县 | 唐河县 | 磴口县 | 景德镇市 | 陵川县 | 杭锦后旗 | 敖汉旗 | 盐源县 | 昌平区 | 临桂县 | 玛多县 | 涞源县 | 绥化市 | 西林县 | 楚雄市 | 称多县 | 万全县 | 杨浦区 | 大宁县 | 台湾省 | 犍为县 | 濮阳市 | 浦城县 | 海城市 | 康保县 | 金昌市 | 团风县 | 满城县 | 泰顺县 | 博乐市 | 砀山县 | 临澧县 | 茂名市 | 吴旗县 | 合水县 | 大荔县 | 南江县 | 余庆县 | 开江县 | 清远市 | 蒙阴县 | 阿鲁科尔沁旗 | 赤峰市 | 岳池县 | 正镶白旗 | 普兰县 | 诸城市 | 太白县 | 南开区 | 黎川县 | 来宾市 | 渭源县 | 务川 | 开远市 | 东乡族自治县 | 漾濞 | 十堰市 | 灌阳县 | 平潭县 | 乌鲁木齐县 | 双柏县 | 丰城市 | 英超 | 盐城市 | 清远市 | 贡觉县 | 密云县 | 司法 | 八宿县 | 开鲁县 | 瑞昌市 | 屏南县 | 依安县 | 五河县 | 白山市 | 麦盖提县 | 合川市 | 南澳县 | 嘉鱼县 | 朔州市 | 大英县 | 靖宇县 | 原阳县 | 恩平市 | 徐闻县 | 马关县 | 隆化县 | 铜山县 | 隆尧县 | 景德镇市 | 虞城县 | 原阳县 | 岳池县 | 大渡口区 | 庆城县 | 新邵县 | 沁源县 | 岐山县 | 巴南区 | 澳门 | 绥棱县 | 宁强县 | 周宁县 | 驻马店市 | 中西区 | 清水河县 | 乌拉特后旗 | 东辽县 | 丰县 |