MSBuild Copy Output Assembly to Additional Dir

1.1k views Asked by At

Problem

Visual Studio's Microsoft.VisualStudio.Web.Host.exe holds a read lock on %DEVPATH%\*.dll during build.

Background

I'm running a website on my development box with Redgate .NET Reflector. .NET Reflector requires that the environment variable DEVPATH be set to %ALLUSERSPROFILE%\Red Gate\.NET Reflector\DevPath\ so that it can create PDBs of referenced assemblies without putting them in your bin directory. When it does create PDBs, it copies the disassembled .dlls to DEVPATH and whatever program you're running references these copies rather than the files in your bin dir.

That's fine except that, in my case, these disassembled dlls use reflection and look in the same directory they are in, assuming it to be the original bin dir, for other assemblies--the ones I've written.

Here's my directory structure:

/inetpub/wwwroot/bin/Arena.Framework.dll          <-- dll to be decompiled
/inetpub/wwwroot/bin/Arena.Custom.Common.dll      <-- my custom dll

/ProgramData/Red Gate/.NET Reflector/DevPath/Arena.Framework.dll    <-- copied by .NET Reflector in order to be decompiled; uses reflection to find types in ./Arena.Custom.*.dll

Things that didn't work

Symbolic link

First I tried using a symbolic link from .../bin/Arena.Custom.Common.dll to %DEVPATH%/Arena.Custom.Common.dll, but that prevented building at all.

Have .NET Reflector copy dlls for me

Next I tried making .NET Reflector generate PDBs for my custom dll rather than having MSBuild do it so that it would automatically copy my dll into the directory. Unfortunately, .NET Reflector is too smart for its own good, recognizing that it's a project dll, and won't do it.

Copy dlls after build in csproj

My next solution was to add a few lines in my Arena.Custom.Common.csproj file:

<Target Name="AfterBuild">
  <Copy SourceFiles="@(MainAssembly)" DestinationFolder="$(DEVPATH)" SkipUnchangedFiles="true" Retries="0" />
  <Message Text="Copied @(MainAssembly) to $(DEVPATH)" />
</Target>

This will copy the output dll to DevPath. This worked the first time I built, and I thought I was done. The next time I built, however, it failed because Microsoft.VisualStudio.Web.Host.exe (hereafter referred to as Host.exe) has it loaded. I assume the reason it can overwrite files in the bin directory is that it doesn't actually load them, but copies them to a temp directory and loads those each time you build. However files in DEVPATH are always loaded by by VS's Host.exe. As .NET Reflector only decompiles dlls that you aren't building yourself, it never needs to copy over those, and thus never runs into the issue I'm having.

Possibly useful info..?

MSDN says you can disable the hosting process in the csproj properties window, and I did so, but it's still running. I'm not certain, but I'm guessing the website project is causing it to run, and a Website's properties window doesn't have a "Debug" tab.

Question

Is there a better work-around than merely copying them to DEVPATH after build?

Maybe I should change the output directory from .../bin to DEVPATH directly? That would copy all the dependency dlls to DEVPATH as well, which isn't ideal.

Perhaps there's a way to either tell Host.exe to unload the files during build, or to kill the process until the build is finished? I tried do this manually and MSBuild.exe started crashing.

I've considered saving a temp copy of %DEVPATH%, clearing the value, somehow retarting Host.exe, building, copying, setting %DEVPATH% back to the original value, and restarting Host.exe again, but I get the feeling that, if Host.exe is enabled, VS relies on it to be running continuously during build.

Another work-around is to close VS, delete the files in DEVPATH, reopen VS, and rebuild every time I need to make changes to my DLLs. This is an awful option, but it works.

Hopefully there are some better solutions out there...

Edit

Per comment, my question is: How can I copy the new version of my compiled DLLs to DEVPATH on/after build?

0

There are 0 answers