这篇文章介绍了
NET的动态编译与WS服务调用详解
有需要的朋友可以参考一下
希望对你有所帮助
动态编译与WS服务有关系么?今天就乱弹一番如何使用动态编译动态生成WS服务调用的代理类然后通过这个代理类调用WS服务
首先动态编译这玩意在NET里面是非常简单的实际上只涉及到两个类型CodeDomProvider以及CompilerParameters他们都位于SystemCodeDomCompiler命名空间
以下代码可将源码动态编译为一个程序集
动态编译
复制代码 代码如下:
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="]
public interface TestService
{
[OperationContract(Action = "
ReplyAction = "]
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框架所以编译时我们需要添加SystemServiceModel的引用当然Systemdll肯定是必 须的这里要注意SystemServiceModeldll应该保存到应用程序目录否则动态编译时会引发异常很简单在工程引用中添加 SystemServiceModel的引用然后在属性中将拷贝到本地属性设置为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 = parametersGetHashCode();
Type clientType = null;
if (proxyTypeCatchContainsKey(key))
{
clientType = proxyTypeCatch[key];
DebugWriteLine("使用缓存");
}
else
{
CodeDomProvider provider = CodeDomProviderCreateProvider("CSharp");
CompilerParameters codeParameters = new CompilerParameters();
codeParametersGenerateExecutable = false;
codeParametersGenerateInMemory = true;
StringBuilder code = new StringBuilder();
CreateProxyCode(code parameters);
codeParametersReferencedAssembliesAdd("Systemdll");
codeParametersReferencedAssembliesAdd("SystemServiceModeldll");
CompilerResults results = providerCompileAssemblyFromSource(codeParameters codeToString());
Assembly assembly = null;
if (!resultsErrorsHasErrors)
{
assembly = resultsCompiledAssembly;
}
clientType = assemblyGetType("RuntimeServiceClient");
proxyTypeCatchAdd(key clientType);
}
ConstructorInfo ci = clientTypeGetConstructor(new Type[] { typeof(Binding) typeof(EndpointAddress) });
BasicHttpBinding binding = new BasicHttpBinding(); //只演示传统的WebService调用
EndpointAddress address = new EndpointAddress(parametersaddress);
Object client = ciInvoke(new object[] { binding address });
MethodInfo mi = clientTypeGetMethod(parametersMethodName);
Object result = miInvoke(client null);
mi = clientTypeGetMethod("Close"); //关闭代理
miInvoke(client null);
return result;
}
}