How to copy additional files on build? - c#

I have a WebApi2 application and it references other projects within the solution. One of these includes some files that I want copied on build. These files have their Copy to Output Directory property set to true.
The files are correctly located in the bin folder of their assembly.
However:
After the build I need them to be copied to the App_Data folder of the web application
Included in the files that get published to IIS
Is it possible?

From my experience you are going to have to get your hands dirty with MSBuild. Its been ages since I've used it but you will need to use the Move Task
This is what Visual Studio uses in the background to build the projects. It may seem daunting but is actually pretty simple once you get used to it. There are tons of tutorials online.
Alternatively, and the most straightforward way, is that you include the files in the APP_DATA folder from within the solution.
EDIT: As mentioned by robor78 you will need to call the Move Task in the Post-Build event

Add build events
In Visual Studio -> Solution Explorer -> right click the project -> properties -> go to build events.
Use something like xcopy
Also if click on "Edit Post-Build" you will see a list of useful folders and file names which you can use e.g. $(OutDir)

You can use Xcopy from the Post build event. It is pretty straight forward but will not run if code not changed. So if you update configs etc. you must force the build I beleive.
See here for how to use xcopy.
http://commandwindows.com/xcopy.htm
There are wild cards and all kinds of useful features, but your situation is pretty simple. Just copy from $(ProjectDir)/bin or something like that to a path.

Related

How to extend Visual Studio with TFS to override the Get command

I am working on a conversion from Accurev to TFS and am being blocked by Accurev's usage of symbolic links, which TFS does not work with. I have tried several methods, but they all seem to fail to work.
What I would like to do is have a file in the project/branch that lists all the linked files and folders that is stored in source control. On every get operation, I would like to read this file and link the folders and files specified in the central file. However, I cannot find a way to extend the get operation. Does anyone have any experience in extending it in VS?
TFS does not provide a way to extend what happens on a Get action. You could easily create a custom powershell or batch file that you use in place of calling tf.exe, but since Team Build and Visual Studio call into TFS directly using the Client Object Model you're not going to make this easy on yourself.
In the end everything is possible of course. You could write a custom build action for Team Build to replace the standard get operation, or create one that triggers after the standard get operation has completed. You can write a vsix visual studio extension that replaces the standard Get operation everywhere in the menu's of Visual Studio and get to a something that could be considered workable. But I would not recommend this. It is far from standard and it is far from sustainable. You'll have to unwire so much default behavior in Visual Studio (that checks out files that are changed, adds files to source control when they're added to the project file etc etc etc).
SourceSafe used to have this feature as well (it was called pinning) and Microsoft removed it when they created TFVC. They now recommend you use branching and merging to synchronize these files across multiple projects, making sure that the source structure in Source control is the same as the ones on disk during build.
You can also make use of the Add-as-Link option in your project files. This allows you to keep the original files in their original location, but MsBuild will understand that in the project structure this file actually lives somewhere else. Or package the linked files up in a NuGet package and use the Dependency Management using NuGet guide to help you place the files in the right location during build.
And finally, you can get very creative using Workspace Mappings, many people never get further than mapping $/project -> $(SourceDir), but in essence the workspace mapping is like the file you describe. A way to layout your sources from Source control to disk. You could do:
$/Project/DEV/MyProject -> $(SourceDir)\MyProject
$/Project/Shared/FilesToCopy -> $(SourceDir)\Shared
And you can even add files from other projects in the same collection:
$/AnotherProject/Shared -> $(SourceDir)\MoreShared
And something not many people know, you can layout individual files:
$/AnotherProject/CompanyAssemblyInfoItems.cs -> $(SourceDir)\CompanyAssemblyInfoItems.cs
The only thing you cannot do, is map files to be children of an already mapped folder. In that case you might need to have the workspace mapping do the fetching of the sources and then a .targets file that you include in your .csproj file to do the copying of files.

What is the best way to publish multiple versions of the same ClickOnce application?

I have a c# ClickOnce application that I need to be able to publish multiple times for OEM purposes.
The way I understand it now is that publish settings are located in the .csproj file.
However, this is inconvenient in the case where I want to publish multiple versions.
for example, Company A needs totally different icons, start menu location, product name etc. from Company B, but the assemblies need not be renamed.
Here are a couple approaches/questions that I can think of to solve this issue...
1.Is there a way to create a separate publish settings file to use during build time?
2.Can I edit specific publish settings (like Start Menu location, etc) at build time with MSBuild.exe? I think this would be ideal...
e.g.
MSBuild.exe project.sln /target:Publish /property:edit-project-publish-settings-here
3.Maybe create a 2nd .csproj file? (Would prefer not to do this...)
Please share your thoughts as to the best approach, or any other clever ways to make this happen. Thanks!
I wish I could give you some brilliant solution, but personally I would probably go with option 3.
I mean, its pretty simple, the changes should be pretty static and it will be difficult(ish) to totally screw it up and deploy the wrong changes to the wrong company.
If you copy the .csproj in your project folder, it will reference all of the same source files and you can just change the executable name. Create another VS solution and you can reference the copied .csproj and get rid of your first one so that you can publish two separate versions.
This isn't ideal for ClickOnce however.
If you use a Singleton object that specifies the "mode" (Company A, B, C, etc.) you can easily store that in the app.config (or another xml file). Then just re-publish your ClickOnce Application but copy the correct version of your configuration file in so it gets shipped with the build. This way, you don't need any additional csprojects Just include all of your icons and set them at run-time on App Start based on your Singleton object.
I found that you are able to edit certain properties using MSBuild.exe like this
MSBuild Solution.sln /target:publish /property:ProductName=ProductA\;Publisher=CompanyA\;ApplicationIcon=companyA.ico
I found another useful post on modifying.csproj files programatically with .NET code. (This would only be needed if you're modifying things that are deeper than just the project properties specified in the ClickOnce documentation below)
The MSBuild documentation here was also useful -- especially under Publishing Properties

Is there a way to make user specific pre/post build events in Visual Studio projects?

I'm currently using a post build event in my project to copy my assemblies to another directory for debugging purposes. This is local to my machine, and is for debugging purposes only, so I would prefer to have it in a *.csproj.user file instead of a *.csproj file. I tried copying the responsible elements from the *.csproj to the *.csproj.user, but that didn't work.
Edit
To clarify, I do not want to put user specific commands in the post-build event in the *.csproj file. Instead, I want to put the post-build event commands in the *.csproj.user file. (From the answers so far, this is looking impossible)
To give more context, it is not a project reference. I am copying my assembly to the directory of the application that loads the assemblies at runtime. (Think plugins)
The short answer is no, not the way you want to do it :|
The slightly longer answer is sorta. You can in theory have specific build events triggered for individual users, but these would still be in the csproj file. You can run external events on builds and then allow these external events to run depending on what user is running them (as a script).
If this is for debug only I'd just insert them, do your build stuff and pull them out before uploading it to your version control system.
Use an if statement and an enviroment variable (in double quotes if required)
if "$(Username)" == "MyUser"
copy /y $(ProjectDir)memcached.$(ConfigurationName).config $(ProjectDir)memcached.config
You can utilize a custom build target that has a condition triggered by an environment variable. Then only set that variable on your machine.
Pre-/Post-build events are kept in the project file. VS provides no options.
You can introduce a custom (external) tool to perform such copying though and call it from menu, or macros and call it too.

Web.Config to not publish certain files

I am curious if it is possible to specify in a web.config file to have visual studio not publish certain files or a certain directory.
The use case that I am trying to solve for is that I have a Test folder on a web app, that provides a series of useful pages for testing and debugging. The pages are very useful for development and qa. However in production they should not exist. What I would like is that when I publish my code with the release config that these files, or the entire folder is not published.
It doesn't really matter where the build conditions are stored, what is important is how you're gonna use them during build/publish. A conditional msbuild script would easily solve your issue - one of build tasks would be to publish/discard files depending of the value of some internal msbuild property and the property value comes from the web.config or any other external source (build script parameter, external XML file, etc.)
You could exclude the folder from your solution, then in publish it would not push it out. Then, if you want it back in your solution, it will still be there. Just right click the folder and include it.
I don't really if this is the "right" way or even possible to do what you are asking.
What I would suggest is to create a second project for your test. I usually go that way and just deploy the second "project" in my test environement.

Move intermediates directory on C# projects in Visual Studio

I'm currently in the process of stripping down, refactoring and cleaning up a medium sized (15 ish projects) Visual Studio solution. The solution contains projects in both C++ and C#.
I'm keen to keep things as neat as possible in terms of output - seperating anything compiler created from source code, as it helps subversion (okay, I can tell it to ignore files, but I still feel it's messy) from freaking out.
The output I would like to achieve is as follows:
SolutionDir/
SolutionDir/src/project1/{ Code here }
SolutionDir/int/project1/configuration/{.obj files and other misc compiler junk here}
SolutionDir/bin/project1/configuration/{The fun stuff goes here}
This seems trivial with C++ projects as you can specify both the output and the intermediates directory. However with C#, at least through the Visual Studio 2008 User Interface it seems impossible to move the obj directory?
After doing some digging, I added
<IntermediateOutputPath>..\..\int\ProjectName\Debug\</IntermediateOutputPath>
to the C# .csproj
This appears to work, sort of. It's true the intermediates appear to end up there, but a directory 'obj' and under it a configuration directory (e.g. 'debug') and then a 'TempPE' directory are created in the old location - all of which are empty.
This isn't really a big deal, but it would be nice to know the cause of this behavior and if possible a way to fix it.
Thanks in advance!
If you add both of the following lines to each build configuration then the "obj" folder is not created by default and there is no need for a post-build action:
<IntermediateOutputPath>Assembly\obj\Debug\</IntermediateOutputPath>
<BaseIntermediateOutputPath>Assembly\obj\Debug\</BaseIntermediateOutputPath>
SVN / SCC ignore properties are also useful if desired
I've been searching for a solution for this problem myself, and came up with something less intrusive.
Create a bat file named "CleanSrcDir.bat" somewhere (i placed mine in my project path) with the following contents:
rmdir /S /Q %1obj
SET %ERRORLEVEL%=0
After this, add something similar to the C# project's post-build events:
$(ProjectDir)CleanSrcDir.bat $(ProjectDir)
(This assumes you placed your bat file in the project directory, of course.)
Then change the post-build settings to "Always", and you're done.
It's a little hackish, but sure makes the version control problem go away.
I'd recommend adding directories that you want to ignore to an SVN ignore property one-level-up. Also, when you do an initial commit and don't add bin and obje directories, SVN clients won't freak. On another note, consider placing generated files into GeneratedFiles subdirectory of your project, and not checking that directory into SVN.

Categories

Resources