. NET dynamic compilation and WS service invocation detailed _ Practical skills

Source: Internet
Author: User
Tags reflection

is dynamic compilation related to the WS service? Luantan today, how to use dynamic compilation to generate a proxy class for a WS service invocation, and then invoke the WS service through this proxy class.
First, dynamically compile this thing in. NET is very simple, actually only involves two types: CodeDomProvider and CompilerParameters They are all in the System.CodeDom.Compiler namespace.
The following code can dynamically compile source code into an assembly:
Dynamic compilation

Copy Code code as follows:

CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
CompilerParameters codeparameters = new CompilerParameters ();
Codeparameters.generateexecutable = false; Compile as DLL, and if true compile as exe
Codeparameters.generateinmemory = true; The compiled assembly is saved in memory
StringBuilder code = new StringBuilder ();
Source code is constructed here
CompilerResults results = Provider.compileassemblyfromsource (codeparameters, code. ToString ());
Assembly Assembly = null; Dynamically compiling a generated assembly
if (!results. Errors.haserrors)
{
Assembly = results.compiledassembly;
}

After we get the assembly, we can then get the types inside the assembly through reflection, then instantiate, call the type method ...
But before we do, we have to construct the proxy class for WS service, what does it look like? We use the WCF framework to create a service proxy class is also very simple, the common proxy class structure is as follows:
Service Invocation proxy class
Copy Code code as follows:

[ServiceContract (namespace= "http://www.jb51.net/")]
public interface Testservice
{
[OperationContract (Action = "Http://www.jb51.net/HelloWorld", replyaction = "Http://www.jb51.net/HelloWorldResponse ")]
String HelloWorld ();
}
public class Testserviceclient:clientbase<testservice>, Testservice
{
Public Testserviceclient (Binding Binding, endpointaddress address):
Base (binding, address)
{
}
public string HelloWorld ()
{
Return base. Channel.helloworld ();
}
}

Therefore, we should dynamically construct the proxy class source code, should know the service namespace, the service method's action address, the Replyaction address, certainly also has the service method the name, the return type, the parameter list. Here, we omit the parameter list of the service method and construct the proxy class, which is actually a problem of string assembly, first creating a type that holds the parameters to be used for constructing the proxy class:

Service proxy class constructor parameters

Copy Code code as follows:

public class Webserviceparamaters
{
public string address;
public string Address
{
get {return address;}
Set
{
address = value;
}
}
private string Servicenamespace;
public string Servicenamespace
{
get {return servicenamespace;}
Set
{
Servicenamespace = value;
}
}
private string methodaction;
public string Methodaction
{
get {return methodaction;}
Set
{
Methodaction = value;
}
}
private string methodreplyaction;
public string Methodreplyaction
{
get {return methodreplyaction;}
Set
{
Methodreplyaction = value;
}
}
private String methodname;
public string methodname
{
get {return methodname;}
Set
{
methodname = value;
}
}
private string ReturnType;
public string ReturnType
{
get {return returntype;}
Set
{
ReturnType = value;
}
}
}

OK, now we just need to construct the proxy class source code, and then dynamically compile the proxy class assembly, and finally invoke the service method by reflection:
Webserviceproxycreator
Copy Code code as follows:

public class Webserviceproxycreator
{
Public Object Webservicecaller (webserviceparamaters parameters)
{
CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
CompilerParameters codeparameters = new CompilerParameters ();
Codeparameters.generateexecutable = false;
Codeparameters.generateinmemory = true;
StringBuilder code = new StringBuilder ();
Createproxycode (code, parameters);
CODEPARAMETERS.REFERENCEDASSEMBLIES.ADD ("System.dll");
CODEPARAMETERS.REFERENCEDASSEMBLIES.ADD ("System.ServiceModel.dll");
CompilerResults results = Provider.compileassemblyfromsource (codeparameters, code. ToString ());
Assembly Assembly = null;
if (!results. Errors.haserrors)
{
Assembly = results.compiledassembly;
}
Type clienttype = assembly. GetType ("Runtimeserviceclient");
ConstructorInfo ci = clienttype.getconstructor (new type[] {typeof (Binding), typeof (EndpointAddress)});
BasicHttpBinding binding = new BasicHttpBinding (); Only demo of traditional WebService calls
EndpointAddress address = new EndpointAddress (parameters.address);
Object client = ci. Invoke (new object[] {binding, address});
MethodInfo mi = clienttype.getmethod (parameters. MethodName);
Object result = mi. Invoke (client, NULL);
Mi = Clienttype.getmethod ("close"); Close Agent
Mi. Invoke (client, NULL);
return result;
}
public static void Createproxycode (StringBuilder code, webserviceparamaters parameters)
{
Code. Appendline ("Using System;");
Code. Appendline ("Using System.ServiceModel;");
Code. Appendline ("Using System.ServiceModel.Channels;");
Code. Append (@ "[ServiceContract (");
if (! String.IsNullOrEmpty (Parameters. Servicenamespace))
{
Code. Append ("namespace=\"). Append (Parameters. Servicenamespace). Append ("\");
}
Code. Appendline (")]");
Code. Appendline ("Public Interface Iruntimeservice");
Code. Appendline ("{");
Code. Append ("[OperationContract (");
if (! String.IsNullOrEmpty (Parameters. Methodaction))
{
Code. Append ("action=\"). Append (Parameters. methodaction). Append ("\");
if (! String.IsNullOrEmpty (Parameters. Methodreplyaction))
{
Code. Append (",");
}
}
if (! String.IsNullOrEmpty (Parameters. Methodreplyaction))
{
Code. Append ("replyaction=\"). Append (Parameters. methodreplyaction). Append ("\");
}
Code. Appendline (")]");
Code. Append (Parameters. ReturnType). Append ("");
Code. Append (Parameters. MethodName). Appendline ("();");
Code. Appendline ("}");
Code. Appendline ();
Code. Appendline ("public class runtimeserviceclient:clientbase<iruntimeservice>, Iruntimeservice");
Code. Appendline ("{");
Code. Appendline ("Public runtimeserviceclient (Binding Binding, endpointaddress address): Base (Binding, Address)");
Code. Appendline ("{");
Code. Appendline ("}");
Code. Append ("public"). Append (Parameters. ReturnType). Append ("");
Code. Append (Parameters. MethodName). Appendline ("()");
Code. Appendline ("{");
Code. Append ("return base.") Channel. "). Append (Parameters. MethodName). Appendline ("();");
Code. Appendline ("}");
Code. Appendline ("}");
}
}

Note that the Red section, because the proxy class uses the WCF framework, So compile when we need to add System.ServiceModel reference, of course System.dll must be, here to note that System.ServiceModel.dll should be saved to the application directory, otherwise dynamic compilation will throw an exception, very simple, in the project reference to add Sy Stem. ServiceModel, and then set the copy to local property to true in the attribute.
In this way, we can invoke the service directly through the incoming service address, service method name, and associated namespace (although we can only invoke the parameterless service, and although we can only invoke services that use basichttpbinding bindings, these limitations are due to ...). I am lazy, OK, I believe that as long as a little change can remove these restrictions.
Unfortunately, our program is still silly: every call to the service need to generate code, compile, create proxy instance finally call, um ... Let's cache it:
To override the GetHashCode method in the Webserviceparameters class:
Copy Code code as follows:

public override int GetHashCode ()
{
Return String.Concat (Servicenamespace, Methodaction, Methodreplyaction, MethodName, ReturnType). GetHashCode ();
}


Then add the caching mechanism to the Webserviceproxycreator:
Copy Code code as follows:

public class Webserviceproxycreator
{
private static Dictionary<int, type> Proxytypecatch = new Dictionary<int, type> ();

Public Object Webservicecaller (webserviceparamaters parameters)
{
int key = parameters. GetHashCode ();
Type clienttype = null;
if (Proxytypecatch.containskey (key))
{
ClientType = Proxytypecatch[key];
Debug.WriteLine ("use cache");
}
Else
{

CodeDomProvider Provider = Codedomprovider.createprovider ("CSharp");
CompilerParameters codeparameters = new CompilerParameters ();
Codeparameters.generateexecutable = false;
Codeparameters.generateinmemory = true;

StringBuilder code = new StringBuilder ();
Createproxycode (code, parameters);

CODEPARAMETERS.REFERENCEDASSEMBLIES.ADD ("System.dll");
CODEPARAMETERS.REFERENCEDASSEMBLIES.ADD ("System.ServiceModel.dll");

CompilerResults results = Provider.compileassemblyfromsource (codeparameters, code. ToString ());
Assembly Assembly = null;
if (!results. Errors.haserrors)
{
Assembly = results.compiledassembly;
}

ClientType = assembly. GetType ("Runtimeserviceclient");

Proxytypecatch.add (key, ClientType);
}
ConstructorInfo ci = clienttype.getconstructor (new type[] {typeof (Binding), typeof (EndpointAddress)});
BasicHttpBinding binding = new BasicHttpBinding (); Only demo of traditional WebService calls
EndpointAddress address = new EndpointAddress (parameters.address);
Object client = ci. Invoke (new object[] {binding, address});

MethodInfo mi = clienttype.getmethod (parameters. MethodName);
Object result = mi. Invoke (client, NULL);
Mi = Clienttype.getmethod ("close"); Close Agent
Mi. Invoke (client, NULL);
return result;
}

}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.