Got an app with plugins that generates the WCF Client Contract programmatically and then hooks it up to the plugins interfaces, however im struggling to work out how to get the generated contract to reuse types found in the plugin dlls.
Does any one know how to setup the ServiceContractGenerator to reuse types in defined assemblies?
This is what i use to generate the contract code 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");
}
Edit: I never got this to work quite right, however i did manage to load the exe as an assembly and use that to generate the 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;
}
as you already know svcutil support this option (/reference flag). so all you need is to open svcutil.exe in reflector and do the same as this method: 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);
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With