Keep visual studio from deleting everything from bin/ on rebuild? - asp.net

I have a web application project. I have DLLs that I reference in the project stored in my bin/ folder. Well, whenever I do a rebuild or clean from Visual Studio, it will delete everything in that folder. How do I prevent this from happening?

Do not put anything into bin yourself. bin is the target folder for binaries - it is not a source folder for binaries.
Create yourself a lib folder or something like that to put your third-party binaries into. You might even name it "Third Party Binaries", since not everyone knows that "lib" means the same thing. Make your references to the binaries in this folder, and Visual Studio will copy them into bin when necessary (including on a rebuild).

I'll stay away from asking the 'why' question and just state the how. Mark the files as read only and VS shouldn't delete them.

Follow John Saunders answer and put your .dll's into a separate folder. In my case I named this folder "ServerAssemblies". Then modify your project file (.csproj in my case) and add an "AfterRebuild" target.
<Target Name="AfterRebuild">
<ItemGroup>
<ExtraAssemblies Include="$(SolutionDir)ServerAssemblies\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(ExtraAssemblies)" DestinationFolder="$(ProjectDir)bin\"></Copy>
</Target>

Can you explain why you have to store it in the bin folder to begin with? i always create a separate folder for example /components where i store all referenced dll's.

One thing the "don't do it that way!" people are forgetting is source control and 3rd party software. Using SVN you often get files that if physical references were used would create mismatches when they're not in the same physical location.
One CMS I'm working with at the moment prebuilds the VS project and solution when you set up another "instance" of it. It dumps in some dlls it needs... but if you rebuild they vanish.
The simple solution in both cases is to do as stated above and call it done.

Related

How to omit CMS from version control while automatically including / restoring them to project?

I believe this question applies to CMSes in general.
I'm using a CMS, Kentico, for a particular web application. The CMS installer generates its own boilerplate project with 10,000+ files, and this project amounts to a runnable web app. Very few of the CMS-provided files are intended for modification. Yet standard practice is to add custom code to the project, and to check the entire project into source control.
I dislike the idea of checking in my entire CMS. I prefer my repository to contain only the code particular to the project, while vendor files are automatically "pulled in" from elsewhere. For example, Visual Studio can restore NuGet packages into a fixed location in the project, and this location can be ignored by version control.
In a way, development with the CMS is dirtier than when using a typical vendor library. Usually your own code depends on a library, while the library is independent from your code. However, the CMS wants to be your app, and your own code interweaves. The CMS requires customization of its own provided files. You can't just "pull in" the CMS files to a fixed location and then ignore that location.
Given this scenario, I'd still like to omit as many of the CMS files as possible. So far, I've settled on this strategy:
Keep a pristine, readonly copy of the CMS-provided files at a standard, local path.
Create a fresh project root directory.
Copy the CMS-provided project file to the project root.
In the copied project file, change the 10,000+ file paths to point to those pristine CMS files, which are external to the project root.
Place only files with custom code into the project root. If a CMS-provided file must be modified, copy it into the project root directory and use that copy.
This strategy sounds good in theory, but it's more complicated in practice. Here are a couple complications:
Changing 10,000+ file paths to "link" in external files turns out to be more than a find-replace operation. More complex mapping is necessary to preserve the pristine project's directory structure.
The web server requires all the files to be in the same directory. Using the project file to link in external files is fine for compilation, but you've split your web root in two.
For the latter problem, it seems the best workaround is to perform post-build copy operations. This is, in itself, more complex than it seems from the outset.
As I write this, I'm starting to feel like I should go ahead and just dump the entire working CMS into my repository. It feels dirty, but it's a hell of a lot simpler. Before I do that, does anyone have any experience or ideas for how I might accomplish my goal?
To restate my question: How can I exclude my CMS's provided files from my version control repository, while still including them both in my project / build script and in my web app root?
Here's another idea for how to accomplish this:
I establish a standard local directory for Kentico DLLs and the Kentico installer, which will not be in version control.
I create KenticoSupport.csproj, a class library of types extending built-in Kentico types, just as they are intended to be extended. This will also contain content, such as JS, CSS, ASPX, ASCX, etc. files. This will be in version control, but it references the central Kentico DLLs, which are not in version control.
I create KenticoBuilder.csproj, a mostly empty project that is mainly a build script. It also contains a few simple *.patch files to modify matching Kentico files, such as Web.config and Global.asax.cs. This is under version control.
Here's what the KenticoBuilder.csproj script does:
Build KenticoSupport.csproj.
Create an output directory that will serve as both a web root and a project directory.
Install / copy the pristine Kentico project files into the output directory.
Apply patches to matching Kentico files in the output directory (mainly to add config lines and custom bootstrapping).
Copy custom DLLs and content from KenticoSupport to matching locations in the output directory.
Build the project at the output directory.
It's complex, but I think it might just work. Thoughts, anyone?
Kentico should hopefully be fixing this soon, with pre-built dlls you can reference rather than rebuilding the entire CMS every time you modify C#.
Until then, have you considered using a Symbolic Links to reference your pristine files? Then just overriding the links with your modified files when need be?
See this other question if you haven't used them before. mklink comes with newer Windows versions (Command-line), but there are a bunch of third party GUI based apps as well.
I came up with an ideal strategy:
Place the pristine CMS files at an external "code libraries" location, and make them read-only for good measure.
Make a copy of the CMS-supplied project file.
Convert all project items to link to the code library's copy, including assembly references. The required link element for MSBuild complicates this, so I wrote a little console app to parse the XML and generate the necessary elements. I also store the path to the library in a property.
At this point, you have a compilable project. The files are all just links to read-only, baseline, CMS-provided files, but the IDE shows a nice directory structure, as if the files were actually in your repository. As you customize, you can replace the links with your own actual files.
However, your website files are now split between two completely different locations. The web server needs them to actually be in the same directory. This is where some scripting comes in handy.
Using your build scripting tool, plug into the post-build event to copy linked files into the project directory. Naturally, you can omit the compiled files. Here's how I did it with MSBuild (thanks to this blog post):
<Target Name="AfterBuild">
<ItemGroup>
<LinkedKenticoFiles Include="#(None);#(EmbeddedResource);#(Content)"
Condition="$([System.String]::new('%(FullPath)').StartsWith('$(MY_LIBRARY_BASE_PATH)'))" />
</ItemGroup>
<Copy SourceFiles="%(LinkedKenticoFiles.Identity)"
DestinationFiles="%(LinkedKenticoFiles.Link)"
SkipUnchangedFiles='true' />
</Target>
Optionally, plug into the cleaning event to remove those files. I used similar MSBuild syntax to delete the files, and because it leaves behind empty directories, I remove empty directories, too. (Thanks to this answer.)
<Target Name="BeforeClean">
<ItemGroup>
<LinkedKenticoFiles Include="#(None);#(EmbeddedResource);#(Content)"
Condition="$([System.String]::new('%(FullPath)').StartsWith('$(MY_LIBRARY_BASE_PATH)'))" />
</ItemGroup>
<Delete Files="%(LinkedKenticoFiles.Link)" />
<ItemGroup>
<Directories Include="$([System.IO.Directory]::GetDirectories($(MSBuildProjectDirectory), '*', System.IO.SearchOption.AllDirectories))" />
<Directories>
<Files>$([System.IO.Directory]::GetFiles("%(Directories.Identity)", "*", System.IO.SearchOption.AllDirectories).get_Length())</Files>
</Directories>
</ItemGroup>
<RemoveDir Directories="#(Directories)" Condition="%(Files)=='0'" />
</Target>
Optionally, make your source control ignore the site / project folder, to avoid checking in the temporary, copied site files.

How to get Visual Studio 'Publish' functionality to include files from post build event?

I am currently attempting to use Visual Studio 2010 'Publish' and MSDeploy functionality to handle my web deployment needs but have run into a roadblock with regards to customizing the package depending on my build configuration.
I develop in a 32bit environment but need to create a release package for a 64bit environment, so in the 'Release' configuration I have a post build event that copies the 64bit version of a third-party dll into the bin directory overwriting the 32bit version. When I use the 'Publish' functionality, even though the correct 64bit dll is being copied to the bin directory, it doesn't get included in the package.
Is there a way to get the 'Publish' to include files that have been copied into the bin directory during a post build event?
I answered a similar but different question at How do you include additional files using VS2010 web deployment packages?.
In your scenario you are using post build event, I would recommend dropping the post build event and implement your actions using your own MSBuild targets instead of post build event. Below you'll find the text of the other answer.
From: How do you include additional files using VS2010 web deployment packages?
Great question. I just posted a very detailed blog entry about this at Web Deployment Tool (MSDeploy) : Build Package including extra files or excluding specific files.
Here is the synopsis. After including files, I show how to exclude files as well.
Including Extra Files
Including extra files into the package is a bit harder but still no bigee if you are comfortable with MSBuild, and if you are not then read this. In order to do this we need to hook into the part of the process that collects the files for packaging. The target we need to extend is called CopyAllFilesToSingleFolder. This target has a dependency property, PipelinePreDeployCopyAllFilesToOneFolderDependsOn, that we can tap into and inject our own target. So we will create a target named CustomCollectFiles and inject that into the process. We achieve this with the following (remember after the import statement).
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
This will add our target to the process, now we need to define the target itself. Let’s assume that you have a folder named Extra Files that sits 1 level above your web project. You want to include all of those files. Here is the CustomCollectFiles target and we discuss after that.
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="..\Extra Files\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Here what I did was create the item _CustomFiles and in the Include attribute told it to pick up all the files in that folder and any folder underneath it. Then I use this item to populate the FilesForPackagingFromProject item. This is the item that MSDeploy actually uses to add extra files. Also notice that I declared the metadata DestinationRelativePath value. This will determine the relative path that it will be placed in the package. I used the statement Extra Files%(RecursiveDir)%(Filename)%(Extension) here. What that is saying is to place it in the same relative location in the package as it is under the Extra Files folder.
Excluding files
If you open the project file of a web application created with VS 2010 towards the bottom of it you will find a line with.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
BTW you can open the project file inside of VS. Right click on the project pick Unload Project. Then right click on the unloaded project and select Edit Project.
This statement will include all the targets and tasks that we need. Most of our customizations should be after that import, if you are not sure put if after! So if you have files to exclude there is an item name, ExcludeFromPackageFiles, that can be used to do so. For example let’s say that you have file named Sample.Debug.js which included in your web application but you want that file to be excluded from the created packages. You can place the snippet below after that import statement.
<ItemGroup>
<ExcludeFromPackageFiles Include="Sample.Debug.xml">
<FromTarget>Project</FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>
By declaring populating this item the files will automatically be excluded. Note the usage of the FromTarget metadata here. I will not get into that here, but you should know to always specify that.
I found a workaround for the problem by using the ExcludeFilesFromDeployment element within the project file. I got the idea from Web Deployment: Excluding Files and Folders
So if you need to package project files as they exist in your project directory after a successful build and associated post build steps then do the following.
Edit "Package/Publish Web" project settings and
select Items to deploy to be "All files in this project folder"
Unload the project
Right click on the unloaded project and select to edit the project config
Locate the PropertyGroup element associated to the configuration setting e.g. "Release"
Within the PropertyGroup element add in the following elements and exclude files and folders you don't want in the package
<ExcludeFilesFromDeployment>*.cs;**\.svn\**\*.*;Web.*.config;*.csproj*</ExcludeFilesFromDeployment>
<ExcludeFoldersFromDeployment>.svn;Controllers;BootstrapperTasks;Properties</ExcludeFoldersFromDeployment>
Save and reload your project
This solves my problem for the time being but if there is a better solution then please let me know, as this is not ideal due to the hackery involved, but then again perhaps this is an uncommon deployment scenario?
Select your files or folders and Change Build action as Content from Properties Window.
I know its a old question but none of these worked for me .
In 2017 VS I just right clicked on the extra folder to be published and select publish it worked.
Example:
Adding the bin folder (and it's contents) to the project caused the files to be copied to the publish output directory.
For me, my issue was that I needed to place a proprietary software license file in the bin/ folder, but did not want to copy it manually each deployment.
This was using Visual Studio 2015 Professional
I know this is an old conversation but I came upon it while trying to do the same thing and I thought it would be helpful to add what I found here.
Nearly all the articles about including extra files in your publication use this method of adding the CopyAllFilesToSingleFolderForPackageDependsOn or CopyAllFilesToSingleFolderForMSDeployDependsOn items in the PropertyGroup and they all same something like "I added this to the end of the file ..."
This is what I did and spent an afternoon trying to find why nothing was happening until I realised there was already a PropertyGroup section at the top of the file. When I put my CopyAllFilesToSingleFolderForPackageDependsOn into that section it worked fine.
Hope this saves someone time some day

How can I prevent Visual Studio 2005's "Clean" command from removing 3rd party binaries?

I have a Sitecore/ASP.NET projects that I'm developing. Today at some point I inadvertently hit the "Clean" option in the solution context menu. It took me a while to figure out why my site was hopelessly broken. Turns out Visual Studio went ahead and deleted several required assemblies from the \bin dir which are not part of my project.
How can I prevent this from happening again?
The odd thing is that it did NOT delete everything... just a small handful. It left many that are not directly referenced by my project. This makes me wonder exactly what this feature is supposed to do? Is there some sort of file flag I can set? None of the files are set to read-only. If you're interested in details, the following got deleted:
Sitecore.Analytics.dll
Sitecore.Client.XML
Stimulsoft.Base.dll
Stimulsoft.Report.dll
Stimulsoft.Report.Web.dll
Stimulsoft.Report.WebDesign.dll
Telerik.Web.UI.dll
UPDATE: You know what... I guess what I'm really more interested in here is WHY Visual Studio is leaving most of the files and only deleting these specific ones.
The correct answer to your problem will depend on how you are referencing the assemblies and how you include them in your project output.
The bin and obj folders generated by a project are best considered "output" folders; these folders should only contain files produced by the project build.
When you perform a clean or rebuild of a project, all intermediary and compiled files are deleted from these folders.
You should be comfortable this is happening.
You should be able to restore these folders by running the build process at any time. If you have added files to these folders directly, it breaks the purpose of these folders and means you ought to rethink how you're adding those files.
The preferred way to reference compiled assemblies is to add them somewhere inside your source folders. From there, they can be added to a source control system as easily as any other file and can be referenced/copied by projects which depend on them. In my work, we have a "Libraries" folder which contains numerous third-party assemblies referenced by multiple projects in our solution hierarchy.
Try using a source tree like this and seeing if it works for you:
/Projects/My Solution/
/Projects/My Solution/Libraries/
/Projects/My Solution/Project A/
/Projects/My Solution/Project B/
We always add an AfterBuild event to the project file containing Sitecore.
<Target Name="AfterBuild">
<CreateItem Include="$(SolutionDir)\Third Party\Sitecore\*.*">
<Output TaskParameter="Include" ItemName="FilesToArchive" />
</CreateItem>
<Copy SourceFiles="#(FilesToArchive)" DestinationFolder="$(TargetDir)\%(FilesToArchive.RecursiveDir)" />
</Target>
Where the CreateItem Include is the path to where you have placed your Sitecore binaries.
Put the dlls in a different directory. You will probably not want them as part of the project. Reference the dlls from the new directory. When you compile the dlls will be copied to the bin directory.
I work with lots of projects and keep a bin directory at the root of my projects to store 3rd party dlls for exactly this reason.
Example directory structure:
MyProjects
- bin
- 3rdParty.dll
- Project1
- Project2
- ProjectN
This allows all the projects to have a well-known reference location for 3rd party dlls without having to copy the dll into each project.
If you are working on a team you should all agree on a standard directory structure for your code. This will save you lots of headaches beyond just this.
In case of Sitecore, just make sure to set the property of the reference(Sitecore.Kernel, Sitecore.Client, etc):
'Copy Local' = false.
I believe that if you put these files in a subdirectory other than bin, Visual Studio won't remove them. You can still make the new subdirectory part of your deployment.
Well, I'm going to go ahead and answer my own question, since it seems like the simplest answer so far. I marked the assemblies in question as Read-only. Now they don't get cleaned.
Still wondering why most of the others don't get deleted.

Subversion and ASP.NET Website Project's Bin folder

We're in the middle of changing from VSS to Subversion and we have a website project on our Subversion Repo. We've removed the Bin folder as it causes all kinds of chaotic tree conflicts since our development solution contains some Class Library projects the Website project depends on (set up as project references in our solution). We also have a couple of 3rd party library DLLs in the Website's Bin folder too.
The next phase of our project involves a designer modifying themes to our website. I'd like for him to be able to just open the Website project in VS 2005, modify the CSS files he needs to on his working copy, and test his files on his localhost. He'll need the most up-to-date DLL files for him to be able to do this.
Is there anyway to add the Bin folder DLLs to subversion, and configure TortoiseSVN or subversion so that we can commit our newest DLLs (project dependencies in developer's solution files) but ignore them on update (per client I guess)? It would also be handy to have our 3rd party website dependencies on Subversion too.
You should not put 3rd-party assemblies into the bin folder. In fact, you should assume that the bin folder will be emptied before each build. It is a place to put the output from a build, not a place to put inputs.
Put these binaries in to some other folder, maybe "3rdPartyAssemblies". Use a file reference to these files, and they'll be copied into the bin folder, as outputs.
Would it not be possible to structure it like this:
Trunk/
WebApp/
ClassLibrary1/
ClassLibrary2/
ClassLibrary3/
3rdPartyDlls/
build.bat
The web app is what pulls all the class libraries and the 3rd party dlls in to the WebApp's Bin folder (All of these will be referenced via relative links). You can then setup TortoiseSvn to call the build.bat file on update through client side hooks. You would also setup IIS on the designer's machine to point to the WebApp directory.
As other users have pointed out, you could use svn externals to pull in those enterprise wide class libraries.
What most everybody else has said regarding '3rdParty' is correct.
You may also consider svn:externals to pull in related directories including a '3rdParty' assemblies directory, or even output directories from builds that can be triggered by a check in to assure currency.
The approach we've taken is, rather than having the Libraries in the same solution, they have separate solutions and we (well, our Build server) compiles them and checks the compiled DLLs into sourcecontrol under "Dependencies" which is always mapped to C:\Dependencies on all developers machines. We then use file references to this folder from the website project.
Thi way you can give your designer the Website project along with a copy of C:\Dependencies and they'll be none-the-wiser =)
We don't sourcecontrol the bin-folder since it would be updated everytime you run a compile. Instead, we keep references to 3rd part libs in a separete folder that is under version control, that we have references to in our project.
With this setup and using "copy local = true", they are automatically added into bin upon compilation.
Secondly, we will only commit new binary files when we update the 3rd-part binaries.
This approach is also possible to do for your internal dlls, so that your designer can just compile his visual-studio-solution so taht any relevant dlls would be put into his bin-folder and hence, create a functional site locally on his machine.

Problem with using SVN with VS.NET to version compiled code - .svn folder conflict with /bin

I'm using SVN to version a ASP.NET web project that I'm working on. I have recently decided to try versioning published versions of the site. I commit these to the repository along with tagged Release versions of the code in the root of the branch. This is proving useful as I can deploy to my server using SVN.
Problem that I'm facing is that I've had to version some files in my project's /bin folder (DLLs without external references), which has created a /bin/.svn folder. Problem is that VS.NET's Publish command insists on copying the .svn from the development branch /bin to the output folder's /bin. This basically 'switches' the binary files in there to point to the dev branch. The result is that the contents of the /bin folder never actually get committed to the compiled bin folder, because the working copy is pointing to a different part of the repository.
Is there any way to force visual studio to ignore the .svn folder on publish? Alternately, is there another way to handle the inclusion of static .dlls in a project without putting them in the bin folder, so that the /bin can be excluded from SVN (as it should be) (not using the GAC)?
Definitely do not put the bin folder in the repository. This will give you nightmares forever.
Just put your static referenced .dll's in a folder called "Libraries" or whatever, and set your project references to them. They'll be copied to the output automatically.
I suggest that you don't version anything in the .bin folder. Instead put all of your referenced assemblies in a folder outside of your project folders. Then deploy it and build it where ever it is going. The build process will pull all of the dlls in as needed. This would then remedy your .svn folder in the bin folder issue!
Hmm.. Put them into a separate folder in the solution and reference them. Now why didn't I think of that (doh!). Think I've been staring at the screen too long.
Thanks all.

Resources