Three ways to dynamically invoke WebService
Most of the time we "add Web references ..." The client proxy class is created in a way that calls WebService, but in some cases we may need to dynamically invoke an unknown service while the program is running. There is something we need in the System.Web.Services.Description namespace of the. NET Framework.
Specific steps:
1. Download the WSDL data from the target URL.
2. Use ServiceDescription to create and format WSDL document files.
3. Create the client proxy class using ServiceDescriptionImporter.
4. Dynamically create client proxy class assemblies using CodeDom.
5. Invoke the relevant WebService method using reflection.
The above steps need to refer to the following four namespaces:
Using System.Web.Services.Description; Description of WS
The following several are used to dynamically generate code based on the description and to dynamically compile the fetch assembly
Using System.CodeDom;
Using Microsoft.csharp;
Using System.CodeDom.Compiler;
The following several important classes are included in the above namespaces:
Using System.Web.Services.Description:
ServiceDescription//WS Description
ServiceDescriptionImporter///Generate client proxy class by description, pay special attention to the style
The following is a description of MSDN for this:
Interfaces for Xmlweb services are typically described by Web Services Description Language (WSDL) files. For example, to get a WSDL description of a asp.net Web service that is exposed using http://localhost/service.asmx, simply navigate to Http://localhost/service.asmx?WSDL. The ServiceDescriptionImporter class makes it easy to import information contained in a WSDL description into a System.CodeDom.CodeCompileUnit object. By adjusting the value of the Style parameter, you can instruct the ServiceDescriptionImporter instance to generate a client proxy class (by transparently calling the class to provide the functionality of the Web service) or to generate an abstract class that encapsulates the functionality of the Web service and does not implement it. If you set the Style property to client, ServiceDescriptionImporter generates client proxy classes that provide the functionality of the described WEB service by calling these classes. If you set the Style property to Server, the ServiceDescriptionImporter instance generates abstract classes that represent the functionality of the XML WEB services described and do not implement them. You can then implement them by writing classes that inherit from these abstract classes, and implement related methods.
Using system.codedom:
codedomunit//It is used to set the dynamic code namespace, class name, etc., you can write the WS description code to the class by Servicedescriptionimporter.import () method for dynamic compilation
Using System.CodeDom.Compiler:
CodeDomProvider//for creating and retrieving instances of code generators and code compilers, we mainly use them to implement subclasses Csharecodeprovider
Can be generated directly using Csharecodeproviderprovider=new Csharecodeprovider (), or Codedomprovider.createprovider ("CSharp") to generate
ICodeCompiler//For compiling source code representations based on System.CodeDom.
It uses the CodeDomProvider CreateCompiler () method to
CompilerResults//Represents the result of the compilation returned from the compiler. It compiles and returns the assembly from the System.CodeDom tree contained in the specified CodeCompileUnit, based on the compiler settings specified by ICodeCompiler. The Compiledassembly property indicates the compiled assembly.
Once you know the information, you can invoke WS dynamically.
OK, look at the specific example.
We want to call the target WebService, whose URL is Http://localhost:60436/Learn.WEB/WebService.asmx
HelloWorld.asmx
[WebService (Namespace = "http://www.rainsts.net/", description= "my Web Service")]
[WebServiceBinding (ConformsTo = wsiprofiles.basicprofile1_1)]
public class WebService:System.Web.Services.WebService {
Public WebService () {
}
[WebMethod]
public string HelloWorld ()
{
Return "Hello wolrd!";
}
}
1. Dynamic Call WebService
Client Dynamic Call Code
Using System.IO;
Using System.Net;
Using System.Reflection;
Using System.CodeDom;
Using System.CodeDom.Compiler;
Using System.Web.Services;
Using System.Web.Services.Description;
Using System.Web.Services.Protocols;
Using System.Xml.Serialization;
1. Use WebClient to download WSDL information.
WebClient Web = new WebClient ();
Stream Stream =web. OpenRead ("Http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
2. Create and format WSDL documents.
ServiceDescription Description = Servicedescription.read (stream);
3. Create the client proxy proxy class.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter ();
Importer. ProtocolName = "Soap"; Specifies the Access protocol.
Importer. Style = servicedescriptionimportstyle.client; Generate the client proxy.
Importer. CodeGenerationOptions = Codegenerationoptions.generateproperties | Codegenerationoptions.generatenewasync;
Importer. Addservicedescription (description, NULL, NULL); Adds a WSDL document.
4. Use CodeDom to compile the client proxy class.
CodeNamespace nmspace = new CodeNamespace (); Adds a namespace to the proxy class, which defaults to global space.
CodeCompileUnit unit = new CodeCompileUnit ();
Unit. Namespaces.add (Nmspace);
Servicedescriptionimportwarnings warning = importer. Import (nmspace, unit);
CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
CompilerParameters parameter = new CompilerParameters ();
Parameter. GenerateExecutable = false;
Parameter. GenerateInMemory = true;
Parameter. Referencedassemblies.add ("System.dll");
Parameter. Referencedassemblies.add ("System.XML.dll");
Parameter. Referencedassemblies.add ("System.Web.Services.dll");
Parameter. Referencedassemblies.add ("System.Data.dll");
CompilerResults result = provider.compileassemblyfromdom (parameter, unit);
5. Use Reflection to invoke WebService.
if (!result. Errors.haserrors)
{
Assembly asm = result.compiledassembly;
Type t = asm. GetType ("WebService"); If you added a namespace to the proxy class earlier, you would need to add the namespace to the front of the type.
Object o = activator.createinstance (t);
MethodInfo method = T.getmethod ("HelloWorld");
Console.WriteLine (method. Invoke (o, null));
}
2. Generate Client Agent assembly files
The above code completes the dynamic invocation process by creating a dynamic assembly in memory. If we want to save the client proxy class build assembly file to a hard disk, you can make the following modifications. After the assembly file is generated, we can load and make reflection calls through Assembly.LoadFrom (). For systems that require multiple calls, it is much more efficient than generating dynamic assemblies at a time.
Using System.IO;
Using System.Net;
Using System.CodeDom;
Using System.CodeDom.Compiler;
Using System.Web.Services;
Using System.Web.Services.Description;
Using System.Web.Services.Protocols;
Using System.Xml.Serialization;
1. Use WebClient to download WSDL information.
WebClient Web = new WebClient ();
Stream Stream =web. OpenRead ("Http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
2. Create and format WSDL documents.
ServiceDescription Description = Servicedescription.read (stream);
3. Create the client proxy proxy class.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter ();
Importer. ProtocolName = "Soap"; Specifies the Access protocol.
Importer. Style = servicedescriptionimportstyle.client; Generate the client proxy.
Importer. CodeGenerationOptions = Codegenerationoptions.generateproperties | Codegenerationoptions.generatenewasync;
Importer. Addservicedescription (description, NULL, NULL); Adds a WSDL document.
4. Use CodeDom to compile the client proxy class.
CodeNamespace nmspace = new CodeNamespace (); Adds a namespace to the proxy class, which defaults to global space.
CodeCompileUnit unit = new CodeCompileUnit ();
Unit. Namespaces.add (Nmspace);
Servicedescriptionimportwarnings warning = importer. Import (nmspace, unit);
CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
CompilerParameters parameter = new CompilerParameters ();
Parameter. GenerateExecutable = false;
Parameter. outputassembly = "Test.dll"; You can specify any file name you want.
Parameter. Referencedassemblies.add ("System.dll");
Parameter. Referencedassemblies.add ("System.XML.dll");
Parameter. Referencedassemblies.add ("System.Web.Services.dll");
Parameter. Referencedassemblies.add ("System.Data.dll");
CompilerResults result = provider.compileassemblyfromdom (parameter, unit);
if (result. Errors.haserrors)
{
displaying compilation error messages
}
Invoke assembly file Demo
Assembly asm =assembly.loadfrom ("Test.dll");
Type t = asm. GetType ("WebService");
Object o = activator.createinstance (t);
MethodInfo method = T.getmethod ("HelloWorld");
Console.WriteLine (method. Invoke (o, null));
3. Get the client proxy class source code
There is also a situation where we need to get the C # source code of the client proxy class.
Using System.IO;
Using System.Net;
Using System.CodeDom;
Using System.CodeDom.Compiler;
Using System.Web.Services;
Using System.Web.Services.Description;
Using System.Web.Services.Protocols;
Using System.Xml.Serialization;
1. Use WebClient to download WSDL information.
WebClient Web = new WebClient ();
Stream Stream =web. OpenRead ("Http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
2. Create and format WSDL documents.
ServiceDescription Description = Servicedescription.read (stream);
3. Create the client proxy proxy class.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter ();
Importer. ProtocolName = "Soap"; Specifies the Access protocol.
Importer. Style = servicedescriptionimportstyle.client; Generate the client proxy.
Importer. CodeGenerationOptions = Codegenerationoptions.generateproperties | Codegenerationoptions.generatenewasync;
Importer. Addservicedescription (description, NULL, NULL); Adds a WSDL document.
4. Use CodeDom to compile the client proxy class.
CodeNamespace nmspace = new CodeNamespace (); Adds a namespace to the proxy class, which defaults to global space.
CodeCompileUnit unit = new CodeCompileUnit ();
Unit. Namespaces.add (Nmspace);
Servicedescriptionimportwarnings warning = importer. Import (nmspace, unit);
CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
5. Save source code to file. Of course, you can also save it directly into the memory string.
TextWriter writer = File.createtext ("Test.cs"); Specify the source code file name you want.
Provider. Generatecodefromcompileunit (unit, writer, null);
Writer. Flush ();
Writer. Close ();
If you invoke the trigger "WebException: Request failed for HTTP status 415: Unsupported Media Type." "Such an exception, then congratulate you and I as depressed, hurriedly turn off the server-side WSE." In cases where WSE must be used, the client needs to be adjusted, and the code needs to be written by yourself. hehe ~ ~ ~ ~ ~