Excel VSTO document specialization can't load dependent DLL - deployment

I have an Excel 2007 document customization assembly that's dependent on another managed assembly (DLL 'A') which in turn is dependent on an unmanaged, native DLL written in C++ (DLL 'B'). I have created a Windows installer project to deploy the customization assembly, its deployment and application manifests, the dependent assembly (A) and the native DLL (B) into "Program Files\" directory, while the Excel document (a template actually) is copied into the user's "My Documents" folder. The template's _AssemblyLocation property has been modified accordingly to find the deployment manifest.
The template fails to load. Looking at the loading sequence in Process Monitor it is clear the Excel template sucessfully loads the customization DLL which finds and loads DLL 'A', but A then fails to find DLL 'B' even though B is in the same directory. Process Monitor shows A looking for B in all the directories listed in the PATH environment variable, but not in its own directory.
What is the convention when searching for dependent assemblies/DLL's in a VSTO document customization solution? Is there a way to help A find B without adding the application directory to the PATH?

Related

NuGet Packaging and referencing dll's

Background: I have two assemblies called "A" and "B". ""A" references "B". "A" also references some additional dll's (Microsoft.Enterprise Library.Data and Microsoft Enterprise Library.Common ) that I think should be packaged in the nupkg.
I believe my nupkg package should contain the assembly output from "A", "B" and the two "Microsoft Enterprise" assemblies so that when someone installs my package it will give them a direct reference to the Assembly "A" and the other three assemblies would be available (but not directly referenced, so that their app would run. What is the correct way of packaging the non references dlls?
Attempt #1: Packing all required dll's in a \net35 folder
According to the NuGet documentation regarding the "references" element "If this element is omitted, then the usual behavior applies, which is to reference every assembly in the lib folder."
So, I assume that by using this element it will only include the assemblies specified as references. This does not seem to be the case if I also use a "file" element <file src=*.dll" target="lib\net35" />. If I have an element like this that copies all dll's to the package it results in the assembly that implements this package to reference ALL the assemblies in the \net35 directory. This is not what I want to do. I expected some magic that only the assembly specified in "references" would be an actual be referenced and all the others would remain in the exploded \packages folder and the app would work since all the dlls are located in the same directory. Maybe I'm incorrect....
Attempt #2 Adding as content to project
If I place the unreferenced assemblies into \content\lib instead of lib\net35 when packaged this creates a \lib folder in the project and directly dumps the \content\lib dlls into that project which then forces us to check them into source control. This works, compiles and runs as I want but, I really don't want these stored in the \lib folder of the project.
I am looking for a solution where the project gets the references to "A" and can still run with the to other required assemblies co-located but not directly referenced. It seems like Attempt #1 is the correct path but maybe there is a bug?
FYI, I entered this as a issue with NuGet directly to see it that team has an answer as well.
This was a bug introduced in Nuget 2.1 and was later fixed in Nuget versions 2.2 which was released in December 2012.
Using Attempt #1 in original posting now works correctly.
I don't think your "Attempt 1" is going to work in practice. If you only reference "A". when you build your package, only "A" will be copied (by default) to the output directory. Then, when you distribute the application, only "A" will exist causing errors.
You should have references to all DLLs to make your application run (or come up with another solution that will automatically copy the referenced DLLs to the output directory, but I'm not sure there is much value in not specifying the reference directly). Since you only have a few DLLs, it is probably best to just leave out the references section so that all of the DLLs are referenced automatically from the lib folder.

MEF dependency questions

Simple example.
Application A has a class library C which is used through out.
Application A uses MEF to discover and load plug in modules P1 and P2 from a plug in directory. One assembly per plug in.
P1 and P2 both have a dependency on C (The class library).
The build process will ensure the version of C used by P1 is identical to the version referenced by A.
I assume that I won't end up with multiple copies of the same assembly loaded at once? By default I end up with a copy of C in the Plugin directory as well as A's application directory.
To ensure you don't end up with duplicate assemblies, you could change the Copy Local property to false of the contract (C) library in your plugin projects, that way on build, it won't be copied to the output directory.
You should be fine I think, as the CLR won't load the same assembly twice thanks to the Fusion loader rules - the first being to see if the target assembly is already loaded in the AppDomain. BUT, you have to be careful, because any code using Assembly.LoadFrom may result in exceptions occurring if it is actually finding that the assemblies have different locations on disk.

VSTO addin dependency resolution

I have a VSTO addin, which works fine. I am trying to give it a plugin-loading mechanism so that others can add plugins to my plugin. I sounds horrific, I know, but it seems to best option for now.
I publish my addin to a folder called 'Published'. This creates the application manifest (Symbols.application) and also a folder called Symbols_x.y.xx.yy with the actual addin assemblies in it. Visual Studio increments this version number each time I publish, so the assemblies are never in the same place twice.
The plugins are in a folder Published\Plugins. I load the plugin assemblies using Assembly.LoadFile(string) and this works OK. The plugins are all in folder which stays in the same place no matter how many times I publish it and I can scan that folder for DLLs and load them.
What doesn't work is when those plugin DLLs have dependencies. In particular, one depends on a COM object. Visual Studio builds an automatic Interop DLL which it puts in the Published\Plugins folder, alongside the corresponding plugin DLL. An exception is thrown as soon as any attempt is made to access the COM object, saying that the interop assembly could not be found.
Putting the interop DLL into the folder Published\Symbols_x.y.xx.yy folder works, but that requires manually putting it there each time. I've tried adding the plugins to the AppDomain's PrivateBinPath, but the documentation says that anything outside the ApplicationBase will be ignored and it seems this is indeed the case - it doesn't work. ApplicationBase is set to Published\Symbols_x.y.xx.yy.
It seems to me I have four options:
Figure out how to change the ApplicationBase, moving it up one level, and then add the Published\Plugins folder to the AppDomain's PrivateBinPath.
Make some change to the application manifest to indicate that assemblies can be loaded automatically from Published\Plugins.
Find some other way of explicitly loading an assembly into the AppDomain, not just into memory using Assembly.LoadFile.
Anything else anyone wants to suggest!
But I can't find any way to get any of these options to work. Help!
The solution was provided by the MSDN forums:
I've added an event handler to AppDomain.CurrentDomain.AssemblyResolve. This gives you a chance to load the assembly in whatever way you like, including by loading it from my plugins directory.

MSTEST folder deployment question

Is there a way to preserve folder structure with MSTEST deployment?
I have a situation with some existing code where I have .config files in a subfolder (called "Configuration"). I can specify this folder using MSTEST deployment but, in it's infinite wisdom, MSTEST just copies the files from this folder to the run folder (TestResult\\Out), i.e. it does not create a subfolder called Configuration. This royally screws up the code and it fails. I don't really want to have to start using complicated pre-test scripts to create folders etc.
Any ideas gratefully received.
Matt
I think I had the same problem...
My tests used a folder called xsd and I wanted to deploy the folder to the test \OUT directory. When I did this, the files inside the xsd folder were copied to the test \OUT directory, but I wanted the folder xsd into the test \OUT directory...
To solve this I read this. (Wayback machine has an archive of this page here)
If you're using the DeploymentItem attribute, it takes a second argument for the name of the directory to copy the files into. If you use the same name as your folder it preserves everything.
To use your test case you'd do:
[DeploymentItem("Configuration", "Configuration")]
class TestClass
....
and it would work.
Yes, you can. read the article Do MSTest deployment items only work when present in the project test settings file?
It explains how to map deployment items.
In Visual Studio 2012 the output directory is the working directory which means that the DeploymentItem attribute isn't needed for the general case (where you don't have specific per-test or per-class deployment items). You can simply click Project | Show All Files and include the subfolder and files in Visual Studio with the 'Copy Always' or 'Copy if newer' attribute to your project and the files will be copied to your output directory with hierarchy intact. The same applies when running vstest.console.exe from the command line.
See here for more information about Deployment Items in Visual Studio 2012.

NUnit GUI Runner Multiple Configuration Files

I created a test project using a web.config file by renaming it to same name as the project, copying it to the bin folder and setting the Configuration File Name of the NUnit GUI runner to the name of my config file. Now I want to add more assemblies to this project but the problem here is each assembly has it's own web.config file.
How can I set the configuration files for the assemblies because I need to get my connection strings from these config files and considering when loading multiple assemblies they need to be in the same directory
While I feel that using config files for NUnit tests is a no-no (it's an integration test, in that case, I assume), there are various approaches you can try:
Put all your different connection strings under web.config in the connectionstrings section, with different keys. Access them via the System.Configuration classes.
For each project or DLL you can add an app.config file where you can store assembly specific information. This will be renamed as ProjectName.dll.config once compiled. Again you can access the contents of this file using System.Configuration
Create a new assembly that simply loads all these connection strings from a single file. And then access this assembly
If you are loading different web applications into the same directory (as you're saying you're accessing web.config files -- which means web applications) then you're making your life difficult. Each application has to have their own folder and virtual directory, and a web.config specific to only that application.