Showing posts with label publish. Show all posts
Showing posts with label publish. Show all posts

Using MsDeploy publish profile .pubxml to create an empty folder structure on IIS and skip deleting it with MsDeploySkipRules

I’m going to share here a pretty nice deployment automation solution for when you need to have a defined set of folders in place when first deploying an app to IIS. On subsequent re-deployments the folder structure will be kept intact with any files users may have added to them.

Let’s work with a simple example: given an ASP.NET MVC app, we need a folder called Files and inside this folder there will be some pre-defined folders named: Folder 1, Folder 2 and Folder 3 with a child folder called Test. Something like this:

App root
|
---Files
   |
   ---Folder 1
   ---Folder 2
   ---Folder 3
      |
      ---Test

When deploying for the 1st time these folders are empty but the folder structure is mandatory let’s say because I’m using a file manager like elFinder.Net that expects that these folders exist on the server. Why? Because the ASP.NET MVC app has links pointing to these folders in some views. The folders should be ready to store files when the app is released. What also comes to my mind is the case where we need an existing Downloads/Uploads folder.

What’s more? We also want all this to happen while using Publish Web command from within Visual Studio and still keeping the option Remove additional files at destination checked:

Figure 1 - Visual Studio Publish Web with File Publish Options => Remove additional files at destinationFigure 1 - Visual Studio Publish Web with File Publish Options => Remove additional files at destination

This setting is nice because when you update jQuery NuGet package for example (jquery-2.1.1.js) it will send the new files to IIS server and will remove the old version (jquery-2.1.0.js) that exists there. This is really important so that the app keeps working as expected and don’t load the wrong version/duplicate files. If we don’t check that option we have to go to the server and delete the old files manually. What a cumbersome and error prone task!

What to do in this case where we want the deployment task do the work “automagically” for us with no human intervention? It’s seems like a lot of requirements and a task not so simple as “it appears to be”… Yep, it requires a little bit of MsDeploy codez.

Here’s what is working for me at the moment after finding some code pieces from here and there:

Given a  publish profile named Local.pubxml that sits here:
C:\Company\Company.ProjectName\Company.ProjectName.Web\Properties\
PublishProfiles\Local.pubxml

Let’s add the code blocks necessary to make all the requirements come to life:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>AddCustomSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>
    <WebPublishMethod>MSDeploy</WebPublishMethod>
    <LastUsedBuildConfiguration>Local</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <MSDeployServiceURL>localhost</MSDeployServiceURL>
    <DeployIisAppPath>SuperCoolAwesomeAppName</DeployIisAppPath>
    <RemoteSitePhysicalPath />
    <SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod> <AllowUntrustedCertificate>True</AllowUntrustedCertificate>
<EnableMSDeployBackup>False</EnableMSDeployBackup> <UserName /> <_SavePWD>False</_SavePWD> <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> </PropertyGroup> <PropertyGroup> <UseMsDeployExe>true</UseMsDeployExe> </PropertyGroup> <Target Name="CreateEmptyFolders"> <Message Text="Adding empty folders to Files" /> <MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 1" /> <MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 2" /> <MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 3\Test"/> </Target> <Target Name="AddCustomSkipRules" DependsOnTargets="CreateEmptyFolders"> <Message Text="Adding Custom Skip Rules" /> <ItemGroup>
      <MsDeploySkipRules Include="SkipFilesInFilesFolder">
        <SkipAction>Delete</SkipAction>
        <ObjectName>filePath</ObjectName>
        <AbsolutePath>$(_DestinationContentPath)\\Files\\.*</AbsolutePath>
        <Apply>Destination</Apply>
      </MsDeploySkipRules>

      <MsDeploySkipRules Include="SkipFoldersInFilesFolders">
        <SkipAction></SkipAction>
        <ObjectName>dirPath</ObjectName>
        <AbsolutePath>$(_DestinationContentPath)\\Files\\.*\\*</AbsolutePath>
        <Apply>Destination</Apply>
      </MsDeploySkipRules>

</ItemGroup>
</
Target> </Project>

This is self explanatory. Pay attention to the highlighted parts as they are the glue that make all the requirements happen during the publish action.

What is going on?

The property

<AfterAddIisSettingAndFileContentsToSourceManifest>
AddCustomSkipRules
</AfterAddIisSettingAndFileContentsToSourceManifest>

calls the target

<Target Name="AddCustomSkipRules"
DependsOnTargets="CreateEmptyFolders">
that in turn depends on the other task
<Target Name="CreateEmptyFolders">

CreateEmptyFolders take care of adding/creating the folder structure on the server if it doen’t exist yet.

AddCustomSkipRules contains two  <MsDeploySkipRules...>. One is to prevent deleting Files and the other prevents deleting the child folders.

Check the targets’ logic. They’re pretty easy to understand…

Note: make sure you don’t forget the

<UseMsDeployExe>true</UseMsDeployExe>

otherwise you may see this error during deployment:

Error    4    Web deployment task failed. (Unrecognized skip directive 'skipaction'. Must be one of the following: "objectName," "keyAttribute," "absolutePath," "xPath," "attributes.<name>.")        0    0    Company.ProjectName.Web

Simple as pie after we see it working. Isn’t it? Winking smile

Hope it helps!

As an interesting point, see the command executed by msdeploy.exe that gets written to the output window in Visual Studio:

C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe -source:manifest='C:\Company\Company.ProjectName\Company.ProjectName.Web\obj\
Local\Package\Company.ProjectName.Web.SourceManifest.xml' -dest:auto,IncludeAcls='False',AuthType='NTLM' -verb:sync -disableLink:AppPoolExtension -disableLink:ContentExtension -disableLink:CertificateExtension -
skip:skipaction='Delete',objectname='filePath',absolutepath='\\Files\\.*' -skip:objectname='dirPath',absolutepath='\\Files\\.*\\*' -setParamFile:"C:\Company\Company.ProjectName\Company.ProjectName.Web\obj\Local\ Package\Company.ProjectName.Web.Parameters.xml" -retryAttempts=2 -userAgent="VS12.0:PublishDialog:WTE2.3.50425.0"

Debugging Microsoft Web Deploy Visual Studio publishing errors

This post is intended for starters with MS Web Deploy as is my case… Shifty

Microsoft Web Deploy is so awesome that I think it’s one of the best features one has at their disposal when developing with the .NET Framework and for the Web with ASP.NET MVC for example. It’s so powerful that it can even publish a database.

Once upon a time (let’s say before 2010) there was no Web Deploy and you had to FTP to the server to deploy the application. This was a tiresome task and led to many errors because one had to be extremely careful of what files needed to be updated, added, removed, etc while installing the application on the server. Backup methods should be in place in case something went wrong. I used to use compressed files (.zip or .rar) to send the app’s files to the server. It was still a big upload in some cases. I had to wait patiently. Once there I had to uncompress the file. Everything needed to be moved into place to make things easier. I even created a step by step readme file to help other peers do the deploy on the server. This readme detailed the workflow that should be followed in order to get things working.

Thanks God today there’s Web Deploy and it changed things drastically: only new or updated files are uploaded to the server. No more long waiting periods to start using the application. As a bonus you also have the option of removing additional files on the server (files/folders that aren’t used anymore). All this happens automatically (could we say automagically) with the click of a button inside Visual Studio 2010 or 2012. You can also run a .cmd file in the command line. This .cmd file is created as part of the Web Deploy Package publish method that you can choose once inside Visual Studio. There’s so many awesome features (read Preview menu option in Figure 4 bellow) that they would not fit in this post… To get a full understanding about Web Deploy look at this post: Visual Studio 2012 RC Deployment Docs.

Well, 2 weeks ago I tried to solve a problem related to Web Deploy. You can read the full history here:

Visual Studio 2012 Web Deploy to Windows Server 2008 R2 with IIS 7 and /msdeploy.axd 404 error

The above problem wasn’t solved but I can tell you that I learned a LOT about IIS administration during that weekend. As a result it was worth the effort. I think that a clean install of Windows Server 2008 is necessary in that case…

Today I was facing a different error (again working against Windows Server 2008 R2) and I followed a simple path to solve it. So here are the basic steps you need to follow to detect the problem’s origin:

Visual Studio 2012 Publish project with Web Deploy and Validate Connection errorFigure 1 - Visual Studio 2012 Publish project with Web Deploy and Validate Connection error

As you see when I clicked the Validate Connection button I got a message: ERROR COULD NOT CONNECT TO REMOTESVC.

If you click the error message, there’s some more info about the error but it doesn’t really tell you what’s causing the problem.  It’s kind of a generic message you get: go check the Web Management Service on your server… I think I don’t need to tell you that it’s started already! Steaming mad

Figure 2 - Visual Studio 2012 Publish project with detailed ERROR informationFigure 2 - Visual Studio 2012 Publish project with “detailed” ERROR information

To really get to the problem, you’ll need to access the server you’re trying to deploy to. Once there go to this folder:

C:\inetpub\logs\wmsvc\W3SVC1

This is the standard path where Web Management Service logs what’s going on…

When I opened the latest .log file I saw this:

#Software: Microsoft Internet Information Services 7.5
#Version: 1.0
#Date: 2012-07-26 15:50:30
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
2012-07-26 12:50:30 192.168.100.77 HEAD /msdeploy.axd site=Default%20Web%20Siste 8172 - 189.24.83.277 - 401 2 5 1918
2012-07-26 12:50:33 192.168.100.77 HEAD /msdeploy.axd site=Default%20Web%20Siste 8172 develop
189.24.83.277 - 550 0 0 2761

As you see highlighted in orange is my developer machine IP address. This let’s me know that my connection to server is working as expected. Port 8172 is not blocked by the firewall, etc.
Highlighted in yellow is a sc-status = 550. This is the key part while debugging errors related to web deploy on the server. Now it’s far easier to know what’s the problem. It’s only a matter of Googling about the 550 status code. The first post that mentions this status code was this one:

Status code 550 when using Msdeploy

The guy lost 1 day to find what was going on and it took me only 1 minute to figure out the error I had with his help. He talks about the site’s name displayed in IIS manager. So I went check mine and to my surprise I had a small mistake in the Site/application name field shown in Figure 1. I typed Default Web Siste instead of only Default Web Site. What a silly mistake!

This is the kind of error that can bother you more than it should… believe it or not. You can go the wrong way while trying to get things working as expected.

After correcting this mistyped named I clicked the Validate Connection button again and to my delight and surprise I got this beautiful green check mark:

Visual Studio 2012 Publish project with Web Deploy and successful connection validationFigure 3 - Visual Studio 2012 Publish project with Web Deploy and successful connection validation

Now if you desire select the Preview menu option to glance at what’s going to the server…

Visual Studio 2012 Publish project with Web Deploy and Previewing the changes
Figure 4 - Visual Studio 2012 Publish project with Web Deploy and Previewing the changes

You can select just the files you want to deploy. This is super useful let’s say when you discover a bug in production and want to change something in whatever file to correct that bug. You already have more changes to pull to the server but you just want to correct that bug. With the Preview tab you can do this: select just the file(s) you changed to correct the bug and deselect all the others. Isn’t this awesome? Of course it is!

If it’s OK, just hit the Publish button and you’re good to go.

I hope this simple post helps you find the root cause of what’s causing errors while you’re trying to deploy your application using MS Deploy.

References
Configuring a Web Server for Web Deploy Publishing (Remote Agent)

Installing and Configuring Web Deploy

Web Deploy error codes