Tuesday, January 21, 2014

ASP.NET MVC, TypeScript, Azure Website and Git Deploy

The Issue

The issue and the workaround in this post applies to:

  • Visual Studio 2013
  • ASP.NET MVC using at least one TypeScript file
  • Azure Website with git deploy
  • Sites build and deployed before kudu issue 721 was resolved

Building a web site with ASP.NET and TypeScript targeting Azure Website I ran into an issue after I added the first TypeScript file and tried to deploy the web site using git deploy. It would fail with the following error message:

C:\DWASFiles\Sites\typescripttest\VirtualDirectory0\site\repository\TypeScriptHTMLApp1.csproj(67,3): error MSB4019: The imported project "D:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\TypeScript\Microsoft.TypeScript.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

The root cause for this is that the file Microsoft.TypeScript.targets file is not yet available using git deploy for Azure Websites.

The issue that I ran into is documented and discussed in a few places, e.g.

Here is my workaround that solved the issue for now. Rumors has it that Microsoft is working on a proper solution for the issue.

Note that the workaround does not require a custom “deploy.cmd” file which I felt was a plus despite having creating custom deploy scripts for other projects and other reasons.

The Workaround

The workaround is based on making the msbuild task and the TypeScript compiler available when the msbuild script (aka solution file and project files) are executed.

In my repository I created a folder 3rdparty in parallel to the solution file.

Next I created a subfolder typescript-sdk and copied the content of “C:\Program Files (x86)\Microsoft SDKs\TypeScript” into “3rdparty\typescript-sdk”. The folder contains a file tsc.exe. Make sure this is version 0.9.1.1. This version worked for me. Apparently there are other versions out there. For example version 0.9.5.0 is reported to create an error.

I also needed the msbuild task. For that I created a subfolder typescript-task and copied the content of “C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\TypeScript” into “3rdparty\typescript-task”.

The next two steps required editing the file “Microsoft.TypeScript.targets” located in “3rdparty/typescript-task” and the ASP.NET MVC project file. I won’t detail these changes here as all of this workaround is available in a repository.

With this workaround I have the same behavior for Azure Website’s git deploy as I have locally building from Visual Studio 2013. To use a TypeScript file, all I have to do is adding the file, reference the resulting javascript in the appropriate place in my views or layouts, commit and push. No further steps required.

Once the issue is resolved, all I have to do is undo the changes in the project file and remove the folders “3rdparty\typescript-sdk” and “3rdparty\typescript-task” and everything else is back to normal.

This workaround should also be applicable for scenarios where you already have a custom deploy script. The workaround does not require any changes to custom deploy scripts.

All of the source code is available in a sample project at https://bitbucket.org/ml_agileutilities/typescript-sample. There is a branch with a version that allows reproducing the problem. There is a second branch that demonstrates that the workaround fixes the issue. If you want to try out either scenario create an Azure Website and have it use git deploy from one the respective branch.

Credits

I’d like to thank Thiago Almeida and David Ebbo, Microsoft, for their awesome support in finding and testing this workaround.

Although I didn’t need a custom deploy script in the end, I would also like to thank Amit Apple for his very helpful description of how to create custom deploy script for Azure Websites.

Monday, July 15, 2013

No Split Window for TypeScript?

In case you installed TypeScript for Visual Studio 2012 and are wondering why you are not getting the split window for a TypeScript file: Check whether you have installed “Web Essentials 2012” as well. The latter gives you the split windows.

We had a couple of cases in one of the teams I’m working with where installing Web Essentials resolved the issue.

Friday, May 24, 2013

Xamarin Studio: Hello, world! fails to build

I just purchased, installed and tried out Xamarin Studio. My motivation is that I want to try out this C#-based approach towards developing applications for Android.

Not that I want to move away from Visual Studio. I’m just working through a few examples and wanted to rule out VS as an influencing factor.

Problem is that the Hello World example already failed. The error message was “The “Aapt” task failed unexpectedly.” And there was also a “System.InvalidOperationException: Sequence contains no elements” and an error code “MSB4018”. Here is a screenshot:

image

To solve it launch the Android SDK Manager. In my case it showed that there was a new update for the Android DSF Platform-tool and also showed that the Android SDK Build-tools were not installed. I just left all checked/unchecked as it was and installed what was checked. Admittedly not very selective but it did the trick. Now it’s building.

Thursday, May 23, 2013

Visual Studio Image Library

Just tried to locate the Visual Studio Image Library. I couldn’t find it. Various sources suggest to locate the file VS2010ImageLibrary.zip. This doesn’t exist on my machine, though.

It turned out that I never had Visual Studio 2010 on this machine, only Visual Studio 2012 has been installed. It appears as if VS2012 doesn’t install it by default.

However, you can download the VS2012 Image Library here. Hopefully this post helps you saving some time.

Saturday, May 04, 2013

WiX: Installing Files to Public Documents Folder

A few days ago I stumbled over the problem of installing files into the “Public Documents” folder using the Windows Installer Toolkit (WiX). Although the different bits a pieces are available somewhere on the internet I couldn’t locate a single source that describes a complete solution.

On Windows based systems each user has their own personal folder but there is also a folder called “Public Documents”. For the task at hand, I wanted to install a few sample text files into a subfolder of the public documents folder using WiX. For this example I used Visual Studio 2012 (Professional Edition or better is sufficient) with the Visual Studio extension installed by WiX 4.0.

Let’s start with the wizard for the WiX setup project:

image

As the name for the setup you can pick anything you like. In this case I chose “Acme.Setup”. The resulting project looks very simple. It has no references and only a single WiX script file in it:

image

The content of Produce.wxs is very basic (Note that the first few digits of all GUIDs in this post are replaced with the string ‘YOURGUID’. You need to replace the GUIDs with your own to make it work):

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
    <Product Id="*" Name="Acme.Setup" Language="1033" Version="1.0.0.0" Manufacturer="" UpgradeCode="YOURGUID-269e-4795-97d7-a392d75749fb">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
        <MediaTemplate />

        <Feature Id="ProductFeature" Title="Acme.Setup" Level="1">
            <ComponentGroupRef Id="ProductComponents" />
        </Feature>
    </Product>

    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLFOLDER" Name="Acme.Setup" />
            </Directory>
        </Directory>
    </Fragment>

    <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
            <!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
            <!-- <Component Id="ProductComponent"> -->
                <!-- TODO: Insert files, registry keys, and other resources here. -->
            <!-- </Component> -->
        </ComponentGroup>
    </Fragment>
</Wix>

Obviously, we now need to change this to add some files. So let’s pick a text file from a different project in the same solution. In this case I created a C# library projects called Acme.Lib and added one simple text file. We can ignore the default class ‘Class1’ that is generated in the Acme.Lib project. It is not relevant for this blog post. Here is what the solution looks like now:

image

The content of the file readme.txt and it’s name are irrelevant as well. Choose what works best for your case.

Next we need to make sure that the installer script knows about the text file and where it is located. The first option is to use your knowledge about the location of the two projects, Acme.Lib and Acme.Setup. So you could change the file Product.wxs as follows:

<Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
        <!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
        <!-- <Component Id="ProductComponent"> -->
            <!-- TODO: Insert files, registry keys, and other resources here. -->
      <Component Id="ReadmeFile" Guid="{YOURGUID-994F-49C0-A7AC-53D1571A295A}">
         <File Id="readme.txt" Name="readme.txt" Source="..\Acme.Lib\readme.txt"></File>
      </Component>
        <!-- </Component> -->
    </ComponentGroup>
</Fragment>

Some points of interest. First of all we need to add a new <Component> to the script. Your installer can consist of thousands of components if you wish. In this case I’m only adding one component with an Id and a GUID. Again, please note that I have replaced the first few digits of the GUID with ‘YOURGUID’. You need to replace all GUIDs in this example with newly generated GUIDs anyways to make it work.

Inside of the component I place a <File> tag with the Id, the name and the Source of the file. The Id needs to be unique within the installer while the name is the name that the file will have once installed. The ‘Source’ attributes tells the WiX toolset where to find the file so it can be included into the installer. Note that in contrast to some other installer tools sets the build of the installer will fail in case the WiX toolset can’t find the file.

At this stage there one additional tweak that we have to do to compile this build script successfully. We need to edit the 'Manufacturer’ attribute at the beginning of Product.wxs. Here are the first four lines (Note that ‘Manufacturer’ has been set to ‘Acme’):

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
    <Product Id="*" Name="Acme.Setup" Language="1033" Version="1.0.0.0" Manufacturer="Acme" UpgradeCode="YOURGUID-269e-4795-97d7-a392d75749fb">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

If you now build your solution it should build without problems.

At this stage all you have is an installer that installs into the into a subfolder in Program Files. It works but it is not what we want. So let’s have a look how we can change that.

The trick is to add some WiX specific extensions. This can be accomplished by adding a reference to the installer project, ‘Acme.Setup"’ in this example. The dialog box looks as follows and we want to add a file called ‘WixUtilExtension.dll’:

image

Adding this reference enables support for functionality that allows installing into the “Public Documents” folder.

The way we can use this is by adding a property reference with the Id ‘WIX_DIR_COMMON_DOCUMENTS’ as follows:

<Product Id="*" Name="Acme.Setup" Language="1033" Version="1.0.0.0" Manufacturer="Acme" UpgradeCode="YOURGUID-269e-4795-97d7-a392d75749fb">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

   <PropertyRef Id="WIX_DIR_COMMON_DOCUMENTS"/>

   <Feature Id="ProductFeature" Title="Acme.Setup" Level="1">
        <ComponentGroupRef Id="ProductComponents" />
    </Feature>
</Product>

WiX will set the property ‘WIX_DIR_COMMON_DOCUMENTS’ to the correct path for the “Public Documents” folder when the installer is executed. We don’t have to worry about that.

Now this property has been referenced we can use it to specify where we would like to install our readme file. For that we first need to change the <Directory> tag content as follows:

<Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="WIX_DIR_COMMON_DOCUMENTS">
         <Directory Id="ACMEDOCUFOLDER" Name="Acme Documentation">
         </Directory>
      </Directory>
      <Directory Id="ProgramFilesFolder">
            <Directory Id="INSTALLFOLDER" Name="Acme.Setup" />
        </Directory>
    </Directory>
</Fragment>
Note the additional directory tag with the Id ‘WIX_DIR_COMMON_DOCUMENTS’. I left the other directory tag in place. We don’t need it for the example in this blog post. For yuor actual installer you may want to use it to place binary files into a folder inside of “Program Files”.

The next change you have to make is adding a new component group that installs into the WIX_DIR_COMMON_DOCUMENTS folder. Here is the snippet that achieves this:

<Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
        <!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
        <!-- <Component Id="ProductComponent"> -->
            <!-- TODO: Insert files, registry keys, and other resources here. -->
      <!-- </Component> -->
   </ComponentGroup>
   <ComponentGroup Id="DocuComponents" Directory="ACMEDOCUFOLDER">
      <Component Id="ReadmeFile" Guid="{YOURGUID-994F-49C0-A7AC-53D1571A295A}">
         <File Id="readme.txt" Name="readme.txt" Source="..\Acme.Lib\readme.txt"></File>
      </Component>
   </ComponentGroup>
</Fragment>

Note that again I left the default component group untouched (Id=”ProductComponents”). Instead I created a new component group and gave it the id ‘DocuCompoents’. Then I moved the component ‘ReadmeFile’ from the former to the latter.

We are not quite finished yet. One item is missing. The installer does not yet know that it should include this new component / component group into the installer. So here is what we need to do to accomplish that:

<Product Id="*" Name="Acme.Setup" Language="1033" Version="1.0.0.0" Manufacturer="Acme" UpgradeCode="YOURGUID-269e-4795-97d7-a392d75749fb">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

   <PropertyRef Id="WIX_DIR_COMMON_DOCUMENTS"/>

   <Feature Id="ProductFeature" Title="Acme.Setup" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
      <ComponentGroupRef Id="DocuComponents" />
   </Feature>
</Product>

Once you build and execute the resulting installer then the result will look as follows:

image

And this screenshot demonstrates that we have accomplished what we wanted: We successfully installed a folder and a file into the “Public Documents” folder.

If you’d like the full source code of this solution please send an email to manfredmlange at gmail dot com.

Happy coding!

Sunday, April 07, 2013

Outstanding Support

I had an issue with JIRA/Greenhopper today and contacted Atlassian’s support at 08:12 am (it’s Sunday here). At 08:17 am I had a message from a human being saying that he was investigating. Communication was flowing and at 08:34 am the issue was resolved. Total time spent: 17 minutes from reporting the problem.

The way I have experienced working with Atlassian they will probably say this is just the normal way they operate. And I agree they have always been very easy to work with.

I’m mentioning it here since I think their support can serve as an example for a lot of other companies. I trust that you can easily create your own list of those who can improve.

Bottom line: Today I experienced excellent support from Atlassian … as usual. Thank you, Nick!

Saturday, March 16, 2013

Ubuntu 12.10 in Virtual Box on Windows 7

Today I spent some time to get Ubuntu 12.10 installed as a virtual machine using VirtualBox. That as such wasn’t the challenge. For example a pretty good description can be found at Windows Seven Forums.

Getting the guest additions installed was the problem. Quite a few sources suggested to use VirtualBox’s menu “Devices” – “Install Guest Additions…” However, what was offered as a solution didn’t work in my case. Note that I’m not a Linux or VirtualBox expert, so my lack of knowledge might have been the reason.

After quite some search I found a very good description on Sysprobs. Dinesh did a fantastic job with his blog post. Now I can resize the VM’s window any way I like and the VM’s screen adjusts properly. Almost seamless integration Nice!