11. March 2013 15:02
This is a technical post about how we automatically deploy new portals that will be run by our own portal software discoverize.
After filling in and submitting our portal creation form we do the following:
Save the entered information into /App_Data/<PortalName>/portal.xml
Trigger the TeamCity build through a web request to a specific URL
Send an email with the request status or any errors that occurred
Display a Thank You page.
Now, the TeamCity build configuration that was triggered under 2. does the following:
Execute the Powershell script create-portal.ps1 in c:\projects\discoverize
create the AppPool Discoverize-Portals if it doesn't exist yet (all our portals run within it)
iterate over all folders inside wwwroot\discoverize.com\App_Data
if a folder with the same name exists under wwwroot\discoverize-portals, skip it
else move the current folder from wwwroot\discoverize.com\App_Data to wwwroot\discoverize-portals
add a line with the full path to the new portal folder to newportals.txt (e.g. C:\inetpub\wwwroot\discoverize-portals\<PortalName>)
add a new site to IIS and set its AppPool to Discoverize-Portals
start the new site in IIS (needs Admin privileges, that's why we use a parameterized task scheduler task for that)
Build the source code from the repository
Execute the Deploy-NewPortals target from deploy.proj using MSBuild in c:\projects\discoverize
Iterate over the entries in newportals.txt, for each entry do:
Copy the build output from step 2. to wwwroot\discoverize-portals\<PortalName>
Run the site setup (this uses Orchard's setup method) with our own recipe (using Orchard.exe)
Call an action (SetupComplete) on the new site to mark deployment as done
Create a default entry so there's something to look at (using Orchard.exe)
The SetupComplete action then finishes doing this:
save the information of the portal.xml into an application specific configuration file
create new user "portal-owner" for content management
send an email about the successful installation of the new portal
Quite complex, if I look at it now, but it works!
6. September 2011 22:18
Recently, we encountered a quite surprising behavior of MSBuild – the continuous integration build of our new collaborative Todo Management app (we hope to go into beta soon!) would produce a broken version whereas the local build with VS2010 was all smooth and well. Our admin and tester already posted about this problem over at his blog: MSBuild does not build like Visual Studio 2010. The exception message finally led me down the right path: Server Error in '/' Application. No constructors on type 'Teamaton.TodoCore.Repositories.TodoRepositoryJson' can be found with 'Public binding flags'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: Autofac.Core.DependencyResolutionException: No constructors on type 'Teamaton.TodoCore.Repositories.TodoRepositoryJson' can be found with 'Public binding flags'. The TodoRepositoryJson is a type we used at the very beginning of our development to quickly get started using a JSON document as data store. Later we switched to SQLite, so now we have another implementation: TodoRepositoryDb. Both implement the same interface ITodoRepository. Turns out, the Autofac type registering code was the culprit: 1: var builder = new ContainerBuilder();
2: builder.RegisterAssemblyTypes(typeof (Todo).Assembly)
3: .Where(t => t.Name.Contains("Repository"))
What worked with Visual Studio, didn’t work with MSBuild: obviously – well, now it is – both ITodoRepository implementations were registered with Autofac, and while Autofac’s assembly scanning delivered them in the order we assumed from the DLL built with VS – first, TodoRepositoryJson, and second, TodoRepositoryDb, thus overriding the first registration – MSBuild seems to build a DLL which returns the inverse order! Very strange.
Honestly, I’m not familiar with the anatomy of DLLs and surprised by this result. But it’s the only explanation I’ve found so far.
Well, the solution to the problem is, of course, to care more about what we register with Autofac and in which order.
21. January 2011 20:19
We recently updated one our largest project to use ASP.NET 4.0, and for this matter the new Package/Publish feature including sub-web.configs which is meant to supersede the Web Deployment Project. For a manual deployment there’s a good write-up on the msdn library titled ASP.NET Web Application Project Deployment Overview which shows how and where to set this up. In our case this was not satisfactory because our deployment process is a bit more complicated. We push our changes to a central repository and use JetBrains’ continuous integration server (CIS) TeamCity Professional, which is totally free for our project size, for a continuous integration process. Once TeamCity has pulled and tested the current version, it is supposed to deploy this version to our staging server where we further test the complete site. The key point in an automatic deployment was the management of the different web.config files for the different environments our project is running on. Unfortunately, until yesterday every deployment that included changes to the web.config file – even to the staging server - required a manual step of editing the web.config that live on our staging system (outside of source control!). What we used to do: after a successful build on our CIS we simply copied the web application (files) to our staging server! But as Scott Hanselman wrote: If You're Using XCopy, You're Doing It Wrong! This post inspired us to move along and take advantage of the new possibilities that we were given. In the meanwhile, before switching to .NET 4.0 actually, we also took a shot at the Web Deployment Project way of doing things but never actually got that far as to fully automate the deployment – somehow the setup was not as easy as we hoped. Anyway, we wanted web.config Transforms! So what does our setup look like and what did we want to do? During local development and testing I use a web.config file that talks to a local DB instance and has some more specific settings. To run the web application on our staging server we need to replace certain values or whole sections in the web.config. For this transformation we use the sub-web.config files, one for each build configuration: Now, with all of these web.config files the simple XCOPY deployment we used to use does not work any longer. We need to trigger the web.config transformation on the build server and then deploy the whole application. As easy as this looks using the built-in menus and dialogs in Visual Studio – it took me quite a while to find how to do this in an automated build, more concretely from the command line. After unsuccessfulle skimming stackoverflow.com for a solution I finally tripped over this very informative blog post on publishing a VS2010 ASP.NET web application using MSBuild. Admittedly, the author focuses on how to publish on the local machine as it’s yet a different process but towards the end he posts the solution I was looking for: 1: msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;DesktopBuildPackageLocation=c:\_Publish\stage\Website.zip" /t:Package
This was it! After running this on my machine with my own settings I looked into the folder with the zip file and found the following 5 files:
At first I just wanted to take the zip file, copy it to the staging server, unpack it – done! But then I peaked into it… and deeper… and deeper… and… still deeper… until I finally saw our application files underneath this directory:
This has got to be one of the longest paths I’ve ever seen and used! How would I automate the extraction of web application files from the zip with such a path? I was already seeing myself hacking away on the command line…
But wait: what about those files that appeared next to the zip file? A ci-stage.deploy.cmd and a readme.txt caught my attention – of course, I opened the cmd file first :-D
Well… maybe the readme file gives me a shortcut to understanding this and the rest of the 190 lines:
Looks promising! I convinced myself to give it a shot. So we set up a new configuration in TeamCity with the following settings:
These settings reflect the command line from above with a few minor changes (removed the DesktopBuildPackageLocation and set the /v[erbose] switch to m[inimal]):
msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release" /t:Package /v:m
The second step is to use the generated script, ci-stage.deploy.cmd. I recommend to run the script by hand once using the /T switch just to make sure everything looks alright. In our case we found out that the deployment of the package would have deleted a lot of files, most of all images, from our website. This was not what we wanted! After a quick search I found this question on stackoverflow.com: MSDeploy: “Leave extra files on destination” from command line? So I added this switch to the parameters list in the build step configuration as follows:
That’s it! This is all we need on the command line to generate a package that is ready for deployment on the staging server. There are a few more necessary settings, including the DesktopBuildPackageLocation, that can be found in the Package settings window inside the project properties of the web application project:
the DesktopBuildPackageLocation can be set here instead of on the command line
the website and application name on the destination IIS server that this package should be installed to
some more options like excluding debug symbols etc.
These settings are saved in the project file and will be used during generation and deployment of the package.
That’s all I have to say right now.
Happy Coding, Oliver