Generally, when we call WebService in a program, we use "add web reference" to let the Vs. NET environment generate a client proxy class for us and then call the corresponding web service.
If the URL of the published Web Service Changes on that day, we need to use the new asmx file connection to add "add web reference" so that vs. Net can generate a proxy and recompile it. In some cases, this is intolerable.
To this end, we need a dynamic WebService call function, and the. NET platform also provides corresponding solutions.
For example, you can save the Web Service URL in the configuration file. When the service URL changes, you only need to modify the configuration file.
There are multiple ways to dynamically call WebService, and the application scenarios are different.
Method 1
The content of the web service is not changed, but the content is changed. For example, from localhost: 8080/a. asmx to localhost: 8090/a. asmx. In this way, you do not have to re-Modify the Web reference by overwriting the URL.
Operation: manually add a "Web reference". For example, name it glwebreference.
Then, we call the WebService link configured in webconfig through configurationmanager. etettings ["gqwebservice. Override the URL address of the WebService object and call the corresponding method.
GLWebReference.SingerLoginWebService service = new GLWebReference.SingerLoginWebService(); service.Url = ConfigurationManager.AppSettings["gqWebService"]; string certificate = service.GetUserCertificate(loginName, domain);
Method 2,
In some cases, we may need to dynamically call an unknown service while the program is running. In the. NET Framework system. Web. Services. Description namespace, we need something.
Procedure:
1. Download the WSDL data from the target URL.
2. Use servicedescription to create and format the WSDL document file.
3. Use servicedescriptionimporter to create the client proxy class.
4. Use codedom to dynamically create client proxy assembly.
5. Call related WebService Methods Using Reflection.
The preceding steps reference the following four namespaces:
Using system. Web. Services. description; // ws description
The following describes how to dynamically generate code and dynamically compile and obtain the assembly.
using System.CodeDom;using Microsoft.CSharp;using System.CodeDom.Compiler;
The preceding namespaces include the following important classes:
Using system. Web. Services. Description:
Servicedescription // ws description
Servicedescriptionimporter // generate the client proxy class through description. Pay special attention to the style
The following is the description of msdn:
Xmlweb services interfaces are generally described in the Web Service Description Language (WSDL) file. For example, to obtain information about using http: // localhost/service. ASP. net web service. You only need to navigate to http: // localhost/service. asmx? WSDL. You can use the servicedescriptionimporter class to conveniently import the information contained in the WSDL description to the system. codedom. codecompileunit object. Adjust
The value of the style parameter indicates that the servicedescriptionimporter instance generates the client proxy class (the web service function can be provided by calling this class transparently) or generate an abstract class (this class encapsulates the functions of web services without implementing this function ). If you set the style attribute to client, servicedescriptionimporter generates client proxy classes and calls these classes to provide the Web service functions described in. If the style attribute is set to server, the servicedescriptionimporter instance generates an abstract class, which indicates
Xmlweb services is not implemented. Then, you can compile classes inherited from these abstract classes to implement them and implement relevant methods.
Using system. codedom:
Codedomunit // It is used to set the dynamic code namespace and class name. You can use servicedescriptionimporter. Import () to write the WS description code to this class for dynamic compilation.
Using system. codedom. Compiler:
Codedomprovider // an instance used to create and retrieve code generators and code compilers. We mainly use it to implement the csf-codeprovider subclass.
You can directly use csf-codeprovider provider = new csf-codeprovider () to generate, or use codedomprovider. createprovider ("CSHARP") to generate
Icodecompiler // compile the source code representation based on system. codedom.
It uses the createcompiler () method of codedomprovider
Compilerresults // indicates the compilation result returned from the compiler. It is compiled and returned by icodecompiler from the system. codedom tree contained in the specified codecompileunit according to the specified compiler settings. The compiledassembly attribute indicates the compiled assembly.
After learning the preceding information, you can call ws dynamically.
For example, the web. config configuration file contains the following WebService connection:
<add key="glWebService" value="http://128.3.110.9/hcs50_gl/App_Code_WebServiceWapper/SingerLoginWebService.asmx"/><add key="gqWebService" value="http://128.3.128.200:88/HCS50_GQKJ/App_Code_WebServiceWapper/SingerLoginWebService.asmx"/><add key="chWebService" value="http://128.3.146.6/HCS50_CHGS/App_Code_WebServiceWapper/SingerLoginWebService.asmx"/><add key="bmWebService" value="http://128.3.5.71:1000/App_Code_WebServiceWapper/SingerLoginWebService.asmx"/><add key="zhWebService" value="http://128.3.131.4:88/App_Code_WebServiceWapper/SingerLoginWebService.asmx"/>
Call
If (! String. isnullorempty (company) {webserviceurl = configurationmanager. deleetask[ company + "WebService"]; // obtain the WebService address of the configuration file hcsurl = configurationmanager. appsettings [company + "hcslink"];}
If (! String. callback (webserviceurl) // If the WebService address is not empty, dynamic WebService call {usercertificate = invokewebservice (webserviceurl, "hcssingerloginservice", "singerloginwebservice", "getusercertificate ", new object [] {loginname, domain}, company ). tostring (); If (! String. isnullorempty (usercertificate) {hcsurl + = string. Format ("? Userid = {0} & Password = & isadmin = false & logintime = & Certificate = {1} & referrer = {2} ", loginname, usercertificate, domain); response. write ("<SCRIPT> window. open ('"+ hcsurl +"') </SCRIPT> ");}}
/// Based on the specified information, call the remote WebService method /// </Summary> /// <Param name = "url"> HTTP address of WebService </param> /// <Param name =" namespace "> namespace of the WebService to be called </param> // <Param name =" classname "> Class Name of the WebService to be called (excluding the namespace prefix) </param> /// <Param name = "methodname"> Method Name of the WebService to be called </param> /// <Param name = "ARGs"> parameter list </param> /// <Param name = "company"> company </param> /// <returns> WebService execution result </returns> Public object in Vokewebservice (string URL, string namespace, string classname, string methodname, object [] ARGs, string Company) {try {// 1. use WebClient to download the WSDL information WebClient WC = new WebClient (); stream = WC. openread (URL + "? WSDL "); // 2. create and format the WSDL document servicedescription srvdesc = servicedescription. read (Stream); // 3. create a client proxy class servicedescriptionimporter srvdescinporter = new servicedescriptionimporter (); srvdescinporter. protocolname = "Soap"; // specify the access protocol srvdescinporter. style = servicedescriptionimportstyle. client; // generate a client proxy. Default Value. Srvdescinporter. addservicedescription (srvdesc, "", ""); // Add a WSDL document. // 4. Use codedom to compile the client proxy class. Codenamespace codenamespce = new codenamespace (namespace); codecompileunit = new codecompileunit (); codecompileunit. namespaces. add (codenamespce); srvdescinporter. import (codenamespce, codecompileunit); codedomprovider provider = codedomprovider. createprovider ("CSHARP"); // indicates the parameter used to call the compiler. System. codedom. compiler. compilerparameters parameter = new system. codedom. compiler. compilerparameters (); parameter. generateexecutable = false; // you can specify whether to generate an executable file. Parameter. generateinmemory = true; // you can specify whether output is generated in the memory. Parameter. referencedassemblies. Add ("system. dll"); // referencedassemblies obtains the Assembly referenced by the current project. Parameter. referencedassemblies. add ("system. XML. DLL "); parameter. referencedassemblies. add ("system. web. services. DLL "); parameter. referencedassemblies. add ("system. data. DLL "); // gets the compilation result returned from the compiler. System. codedom. compiler. compilerresults Cr = provider. compileassemblyfromdom (parameter, codecompileunit); If (true = CR. errors. haserrors) {system. text. stringbuilder sb = new system. text. stringbuilder (); foreach (system. codedom. compiler. compilererror Ce IN Cr. errors) {sb. append (CE. tostring (); sb. append (system. environment. newline);} Throw new exception (sb. tostring ();} // obtain the compiled assembly and call it dynamically through reflection.. System. reflection. assembly = CR. compiledassembly; type T = assembly. getType (namespace + ". "+ classname, true, true); // if you have added a namespace for the proxy class before, you must add the namespace before the type. Object OBJ = activator. createinstance (t); system. reflection. methodinfo MI = T. getmethod (methodname); Return mi. invoke (OBJ, argS);} catch (exception ex) {// throw new exception (ex. innerexception. message, new exception (ex. innerexception. stacktrace); Switch (company) {Case "Gl": companyName = "Guang le Company"; break; Case "GQ": companyName = "Guang Qing Company"; break; case "BM": companyName = "Bao Mao Company"; break; Case "ZH": companyName = "Zhao Hua Company"; break; Case "ch ": companyName = "chaohui Company"; break;} showformat. showmsg ("Remote Access failed" + companyName); Return "";}}
Generate client proxy Assembly File
The above code completes the dynamic calling process by creating a dynamic assembly in the memory. If you want to save the Assembly file generated by the client proxy class to the hard disk, you can make the following changes. After the Assembly file is generated, we can load it and call it through Assembly. loadfrom. Systems that require multiple calls are much more efficient than generating a dynamic assembly each 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 the WSDL information. WebClient web = new WebClient (); stream = web. openread ("http: // localhost: 60436/learn. Web/WebService. asmx? WSDL "); // 2. Create and format the WSDL document. Servicedescription description = servicedescription. Read (Stream); // 3. Create a client proxy class. Servicedescriptionimporter importer = new servicedescriptionimporter (); importer. protocolname = "Soap"; // specify the access protocol. Importer. Style = servicedescriptionimportstyle. Client; // generate a client proxy. Importer. codegenerationoptions = codegenerationoptions. generateproperties | codegenerationoptions. generatenewasync; importer. addservicedescription (description, null, null); // Add a WSDL document. // 4. Use codedom to compile the client proxy class. Codenamespace nmspace = new codenamespace (); // Add a namespace for the proxy class. The default value is 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 need. 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) {// display the compilation error message} call the Assembly file to demonstrate 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 ));