Compile a version agnostic DLL in .NET

前端 未结 5 649
無奈伤痛
無奈伤痛 2020-12-05 01:14

Scenario

I have two wrappers around Microsoft Office, one for 2003 and one for 2007. Since having two versions of Microsoft Office running side by side is \"not of

相关标签:
5条回答
  • 2020-12-05 01:54

    Just a thought - could you use TlbExp to create two interop assemblies (with different names and assemblies), and use an interface/factory to code against the two via your own interface? Once you have the interop dll, you don't need the COM dependency (except of course for testing etc).

    TlbImp has a /asmversion for the version, so it could be done as part of the build script; but I'm sure you even need this: just make sure that "specific version" is false in the reference (solution explorer)?

    Also - I know it doesn't help, but C# 4.0 with dynamic and/or "No PIA" might help here (in the future; maybe).

    0 讨论(0)
  • 2020-12-05 01:58

    Nice sleuthwork! I just threw together an implementation based on the concept presented above, and it works wonderfully:

    static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
         string partialName = args.Name.Substring(0, args.Name.IndexOf(','));
         return Assembly.Load(new AssemblyName(partialName));
    }
    

    Of course there is room for enhancement, but this does the trick for me!

    0 讨论(0)
  • 2020-12-05 02:00

    Installing Office 2003 and 2007 side-by-side on the same machine is definitely possible - we do it in our organisation even on end-user production workstations.

    In that linked article, Microsoft recommend that you don't do this for actual use. But in your case it appears to be just for a single build machine, i.e. you're not going to actually use either version of Office on that machine. In this context, I would try to see if you can make the side-by-side installation work.

    My assumption might be wrong, and you're attempting to do this for every developer's machine. In that case, you should ignore this answer :-)

    0 讨论(0)
  • When the .NET assembly resolver is unable to find a referenced assembly at runtime (in this case, it cannot find the particular wrapper DLL version the application was linked against), its default behavior is to fail and essentially crash the application. However, this behavior can be overridden by hooking the AppDomain.AssemblyResolve event. This event is fired whenever a referenced assembly cannot be found, and it gives you the opportunity to substitute another assembly in place of the missing one (provided that they are compatible). So, for instance, you could substitute an older version of the wrapper DLL that you load yourself.

    The best way I've found to do this is to add a static constructor on the main class of the application that hooks the event, e.g.:

    using System.Reflection;
    
    static Program()
    {
        AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
        {
            AssemblyName requestedName = new AssemblyName(e.Name);
    
            if (requestedName.Name == "Office11Wrapper")
            {
                // Put code here to load whatever version of the assembly you actually have
    
                return Assembly.LoadFile("Office11Wrapper.DLL");
            }
            else
            {
                return null;
            }
        }
    }
    

    By putting this in a static constructor of the main application class, it is guaranteed to run before any code attempts to access anything in the wrapper DLL, ensuring that the hook is in place ahead of time.

    You can also use policy files to do version redirection, but that tends to be more complex.

    0 讨论(0)
  • 2020-12-05 02:11

    I'm not sure I am completely following everything you stated, but let me try:

    It sounds like you have one solution with 2(?) projects. One is the actual application, and the other is a wrapper for the Office API. Your application then has a project reference to your Office API wrapper. I've never programmed for office before, but it sounds like the programming APIs are a common component that you can only have one version of on a machine (ie. 2003 or 2007, not both). And maybe this is where the problem is, but because you have a project reference, the wrapper will be compiled first, copied to the bin directory of your application, where your application will be linked to that build of the wrapper. This will cause the manifest of the application to specifically request that version of the wrapper at run time.

    If you had the wrapper in a separate solution, and added a reference to the compiled library rather than the project, you would always link your application to that version of the wrapper and you could avoid the problem.

    Another possible choice is Assembly Binding Redirection. This is more advanced, and comes with it's own set of problems, but you can read about it here.

    Or similar to Marc's idea, you could extract an interface and pull some common objects into a Framework library, and code your application against the interface and common objects. Then at runtime use reflection to load the assembly and instantiate the wrapper you want.

    I think the key is to remove the project dependency if you can. It sounds like the wrapper is pretty stable and isn't changing, otherwise you wouldn't be asking to link to a previous version of it.

    0 讨论(0)
提交回复
热议问题