Setting up an integrated build and deploy pipeline for LightSwitch applications (part 2)

Introduction

We continue in this article the deployment of a LightSwitch application from a build server. Basically, the approach can be used for any other web application type, so not only for LightSwitch applications.

I have written already a whole series of articles in preparation of this one:

AUTOMATICALLY DEPLOY A LIGHTSWITCH-READY HOSTING WEBSITE WITH ABILITY TO SET THE HTTPS CERTIFICATE.

AUTOMATICALLY DEPLOY A LIGHTSWITCH-READY APPLICATION POOL WITH ABILITY TO SET THE APP POOL IDENTITY.

What will we cover in this article?

The first part of this series explained how we can correctly setup a build server and the build script to get everything built and to get a generated webdeploy package.

In this article we will elaborate a command file that will be eventually called from the build server in order to deploy the site, app pool and application on the target server.

So basically we are skipping, for the time being, the step in between: a dedicated TFS build server process template which will call this command file.

The advantage of this approach is that you can already start with manually executing this script. Anyhow, if things go wrong on the build server, the best approach is to call the script manually so that you can find out if things are going wrong with the process template or with the deployment script.

The big picture

Let’s first depict which servers are involved:

overall

What’s the process?

process

Which files do we need?

This ones:

files

 

Let’s explore them one by one:

  • The LightSwitch package (LSFullDeployment.zip): obviously, we will not need to provide this file, because it will be generated by the build server. It’s the same file that would be generated by visual studio on your development machine, when you publish your application. Of course we make sure that on the build machine the “release” build is built.
  • TemplateAppPoolPackage: this is a fixed zip file, you need to create it once. This is explained in detail here: AUTOMATICALLY DEPLOY A LIGHTSWITCH-READY APPLICATION POOL WITH ABILITY TO SET THE APP POOL IDENTITY. Since the file is the same for all deployments, it could make sense to store it on the build server in a dedicated place, in such a way the build process template processing could pick it up.
  • TemplateWebSitePackage: basically the same logic as for the TemplateAppPoolPackage. If you want to know how to create it: AUTOMATICALLY DEPLOY A LIGHTSWITCH-READY HOSTING WEBSITE WITH ABILITY TO SET THE HTTPS CERTIFICATE. Since the file is the same for all deployments, it could make sense to store it on the build server in a dedicated place, in such a way the build process template processing could pick it up.
  • RemoteDeployFromBuildserver.cmd: this is the main process. This will be the command file that will be called from the build server process template on the build server and it will trigger the remote deployment. We’ll see later in this article the further details. This command file is also generic for all applications, but you could also decide to keep it specific per project.
  • RunOnIISServer.cmd: this is an “auxiliary” command file which is called from RemoteDEployFromBuildServer. This file will be triggered from the build server but directly executed on the target IIS server. So, in practice this file is transferred from the build server to the target server and executed there locally. The reason why we need this functionality is because it contains some AppCmd commands which can not be executed remotely. . This command file is also generic for all applications but have as well the option to make it specific per application.
  • SetWebAppAndAppPoolParameters.xml: this xml files contains the application and application pool parameters used during deployment. This file should be provided inside your visual studio solution and should be checked-in in TFS. Obviously, this xml file is specific per application.
  • WebAppDeclareParameters: there are occasions where you want to have more application specific parameters and corresponding parameter values in your web.config. This mechanism is explained here: TWEAKING THE LIGHTSWITCH WEBDEPLOY PACKAGE WITH A SIMPLE SCRIPT. The parameters that you want additionally are stored in WebAppDeclareParameters.xml. The WebAppDeclareParameters file is optional and should be provided inside your visual studio solution and should be checked-in in TFS. Obviously, this xml file is specific per application.

 Let’s explore RemoteDeployFromBuildServer.cmd

Schematically I goes as follows:

deployCmd

And here is the script:

rem ******************************
rem deployment specific parameters
rem ******************************

SET "SiteName=TESTSITE"
SET "AppName=LSFullDeployment"
SET "AppPoolName=TESTAppPool"
SET "SiteHttpsPort=*:123:"
SET "WebAppSourcePackageName=LSFullDeployment.zip"

rem *************************************
rem  server specific params
rem *************************************
SET _httpsSiteCertificate="de0e36943ab3fab29322ee58edebb2e304a48370"
SET _dummyPassword="secret"  
SET "_physicalRootPath=D:\Inetpub\"
SET "_computerName=https://myserver.cloudapp.net:8172/msdeploy.axd,UserName='administrator',Password='mysecretpassword',AuthType='Basic' -allowUntrusted"

rem ********************
rem invariant parameters
rem ********************

SET "_appPoolParametersFile=SetWebAppAndAppPoolParameters.xml"
SET "_webAppParametersFile=SetWebAppAndAppPoolParameters.xml"
SET "_webAppTargetpackageName=DEPLOY.%WebAppSourcePackageName%
SET "_destinationWebSitePhysicalPath=%_physicalRootPath%%SiteName%"

net start msdepsvc

rem ***********************
rem prereqs RUNCOMMAND deletion of web app and website
msdeploy -verb:sync -source:runcommand=RunOnIISServer.cmd -dest:auto,ComputerName=%_computerName%
rem ***********************

rem **********************************************
rem ***************create app pool****************
rem **********************************************

msdeploy.exe -verb:sync -source:package="TemplateAppPoolPackage.zip",encryptpassword=%_dummyPassword% -dest:appPoolConfig=%AppPoolName%,computerName=%_computerName% -setParamFile=%_appPoolParametersFile%

rem **********************create web site*************
rem **************************************************
rem **************************************************

rem todo add  

msdeploy  -verb:sync -source:package="TemplateWebSitePackage.zip",encryptpassword=%_dummyPassword% -dest:appHostConfig=%SiteName%,ComputerName=%_computerName% -replace:objectName=virtualDirectory,targetAttributeName=physicalPath,match="^D:\\inetpub\\PreTemplateWebSite",replace=%_destinationWebSitePhysicalPath%  -setParam:"Application Pool"=%AppPoolName% -replace:objectName=httpCert,targetAttributeName=hash,replace=%_httpsSiteCertificate% -setParam:"Site-https"=%SiteHttpsPort%

rem *********************************************************
rem **********************create web application*************
rem *********************************************************

msdeploy.exe -verb:sync -source:package=%WebAppSourcePackageName% -dest:package=%_webAppTargetPackageName% -declareParamFile="WebAppDeclareParameters.xml"

msdeploy.exe -verb:sync -source:package=%_webAppTargetPackageName%  -dest:auto,ComputerName=%_computerName% -setParamFile=%_webAppParametersFile% -skip:ObjectName=dbFullSql

 

 What’s in RunOnIISServer.cmd?

This command will completely destroy the site and the application. That’s just one approach is it’s the brute force approach.

rem ******************************
rem deployment specific parameters
rem ******************************

SET "SiteName=TESTSITE"
SET "AppName=LSFullDeployment"

rem *********************************************
rem ***********remove site and app **************
rem *********************************************
SET appPath=

FOR /F %%s in ('c:\windows\System32\inetsrv\appcmd list app /path:/%AppName% /Site.Name:%SiteName%') do SET  appPath=%%s

IF /I "%appPath%" EQU "" (
 echo "Great,nothing to delete... app %SiteName%/%AppName% does't exist"
 ) ELSE (
 c:\windows\System32\inetsrv\appcmd delete app /app.name:%SiteName%/%AppName%
 )

SET siteID=

FOR /F %%s in ('c:\windows\System32\inetsrv\appcmd.exe list sites %SiteName% /text:id') do SET  siteID=%%s

IF /I "%siteid%" EQU "" (
 echo "Great,nothing to delete... Site %SiteName% does't exist"
) ELSE (
 echo SiteName=%SiteName% && echo SiteID=%SiteID%
c:\windows\System32\inetsrv\appcmd delete site /site.name:%SiteName%
 )

 

As you can see, we use AppCmd, and that can not be execute remotely. That’s why in the RemoteDeployFromBuildServer.cmd command, we execute this file as a webdeploy ‘RunCommand’. The command file is simply transfered to the IIS server and executed over there locally (where it has access to AppCmd).

What about the parameter file?

In fact I put both the web application parameters and the application parameters in the same file:

<?xml version="1.0" encoding="utf-8"?>
<parameters>
  <setParameter name="IisWebApplication" value="TESTSITE/LSFullDeployment" />
  <setParameter name="ApplicationDataConnectionString" value="Data Source=mydbserver;Initial Catalog=MyDB; Integrated Security=true" />
  <setParameter name="SecurityDataConnectionString" value="Data Source=mydbserver;Initial Catalog=MyDB; Integrated Security=true" />
  <setParameter name="MembershipConnectionStringReference" value="_securityData" />
  <setParameter name="RoleConnectionStringReference" value="_securityData" />
  <setParameter name="ProfileConnectionStringReference" value="_securityData" />
  <setParameter name="LoginUrl" value="~/Security.aspx" />

 <setParameter name="managedPipelineMode" value="Integrated" /> 
 <setParameter name="identityType" value="SpecificUser" />
 <setParameter name="username" value="MyDomain\MyUser" /> 
 <setParameter name="password" value="MyUserPassword" /> 
 <setParameter name="managedRuntimeVersion" value="v4.0" />
</parameters>

 What should be installed on my build server?

Visual studio ! Theoretically it is not necessary, but I strongly advice to simply install visual studio and check if everything works fine, e.g. building a LightSwitch project.

What should be installed on the IIS web server?

Webdeploy obviously. Also worth mentioning that IIS should be installed as well :)

In order to be able to run the msdeploy RunCommand execute the following from the command line:

sc privs wmsvc SeChangeNotifyPrivilege/SeImpersonatePrivilege/SeAssignPrimaryTokenPrivilege/SeIncreaseQuotaPrivilege

Don’t forget to restart the WmSvc service afterwards. I can assure you, If you don’t know the above, it can take weeks… :)

You will need also an administrator account on the IIS server which you can use in the deployment script.  Remember this line in the deploy command:

SET "_computerName=https://myserver.cloudapp.net:8172/msdeploy.axd,UserName='administrator',Password='mysecretpassword',AuthType='Basic' -allowUntrusted"

The userName here is the administrator account on the IIS Server.  The allowUntrusted parameter tells webdeploy to trust also an https connection without a valid certificate.

Finally, port 8172 should be accessible on your IIS server. That’s the port that webdeploy uses.

Conclusion

We have now everything in place to call from the build server in order to trigger a full blown deployment based on parameters.

The above can also be interesting if you don’t use a build server, but simply want to deploy from the command line. In a next article we’ll integrate everything in the build process template.