動態Web Service呼叫,解決記憶體回收基本問題...
阿新 • • 發佈:2019-01-03
原因:同步工具,需要實時呼叫第三方客戶提供的介面進行解析,沒有使用直接引用方式.考慮到方法後期會有變動,那樣子得去更新引用.就用動態建立ws的程式碼(動態建立ws程式碼直接搜尋出複製過來的.)).動態建立通過反射建立的代理物件,不能有效的釋放記憶體(我的程式就是由於這原因導致記憶體每次請求都增加記憶體).所以使用了appdomian的方式進行程式隔離來請求ws,然後在解除安裝appdomian,來到達回收記憶體.(記憶體回收是基本達到了,但是程式的cpu使用率也上去了.暫時還找不出什麼原因.)
/// <summary> /// 動態呼叫WebService /// </summary> /// <param name="url">WebService地址</param> /// <param name="methodname">方法名(模組名)</param> /// <param name="args">引數列表</param> /// <returns>object</returns> public object InvokeWebService(string url, string methodname, object[] args) { try { return InvokeWebService(url, null, methodname, args); } catch (Exception) { throw; } } /// <summary> /// 動態呼叫WebService /// </summary> /// <param name="url">WebService地址</param> /// <param name="classname">類名</param> /// <param name="methodname">方法名(模組名)</param> /// <param name="args">引數列表</param> /// <returns>object</returns> private object InvokeWebService(string url, string classname, string methodname, object[] args) { try { string @namespace = "SyncTools.WebService.DynamicWebLoad"; if (classname == null || classname == "") { classname = GetClassName(url); } classname = @namespace + "." + classname; // Construct and initialize settings for a second AppDomain. AppDomainSetup appDomainSetup = new AppDomainSetup { ApplicationBase = System.Environment.CurrentDirectory, DisallowBindingRedirects = false, DisallowCodeDownload = false, ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile }; // Create the second AppDomain. // AppDomain appDomain = AppDomain.CreateDomain("SyncTools.WebService.DynamicWebLoad", null, appDomainSetup); AppDomain appDomain = AppDomain.CreateDomain("SyncTools.WebService.DynamicWebLoad"); Type t = typeof(ProxyObject); ProxyObject obj = (ProxyObject)appDomain.CreateInstanceAndUnwrap(t.Assembly.FullName, t.FullName); obj.LoadAssembly(url, @namespace); obj.Invoke(classname, methodname, args); var result = obj.Resutl; AppDomain.Unload(appDomain); appDomain = null; obj = null; return result; } catch (Exception) { throw; } finally { GC.Collect(); } } private string GetClassName(string url) { //URL為"http://localhost/InvokeService/Service1.asmx" //返回值為 Service1 string[] parts = url.Split('/'); string[] pps = parts[parts.Length - 1].Split('.'); return pps[0]; }
這段程式碼載入ws介面,通過相關引數的傳遞獲取介面的返回結果值(Result).
internal class ProxyObject : MarshalByRefObject { Assembly assembly = null; private Object result = null; public Object Resutl { get { return this.result; } } public void LoadAssembly(string url, string @namespace) { // assembly = Assembly.LoadFile(@"TestDLL.dll"); //獲取服務描述語言(WSDL) using (WebClient wc = new WebClient()) { using (Stream stream = wc.OpenRead(url + "?WSDL")) { ServiceDescription sd = ServiceDescription.Read(stream); ServiceDescriptionImporter sdi = new ServiceDescriptionImporter(); sdi.AddServiceDescription(sd, "", ""); CodeNamespace cn = new CodeNamespace(@namespace); //生成客戶端代理類程式碼 CodeCompileUnit ccu = new CodeCompileUnit(); ccu.Namespaces.Add(cn); sdi.Import(cn, ccu); CSharpCodeProvider csc = new CSharpCodeProvider(); ICodeCompiler icc = csc.CreateCompiler(); //設定編譯器的引數 CompilerParameters cplist = new CompilerParameters(); cplist.GenerateExecutable = false; cplist.GenerateInMemory = false; 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 = icc.CompileAssemblyFromDom(cplist, ccu); if (true == cr.Errors.HasErrors) { System.Text.StringBuilder sb = new StringBuilder(); foreach (CompilerError ce in cr.Errors) { sb.Append(ce.ToString()); sb.Append(System.Environment.NewLine); } throw new Exception(sb.ToString()); } //生成代理例項,並呼叫方法 assembly = cr.CompiledAssembly; } } } public bool Invoke(string className, string methodName, params Object[] args) { if (assembly == null) return false; Type tp = assembly.GetType(className, true, true); if (tp == null) return false; MethodInfo method = tp.GetMethod(methodName); if (method == null) return false; Object obj = Activator.CreateInstance(tp); result = method.Invoke(obj, args); return true; }
記憶體回收
#region 記憶體回收 //[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")] [DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize); /// <summary> /// 釋放記憶體 /// </summary> public static void ClearMemory() { SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); } #endregion