优化动态调用WebSerivce
起因
因为在项目调用WebApi,但在WebApi调用了一个WebSerivce,看到动态调用WebSerivce,因为是另外一个组开发的,只是感觉这样动态调用WebSerivce性能不太好.并进行了代码调整.调整优化的思路:
- 减少每次都通过WebClient获取Wsdl
- 减少每次都根据Wsdl,生成请求代理类
- 减少程序集加载的次数
项目中的代码(待优化版本)
带优化的版本,存在以下问题:- 每次调用都会通过WebClient请求以下WebSerivce的wsdl描述文件(没有必要)
- 每次调用动态生成dll,如果请求数量比较大时,会造成CPU很高
- 每次都会加载新生成dll(程序集),然后反射.
private static object CallWebService(string url, string methodname, object[] args)
{
string nameSpace = "qiufeng.webservice";
try
{
//获取WSDL
WebClient wc = new WebClient();
Stream stream = wc.OpenRead(url + "?WSDL");
ServiceDescription sd = ServiceDescription.Read(stream);
string classname = sd.Services[0].Name;
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, "", "");
sdi.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;//标准和异步
CodeNamespace cn = new CodeNamespace(nameSpace);
//生成客户端代理类代码
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
CSharpCodeProvider csc = new CSharpCodeProvider();
CompilerParameters cplist = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true,
OutputAssembly = string.Format("{0}/{1}.dll", Directory.GetCurrentDirectory(), "WebService1")
};
cplist.ReferencedAssemblies.Add("System.dll");
cplist.ReferencedAssemblies.Add("System.XML.dll");
cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
cplist.ReferencedAssemblies.Add("System.Data.dll");
//编译代理类
CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
if (true == cr.Errors.HasErrors)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (CompilerError ce in cr.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
}
//生成代理实例,并调用方法
Assembly assembly = cr.CompiledAssembly;
Type t = assembly.GetType(nameSpace + "." + classname, true, true);
object obj = Activator.CreateInstance(t);
MethodInfo mi = t.GetMethod(methodname);
object objs = mi.Invoke(obj, args);
return objs;
}
catch (Exception ex)
{
return ex;
}
}
string url = "http://localhost:50309/WebService1.asmx";
object o1 = CallWebService(url, "GetName", new object[] { "Hello" });
Console.WriteLine(o1);
优化第一版
/// <summary>
/// 优化第一版
/// </summary>
/// <param name="url"></param>
/// <param name="methodname"></param>
/// <param name="args"></param>
/// <returns></returns>
private static object CallWebService_Optimize2(string url, string methodname, object[] args)
{
const string nameSpace = "qiufeng.webservice";
object objs = null;
try
{
//1. 判断是否加过Service的程序集
if (serviceAssm == null)
{
//2. 判断文件当前目录是否生成WebSerivce的dll
string filePath = string.Format("{0}/{1}.dll", Directory.GetCurrentDirectory(), nameSpace);
if (File.Exists(filePath))
{
serviceAssm = Assembly.LoadFrom(filePath);
fullName = ConfigurationManager.AppSettings[nameSpace];
}
else
{
//3. 没有生成Service的dll文件情况
//获取WSDL
WebClient wc = new WebClient();
Stream stream = wc.OpenRead(url + "?WSDL");
ServiceDescription sd = ServiceDescription.Read(stream);
string classname = sd.Services[0].Name;
string classFullName = $"{nameSpace}.{classname}";
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, "", "");
sdi.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;//标准和异步
CodeNamespace cn = new CodeNamespace(nameSpace);
//生成客户端代理类代码
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
CSharpCodeProvider csc = new CSharpCodeProvider();
//设定编译参数
CompilerParameters cplist = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true,
OutputAssembly = filePath
};
cplist.ReferencedAssemblies.Add("System.dll");
cplist.ReferencedAssemblies.Add("System.XML.dll");
cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
cplist.ReferencedAssemblies.Add("System.Data.dll");
//编译代理类
CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
if (true == cr.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError ce in cr.Errors)
{
sb.Append(ce.ToString());
sb.Append(Environment.NewLine);
}
throw new Exception(sb.ToString());
}
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings[nameSpace].Value = classFullName;
config.AppSettings.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
fullName = classFullName;
serviceAssm1 = Assembly.LoadFrom(filePath);
}
}
Type t = serviceAssm.GetType(fullName, true, true);
object obj = Activator.CreateInstance(t);
MethodInfo mi = t.GetMethod(methodname);
objs = mi.Invoke(obj, args);
return objs;
}
catch (Exception ex)
{
return ex;
}
}
发现调整后,性能还是很明显的.调整前在BenchmarkDotNet.没有显示时间.
其他的优化思路
每次调用调用WebSerivce的时候都会对生成的请求代理类,进行反射创建.可以改为委托创建,并缓存委托.private static T GenerateNewObjDelegate<T>(Type type) where T : class
{
// Create a new, parameterless (specified by Type.EmptyTypes) dynamic method.
var dynamicMethod = new DynamicMethod("Ctor_" + type.FullName, type, Type.EmptyTypes, true);
var ilGenerator = dynamicMethod.GetILGenerator();
// Look up the constructor info for the type we want to create
var ctorInfo = type.GetConstructor(Type.EmptyTypes);
if (ctorInfo != null)
{
ilGenerator.Emit(OpCodes.Newobj, ctorInfo);
ilGenerator.Emit(OpCodes.Ret);
object del = dynamicMethod.CreateDelegate(typeof(T));
return (T)del;
}
return null;
}
秋风
2021-04-05