<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Gat &amp; Gax</title>
        <link>http://agilior.pt/blogs/pedro.rainho/category/60.aspx</link>
        <description>Gat &amp; Gax</description>
        <language>pt-PT</language>
        <copyright>Pedro Rainho</copyright>
        <managingEditor>pedro.rainho@agilior.pt</managingEditor>
        <generator>Subtext Version 1.9.0.27</generator>
        <item>
            <title>Load and unload assemblies</title>
            <link>http://agilior.pt/blogs/pedro.rainho/archive/2009/03/15/7328.aspx</link>
            <description>&lt;p&gt;Last week, I had a problem that probably some .Net developer had faced. The problem consists in load and unload an assembly?.&lt;/p&gt;  &lt;p&gt;Can I do that??? Well, I can’t do it in a simple way. One of the things that Assembly doesn’t support in unload, check this &lt;a href="http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx"&gt;post&lt;/a&gt; to see why. &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;So, like I wrote, last week I was developing a new feature for a software factory and that feature consisted in get all references and do something else. &lt;/p&gt;  &lt;p&gt;My recipe does something like this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Get project assembly &lt;/li&gt;    &lt;li&gt;Copy the assembly DLL to a location &lt;/li&gt;    &lt;li&gt;Get all assembly references &lt;/li&gt;    &lt;li&gt;Generate a file &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;Do number 1 is simple.&lt;/p&gt;  &lt;p&gt;Do number 2 is also simple, but has a problem.&lt;/p&gt;  &lt;p&gt;Do number 3 is also simple, but has a problem.&lt;/p&gt;  &lt;p&gt;Do number 4 is simple.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;I’m going to explain first problem number 3 then problem 2&lt;/p&gt;  &lt;p&gt;The problem with number 3 it’s because I load a assembly and they I get referenced assemblies. To get referenced assemblies I just do:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Assembly &lt;/span&gt;assembly = &lt;span style="color: #2b91af"&gt;Assembly&lt;/span&gt;.LoadFrom(&lt;span style="color: #a31515"&gt;@"c:\myAssembly.dll"&lt;/span&gt;);
&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;[] references = assembly.GetReferencedAssemblies();&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This piece of code has a problem, since I’m loading the assembly and they get referenced assemblies the file myAssembly.dll is now locked this means that the next time I try to  run number 2 I will get an exception and the file will not ne copied. And this is why I had problem  number 2.&lt;/p&gt;

&lt;p&gt;Now, how can I load the assembly and then unload that assembly so the file won’t be locked???&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;I came across some solutions.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;One of the possible solutions is just copy the assembly to something unique like {GUID}.DLL and then load that {GUID}.DLL, and do everything I need to do, this way I won’t lock my file. 
    &lt;ol&gt;
      &lt;li&gt;Problem: I will have the assembly {GUID}.DLL loaded (in memory) every time, and can’t delete file {GUID}.DLL, because it’s locked. And finally I can’t unload unless I close Visual Studio. &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;Why don’t I just load the assembly into an array of bytes and then load the assembly, like this: 
    &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Assembly &lt;/span&gt;assembly = &lt;span style="color: #2b91af"&gt;Assembly&lt;/span&gt;.Load(&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.ReadAllBytes(&lt;span style="color: #a31515"&gt;@"c:\myAssembly.dll"&lt;/span&gt;));&lt;/pre&gt;
    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

    &lt;ol&gt;
      &lt;li&gt;Problem: I can do this and my file will not be locked but that array of bytes will be in memory and my visual studio memory will grow every time I run that recipe. That memory will be released only when I close the Visual Studio. &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;I can load the assembly in a new AppDomain and then unload the AppDomain. 
    &lt;ol&gt;
      &lt;li&gt;Problem: tThis was a strange problem and I don’t know why but I load the assembly in a new AppDomain and that assembly become part of the new AppDomain and the AppDomain.Current. This was strange. Don’t know if I was doing something wrong. Now since the Assembly is loaded in AppDomain.Current I wasn’t able to copy the file, because it was locked. &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;The last solution I came across to load the assembly and unload it. This solution Consists in create a new AppDomain and then use method DoCallBack: &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here it is the source code:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;AppDomainSetup &lt;/span&gt;setup = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;AppDomainSetup&lt;/span&gt;();
setup.ApplicationBase = ApplicationBasePath;

&lt;span style="color: #2b91af"&gt;AppDomain &lt;/span&gt;newDomainReferences = &lt;span style="color: #2b91af"&gt;AppDomain&lt;/span&gt;.CreateDomain(&lt;span style="color: #a31515"&gt;"AppDomain"&lt;/span&gt;, &lt;span style="color: blue"&gt;null&lt;/span&gt;, setup);

CallBackAssemblyReferences call = &lt;span style="color: blue"&gt;new &lt;/span&gt;CallBackAssemblyReferences(newDomainReferences, filepath);
newDomainReferences.DoCallBack(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CrossAppDomainDelegate&lt;/span&gt;(call.LoadAssemblyReferences));
&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;[] assName = (&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;[])newDomainReferences.GetData(&lt;span style="color: #a31515"&gt;"AssemblyReferences"&lt;/span&gt;);

&lt;span style="color: #2b91af"&gt;AppDomain&lt;/span&gt;.Unload(newDomainReferences);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This solution enables me to do a callback in a different domain. My class CallBackAssemblyReferences just does this:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;Serializable&lt;/span&gt;]
&lt;span style="color: blue"&gt;internal class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CallBackAssemblyReferences
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;#region &lt;/span&gt;Members Variables
    &lt;span style="color: blue"&gt;private string &lt;/span&gt;assemblyFile;
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;AppDomain &lt;/span&gt;domain;
    &lt;span style="color: blue"&gt;#endregion

    #region &lt;/span&gt;Public Implementation
    &lt;span style="color: blue"&gt;public &lt;/span&gt;CallBackAssemblyReferences()
    {

    }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;CallBackAssemblyReferences(&lt;span style="color: #2b91af"&gt;AppDomain &lt;/span&gt;domain, &lt;span style="color: blue"&gt;string &lt;/span&gt;assemblyFile)
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.assemblyFile = assemblyFile;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.domain = domain;
    }

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;LoadAssemblyReferences()
    {
        &lt;span style="color: #2b91af"&gt;Assembly &lt;/span&gt;assembly = &lt;span style="color: blue"&gt;this&lt;/span&gt;.domain.Load(&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;.GetAssemblyName(&lt;span style="color: blue"&gt;this&lt;/span&gt;.assemblyFile));

        domain.SetData(&lt;span style="color: #a31515"&gt;"AssemblyReferences"&lt;/span&gt;, assembly.GetReferencedAssemblies());
    }
    &lt;span style="color: blue"&gt;#endregion
&lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This class has a constructor that receives the new domain I’m working on and the path to the assembly I want to load. &lt;/p&gt;

&lt;p&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;CallBackAssemblyReferences(&lt;span style="color: #2b91af"&gt;AppDomain &lt;/span&gt;domain, &lt;span style="color: blue"&gt;string &lt;/span&gt;assemblyFile) &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Then I just have my callback method WITH NO PARAMETERS. &lt;/p&gt;

&lt;p&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;LoadAssemblyReferences() &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This is the method that will be called when I do &lt;/p&gt;

&lt;p&gt;newDomainReferences.DoCallBack(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CrossAppDomainDelegate&lt;/span&gt;(call.LoadAssemblyReferences)); &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The callback method only loads the assembly in the new domain and then sets data in the new domain. These data are the assembly references. &lt;/p&gt;

&lt;p&gt;When the DoCallBack returns I just had to do &lt;/p&gt;

&lt;p&gt;&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;[] assName = (&lt;span style="color: #2b91af"&gt;AssemblyName&lt;/span&gt;[])newDomainReferences.GetData(&lt;span style="color: #a31515"&gt;"AssemblyReferences"&lt;/span&gt;);&lt;/p&gt;

&lt;p&gt;To get the references I had saved. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Finally I just unload the AppDomain. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Now I can run my recipe every time I need without lock the file and without decrease visual studio performance.&lt;/p&gt;&lt;img src="http://agilior.pt/blogs/pedro.rainho/aggbug/7328.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Pedro Rainho</dc:creator>
            <guid>http://agilior.pt/blogs/pedro.rainho/archive/2009/03/15/7328.aspx</guid>
            <pubDate>Sun, 15 Mar 2009 17:59:14 GMT</pubDate>
            <wfw:comment>http://agilior.pt/blogs/pedro.rainho/comments/7328.aspx</wfw:comment>
            <comments>http://agilior.pt/blogs/pedro.rainho/archive/2009/03/15/7328.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://agilior.pt/blogs/pedro.rainho/comments/commentRss/7328.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>