- | rssFeed | My book on MSBuild and Team Build | Archives and Categories Saturday, October 27, 2012

MSBuild: how to set the configuration property

When you are building a .sln file or a .csproj/.vbproj/etc you need to be careful how you set the Configuration property. Once this property is set you do not want to change the value of it. Because of this it is best to specify this as a global property. To do that you can pass it in on the command line. If you are using the MSBuild task then you can pass it in via Properties or AdditionalProperties. What you do not want to do is to set this value inside your .csproj/.vbproj or any imported file. The only time when this is OK if there is a condition which will not set the property if it’s already been set. This is exactly how the default .csproj/.vbproj files are authored:

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

If you do set this property w/o the conditional not to overwrite an existing value you may experience really strange behavior during your builds. And it may be difficult to diagnose the issue as well.

Now let me explain why you cannot do this. When you build a .csproj/.vbproj MSBuild will start creating an in-memory representation of the entire project. It will start with the .csproj/.vbproj file itself. It will read the file from top to bottom. When a property is encountered it is evaluated. If a property is encountered that relies on another one, for example

<IntermediateOutputPath Condition=" '$(PlatformName)' == 'AnyCPU' ">$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>

The properties inside the expression will be evaluated on whatever values exist for the properties at the time. In this case ItermediateOutputPath will be the value of BaseIntermediateOutputPath and Configuration.

If a property is encountered which specifies a value for a property which has been previously declared, the previous value will be discarded.

The implications of this are subtle but very simple; once a property has been set which has dependent properties you must not overwrite that property. This is because when a dependent property is encountered it is evaluated immediately. You cannot re-evaluate that property. So if you set a property during your build, some existing dependent properties which were evaluated before the value change will continue to use the old value. There is no way to re-evaluate those properties.

Now lets see how this relates to the Configuration property specifically.

The contents of the .csproj/.vbproj are properties/items along with an import to Microsoft.csharp.targets (Microsoft.VisualBasic.targets for .vbproj) which then imports Microsoft.Common.targets. If you look in Microsoft.common.targets you will see many different properties which are declared using $(Configuration). So this means that you must treat the Configuration property with care and abide by the rule that I have outlined above.

FYI If you want more details on this I have explained this entire process in great detail in my book Inside MSBuild and Team Build.

Configuration for web publishing

If you have used the new web publish experience in Visual Studio 2012 (also available for VS2010 from the Azure SDK) you may have noticed that the web publish profiles are MSBuild files. They are stored under Properties\PublishProfiles (My Project\PublishProfiles for VB) and have extensions of .pubxml. In that file (or in a .pubxml.user file associated with it) you will find a property defined as

<LastUsedBuildConfiguration>Release</LastUsedBulidConfiguration>

This value corresponds to the value for the Configuration drop down in the VS web publish dialog. When you kick off a publish in VS we use this value and kick off a build and specify Configuration as a global property which is passed in. The reason why we did not name this property Configuration is because the web publish profile is imported into the web project itself during the publish process. By the file being imported you can natively access all the properties/items of the .csproj/.vbproj and also easily extend the build process. Since that is the case we cannot set the Configuration property because we know it’s value has already been set. Due to this when publishing from the command line you must specify the Configuration property.

Sayed Ibrahim Hashimi | @SayedIHashimi

msbuild | MSDeploy | Visual Studio | Visual Studio 2008 | Visual Studio 2010 Saturday, October 27, 2012 3:49:02 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, October 15, 2012

My blog sucked, here’s how I fixed it

When I setup this blog back in 2005 I had just graduated from college and most of my development experience at the time was in Java, but I had taken a job as an ASP.NET developer. When I setup the blog I didn’t know that much about web development. Last week Doug Rathbone let me know he was having issues viewing my site. This led me to take a closer look at my blog and I have to say that I’m embarrassed by what I found. I should have made the improvements outlined in this post a long time ago. In the long term I’d like to move off of dasBlog but I haven’t had the time to do that, but I needed to do something. I think I’m in a much better place, and wanted to share what I did. Before that let me recap what problems I discovered.

Poor performance

By far the most egregious aspect of my blog was it poor performance. I was violating every rule in the book! Ok well maybe not every rule as I somehow received a B rating in YSlow. After running YSlow with the Small Site or Blog settings on the site here were the results.

image

I was making too many http requests which was killing my site. Some of the request were for images in the content but from static content I had the following.

Step: Reduce the startup time of the page

My pages were loading slowly, and for the most part un-necessarily. Two things that my site had which were slowing it down were the .js files are imported at the top of the page and un-needed ads showing content. I moved all the .js includes to the bottom of the page which helped the startup time. I also simply removed the ads.

Step: Reduce the number of http request

In total there were 65 requests, not all to my webserver but most of them. The .css files were mostly for the various webparts used by the theme and the generic dasBlog .css files. Many of the .js files were brushes for the syntax highlighter that I use. To take care of this I decided to update the way that my blog looked to avoid the un-necessary images used for styling. After that I removed the un-used .css files from the site template.

Then I downloaded Packer .NET. I used that to compress and combine all the .css files into a single minified .css file for the entire site. I had to update some relative paths in the .css file but other than that it was pretty simple. I also used packer to do the same for the .js files.

Step: Reduce the size of the content being sent

Not only did I want to reduce the number of request going back and forth but I wanted to reduce the overall number of bytes going back and forth. When I was viewing the request going back in forth in my browser I noticed that a lot of .pngs were being sent back and forth because most of my entries have at least 1 image. So I downloaded PNGGauntlet to take care of it. I searched for all .png files in my site and drag tem to PNGGauntlet and let it optimize them for me. After running that I knew that all the images were optimized. I plan to run this tool on all new .png files ever few months. I post my blogs with Windows Live Writer and I haven’t researched if I can integrate this directly into it. I also changed the site’s layout to reduce the content of the web request itself. More on those changes later.

Poor readability

I’m not a designer or a fashion expert but even I could tell that my site was not laid out correctly. It had a lot of elements which were distracting, un-necessary and downright ugly. Below you’ll see thumbnails of how my blog looked like on a hi-res screen and a mid-res screen.

image image

You can see that the left hand column is an offender in both cases equally. The title bar is taking ~10% of the page on the hi-res screen and on the mid-res screen ~35% WTF!!! The most important thing on any blog is the content and the site should be optimized for readers to view the content. Everything else is just a distraction. The column on the left hand side had to go and the title bar needed some serious work. From the content in the sidebar the only items which I liked were; search, link to months, posts on this page and the categories. Everything else pretty much sucked.

Here is what I did; updated the title to be way more compact and less verbose. Removed the sidebar with ads and links. I placed the verbose sidebar content which I did like at the bottom of the page with an anchor. I linked to that in the hearder, which is where I placed the search bar. Now the distracting header is hopefully no longer distracting and the sidebar went away entirely. But all useful functionality and content were preserved.

While doing this I also looked at the HTML content which was being rendered. There were some un-needed <div/<span/<table elements coming through. I removed as much as I could in the template files. It’s still pretty bad, but until I move off of dasBlog I think this is about as good as it gets.

Lack of mobile support

My site was completely unusable on a mobile device. Here are some screen shots of how my blogged looked on a mobile device.

imageimageimage

If you ever visited my site on a mobile device, I apologize :(

Since I had already removed the columns and made the title much smaller I was already on my way. But I also needed to add the view port meta tag to the header of the site so that the browser would render the site in the correct way.

<meta name="viewport" content="width=device-width"/>

Even with the decreased title when viewed on a mobile device it was too large. I used a simple CSS media query to create styles when the site was viewed in narrow views.

@media only screen and (max-width:600px)
{
    /* Insert css here */
}

When testing this you can either download a mobile emulator, like Electric Plum, or simply resize your browser until it is less than the desired size. After the changes here are the screen shots of my new layout on a mobile device.

imageimageimage

As you can see it’s much easier to see the contents of the entries. The title bar is still a bit big, but I’d have to have to shorten the text to make it smaller, but I’m OK with how it is currently.

View when docked in Windows 8

Then I looked at my site when it was docked on the left or right in Windows 8. Below is what my site looked like before any changes.

image

Not surprising, I thought it was gonna suck. Here was my site after the updates above.

image

To my surprise it still sucked! The problem here is a similar issue as to the mobile view. The device does not know the size to make the viewport. I had to add one line of css to enable my site to be rendered correctly.

@media screen and (max-width: 320px) {
    @-ms-viewport { width: 320px; }
}

More info on this at http://blogs.msdn.com/b/ie/archive/2012/06/19/adapting-your-site-to-different-window-sizes.aspx. You can combine this with css media queries if you want to have finer grained control. More info on this at http://msdn.microsoft.com/en-us/library/ie/hh708740(v=vs.85).aspx. After that simple change here is what I now have. Much better.

image

After that I did a bit of looking around to see what sites look like docked in windows 8, there are very few which actually look nice.

Good sites

Scott Hansleman’s site is very readable for Windows 8 when docked. Kudos Scott! This doesn’t surprise me at all for Scott.

image

Microsoft.com this site is optimized for being docked, which I would expect.

image

 

Bad sites

Mads Kristensen’s blog is completely unreadable without zooming.

image

Even top-tier sites are not usable on windows 8 when docked. They still have a few weeks to GA, but they will need to get this taken care of soon.

Facebook

image

Twitter

image

cnn.com

image

Not many sites ready for being docked in windows 8.

Conclusion

After all these changes m site loads much faster, looks way better and is much easier to read on a variety of devices. After all of these changes I was able to get my YSlow score up to 98. The only remaining issue is to reduce the number of DOM elements. In order to address that issue I’ll have to wait until I can upgrade my blog software. For now I’m happy with where I’m at.

image

One thing that I haven’t done yet is to set expires headers for all my static content. I’m planning to do this, but after I make some other updates first.

For those of you who have been reading my blog for a while, I’m sorry to put you through the pain I did :) But I’m hoping that things are much better now. If I missed anything else please let me know.

FYI Scott Hanselman has a good post discussing these topics at http://www.hanselman.com/blog/TheImportanceAndEaseOfMinifyingYourCSSAndJavaScriptAndOptimizingPNGsForYourBlogOrWebsite.aspx.

Thanks,
Sayed Ibrahim Hashimi | @SayedIHashimi

Personal Monday, October 15, 2012 3:33:05 AM (GMT Daylight Time, UTC+01:00)  #     | 
Tuesday, October 09, 2012

VS Web Publish: How to include files outside of the project to be published

I just received an email asking the following:

“I’m using Visual Studio 2012 and publishing web projects to the file system. How can I include files to be published which are not a part of my project"?”

I thought that I would answer here so that everyone could see the answer.

In Visual Studio 2012 (and in VS 2010 if you have downloaded the web publish updates via the Azure SDK) when you create a web publish profile we will create a .pubxml file under the Properties\PublishProfiles for C# or My Project\PublishProfiles for VB. If you open that file you will notice that it is actually an MSBuild file. When you publish your web project (either from the VS dialog or from the command prompt) the .pubxml file is combined with your project file to execute the publish. Since this is an MSBuild file you can directly edit the file to customize behavior of the publish process. In this case the question asker, lets call him Chris, has asked how to include some additional files into the publish payload.

This can be accomplished by the following.

  1. Create an MSBuild target which can gather the set of files to be added
  2. Extend the web publish process to include the files

Creating a target is pretty simple, and I’ll cover the contents of the target but first lets look at issue #2.

We need to add an MSBuild target which executes during the period in which files are being collected to be published. We have an MSBuild property which contains the set of targets which make up this phase, PipelineCollectFilesPhaseDependsOn, which is used as a dependency property as you might have guessed. In order to insert a target into that you can use something like the following in your .pubxml file.

<PropertyGroup>
  <PipelineCollectFilesPhaseDependsOn>
    CustomCollectFiles;
    $(PipelineCollectFilesPhaseDependsOn);
  </PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>

Here I extend the PipelineCollectFilesPhaseDependsOn by pre-pending CustomCollectFiles, which is a target that I declared directly in the .pubxml file. This will make sure that my target gets executed at the correct time. Now when you publish your web app the CustomCollectFiles will be executed. Now let’s move on to what the contents of the target should contain. One way that you can do this is to add files to the FilesForPackagingFromProject item list. In my case I wanted to publish all the files in a folder named “additional files” which was one folder above the project directory. Take a look at the modifications that I made to my .pubxml file.

<PropertyGroup>
  <PipelineCollectFilesPhaseDependsOn>
    CustomCollectFiles;
    $(PipelineCollectFilesPhaseDependsOn);
  </PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>

<Target Name="CustomCollectFiles">
  <Message Text="Inside of CustomCollectFiles" Importance="high"/>
  <ItemGroup>
    <_CustomFiles Include="$(MSBuildThisFileDirectory)..\..\..\additional files\**\*" />

    <FilesForPackagingFromProject  Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>additional files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

In this case the CustomCollectFiles target gathers the files into the _CustomFiles item. Notice how I declared the path to the folder. I used the MSBuildThisFileDirectory property. This property was introduced in MSBuild 4.0 and it points to the folder of the MSBuild file which contains it. So it will point to the folder which contains the .pubxml file (either Properties\PublishProfiles or My Project\PublishProfiles). After that, the files are included in the FilesForPackagingFromProject item list. The one special item to take notice of here is the declaration for the DestinationRelativePath metadata value. Since this file is not in the project we have no context on where the files should be placed when published. This is where the DestinationRelativePath metadata comes in. Here you specify the relative location to the publish root of the file. In my case I used additional files\%(RecursiveDir)%(Filename)%(Extension). Which will place all the files in the additional files folder under the same relative path to where they were picked up from.

You can see a sample project at https://github.com/sayedihashimi/publish-samples/tree/master/FileSysIncludeOtherFiles and if you are just looking for the .pubxml file https://github.com/sayedihashimi/publish-samples/blob/master/FileSysIncludeOtherFiles/FileSysIncludeOtherFiles/Properties/PublishProfiles/ToFilesys.pubxml.

Sayed Ibrahim Hashimi | @SayedIHashimi

Tuesday, October 09, 2012 6:12:19 AM (GMT Daylight Time, UTC+01:00)  #     |