Prev: Chart Question
Next: SQL Server 2005 SP3 Failed IIS 6.0
From: Arrow on 19 Apr 2010 10:47 Wondering if anyone has done this successfully and has any code they can share ? I have a non-GUI app that runs 24 / 7, and there has always been a memory leak in the LocalReport.Render call. In VS 2008 this was around (average) 20k per report, with VS 2010, I was hoping this leak would be fixed, instead it's much worse ! ...around 3 meg per report ! Add features without fixing the current problems ! So from searching, the idea of a separate AppDomain came up so I could unload Microsoft.ReportViewer.WinForms after so many calls and release the memory. Basically to have a separate class: namespace MyApp { [ClassInterface(ClassInterfaceType.AutoDual)] public class LocalReportFactory : MarshalByRefObject { public AppDomain LocalAppDomain = null; public string ErrorMessage = string.Empty; /// <summary> /// Creates a new instance of the LocalReportParser in a new AppDomain /// </summary> /// <returns></returns> public LocalReport CreateLocalReportParser() { this.CreateAppDomain(null); LocalReport parser = null; // string AssemblyPath = Assembly.GetExecutingAssembly().Location; try { // parser = (LocalReport) this.LocalAppDomain.CreateInstanceFrom(AssemblyPath, typeof(LocalReport).FullName).Unwrap() ; Type MyLR = typeof(LocalReport); parser = (LocalReport)this.LocalAppDomain.CreateInstanceAndUnwrap(MyLR.Assembly.FullName, MyLR.FullName); // Assembly RPAssembly = this.LocalAppDomain.Load("Microsoft.ReportViewer.WinForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); // Type tInvokerType = RPAssembly.GetType("Microsoft.Reporting.WinForms.LocalReport"); // parser = (LocalReport)Activator.CreateInstance(tInvokerType); } catch (Exception ex) { this.ErrorMessage = ex.Message; } return parser; } public bool CreateAppDomain(string appDomain) { if (string.IsNullOrEmpty(appDomain)) appDomain = "LocalReportParser" + Guid.NewGuid().ToString().GetHashCode().ToString("x"); AppDomainSetup domainSetup = new AppDomainSetup(); // domainSetup.ApplicationName = appDomain; // *** Point at current directory // domainSetup.ApplicationBase = Environment.CurrentDirectory; // AppDomain.CurrentDomain.BaseDirectory; domainSetup.DisallowBindingRedirects = false; domainSetup.DisallowCodeDownload = true; this.LocalAppDomain = AppDomain.CreateDomain(appDomain, null, domainSetup); // *** Need a custom resolver so we can load assembly from non current path // AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); this.LocalAppDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); return true; } /* Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { Assembly assembly = null; try { assembly = System.Reflection.Assembly.Load("Microsoft.ReportViewer.WinForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); // if (assembly != null) // return assembly; } catch { // ignore load error } // *** Try to load by filename - split out the filename of the full assembly name // *** and append the base path of the original assembly (ie. look in the same dir) // *** NOTE: this doesn't account for special search paths but then that never // worked before either. // string[] Parts = args.Name.Split(','); // string File = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + Parts[0].Trim() + ".dll"; // return System.Reflection.Assembly.LoadFrom(File); return assembly; } */ Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { foreach (Assembly LR in AppDomain.CurrentDomain.GetAssemblies()) { if ( string.Compare(LR.GetName().Name, args.Name, true) == 0 || string.Compare(LR.FullName, args.Name, true) == 0 ) return LR; } return null; } /// <summary> /// /// </summary> public void Unload() { if (this.LocalAppDomain != null) { AppDomain.Unload(this.LocalAppDomain); this.LocalAppDomain = null; } } } } Then in the main part of my app LocalReportFactory factory = new LocalReportFactory(); LocalReport report = factory.CreateLocalReportParser(); then when all done I expected after calling: factory.Unload(); that "Microsoft.ReportViewer.WinForms" would get unloaded, but it doesn't !? Anyone have an idea why and how I can fix it ...thanks !!!
|
Pages: 1 Prev: Chart Question Next: SQL Server 2005 SP3 Failed IIS 6.0 |