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?