展会信息港展会大全

.NET的动态编译与WS服务调用详解
来源:互联网   发布日期:2016-01-27 15:17:30   浏览:1353次  

导读:这篇文章介绍了 NET的动态编译与WS服务调用详解,有需要的朋友可以参考一下,希望对你有所帮助 动态编译与WS服务,有关系么?今天就乱弹一番,如何使用动态编译动态生成WS服务调用的代理类,然后通过这个代理 ...

这篇文章介绍了.NET的动态编译与WS服务调用详解,有需要的朋友可以参考一下,希望对你有所帮助

动态编译与WS服务,有关系么?今天就乱弹一番,如何使用动态编译动态生成WS服务调用的代理类,然后通过这个代理类调用WS服务。

首先,动态编译这玩意在.NET里面是非常简单的,实际上只涉及到两个类型:CodeDomProvider以及CompilerParameters他们都位于System.CodeDom.Compiler命名空间。

以下代码可将源码动态编译为一个程序集:

动态编译

复制代码 代码如下:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

CompilerParameters codeParameters = new CompilerParameters();

codeParameters.GenerateExecutable = false; //编译为dll,如果为true则编译为exe

codeParameters.GenerateInMemory = true; //编译后的程序集保存到内存中

StringBuilder code = new StringBuilder();

//此处构造源代码

CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());

Assembly assembly = null; //动态编译生成的程序集

if (!results.Errors.HasErrors)

{

assembly = results.CompiledAssembly;

}

获得assembly后,随后我们即可以通过反射获取程序集里面的类型,然后实例化,调用类型方法

不过在此之前,我们得构造WS服务的代理类,它是什么样子的呢?我们使用WCF框架,创建服务代理类也是十分简单的,常见的代理类结构如下:

服务调用代理类

复制代码 代码如下:

[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();

}

}

所以,我们要动态构造出代理类源码,应该知道服务的命名空间、服务方法的Action地址、ReplyAction地址,当然还有服务方法的名称,返回类 型,参数列表。这里,我们省略掉服务方法的参数列表,构造代理类,实际上就是一个字符串组装的问题,先创建一个类型,用于保存构造代理类所要用到的参数:

服务代理类构造参数

复制代码 代码如下:

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;

}

}

}

好,现在我们只需要构造出代理类源码,然后动态编译出代理类的程序集,最后通过反射调用服务方法:

WebServiceProxyCreator

复制代码 代码如下:

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(); //只演示传统的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"); //关闭代理

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("}");

}

}

注意,红色部分,由于代理类使用了WCF框架,所以编译时我们需要添加System.ServiceModel的引用,当然System.dll肯定是必 须的,这里要注意,System.ServiceModel.dll应该保存到应用程序目录,否则动态编译时会引发异常,很简单,在工程引用中添加 System.ServiceModel的引用,然后在属性中将拷贝到本地属性设置为true。

到此,我们就可以直接通过传入的服务地址、服务方法名称以及相关的命名空间,即可调用服务(尽管我们只能调用无参服务,并且尽管我们也只能调用使用 BasicHttpBinding绑定的服务,这些限制的原因是 我懒,好吧,相信只要经过一点改动即可去掉这些限制)。

可惜,我们的程序还很傻:每次调用服务都需要去生成代码、编译、创建代理实例最后再调用,嗯 那就缓存吧:

在WebServiceParameters类中重写GetHashCode方法:

复制代码 代码如下:

public override int GetHashCode()

{

return String.Concat(serviceNamespace, methodAction, methodReplyAction, methodName, returnType).GetHashCode();

}

然后在WebServiceProxyCreator中加入缓存机制:

复制代码 代码如下:

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("使用缓存");

}

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(); //只演示传统的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"); //关闭代理

mi.Invoke(client, null);

return result;

}

}

赞助本站

人工智能实验室

相关热词: 编译 NET

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港