在运行时从XSD生成类

时间:2015-04-21 13:20:29

标签: c#

如何在运行时从XSD生成C#类?

此外,它如何列出类型包含的属性?

1 个答案:

答案 0 :(得分:3)

绝对有可能..而且不太复杂。你只需要添加一些不同的技术。 您可以使用"描述导入器"在运行时导入服务描述。 Link

我所做的基本上是创建以下步骤:

1)使用阅读器(本地或远程,不同方法)获取WSDL文件

XmlTextReader myXmlReader;
myWebService = new WebServiceImporterCompiler(WSDLPath, soapVersion);

if (useLocalWSDL)
{
     FileWebRequest wr = (FileWebRequest)FileWebRequest.Create(WSDLPath);
     FileWebResponse wres = (FileWebResponse)wr.GetResponse();
     myXmlReader = new XmlTextReader(wres.GetResponseStream());
}
else
{
     Uri uri = new Uri(WSDLPath); //WEBSERVICE URI
     HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(uri.OriginalString + "?wsdl");
     wr.Credentials = wr.Credentials = new NetworkCredential(userName, password ?? "");
     HttpWebResponse wres = (HttpWebResponse)wr.GetResponse();
     myXmlReader = new XmlTextReader(wres.GetResponseStream());
}

2)从definition / myXmlReader

构建程序集

检查xml是否可读

if (!System.Web.Services.Description.ServiceDescription.CanRead(myXmlReader)) 
{
           throw new IOException("WSDL not readable");
}

使用一些基本选项加载导入程序(您可以在此处添加/更改内容) 我创建了一个程序集(dll),但是使用开关 parameters.GenerateInMemory ,您将能够生成内存类。

ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
ServiceDescription serviceDescription = ServiceDescription.Read(myXmlReader);
descriptionImporter.ProtocolName = soapVersion.ToString(); // EITHER SOAP OR SOAP12
descriptionImporter.AddServiceDescription(serviceDescription, null, null);
descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

使用CodeDomProvider编译程序集

CodeCompileUnit codeUnit = new CodeCompileUnit();
CodeNamespace codeNamespace = new CodeNamespace();
codeUnit.Namespaces.Add(codeNamespace); // Add additional Namespaces
ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);
if (importWarnings == 0)
{
      using (CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp"))
      {
           string[] references = { "System.dll", "System.Web.Services.dll", "System.Xml.dll" };
           CompilerParameters parameters = new CompilerParameters(references); 
           parameters.GenerateExecutable = false;
           parameters.GenerateInMemory = false;
           parameters.IncludeDebugInformation = false;
           parameters.CompilerOptions = "/optimize";
           parameters.TempFiles = new TempFileCollection(System.IO.Path.GetTempPath() + "xxx", false);
           parameters.ReferencedAssemblies.Add("System.dll");

           results = compiler.CompileAssemblyFromSource(parameters, CSharpCode);
           foreach (CompilerError cError in results.Errors)
           {
               // log errors
           }
           if (results.Errors.Count > 0 || results.CompiledAssembly == null) throw new Exception("Kompilierfehler bei Assemblyerstellung");
       }
 }

3)使用生成的asssembly对象来调用方法,例如调用服务

public T InvokeMethod <T>(Assembly assembly, string serviceNameToCall, MethodInfo methodToCall)
{
        SoapHttpClientProtocol mySoapProtocoll;
    try
    {
         object serviceInstance = myAssembly.CreateInstance(serviceNameToCall);
         mySoapProtocoll = (SoapHttpClientProtocol)serviceInstance;
         mySoapProtocoll.Credentials = CredentialCache.DefaultCredentials; // or use your own
         object myObject = (T)ServiceType.InvokeMember(methodToCall, BindingFlags.InvokeMethod, null, mySoapProtocoll, args);
    }
}

要获取methodInfo对象/可用方法,请使用反射来迭代程序集/类。

可以找到完整的反思指南here