. NET Dynamic compilation and WS service calling

Source: Internet
Author: User

Is dynamic compilation related to the WS service? Today, we are just a little confused about how to use dynamic compilation to dynamically generate the WS service call proxy class, and then call the WS service through this proxy class.
First, dynamic compilation is very simple in. NET. In fact, it only involves two types: CodeDomProvider and CompilerParameters, all of which are in the System. CodeDom. Compiler namespace.
The following code dynamically compiles the source code into an assembly:
Dynamic Compilation
Copy codeThe Code is as follows:
CodeDomProvider provider = CodeDomProvider. CreateProvider ("CSharp ");
CompilerParameters codeParameters = new CompilerParameters ();
CodeParameters. GenerateExecutable = false; // compile to dll. If it is true, compile to exe.
CodeParameters. GenerateInMemory = true; // The compiled assembly is saved to the memory.
StringBuilder code = new StringBuilder ();
// Construct the source code here
CompilerResults results = provider. CompileAssemblyFromSource (codeParameters, code. ToString ());
Assembly assembly = null; // The Assembly generated by dynamic compilation
If (! Results. Errors. HasErrors)
{
Assembly = results. CompiledAssembly;
}

After the assembly is obtained, we can then obtain the types in the assembly through reflection, instantiate them, call the type method...
But before that, we have to construct the WS service proxy class. What does it look like? Using the WCF framework, it is also very simple to create a service proxy class. The common proxy class structure is as follows:
Service call proxy
Copy codeThe Code is 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, to dynamically construct the proxy source code, we should know the service namespace, service method Action address, ReplyAction address, and of course the service method name, return type, and parameter list. Here, we omit the parameter list of the service method and construct the proxy class, which is actually a string assembly problem. First, create a type to save the parameters used to construct the proxy class:

Service proxy class construction parameters
Copy codeThe Code is 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;
}
}
}

Well, now we only need to construct the proxy class source code, then dynamically compile the proxy class assembly, and finally call the service method through reflection:
WebServiceProxyCreator
Copy codeThe Code is 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 demonstrate the call of traditional WebService
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"); // disable the proxy
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: In the red part, because the proxy class uses the WCF framework, we need to add System during compilation. serviceModel reference, of course, System. dll is required. Note that System. serviceModel. dll should be saved to the application directory. Otherwise, an exception is thrown during dynamic compilation. It is very easy to add System to the project reference. reference of ServiceModel, and set the copy to local property to true in the property.
At this point, we can directly call the service by passing in the service address, service method name, and related namespace (although we can only call the service without parameters, and even though we can only call services bound with BasicHttpBinding, the reasons for these restrictions are... I'm lazy, okay. I believe that these restrictions can be removed after a few changes ).
Unfortunately, our program is still silly: Every time we call a service, we need to generate code, compile, create a proxy instance, and then call it... Then cache it:
In the WebServiceParameters class, override the GetHashCode method:
Copy codeThe Code is as follows:
Public override int GetHashCode ()
{
Return String. Concat (serviceNamespace, methodAction, methodReplyAction, methodName, returnType). GetHashCode ();
}


Then add the cache mechanism to WebServiceProxyCreator:
Copy codeThe Code is 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 ("Using 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 demonstrate the call of traditional WebService
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"); // disable the proxy
Mi. Invoke (client, null );
Return result;
}

}

Related Article

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.