Skip to content
Archive of posts filed under the Azure category.

Continuous Integration with Azure from TFS Build

Recently I have been doing some TFS work.  One of the tasks I have completed was to implement automatic publishing to Azure from TFS build.  Our goal is to automate as much as possible to make it easy for QA to test as well as ensure that every night we have a fresh build for them ready.  In addition to that there are a few side benefits of this approach that I really like.  It is very much in line with agile methodology, ensuring that we have a shippable version of the software as often as possible.  In addition to that it is nice to test the final product in eventual production environment as often as possible and as early as possible.  With this, let’s dive into the solution.

Our software solution is a typical web application, using ASP.NET MVC, Enterprise Library Data Access blocks based DAL, stored procedures, business objects layer and services layer.   We use VS Database project to manage database changes and deploy to QA.  We use VS 2010 and TFS 2008.

I already wrote a TFSBuild.proj file that I use to publish to QA.  This build does the following tasks

  • Build the solution
  • Migrates the database using Visual Studio Database Project
  • Deploys the solution to QA web site on premises.

Our unit and integration tests are run by Continuous integration build, so we do not run unit tests as part of QA build.  I decided to use this QA build as my base. 

Everything I read about publishing to Azure from build ignored one important issue – what to do with the database.  Unfortunately, database project does not support publishing to Azure.  It is a sad fact give the importance Microsoft put on Azure.

I have been using Red Gate products for many years, almost 10 to be specific.  Red Gate SQL Compare to the rescue.  The newest version 10 has Azure support.  More specifically, it allows one to compare local SQL Server 200 R2 database to Azure SQL Server database and synchronize them. Cool.  So, here is the outline of my TFSBuild.proj file.  More specifically, here are the tasks at the high level.

Build Azure based solution.  I created the solution by copying existing solution, then adding Azure project to it.

  • Deploy database using database project to a SQL Server.
  • Use SQL Compare to synchronize this database with a database on Azure that was created at some point.  It can be just blank database, as SQL Compare will create the structure for us.
  • Create Post deployment script by combining all post deployment scripts from database project, using Script.PostDeployment.sql and its data as the guideline.  Run this script against Azure database using a utility.
  • Use Azure Cmdlets package from CodePlex to deploy package to Azure.

No, let’s dive into the details.

To deploy database project from TFS Build, you just need the following task in your proj file.

    <PropertyGroup>
        <TargetConnString>Data&#x20;Source=MyServer%3BUser&#x20;myUserID%3BPassword=myPassword</TargetConnString>

A few key things to notice.  You have to en


    <Target Name="AfterDropBuild">
        <Message Text="Starting to deploy database project"/>
        <MSBuild Projects="$(SolutionRoot)\MySolution\MyDatabaseProject\MyDatabase.dbproj"               Properties="TargetDatabase=AZURE_TEST;Configuration=Release;OutDir=$(DropLocation)\$(BuildNumber)\Release\;TargetConnectionString=$(TargetConnString);DeployToDatabase=true"               Targets="Deploy"/>
        <Message Text="Finished deploying database project"/>

code connection string, or you will get some errors.  You do have to add the property DeployToDatabase=true to your command line or it will not deploy.  You will see that the build does run successfully, just does not apply updates.

Now off to Azure synchronization.  I wrote a little command line utility I will call to do two tasks: synchronize with Azure SQL DB and run the scripts against it.  The code is very simple for this utility, it just launches SQLCompare.exe, which comes with Professional version of SQL Compare, then does some string parsing to create post deployment script and runs it in.  Here is what the method that synchronizes DB looks like:

        public static bool UpdateAzureDB(string logFileName)
        {
            var process = new Process();
            if (File.Exists(logFileName))
            {
                File.Delete(logFileName);
            }
            var commandLine =
                @" /db1:AZURE_TEST /p1:localPassword /u1:localUserID /s1:localServer /db2:AZURE_DB /p2:azurePassword " +
                @"/u2:azureUserID /s2:********.database.windows.net /exclude:user /exclude:role " +
                @"/r:" + logFileName + @" /rt:Simple /sync  /include:identical";
            var startInfo = new ProcessStartInfo(
                @"C:\Program Files (x86)\Red Gate\SQL Compare 10\SqlCompare.exe", commandLine);
            process.StartInfo = startInfo;
            process.Start();
            process.WaitForExit();
            return process.ExitCode == 0;
        }

A couple of imporant notes.  We have to know if the process scusseeds, so we are trapping return value.  SQLCOmpare will return non-zero value if something goes wrong.  We are also creating a log file just in case in HTML format.  We are excluding database users and roles, since I do not need to synchronize those.

Next step is to create data massaging.  We are following database project best practices.  We are breaking down data massaging into multiple scripts, then combining them in Script.PostDeployment.sql.  Here is an example of that script:

/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
 This file contains SQL statements that will be appended to the build script.
 Use SQLCMD syntax to include a file in the post-deployment script.
 Example:      :r .\myfile.sql
--------------------------------------------------------------------------------------
*/
:r .\Table1.Data.SQL
:r .\Table2.Data.SQL

My utility will accept the directory name where this file is located, will parse the file, and create one giant string with the content of all the sub-scripts.  Once that is done, it will use passed in connection string and will fire out the final script.  Again, code is pretty simple.

        public static void UpdateData(string folderName, string azureConnectionString)
        {
            var scriptData =
                File.ReadAllLines(string.Format(@"{0}\{1}", folderName, "Script.PostDeployment.sql"));
            var finalScript =
                (from line in scriptData
                 where line.StartsWith(":r")
                 select line.Substring(line.IndexOf(@"\") + 1))
                    .Aggregate("", (current, fileName) => current + File.ReadAllText(string.Format(@"{0}\{1}", folderName, fileName)));

            using (var connection = new SqlConnection(azureConnectionString))
            {
                connection.Open();
                using (var command = connection.CreateCommand())
                {
                    command.CommandType = CommandType.Text;
                    command.CommandText = finalScript;
                    var rowsAffected = command.ExecuteNonQuery();
                }
            }
        }

Now, I just have a wrapper utility that calls both methods in susccessing, traps errors and only returns zero if both methods execute properly.  I need this so that I can stop the build in case of non-zero exit code from my utility. To do so, I use Environment.Exit(0) or non-zero value in case of errors.  I also use Console.WriteLine,because this data will end up in the build log and will help me troubleshoot issues.  Now, I just need to call it from TFSBuild.proj:

    <PropertyGroup>
        <DatabaseUpdaterExecutable>UpdaterApp.exe</DatabaseUpdaterExecutable>
        <AzureConnectionString>"Data&#x20;Source=xxxxxxxx.database.windows.net%3BInitial&#x20;Catalog=AZURE_DB%3BPersist&#x20;Security&#x20;Info=True%3BUser&#x20;ID=remoteUserID%3BPassword=remotePassword"</AzureConnectionString>
        <AzureDeploymentReportFileLocation>C:\Temp\AzureDBReport.html</AzureDeploymentReportFileLocation>

 

        <Message Text="Working on Azure DB"/>
        <Message Text="Executable: $(SolutionRoot)\Deployment\$(DatabaseUpdaterExecutable)"/>
        <Message Text="PostDeploymentScriptLocation: $(SolutionRoot)\MySolution\MyDatabaseProject\Scripts\Post-Deployment"/>
        <Message Text="AzureConnectionString: $(AzureConnectionString)"/>
        <Message Text="AzureDeploymentReportFileLocation: $(AzureDeploymentReportFileLocation)"/>
        <Exec Command="&quot;$(SolutionRoot)\Deployment\$(DatabaseUpdaterExecutable)&quot; &quot;$(SolutionRoot)\MySolution\MyDatabaseProject\Scripts\Post-Deployment&quot; $(AzureConnectionString) $(AzureDeploymentReportFileLocation)" ContinueOnError="false"/>
        <Message Text="Finished working on Azure"/>

Now, deploying the solution to Azure.  I ran into an issue installing Cmdlets.  I was getting “No snapins are installed error” when running PowerShell.exe.  What I ended up doing is installing both 32 and 64 bit versions of Cmdlets.  You can do that by opening installPSCmdlets.cmd that will be in your scripts folder after you install Cmdlets from CodePlex, and running it in both 32 and 64 bit code path.  You can just manually set powerShellDir variable to both values and running it twice.  Then do the same with installPSSnapIn.cmd.  Of course, make sure you do all that on your build server

Now, let’s update TFSBuild.proj file.  Here is the command in it:

    <PropertyGroup>
        <PackageName>MySolutionAzure.cspkg</PackageName>
        <ServiceConfigName>ServiceConfiguration.Cloud.cscfg</ServiceConfigName>
        <HostedServiceName>myServiceName</HostedServiceName>
        <Thumbprint>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Thumbprint>
        <SubscriptionID>XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX</SubscriptionID>
        <Slot>Production</Slot>
        <StorageName>myStorageServiceName</StorageName>
    <Target Name="AfterDropBuild">

        <Message Text="Copying Azure configuration file"/>
        <Copy SourceFiles="$(SolutionRoot)\Configuration\Azure\Web.config"
            DestinationFolder="$(SolutionRoot)\MySolution\MyWebProject" OverwriteReadOnlyFiles="true"/>

        <Message Text="Starting to build azure project for deployment"/>
        <MSBuild Projects="$(SolutionRoot)\MySolution\MyAzureProject\MyAzureProject.ccproj" Properties="Configuration=Release;OutDir=$(DropLocation)\$(BuildNumber)\Release\app.publish\;PackageForComputeEmulator=true;" Targets="Rebuild;Publish"/>
        <Message Text="Finished to build azure project for deployment"/>

        <Copy SourceFiles="$(SolutionRoot)\MySolution\MyAzureProject\bin\Release\app.publish\MyAzureProject.cspkg"
            DestinationFolder="C:\temp" OverwriteReadOnlyFiles="true"/>

        <Copy SourceFiles="$(SolutionRoot)\MySolution\MyAzureProject\bin\Release\app.publish\\ServiceConfiguration.Cloud.cscfg"
            DestinationFolder="C:\temp" OverwriteReadOnlyFiles="true"/>

        <Message Text="Starting to push package to Azure.  Package location follows"/>
        <Message Text="$(DropLocation)\$(BuildNumber)\Release\"/>

        <Exec WorkingDirectory="$(SolutionRoot)\Deployment\" ContinueOnError="false"
              Command=" $(windir)\system32\WindowsPowerShell\v1.0\powershell.exe -f AzureDeploy.ps1 C:\temp\ $(PackageName) $(ServiceConfigName) $(HostedServiceName) $(Thumbprint) $(SubscriptionID) $(Slot) $(StorageName)"/>

        <Message Text="Done pushing package to Azure"/>

There are a couple of changes I made to ps1 file though.  You can find that file in a ton of places on the internet.  They all have the same issues.

  • No error handling
  • No checking to see if a depolyment already exists
  • They do not return non-zero exit code to signal to build that deployment failed.

You have to address these issues for clean deployment.

Here is my version:

$buildPath = $args[0]
$packagename = $args[1]
$serviceconfig = $args[2]
$servicename = $args[3]
$thumbprint = $args[4]

$cert = Get-Item cert:\CurrentUser\My\$thumbprint
$sub = $args[5]
$slot = $args[6]
$storage = $args[7]
$package = join-path $buildPath $packageName
$config = join-path $buildPath $serviceconfig
$a = Get-Date
$buildLabel = $a.ToShortDateString() + "-" + $a.ToShortTimeString()

write-host  "parameters"
write-host  $args[0]
write-host  $args[1]
write-host  $args[2]
write-host  $args[3]
write-host  $args[4]
write-host  $args[5]
write-host  $args[6]
write-host  $args[7]
write-host  "package data"
write-host  $package
write-host  $config
write-host  $servicename

#Important!  When using file based packages (non-http paths), the
#cmdlets will attempt to upload the package to blob storage for
#you automatically.  If you do not specifiy a –
#StorageServiceName option, it will attempt to upload a storage
#account with the same name as $servicename.  If that
#account does not exist, it will fail.  This only applies to
#file-based package paths.
$exitCode=0
Try
{
    $ErrorActionPreference = "stop"

    Add-PSSnapin WAPPSCmdlets
    Try
    {
        $hostedService = Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub | Get-Deployment -Slot $slot

        if ($hostedService.Status -ne $null)
        {
            $hostedService |
              Set-DeploymentStatus 'Suspended' |
              Get-OperationStatus -WaitToComplete
            $hostedService |
              Remove-Deployment |
              Get-OperationStatus -WaitToComplete
        }
    }
    Catch
    {
        # eat errors as we may not have an active deployment
    }

    Get-HostedService -ServiceName $servicename -Certificate $cert -SubscriptionId $sub | New-Deployment -Slot $slot -Package $package -Configuration $config -Label $buildLabel -ServiceName $servicename -StorageServiceName $storage |
        Get-OperationStatus -WaitToComplete

    Get-HostedService -ServiceName $servicename -Certificate $cert -SubscriptionId $sub |
        Get-Deployment -Slot $slot |
        Set-DeploymentStatus 'Running' |
        Get-OperationStatus -WaitToComplete
}
Catch
{
    $exitCode=-1
    write-host $error
}
exit $exitCode

I also added a few more thing.  I echo to the build some important information, which makes it much easier to debug the problems when they occur

To do initial push, I recommend you you Publish feature from studio, as it will handle all the myriad of certificates you need to get right to publish from the power shell.

Make sure you pick correct certificate for deployment.  If you are looking at your Windows Azure management console, you need the one listed under Management tab.  Look at the thumbprint, then find it on the machine that you did initial push for. I recommend using management console in Windows.  Type “mmc” in Start->Run.  Then add a Certificates Snap in, find it under the very first node, export it to PFX file using mmc, then import it on Build machine after you login with the same account your build runs under.  While on the subject, you should install ALL required software under that account just in case.  This includes Azure SDK, which you will need, and other dependencies from Cmdlets, etc…

Now, just schedule your build, and you are ready to go.

Post to Twitter

Do You Want to Learn More About Azure?

clip_image002

Microsoft and Magenic want to show you the best way to include cloud computing into your technology solution set. Dan Sandlin (Azure Solution Specialist) will discuss which projects are right for cloud computing and which ones you should avoid, as well as how to select your first cloud project and the ROI of Azure. Sergey Barskiy (Magenic Principal Consultant) will discuss how cloud is more than just an enormous virtual machine and the building blocks of Azure.

Windows Azure offers flexibility, growth opportunities and long term stability, but only when approached the right way. Come learn where to start.

We will gather at the Ravinia Club in Atlanta on Thursday, April 21 from 7:30-10:30 am. Breakfast will be served.

clip_image004

clip_image002[4]

 

Event Details

Date:
Thursday, April 21
7:30-10:30am
Location:
2 Ravinia Drive #100
Atlanta, GA 30346

clip_image008

View Map on Bing

Get Directions

clip_image010

Post to Twitter

ReMix Talk

As I posted previously, I talked at Atlanta ReMix 2010 conference past Saturday.  Entire event was a a success, we had over 200 people there.  We had great presenters and good topics.  My topic was “Microsoft Silverlight and Windows Azure: A Match Made for the Web”

You can download PowerPoint presentation here.  You can download solution here.  To get solution up and going, you need to have Visual Studio 2010 installed, along with Silverlight 4 tools and Azure tools.  You will also need to sign up for an account on Azure and SQL Azure.  You will need to update web.config file and ServiceReference.ClientConfig file.

Please let me know if you have any questions.

Thank you.

Post to Twitter

ReMix 2010 in Atlanta

If you have not registered for this fine event I blogged about previously, you have a week left.

You can register for it here: http://reMIXatlanta.org.  You can also check out the list of session that will be presented there.

Yours truly will be presented a session there as well.  The title will be “Microsoft Silverlight and Windows Azure: A Match Made for the Web”.

Here is what they session is about:

By combining the rich user experience of Silverlight with the scalability of Windows Azure compute and storage, you can build some incredible end-to-end web applications. In this session we will discuss the business advantages of running Silverlight applications in the cloud. We will cover the steps necessary to build Silverlight applications for deployment in Azure including: data access with SQL Azure, cloud storage, communication mechanisms and data access options. We will also demonstrate how the same approach works for Windows Phone 7 development.

I am just as excited about speaking as I am about attending other sessions.  One can always learn a ton at the community events.

Post to Twitter

Windows Azure

I just want to relay Microsoft’s new offer to everyone.  Windows Azure is now offered for free for a limited time.  This is an introductory offer to get more people to use new cloud platform from Microsoft.  Please see this link for details.

Post to Twitter

Speaking at Atlanta .NET Users Group

I spoke at Atlanta.NET Users Group yesterday, My topic was Azure Step-by-Step.

I talked about why someone would use Windows and SQL Azure, then I built a Silverlight application from scratch.  The application was designed to run in Windows Azure and use SQL Azure as database.  I demonstrated how to get maximum code re-use between traditional .NET web application and the same application developed for Azure.  At the end, I had an application that could run on either platform with just web.config change.

You can download the zip file with PowerPoint slides with useful links as well as the sample project I built here.

Please let me know if you have any questions.

Post to Twitter

Talk at GGMUG

As always I had fun presenting at Gwinnett Georgia Microsoft Users Group on Thursday.  The subject of my talk was “Getting started with SQL Azure”.  I documented all the steps in this blog post.  There are also useful links that I mentioned in this post to help you get started.

There are many advantages to use SQL Azure.  Number of reason is probably the fact that one can eliminate the need to house expensive hardware and software on premises.  As long as you are fine with living with certain limitations of SQL Azure compared to SQL Server 2008, you can take advantage of this great technology.  The primary limitation is probably the size of the database.  You cannot have a database bigger than 10 GB.

Feel free to ask any questions on the topic.

Post to Twitter

Windows Azure Application

This is purely a bragging post :-)

I just deployed a test application to the cloud (Microsoft Azure): http://rolodex.cloudapp.net/

Here is the technology stack for it:

  1. Windows Azure
  2. SQL Azure
  3. CSLA 3.8.1
  4. Silverlight
  5. Entity Framework
  6. WCF
  7. Prism (Composite Application Guidance)
  8. Silverlight Toolkit

I promise to write a blog entry in the near future, the steps one has to follow through to create an Azure application.

Post to Twitter