2012-05-18 27 views
5

獲得了一個插件應用程序,該插件以編程方式生成WCF客戶端合約,然後將其掛接到插件接口,但是我正努力解決如何讓生成的合約重用類型在插件DLL中找到。以編程方式生成WCF客戶端合同時的重用類型

是否有人知道如何設置ServiceContractGenerator以在定義的程序集中重用類型?

這是我用來生成合約代碼大氣壓:

 public Assembly CreateProxy(String url) 
    { 
     MetadataExchangeClient mexClient = new MetadataExchangeClient(new Uri(url + "/mex"), MetadataExchangeClientMode.MetadataExchange); 
     mexClient.ResolveMetadataReferences = true; 

     MetadataSet metaDocs = mexClient.GetMetadata(); 
     WsdlImporter importer = new WsdlImporter(metaDocs); 

     ServiceContractGenerator generator = new ServiceContractGenerator(); 

     generator.NamespaceMappings.Add("*", "NameSpace123"); 

     Collection<ContractDescription> contracts = importer.ImportAllContracts(); 
     ServiceEndpointCollection endpoints = importer.ImportAllEndpoints(); 

     foreach (ContractDescription contract in contracts) 
      generator.GenerateServiceContractType(contract); 

     if (generator.Errors.Count != 0) 
      throw new Exception("There were errors during code compilation."); 

     CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("C#"); 
     CompilerParameters parameters = new CompilerParameters(); 

     parameters.CompilerOptions = string.Format(@" /lib:{0}", "\"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\v3.0\""); 
     parameters.ReferencedAssemblies.Add("System.ServiceModel.dll"); 
     parameters.ReferencedAssemblies.Add("System.Runtime.Serialization.dll"); 

     parameters.GenerateExecutable = false; 
     parameters.GenerateInMemory = true; 
     parameters.IncludeDebugInformation = true; 
     parameters.OutputAssembly = "WCFGenerated.dll"; 

     CodeCompileUnit codeUnit = generator.TargetCompileUnit; 
     CompilerResults results = codeDomProvider.CompileAssemblyFromDom(parameters, codeUnit); 

     foreach (CompilerError oops in results.Errors) 
      throw new Exception("Compilation Error Creating Assembly: " + oops.ErrorText); 

     //Must load it like this otherwise the assembly wont match the one used for the generated code below 
     return Assembly.LoadFile(Directory.GetCurrentDirectory() + "\\WCFGenerated.dll"); 
    } 

編輯:我從來沒有得到這個工作很正確,但是我沒有管理加載exe文件彙編,並用它來生成代理:

 try 
     { 
      Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentUICulture.GetConsoleFallbackUICulture(); 
      if (Console.OutputEncoding.CodePage != Encoding.UTF8.CodePage && Console.OutputEncoding.CodePage != Thread.CurrentThread.CurrentUICulture.TextInfo.OEMCodePage) 
      { 
       Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); 
      } 

      var assembly = Assembly.LoadFile(Path.Combine(info.TempDir, SVCUTIL_EXE)); 

      var optionsType = assembly.GetType("Microsoft.Tools.ServiceModel.SvcUtil.Options"); 
      var runtimeType = assembly.GetType("Microsoft.Tools.ServiceModel.SvcUtil.ToolRuntime"); 

      //Options option = Options.ParseArguments(args); 
      var options = optionsType.InvokeMember("ParseArguments", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { info.Args }); 

      //ToolRuntime toolRuntime = new ToolRuntime(option); 
      ConstructorInfo c = runtimeType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { optionsType }, null); 
      var runtime = c.Invoke(new Object[] { options }); 

      //var runtime = Activator.CreateInstance(runtimeType, , null, options); 

      //toolRuntime.Run(); 
      var exitCode = (int)runtimeType.InvokeMember("Run", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, runtime, null); 

      if (exitCode != 0) 
       throw new Exception(String.Format("Failed to generate wcf contract code [Bad Result: {0}]", exitCode)); 
     } 
     catch (Exception e) 
     { 
      if (e is TargetInvocationException) 
       e = e.InnerException; 

      info.E = e; 
     } 
+1

這裏有什麼問題? – MrWuf

+0

編輯添加問題 – Lodle

回答

1

如果你想重用從實際使用的web服務的合同類型的組件,那麼就加入它像@peer建議或許應該努力!所有svcutil應該需要的是/參考選項,映射到他所說的內容。如果沒有,那麼svcutil.exe認爲程序​​集中的類型「A」和服務中的類型「A」不相同。在名稱或命名空間中或者在XML命名空間中(或者模式實際上是不同的)有細微差別。

請檢查"Reuse existing types" is ignored when adding a service reference - 我的意思是,確保'現有程序集'中的'現有類型'真正映射到相同的模式領域。請注意,contract-attribute必須位於定義類型的程序集內部!如果它是你的,只需添加並重新編譯。

另外,你有沒有嘗試在控制檯中手動運行svcutil?你可能會在那裏得到一些額外的錯誤/警告,也許他們會指出什麼是實際問題。

5

因爲你已經知道svcutil支持這個選項(/ reference flag)。因此,所有你需要的是在反射器打開svcutil.exe的,做與此相同的方法:Microsoft.Tools.ServiceModel.SvcUtil.ImportModule + InitializationHelper.InitReferencedContracts

internal static void InitReferencedContracts(Options options, WsdlImporter importer, ServiceContractGenerator contractGenerator) 
{ 
    foreach (Type type in options.ReferencedTypes) 
    { 
     if (type.IsDefined(typeof(ServiceContractAttribute), false)) 
     { 
      try 
      { 
       ContractDescription contract = ContractDescription.GetContract(type); 
       XmlQualifiedName key = new XmlQualifiedName(contract.Name, contract.Namespace); 
       importer.KnownContracts.Add(key, contract); 
       contractGenerator.ReferencedTypes.Add(contract, type); 
       continue; 
      } 
      catch (Exception exception) 
      { 
       if (Tool.IsFatal(exception)) 
       { 
        throw; 
       } 
       throw new ToolRuntimeException(SR.GetString("ErrUnableToLoadReferenceType", new object[] { type.AssemblyQualifiedName }), exception); 
      } 
     } 
    } 
} 
+0

看看scvutil,但沒有看到這個。會試試看。謝謝 – Lodle

相關問題