4

I have some issue with a program I'm working on. It's composed of 2 DLLs, with dll A referencing dll B. Dll A contains one public method, in which first action (before instanciating any class in B) is to check some network location to see if a new version of dll B is available. If so, it downloads it at the same location of current B, which should not be a problem since nothing from B is instanciated. Sadly, it is instanciated and so I get an error it is already referenced by the process that owns A and cannot be replaced.

Do you have any idea of the reason why it is already referenced, and if there is any solution to avoid this?

public class L10nReports//Class in DLL A
{
    public L10nReports() //constructor
    {
    }

    //only public method is this class
    public string Supervise(object projectGroup, out string msg)
    {
        //Checks for updates of dll B and downloads it if available. And fails.
        manageUpdate();

        //first instanciation of any class from dll B
        ReportEngine.ReportEngine engine = new ReportEngine.ReportEngine();

        string result = engine.Supervise(projectGroup, out msg);

        return result;
    }
casperOne
  • 73,706
  • 19
  • 184
  • 253
Antoine
  • 5,055
  • 11
  • 54
  • 82

2 Answers2

6

By the time your "Supervise" method is JITted, the B dll will be loaded. THe issue here is that the DLL is loaded the first time type information for some type in B.dll is needed, not the first time an object is instantiated.

So you must check for update before you reference any type in B.dll, and before you call any methods that use a type in B.dll.

public class L10nReports//Class in DLL A
{
    public L10nReports() //constructor
    {
    }


    //only public method is this class
    public string Supervise(object projectGroup, out string msg)
    {
       manageUpdate();
       return SuperviseImpl(projectGroup, out msg);
    }


    private string SuperviseImpl(object projectGroup, out string msg)
    {
        //first instanciation of any class from dll B
        ReportEngine.ReportEngine engine = new ReportEngine.ReportEngine();

        string result = engine.Supervise(projectGroup, out msg);

        return result;
    }
Philip Rieck
  • 32,368
  • 11
  • 87
  • 99
5

The Jit compiler needs to load Dll B, in order to check/validate the Supervise method.

Move calls to Dll B into another method, and prevent this method from being inlined ([MethodImpl(MethodImplOptions.NoInlining)]). Otherwise you might have strange effects switching from Debug to Release mode.

If I remember it correctly, inlining is not used for Debug compiled code, but release code might inline the called method, making the jitter load Dll B before the check.

    //only public method is this class
    // all calls to dll B must go in helper function
    public string Supervise(object projectGroup, out string msg)
    {
        //Checks for updates of dll B and downloads it if available. And fails.
        manageUpdate();

        return SuperviseHelper(projectGroup, out msg);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public string SuperviseHelper(object projectGroup, out string msg) {
        //first instanciation of any class from dll B
        ReportEngine.ReportEngine engine = new ReportEngine.ReportEngine();

        string result = engine.Supervise(projectGroup, out msg);

        return result;
    }
GvS
  • 52,015
  • 16
  • 101
  • 139
  • 1
    Guess how I found out? It still hurts. – GvS Mar 24 '11 at 16:07
  • I put the class instantiation in another method (see my comment in Philip Rieck's answer) but that doesn't work. And adding the non-inlining attribute doesn't change, I still get the same eror that dll is alrady referenced. – Antoine Mar 24 '11 at 16:31
  • When debugging, step by step, you should see the message in the output pane, when the dll is loaded. What's inside manageUpdate()? Does your class expose members that contain types from dll B? – GvS Mar 24 '11 at 16:34
  • You could remove/rename dll B before running/debugging, and see where it crashes. – GvS Mar 24 '11 at 16:35
  • I can see that dll B is loaded when the debugger enters ManageUpdate() method, although I'm practically certain that dll B has nothing to do in there. Will check in details though. – Antoine Mar 24 '11 at 16:40
  • Got it, have the line Assembly.GetAssembly(typeof(ReportEngine.ReportEngine)).GetName().Version.ToString(); in ManageUpdate() to retrieve it's version number :/. Any idea I could get this info without loading it? – Antoine Mar 24 '11 at 16:42
  • `AssemblyName.GetAssemblyName("assembly.dll")` [Source](http://stackoverflow.com/questions/187999/how-do-i-get-the-version-of-an-assembly-without-loading-it) – GvS Mar 24 '11 at 16:51
  • Yes I saw that on http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-get-assembly-version-without-loading-it.aspx and I got it working. The issue now is that now the dll's version number has changed, the reference to it is not found anymore and I can't use it. I guess I have to go with reflection and some kind of late-binding. – Antoine Mar 24 '11 at 17:06