背景
由于公司的软件要和第甲方webservice对接而且涉及到其他后续的甲方都要对接,用服务器引用的方式代码管理部方便。
设计原理
针对代码管理麻烦的问题: 通过读取甲方给的webservice地址,将webservice服务动态解析后生到本地dll中。再从本地dll中通过反射进行调用。这样就需要管理我写的代码就行了,如果甲方代码变了我只需要删除之前生成的dll就行了。
针对对接多个甲方的问题: 使用反射工厂原理,通过配置甲方信息执行对应功能的代码,这样我只需管理一套程序,实现多个甲方对接。
具体代码
原调用方式
var service = new HIPService
{
AuthenticationValue = new Authentication()
{
appsys_id = userName, appsys_token = pwd
}
};
apiResult = service.HIPMessageServer(参数1, 参数2);
反射调用方式
这里主要对大家有用的就是通过反射创建实例。这个不难,网上的代码也很多。难的是给反射出来的实例的属性类字段赋值,这个我网上找了好久,都没找到现成的答案。最后终于摸索出来了。
//读取用户名密码配置
var userName = ConfigurationManager.AppSettings["UserName"];
var pwd = ConfigurationManager.AppSettings["Password"];
//反射方式调用
var hipService = new WebServiceHelper("动态编译后的本地库.dll", url, "HIPService", new List<string>() { "HIPMessageServer" });
//得到需要赋值的字段类型(本问关键代码)
var ap = hipService.m_ObjInvoke.GetType().GetProperty("AuthenticationValue").PropertyType;
//实例化类
var instance = Activator.CreateInstance(ap);
//设置用户名、密码(给类相应字段复制)
instance.GetType().GetProperty("appsys_id").SetValue(instance, userName, null);
instance.GetType().GetProperty("appsys_token").SetValue(instance, pwd, null);
//授权类赋值
hipService.m_ObjInvoke.GetType().GetProperty("AuthenticationValue").SetValue(hipService.m_ObjInvoke, instance, null);
//调用服务
var result = hipService.InvokeMethod("HIPMessageServer", 参数1, 参数2);
webservice反射类
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Reflection;
using System.Web.Services.Description;
using System.Xml.Serialization;
using ServiceDescription = System.Web.Services.Description.ServiceDescription;
namespace Tzw.Common
{
public class WebServiceHelper
{
/// <summary>
/// 输出的dll文件名称
/// </summary>
private string m_OutputDllFilename = "WS.dll";
/// <summary>
/// WebService代理网址
/// </summary>
public string m_WebServiceUrl = "http://127.0.0.1:8080/uapws/service/classname";
/// <summary>
/// WebService代理类名称
/// </summary>
public string m_ProxyClassName = "WebService1";
public Type m_asmType;
/// <summary>
/// WebService代理类实例
/// </summary>
public object m_ObjInvoke;
/// <summary>
/// 调用方法名列表
/// </summary>
public List<string> m_MethodName;
/// <summary>
/// WebService接口方法字典
/// </summary>
public Dictionary<string, MethodInfo> m_MethodDic = new Dictionary<string, MethodInfo>();
/// <summary>
/// WebService 代理是否运行
/// </summary>
public bool bProxyRun = false;
public WebServiceHelper(string dllname, string WSURL, string className, List<string> methodName)
{
m_OutputDllFilename = dllname;
m_WebServiceUrl = WSURL + "?WSDL";
m_ProxyClassName = className;
m_MethodName = methodName;
bProxyRun = false;
if (CreateWebService())
{
bProxyRun = true;
}
}
/// <summary>
/// 创建webservice代理
/// </summary>
/// <returns></returns>
public bool CreateWebService()
{
//try
//{
// 如果程序集已存在,直接使用
if (File.Exists(Path.Combine(Environment.CurrentDirectory, m_OutputDllFilename)))
{
if (BuildMethods())
{
return true;
}
else
{
return false;
}
}
else
{
UpdateWebService();
}
//}
//catch (Exception ex)
//{
// //DelegateState.DelegateTipsText(ex.Message);
//}
return false;
}
/// <summary>
/// 更新WebService
/// </summary>
/// <returns></returns>
public bool UpdateWebService()
{
//使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
//Stream stream = web.OpenRead(m_WebServiceUrl);
Stream stream = File.OpenRead("D:\\Desktop\\HIPService.asmx");
//创建和格式化 WSDL 文档
if (stream != null)
{
// 格式化WSDL
ServiceDescription description = ServiceDescription.Read(stream);
// 创建客户端代理类
ServiceDescriptionImporter importer = new ServiceDescriptionImporter
{
ProtocolName = "Soap",
Style = ServiceDescriptionImportStyle.Client,
CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync
};
// 添加 WSDL 文档
importer.AddServiceDescription(description, null, null);
//使用 CodeDom 编译客户端代理类
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameter = new CompilerParameters
{
GenerateExecutable = false,
// 指定输出dll文件名。
OutputAssembly = m_OutputDllFilename
};
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll");
// 编译输出程序集
CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
// 使用 Reflection 调用 WebService。
if (!result.Errors.HasErrors)
{
if (BuildMethods())
{
return true;
}
else
{
return false;
}
}
else
{
//DelegateState.DelegateTipsText("反射生成dll文件时异常");
}
stream.Close();
stream.Dispose();
}
else
{
//DelegateState.DelegateTipsText("打开WebServiceUrl失败");
}
return false;
}
/// <summary>
/// 反射构建Methods
/// </summary>
private bool BuildMethods()
{
//try
//{
//LoadFrom 加载完后会一直占用 如果更新会导致失败
//Assembly asm = Assembly.LoadFrom(m_OutputDllFilename);
//var types = asm.GetTypes();
byte[] fileData = File.ReadAllBytes(m_OutputDllFilename);
Assembly asm = Assembly.Load(fileData);
m_asmType = asm.GetType(m_ProxyClassName);
m_ObjInvoke = Activator.CreateInstance(m_asmType);
//清空调用方法字典 m_MethodDic
m_MethodDic.Clear();
//重建调用方法字典 m_MethodDic
foreach (string name in m_MethodName)
{
MethodInfo item = m_asmType.GetMethod(name);
m_MethodDic.Add(name, item);
}
return true;
//}
//catch (Exception ex)
//{
// //DelegateState.DelegateTipsText(ex.Message);
// return false;
//}
}
/// <summary>
/// 获取请求响应
/// </summary>
/// <param name="method"></param>
/// <param name="para"></param>
/// <returns></returns>
public object InvokeMethod(string method, params object[] para)
{
object obj = null;
//System.Reflection.MethodInfo mi = m_asmType.GetMethod(method);
//object obj = mi.Invoke(m_ObjInvoke, para);
//Type t = obj.GetType();
//PropertyInfo[] pi = t.GetProperties();
if (m_MethodDic.ContainsKey(method))
{
obj = m_MethodDic[method].Invoke(m_ObjInvoke, para);
}
return obj;
}
// <summary>
/// 将一个对象转换为指定类型
/// </summary>
/// <param name="obj">待转换的对象</param>
/// <param name="type">目标类型</param>
/// <returns>转换后的对象</returns>
private object ConvertObject(object obj, Type type)
{
if (type == null) return obj;
if (obj == null) return type.IsValueType ? Activator.CreateInstance(type) : null;
Type underlyingType = Nullable.GetUnderlyingType(type);
if (type.IsAssignableFrom(obj.GetType())) // 如果待转换对象的类型与目标类型兼容,则无需转换
{
return obj;
}
else if ((underlyingType ?? type).IsEnum) // 如果待转换的对象的基类型为枚举
{
if (underlyingType != null && string.IsNullOrEmpty(obj.ToString())) // 如果目标类型为可空枚举,并且待转换对象为null 则直接返回null值
{
return null;
}
else
{
return Enum.Parse(underlyingType ?? type, obj.ToString());
}
}
else if (typeof(IConvertible).IsAssignableFrom(underlyingType ?? type)) // 如果目标类型的基类型实现了IConvertible,则直接转换
{
try
{
return Convert.ChangeType(obj, underlyingType ?? type, null);
}
catch
{
return underlyingType == null ? Activator.CreateInstance(type) : null;
}
}
else
{
TypeConverter converter = TypeDescriptor.GetConverter(type);
if (converter.CanConvertFrom(obj.GetType()))
{
return converter.ConvertFrom(obj);
}
ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
if (constructor != null)
{
object o = constructor.Invoke(null);
PropertyInfo[] propertys = type.GetProperties();
Type oldType = obj.GetType();
foreach (PropertyInfo property in propertys)
{
PropertyInfo p = oldType.GetProperty(property.Name);
if (property.CanWrite && p != null && p.CanRead)
{
property.SetValue(o, ConvertObject(p.GetValue(obj, null), property.PropertyType), null);
}
}
return o;
}
}
return obj;
}
}
}