Automatic build/deploy of ASP.NET CMS modules using TFS2010 - asp.net

We are using a CMS system which is not included as part of our Visual Studio solution. When we develop for the CMS, we create individual projects within the solution for:
Widgets
Templates
Masterpages
Controls
Each of the projects has a designated destination folder within the CMS, so the website looks like this:
\\mywebsite\controls\mycontrol.ascx
\\mywebsite\templates\single-column-template.aspx
\\mywebsite\widgets\tabbed-content.ascx
\\mywebsite\masterpages\main.master
And each of their compiled assemblies need to go in \\mywebsite\bin\
Each time a project is built within the Build Definition's process template, MSDeploy is called, but I cannot get MSDeploy to place the .ascx, .aspx, and .master files into their corresponding subfolders while also having their assemblies placed into the bin.
Within the Build Definition's MSBuild Arguments, I have the following string:
/p:DeployOnBuild=true /p:DeployTarget=MSDeployPublish /p:MSDeployPublishMethod=WMSVC /p:MSDeployServiceUrl=myserver:8172/msdeploy.axd /p:AllowUntrustedCertificate=True /p:DeployIISAppPath="myserver/mywebsite" /p:Username={user} /p:Password={password}
If I modify the /p:DeployIISAppPath to be /p:DeployIISAppPath="myserver/mywebsite/controls", then MSDeploy creates a bin folder under that subdirectory, so using a custom parameter during the build process doesn't seem like it will work. Can anyone help me understand how I might be able to accomplish this?

Related

Location on nant build file in Visual Studio solution

I am just starting to use Nant and have a quick question -
When using Nant with a ASP.NET web application, where is the recommended place to put the build file? Should it be part of the web project or should it be just directly under the solution? Am I over thinking this?
I recommend you to place your build file along with the whole project. You also should create a separate directory for this build file (e.g. named Build), because in future you will have to create one more build (or .include) file and one more and then you will have a set of build files that should be grouped.

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.

MvcBuildViews seems to build more files than are included in the .csproj file

Is there any way to limit the view building to only files included in the .csproj file? Or is there at least a way to exclude certain folders from being built?
In our project folder structure we have an \Admin\Mocks folder which contains lots of mocked up .aspx and .cshtml files, and while the \Admin\Mocks folder isn't included in the .csproj file (though \Admin is), it seems that all the files in that tree are getting built. This of course generates LOTS of build errors.
I'm not sure that this makes a difference, but our project is a hybrid WebForms/Mvc3 application (both WebForms and Razor View Engines) using Asp.Net 4.
Based on the time stamp I assume you eventually worked around this but I got here Googling for a solution to the same problem.
We have a bunch of old Webforms views that are only checked in (not referenced by the project) for reference purposes and for A/B testing while we are updating the application. (Webforms -> Razor, MVC2 -> MVC4, etc)
This was an issue as both the .cshtml and .aspx files were being built and the errors from the Webform views were breaking the build.
The solution for us was to rename the the old view files from Index.aspx to Index.aspx.old
(In your case I would suggest Index.aspx.mock ?)
This meant they were excluded from the MvcBuildViews = True processing, but were still easily accessible and able to be opened from Visual Studio.
The additional benefit is you can change the default open with for that extension to use the Webforms editor so you still get highlighting and all.
If possible, create a separate web project and put the content you don't want to be built in there, making sure to set MVCBuildViews to false.

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 do I make an ASP.NET 2.0 Web App compile like a 1.1 App?

When compiling an ASP.NET 2.0 App names MySite for deployment I get a series of assemblies that resemble something like "bin/APP_xyz123.dll", "bin/APP_xyz456.dll" and so on.
Everything works fine but if I make a small code change I have to update the entire site because the "_xyz123" and "_xyz456" part of the assembles names change with each new build.
What I desire is to have one assembly called MySite.dll that I can update as needed, right now there is no clear way to accomplisht this. Does anyone know a way I can create the desired outcome I want?
In 2005 and 2008 there are two options for creating a website--the WebSite project and the Web Application project.
The WAP is the one you want. Its available by default in 2008, but you have to download an update in 2005 to get it.
You can read more about it on the Gu-ster's blog.
Yes, WAP project you want. And you need to add a Web Deployment Project (.wdproj). Then in the property pages you go to the Output Assemblies page and you select the option you want (sounds like you would want 'Merge all pages and control outputs to a single assembly') and you give it the name you want (mysite.dll).
All cs files (in App_code and page behind files) will be merged into this single dll (if that's the option you select).
Then everytime you compile just copy the output from the wdproj debug or release folders (if no aspx pages changed you can just copy the dll.
Another option is to use the aspnet_merge.exe tool which can generate a single assembly for your application.

Resources