Showing posts with label delete. Show all posts
Showing posts with label delete. 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"

Delete temporary file sent through StreamContent in ASP.NET Web API HttpResponseMessage

Recently I had to delete a temporary (temp) file/resource sent through HttpResponseMessage. The code I tried first was like this:

var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.OK;
                response.Content = new StreamContent(fileStream);
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = fileName
                };
File.Delete(filePath);
return response;

Fooling myself I didn’t notice that one cannot do File.Delete(filePath); before returning the file because it’ll be deleted from the server disk before arriving at the client – see that response.Content receives a StreamContent, that is, the file is yet to be streamed to the client – only after it’s been streamed is that we can delete the file.

This is the exception that was being logged:

20131028 18:29:10 435 [7299] ERROR com.itvizion.data.services.Controllers.DataTablesController - Unhandled exception during file action Could not find a part of the path 'C:\ITVizion\MyProject\FileExportService\Files\datatable.csv'.

Sure it could not find the file, it had already been deleted. D'oh

So how can we dispose a managed resource (in this case the file) after the client has successfully downloaded it? That’s a damn good question I made myself and Google yesterday.

Googling I found this StackOverflow question:

How to delete the file that was sent as StreamContent of HttpResponseMessage

The asker pointed me in the right direction. One has to inherit from HttpResponseMessage and override the Dispose method like this:

public class FileHttpResponseMessage : HttpResponseMessage
{
    private string filePath;

    public FileHttpResponseMessage(string filePath)
    {
        this.filePath = filePath;
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

        Content.Dispose();

        File.Delete(filePath);
    }
}

Note the order of the calls inside the Dispose method. This is an essential part that differs from the hint given by the SO question I mentioned above.

Now what’s left is put FileHttpResponseMessage to use like this:

var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

var response = new FileHttpResponseMessage(filePath);
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = fileName
};

return response;

FileHttpResponseMessage will take care of calling Dispose on the correct time deleting the temporary file from the server disk right after the client has finished downloading the file.

Cleaning up the server disk is a good practice after all. This can avoid future headaches.

Hope it helps.

Delete Blogger Navbar section/widget from your blog template code

In the past I used to just hide Blogger’s navbar widget with some CSS code but it was still there being loaded in the HTML code. This approach is inefficient because I really don’t want the navbar. So why should it still be there in the code taking some precious time to load and impacting the user experience?

Blogger navbarFigure 1 - Blogger navbar

In my case when I looked at the Layout section of my blog in Blogger dashboard I saw that the navbar section was locked (see the locked=’true’ in Figure 2) which means I could not delete it in the Layout screen. So there’s only one option to really get rid of it and it is through the widget code.

If you look carefully you’ll note that the navbar’s code loads some JavaScript files as the Google Plus One plusone.js file. This is impacting my page load speed because I’m already loading the plusone script somewhere else since I have a customized template. This leads to duplicate requests for the same JavaScript file. This is really really bad. There’s no need for it.

So I was after a way of removing the navbar forever; not just hiding it with CSS. I then found a way of doing it but it didn’t work for me. Blogger redesigned its interface and maybe this is the problem.

Then I just thought: what if I try to select the navbar section code and delete it and hit save on the HTML template – who knows… this can work out. What’s the result: it does work out.

How to do it? Follow these 10 simple steps…

1 - First save a backup copy of your blog template for the case where something goes wrong;

2 - Go to Blogger dashboard and select Template in the menu on the left;

3 - Hit the Backup / Restore button at the screen top right and save a backup copy of your layout;

4 - In the Template screen, click Edit HTML button;

5 - Click the checkbox Expand Widget Templates;

6 - Hit Ctrl + F and find the string ‘navbar’;

7 - Select the section code like the one shown in the following screenshot:

Selecting the navbar section/widget code while editing the blog’s template HTML codeFigure 2 - Selecting the navbar section/widget code while editing the blog’s template HTML code

8 - Hit delete on the keyboard;

9 - Click the Save template button in orange. You should get this message:

Warning message informing that deleting the navbar widget cannot be undoneFigure 3 - Warning message informing that deleting the navbar widget cannot be undone

10 - Click Delete widgets button and you’re done. Smile

Now your page will load a bit faster and this is pretty nice for the user visiting your blog.