2012-05-18 11 views
5

Tengo una aplicación con complementos que genera el Contrato de Cliente WCF programáticamente y luego lo conecta a las interfaces de complementos, sin embargo, estoy luchando para encontrar la forma de obtener el contrato generado para reutilizar los tipos encontrado en el plugin dlls.Reutilice tipos al generar WCF Cliente Contrato programáticamente

¿Alguien sabe cómo configurar ServiceContractGenerator para reutilizar tipos en ensamblados definidos?

Esto es lo que yo uso para generar el código de contrato atm:

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

Editar: Nunca tuve que esto funcione del todo bien, sin embargo, me las arreglé para cargar el archivo ejecutable como un conjunto y el uso que para generar el proxy:

 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

¿Cuál es la pregunta aquí? – MrWuf

+0

Editado para agregar la pregunta – Lodle

Respuesta

1

Si el conjunto desea volver a utilizar los tipos de que realmente utilizado por el contrato del servicio web, a continuación, sólo añadir que como @peer sugerido probablemente debería trabajar! todo lo que svcutil debería necesitar es una opción de referencia, lo que se corresponde con lo que dijo. si no lo hace, svcutil.exe considera que el tipo "A" del ensamblado y el tipo "A" del servicio no son los mismos. O bien hay una diferencia sutil en los nombres, o espacios de nombres, o - en los espacios de nombres XML (o los esquemas son realmente diferentes).

por favor, compruebe "Reuse existing types" is ignored when adding a service reference - Es decir, asegúrese de que los "tipos existentes" en el "ensamblaje existente" están realmente asignados al mismo reino de esquema. ¡Tenga en cuenta que ese atributo de contrato debe estar dentro de ese conjunto que define los tipos! si es tuyo, simplemente agrega y vuelve a compilar.

Además, ¿ha intentado ejecutar svcutil manualmente en la consola? es probable que reciba algunos errores/advertencias adicionales allí, tal vez le señalen cuál es el problema real.

5

Como ya sabe, svcutil admite esta opción (/ bandera de referencia). así que todo lo que necesita es abrir svcutil.exe en el reflector y hacer lo mismo ya que este método: 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

Miré scvutil pero no vi esto. Le daría una oportunidad. Gracias – Lodle

Cuestiones relacionadas