c#

位置:IT落伍者 >> c# >> 浏览文章

.NET的动态编译与WS服务调用详解


发布日期:2022年04月24日
 
.NET的动态编译与WS服务调用详解
这篇文章介绍了NET的动态编译与WS服务调用详解有需要的朋友可以参考一下希望对你有所帮助

动态编译与WS服务有关系么?今天就乱弹一番如何使用动态编译动态生成WS服务调用的代理类然后通过这个代理类调用WS服务
首先动态编译这玩意在NET里面是非常简单的实际上只涉及到两个类型CodeDomProvider以及CompilerParameters他们都位于SystemCodeDomCompiler命名空间
以下代码可将源码动态编译为一个程序集
动态编译

复制代码 代码如下:
CodeDomProvider provider = CodeDomProviderCreateProvider("CSharp");
CompilerParameters codeParameters = new CompilerParameters();
codeParametersGenerateExecutable = false; //编译为dll如果为true则编译为exe
codeParametersGenerateInMemory = true; //编译后的程序集保存到内存中
StringBuilder code = new StringBuilder();
//此处构造源代码
CompilerResults results = providerCompileAssemblyFromSource(codeParameters codeToString());
Assembly assembly = null; //动态编译生成的程序集
if (!resultsErrorsHasErrors)
{
assembly = resultsCompiledAssembly;
}


获得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 baseChannelHelloWorld();
}
}


   所以我们要动态构造出代理类源码应该知道服务的命名空间服务方法的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 = 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;
}
Type clientType = assemblyGetType("RuntimeServiceClient");
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;
}
public static void CreateProxyCode(StringBuilder code WebServiceParamaters parameters)
{
codeAppendLine("using System;");
codeAppendLine("using SystemServiceModel;");
codeAppendLine("using SystemServiceModelChannels;");
codeAppend(@"[ServiceContract(");
if (!StringIsNullOrEmpty(parametersServiceNamespace))
{
codeAppend("Namespace="")Append(parametersServiceNamespace)Append(""");
}
codeAppendLine(")]");
codeAppendLine("public interface IRuntimeService");
codeAppendLine("{");
codeAppend("[OperationContract(");
if (!StringIsNullOrEmpty(parametersMethodAction))
{
codeAppend("Action="")Append(parametersMethodAction)Append(""");
if (!StringIsNullOrEmpty(parametersMethodReplyAction))
{
codeAppend(" ");
}
}
if (!StringIsNullOrEmpty(parametersMethodReplyAction))
{
codeAppend("ReplyAction="")Append(parametersMethodReplyAction)Append(""");
}
codeAppendLine(")]");
codeAppend(parametersReturnType)Append(" ");
codeAppend(parametersMethodName)AppendLine("();");
codeAppendLine("}");
codeAppendLine();
codeAppendLine("public class RuntimeServiceClient : ClientBase<IRuntimeService> IRuntimeService");
codeAppendLine("{");
codeAppendLine("public RuntimeServiceClient(Binding binding EndpointAddress address) :base(binding address)");
codeAppendLine("{");
codeAppendLine("}");
codeAppend("public ")Append(parametersReturnType)Append(" ");
codeAppend(parametersMethodName)AppendLine("()");
codeAppendLine("{");
codeAppend("return baseChannel")Append(parametersMethodName)AppendLine("();");
codeAppendLine("}");
codeAppendLine("}");
}
}


   注意红色部分由于代理类使用了WCF框架所以编译时我们需要添加SystemServiceModel的引用当然Systemdll肯定是必 须的这里要注意SystemServiceModeldll应该保存到应用程序目录否则动态编译时会引发异常很简单在工程引用中添加 SystemServiceModel的引用然后在属性中将拷贝到本地属性设置为true
  到此我们就可以直接通过传入的服务地址服务方法名称以及相关的命名空间即可调用服务(尽管我们只能调用无参服务并且尽管我们也只能调用使用 BasicHttpBinding绑定的服务这些限制的原因是…我懒好吧相信只要经过一点改动即可去掉这些限制)
可惜我们的程序还很傻每次调用服务都需要去生成代码编译创建代理实例最后再调用嗯…那就缓存吧
在WebServiceParameters类中重写GetHashCode方法

复制代码 代码如下:
public override int GetHashCode()
{
return StringConcat(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;
}

}

               

上一篇:.net 自定义控件显示及传参

下一篇:.net SMTP发送Email实例(可带附件)