2012-05-18 2 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

실제로 웹 서비스의 계약에 의해 사용에서 유형을 다시 사용하려는 어셈블리는, 그럼 그냥 제안 @peer처럼 추가하면 아마 작업을해야하는 경우! 모든 svcutil은/reference 옵션이 필요하다. 그가 말한 것과 매핑되는 것은 무엇인가. 그렇지 않은 경우 svcutil.exe는 어셈블리의 "A"유형과 서비스의 "A"유형이 같지 않다고 생각합니다. 이름이나 네임 스페이스 또는 XML 네임 스페이스 (또는 스키마가 실제로는 다릅니다)에 미묘한 차이가 있습니다.

확인하시기 바랍니다. "Reuse existing types" is ignored when adding a service reference - '기존 어셈블리'의 '기존 유형'이 실제로 동일한 스키마 영역에 매핑되어 있는지 확인하십시오. 그 contract-attribute가 타입을 정의하는 어셈블리 안에 있어야한다는 것을 명심하십시오! 그것이 당신 것이면, 그냥 추가하고 다시 컴파일하십시오.

도 콘솔에서 svcutil을 수동으로 실행 해 보셨습니까? 당신은 아마 거기에 몇 가지 추가 오류/경고를 얻을 것이다, 아마도 그들은 실제 문제가 무엇인지 지적 할 것입니다.

5

당신이 이미 svcutil이 옵션 (/ 참조 플래그)을 지원한다는 것을 알고 있기 때문에. 그래서 당신이 필요로하는 모든 반사판에 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

관련 문제