views:

538

answers:

7

Let's say you have a class library project that has any number of supplemental files that also need to be included with the compiled assembly (e.g. simple text files or even a legacy unmanaged DLL that's wrapped by the assembly as an interop layer). While embedding the supplemental files into the assembly itself is relatively straightforward, we have situations where this is not possible or just undesirable. We need to have them as "sidecar" files (i.e. files alongside the assembly, potentially in subdirectories relative to the assembly)

Adding those files to the project with an appropriate value for "Copy to Output Directory" specified appears to be sufficient for projects that are completely self-contained within a solution. But if a separate project in another solution adds a reference to the assembly, it does not automatically pickup its sidecar files. Is there a way in the project to somehow mark the resulting assembly such that anything referencing the assembly will also know it needs to include the associated sidecar files? How do you do this?

+1  A: 

Have you tried creating a setup for your solution ? There's an option of including sidecar files targeting to application installation directory.

Another option would be to include the sidecar files in the Assembly resources and un-wrap them to disk when run for the first time.

this. __curious_geek
With the frequency of changes to the library code that uses the sidecar files, we'd like to avoid having to install before it's usable by the application developers. Also, the application installer (which needs to include the underlying library) won't automatically know about the sidecar files.Including the sidecar files as embedded assembly resources and then unwrapping them to disk is an interesting idea that we'll need to examine. I'm not confident it will meet all our use cases though.
iammichael
We actually successfully did runtime unwrapping of Interop dlls and other resources. We solved the 'assembly resolution by path' problem using this. No matter which application domain or host process you execute the assembly from, it will dynamically unwrap them to disk during runtime and we resolve the reference to recently unwrap assemblies. This was also found useful in distributing application updates.
this. __curious_geek
Did you run into any permission issues with the executing user being unable to write the interop DLL to disk?
iammichael
@iammichael: yes, you are right.The task of unwrapping resouces to disk, requires DiskI/O rights for executing code.In XP it works without any problem but in vista it'd generate nag security cnfirmation popups.
this. __curious_geek
A: 

Unfortunately there doesn't appear to be a lot of built-in support in Visual Studio for this, although I can definitely see the use case.

If you use Subversion for your source control, then you could link in an external reference as an externals definition. This would bring in the source code, and you'd be making a reference to the necessary assembly as a project reference instead of a DLL reference, and then the copy to output directory rules would come into play.

If that's not possible, another solution would be to include commands in the pre/post-build events of your in-solution project to copy the most up-to-date sidecar files from the remote assembly on a build. Of course this comes with the caveat that it doesn't set itself up automatically when you include the DLL in your project; you have to take manual steps to set it up.

David
We're using TFS, not subversion, and even still I'm not sure that solves the problem since the application referencing the library shouldn't need to know about the individual sidecar files (which I think would be requried if you're adding them as project references per your description). Though, I may be misunderstanding what you're saying here. As for the pre/post build events, the lack of it being automatic is sort of a deal breaker. See also my comment to Lucas who also suggested pre/post-build events.
iammichael
If you were using some sort of externals definition, it's like including a virtual copy of the included project in your solution. Then, for each sidecar file in the included project, you can set the "Copy to Output Directory" attribute in the Visual Studio Properties editor to Copy Always. When you do this, and include the project by project reference, and build the solution, Visual Studio knows to copy the sidecar files to the primary output directory.
David
+2  A: 

You can use al.exe, but there also appears to be a C# compiler option. You want to create a multifile assembly using the /linkresource C# compiler option. Instructions are here, but the command is similar to this:

csc /linkresource:N.dll /t:library A.cs

Where N.dll is a native DLL that will go wherever the managed assembly goes (including into the GAC.) There's a very clear description at the link I provided.

GuyBehindtheGuy
I read though the linked docs and a couple others I found relating to multi-file assemblies, but I'm still not sure how this may be applicable to answering my question. Can you edit your answer to include more details about how this could be used to solve the problem of, say, an unmanaged DLL wrapped by a managed assembly which need to be made available in a common library location for use within a higher-level managed application that exists in a separate solution (it can easily reference the managed wrapper, but that doesn't automatically include the unmanaged DLL in its output dir)?
iammichael
Thanks for the edit; this seems like it might be suitable to solve the problem. However, since it'd require changing our build process from simple visual studio builds to an MSBuild or other command line-based build (The linked reference states "This compiler option is unavailable in Visual Studio and cannot be changed programmatically."), I'm unable to test at the moment to verify. It certainly does look promising though.
iammichael
Haven't been able to verify, don't anticipate the time to do so, and have ended up using a less-than-ideal manual copy for the files, but this seems like the actual answer to the question, so I'm accepting.
iammichael
A: 

I deal with this some time ago. Its a common problem.

You can create some postbuild actions:

http://www.codingday.com/execute-batch-commands-before-or-after-compilation-using-pre-build-or-post-build-events/

Hope this helps... :)

Lucas
Post-build actions on the library would require your library assembly to know about the applications that depend on it and thus where the additional files are needed. Pre-build actions on the app depending on the library means that the app needs to know what to copy and that info really is known only by the library itself. Things get even more complicated if the dependency chain is longer with multiple layers of libraries needing to know about the sidecar files that have to manually be copied. So, this doesn't fully meet the need.
iammichael
A: 

It appears to me that you're using the wrong type of reference. There are two types of references- Reference and ProjectReference. Reference is an explicit reference to a specific assembly. ProjectReference is a reference to another project (say .csproj).

What you're looking for is ProjectReference. VS and the default MSBuild targets are setup to do CopyLocal. If you set CopyToOutputPath true for your "sidecar" files, any ProjectReferences to this project now will also pull in the same files.

I'm not sure if you can to ProjectReferences across solutions in the IDE. I deal a lot with MSBuild where sln files are not relevant and this is how I deal with it.

gokult
Yeah, if things are within one solution, referencing the project works fine. I sort of implied that in the question. It doesn't work with separate solutions, nor is it likely to work if the library project file is not available (i.e. if the application developers just have the assembly plus sidecar files and not the actual project file)
iammichael
A: 

What we did in our project is that we created as separate build file to do all those stuffs.

In your build file you can have tags to build your main solution, then add tags to copy files you need after build.

NAnt is also your option, but right now I'm happy using Rake as my build/debug automation.

Since this cannot be integrated within Visual Studio, what I'm doing is I create a task (either in MSBuild, NAnt or Rake), that executes vsjitdebugger.exe in the end to attach it to my Visual Studio when debugging.

These are just my styles for now, you can maybe create your own style.

Marc Vitalis
+1  A: 

What if you create a merge module containing the library plus its dependencies? Your installer will then need to reference this module, but you will ensure all of the necessary files will be present.

Pedro
This sounds like it'd work in some situations, but we currently are not using installers for either our library components or our website applications, so this would add a lot of overhead both to our deployment process and more importantly to the development process.
iammichael