要求:
我无法使用MetadataExchangeClient,因为不会托管WSDL。
实施
var serviceDescription = ServiceDescription.Read(@"C:\Contacts.WSDL");
var metadataSection = new MetadataSection
{
Dialect = MetadataSection.ServiceDescriptionDialect,
Identifier = serviceDescription.TargetNamespace,
Metadata = serviceDescription
};
var metadataSections = new List<MetadataSection> {metadataSection};
var metadatSet = new MetadataSet(metadataSections);
var wsdlImporter = new WsdlImporter(metadatSet);
var services = wsdlImporter.ImportAllEndpoints();
路障:
object retVal = instance.GetType().GetMethod(operationName) .Invoke(instance, operationParameters); // Invoke
我尝试通过硬编码操作名称,手动从WSDL解析,但随后它在参数上失败了。它期望包含层次结构的复杂类型如下:
ContactInput - &gt; ListOfContacts - &gt;联系 - &gt; FirstName,LastName
后续步骤:
如果有人可以帮我解决障碍,那么我可以继续采用上述方法。
否则,我必须开始研究在运行时使用svcutil.exe
谢谢, 开发
答案 0 :(得分:8)
有一个解决方案可以执行本文中描述的操作:
Generate proxy code for a web service dynamically
虽然你可以打开那个链接并阅读它,但我在这里包含了代码,以防链接在任何时候死亡:
此方法返回Web服务公开的操作列表。我已经使用ServiceDescription实现了这一点,因为我无法仅反映生成的Web方法名称。有了可用的操作名称,剩下的就是找出每种方法的输入和返回参数。
public string[] GenerateProxyAssembly()
{
//create a WebRequest object and fetch the WSDL file for the web service
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(this.uri);
request.Credentials = CredentialCache.DefaultCredentials;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
System.IO.Stream stream = response.GetResponseStream();
//read the downloaded WSDL file
ServiceDescription desc = ServiceDescription.Read(stream);
//find out the number of operations exposed by the web service
//store the name of the operations inside the string array
//iterating only through the first binding exposed as
//the rest of the bindings will have the same number
int i = 0;
Binding binding = desc.Bindings[0];
OperationBindingCollection opColl = binding.Operations;
foreach (OperationBinding operation in opColl)
{
listOfOperations[i++] = operation.Name;
}
//initializing a ServiceDescriptionImporter object
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
//set the protocol to SOAP 1.1
importer.ProtocolName = "Soap12";
//setting the Style to Client in order to generate client proxy code
importer.Style = ServiceDescriptionImportStyle.Client;
//adding the ServiceDescription to the Importer object
importer.AddServiceDescription(desc, null, null);
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync;
//Initialize the CODE DOM tree in which we will import the
//ServiceDescriptionImporter
CodeNamespace nm = new CodeNamespace();
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nm);
//generating the client proxy code
ServiceDescriptionImportWarnings warnings = importer.Import(nm, unit);
if (warnings == 0)
{
//set the CodeDOMProvider to C# to generate the code in C#
System.IO.StringWriter sw = new System.IO.StringWriter();
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions());
//creating TempFileCollection
//the path of the temp folder is hardcoded
TempFileCollection coll = new TempFileCollection(@"C:\wmpub\tempFiles");
coll.KeepFiles = false;
//setting the CompilerParameters for the temporary assembly
string[] refAssembly = { "System.dll", "System.Data.dll",
"System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters param = new CompilerParameters(refAssembly);
param.GenerateInMemory = true;
param.TreatWarningsAsErrors = false;
param.OutputAssembly = "WebServiceReflector.dll";
param.TempFiles = coll;
//compile the generated code into an assembly
//CompilerResults results = provider.CompileAssemblyFromDom(param, unitArr);
CompilerResults results
= provider.CompileAssemblyFromSource(param, sw.ToString());
this.assem = results.CompiledAssembly;
}
//return the list of operations exposed by the web service
return listOfOperations;
}
此方法返回ParameterInfo []列表中的输入参数。要获取输出参数,只需使用ReturnParameter属性替换对MethodInfo类的GetParamters()的调用,并将其放入新方法中。将这3个方法放在dll中,并从任何客户端应用程序添加对它的引用。这就是全部。只需提供URL并使用Web服务,任何Web服务。每次要使用新的Web服务时,都不必完成创建代理文件的过程。
public ParameterInfo[] ReturnInputParameters(string methodName)
{
//create an instance of the web service type
//////////////to do/////////////////////////
//get the name of the web service dynamically from the wsdl
Object o = this.assem.CreateInstance("Service");
Type service = o.GetType();
ParameterInfo[] paramArr = null;
//get the list of all public methods available in the generated //assembly
MethodInfo[] infoArr = service.GetMethods();
foreach (MethodInfo info in infoArr)
{
//get the input parameter information for the
//required web method
if (methodName.Equals(info.Name))
{
paramArr = info.GetParameters();
}
}
return paramArr;
}