A
Arrow
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 !!!
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 !!!