Diagnosing ASP.NET page compilation errors

Page compilation errors are a common cause of ‘yellow screens of death’ (YSOD) encountered by ASP.NET developers. Like most developers, I have a tendency to ignore the details of error messages, preferring some quick trial & error and finger crossing, instead of proper debugging. But today I decided to pay attention to an error so I could put an issue to rest once and for all.

Are you missing an assembly reference?

I’m going to tackle some of the most common page compilation errors, which relate to missing references and/or incorrect using statements. The screenshot below shows a typical 'CS0234' error:

The compiler error message reads:

The type or namespace name ‘Helpers’ does not exist in the namespace ‘System.Web’ (are you missing an assembly reference?).

Page compilation errors

To understand what is going on it’s useful to have a quick reminder of how ASP.NET works under the hood.

Every page or view in an ASP.NET site ultimately gets converted into executable code. By default this happens at runtime.

It’s a two-step process: Using a Razor view as an example, first the Razor view engine uses code generation to translate the .cshtml file into a .cs file. Then ASP.NET compiles that .cs source into an executable binary.

It’s errors occuring during this second step which reveal themselves as YSODs like the one shown above. YSODs do actually include useful debug information…

YSOD examined

Clicking ‘Show Complete Compilation Source’ shows me the full C# source file which has been generated by the view engine for the requested page. Here you can clearly see all the using statements generated by the view engine code generator.

Clicking on ‘Show Detailed Compiler Output’ shows you exactly how csc.exe (the C# compiler) was invoked by ASP.NET in order to compile the page’s generated C# code. Importantly the /R: parameters are the referenced assemblies.

Every C# developer knows that in order to succesfully build an assembly from a module of code you need to make sure all the types you use are made available to the compiler via references.

With normal C# projects you add your own references and write your own using statements. But what determines the references and using statements when code is generate for pages and compiled by ASP.NET?

References

The references used by ASP.NET during page compilation are specified entirely in configuration files using the assemblies element for compilation.

“But I haven’t specified an assemblies element!”, I hear you say.

The reason you still get some by default is that the root-level web.config file (typically found in
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config)
, that comes distributed with .NET, contains something akin to the following:

    <compilation>
        <assemblies>
            <remove assembly="Microsoft.VisualStudio.Web.PageInspector.Loader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="Microsoft.VisualStudio.Web.PageInspector.Loader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="mscorlib" />
            <add assembly="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add assembly="System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.ServiceModel.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.WorkflowServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add assembly="System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.Web.DynamicData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add assembly="*" />
            ...
        </assemblies>
    </compilation>

Unless you make configuration changes this list will match the referenced assemblies you observe ‘Show Detailed Compiler Output’ section of the YSOD. Excluding one important exception…

Note that the final entry is special. It uses a star ‘*’ instead of providing an assembly name. The remarks on MSDN explain it’s purpose:

Optionally, you can specify the asterisk (*) wildcard character to add every assembly within the private assembly cache for the application, which is located either in the \bin subdirectory of an application or in the.NET Framework installation directory (%systemroot%\Microsoft.NET\Framework\version).

The implications of this are that you can easily ensure additional assemblies get referenced during page compilation by placing them in your private assembly cache. And you do that simply by changing the “Copy Local” property of an assembly to true (correlated with the Private reference attribute within an MSBUILD file).

But what if you don’t want to add the assembly to your private assembly cache? In that case you just explicity add it to your application-level web.config using the same assemblies.add element shown above.

Namespaces

Where do the default using statements come from for the generated code? Well this actually depends on the view engine you are using. The default view engine (Web Forms) takes its defaults from the root-level web.config under the namespaces element:

    <pages>
        <namespaces>
            <add namespace="System" />
            <add namespace="System.Collections" />
            <add namespace="System.Collections.Generic" />
            <add namespace="System.Collections.Specialized" />
            <add namespace="System.ComponentModel.DataAnnotations" />
            <add namespace="System.Configuration" />
            <add namespace="System.Linq" />
            <add namespace="System.Text" />
            <add namespace="System.Text.RegularExpressions" />
            <add namespace="System.Web" />
            <add namespace="System.Web.Caching" />
            <add namespace="System.Web.DynamicData" />
            <add namespace="System.Web.SessionState" />
            <add namespace="System.Web.Security" />
            <add namespace="System.Web.Profile" />
            <add namespace="System.Web.UI" />
            <add namespace="System.Web.UI.WebControls" />
            <add namespace="System.Web.UI.WebControls.WebParts" />
            <add namespace="System.Web.UI.HtmlControls" />
            <add namespace="System.Xml.Linq" />
        </namespaces>
        ...
    </page>

Namespaces with Razor

If you are using Razor the default namespaces are hardcoded!

You can easily add to the list of default namespaces by adding a razor-specific namespaces element to your web.config (sample shown below), but you cannot easily remove default namespaces. Even attempting to use <clear/> does not work. If you really need to get rid of default namespaces you will have to do it in code.

<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="System.Web.Mvc.WebViewPage">
   <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Optimization"/>
    <add namespace="System.Web.Routing" />
   </namespaces>
  </pages>
</system.web.webPages.razor>

A note about Web.configs

Bare in mind that projects often have a web.config specifically for the Views folder (e.g. MVC) and the page compiler will pay attention to the config heirarchy. Typically you will want to makes changes specific to your Views web.config.

Conclusion

Using the information in this blog post you should be able to understand and resolve any page compilation errors relating to missing references and/or incorrect using statements. Good luck!

The Economics of Microsoft Surface

This is a post I wrote August 2009 but never got around to publishing. Whilst spring cleaning my drafts, I re-read it and decided it wasn’t that bad, so here it is. I wonder if the issues are still the same in 2011….

——————–

It’s almost a year ago to the month that Amnesia Razorfish smuggled the first Microsoft Surface tables into Australia with the help of parent company Razorfish, much to the excitement of local geeks. There was also a fair bit of uproar from surprised parties who hadn’t expected to be usurped in such spectacular fashion.

I was hired by Amnesia shortly before Surface arrived, partly on speculation that they would soon need a Surface developer. I had experience with the technologies it uses, and a great interest in the product, so was really excited to get such an opportunity. It was also a bit of a gamble on my part, as it was by no means guaranteed at the time they would even be getting a table, let alone any paying clients.

The first few weeks, maybe months, there was a great buzz and curiosity from clients and media about this new device. The phones were ringing off the hook and there were regular coffee table tours.

Despite this, and the amazing stock of talent Amnesia had at its disposal, I think it’s safe to say that during my year there, they never needed more than this one, solitary, Surface developer.

How can that be? “Surely it would be as easy as selling antifreeze to Eskimos!”, I hear you mutter…

Here’s why: In many scenarios, the economics of Surface development simply don’t add up.

For background, let’s put a few ballpark figures on the coffee table:

- Cost of a MS Surface table: $10k
- Cost of  development/design time: $200/hour

Let’s tackle the most obvious thing first: This Is Software Development.

It’s been many years since the Adobe Flash experiences that draw crowds on the web have been built entirely with a visual tool. Most are chock full of ActionScript. In fact, dare I say, they probably contain more programming hours than design hours.

Suffice to say there are very few digital experiences of the richness that people expect these days, that can be built without significant software development capabilities, and that goes for Microsoft Surface too.

Microsoft Surface carries the extra burden of not only having slightly less mature tools than industry mainstay Adobe Flash, but more importantly having a much smaller experience pool, particularly in the crucial “devigner” niche. And as with any new technology, the early days often mean higher costs and higher risks.

So, creating a quality Surface experience means building software. But what do you get for your money? Well it could easily cost you $6000 per man week, and even after many weeks development the chances are you won’t get that award winning experience you were hoping for. My guess is that most commercial Surface applications you see being touted cost in the region of $300,000. Definitely in the hundreds of thousands. Let your imagination go wild and you could easily spend half a million.

The next most obvious thing is: Penetration.

Unlike building a user experience for the web, prospective clients will be footing the bill for each and every device that will end up in front of users. If you are going to pay a hefty sum for bespoke software development you sure as hell want to leverage that investment by deploying it to the maximum number of locations.

You can keep the costs low by only having a tiny number of tables (and maybe even spin that to your boss by claiming the experience would then be truly unique/exclusive!), but ultimately you are talking about investing in a piece of custom-written software that will only ever be seen by a tiny audience. Yes, that might be tenable for a small number of luxury brands, but for the majority who actually need to justify there expenditure? I think not.

So, to get “good value” from your investment in a Surface experience you need to also purchase a reasonably large number of tables. I would say at least in the tens if not hundreds (e.g. retail locations). There’s $500,000 right there.

Lastly: Cost/benefit.

At the end of the day, clients have to estimate how much a Surface experience is going to be worth to them. It’s obvious that many applications of Surface can be categorized as marketing in some sense; whether its experiential branding, attractive gimmick, or 9 o’clock news hype.

I can only imagine it’s very hard to estimate the financial benefits such a Surface experience will bring, because in the majority of cases it’s going to be an indirect effect at best. And such financial benefits are almost certainly going to be impossible to determine a-priori.

Which is also the case if Surface is used as Point-of-Sale platform – it’s all pretty much undiscovered country. With such little data on natural user interfaces, not to mention Surface specifically, it’s very hard at this stage to make confident guesses about how conversion rates or stickiness can be improved. The only way to find out for sure is by putting down the cash. And that’s a risk many firms can’t or wont take.

Running uTorrent as a Service on Windows Home Server 2011

Step 1: Download and Install uTorrent

  • Download uTorrent 2.2.1 (390 KB)
  • Install uTorrent as normal, by opening the downloaded EXE
  • It should install itself into C:\Program Files (x86)\uTorrent

Step 2: Configure uTorrent Web UI

  • Run uTorrent as normal (e.g. Start Menu)
  • Go to Options menu and select Preferences
  • Go to the Directories folder and set the folders where you want your torrents to be stored
    • Make a note of these directories, as you will need them in step 8

image

  • Go to the Web UI section and make three changes
    • Tick “Enable Web UI”
    • Set a username and password
    • Tick “Alternative Listening Port”; leave the number as 8080
      • Note: This sub-step is not strictly necessary but gives you a higher chance of things working first time

image

Step 3: Test uTorrent Web UI

  • Using a different computer on the local network ensure you can get to the uTorrent Web UI
  • The web address should of the form http://homeserver:8080/gui/
  • Note: You must replace homeserver in the above URL with the name of the computer where you install uTorrent.
  • The browser should ask for a username and password. Use the values provided in Step 2
  • You should see the uTorrent Web UI.
  • If you do not see the uTorrent Web UI do not proceed any further. You have a networking problem. Seek help.
  • At this stage you have a working uTorrent Web UI but it is NOT running as a service. This means that torrents can still only be downloaded when a user is logged on and running uTorrent. Continue with the following steps to run it as a service…
  • Important: Now Close down uTorrent by choosing File->Exit.

Step 4: Copy the uTorrent settings file

  • Copy the settings.dat file from C:\Users\<User>\AppData\Roaming\uTorrent to C:\Program Files (x86)\uTorrent

Note: Depending on your username you will need to substitute <User> in the above path

Step 5: Download and Install SRVANY.exe

  • Download Windows Server 2003 Resource Kit Tools (11.8 MB).
  • Install the entire tool suite as normal, by opening the downloaded exe.
  • By default srvany.exe will be installed to C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe

Step 6: Create Windows Service for uTorrent

  • Open an administrative command prompt by following these steps:
    • Navigate to Start Menu –> Accessories –> Command Prompt
    • Right click and select “Run as Administrator”
  • At the command prompt enter the following:
      sc create uTorrent binPath= "C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe" obj= "NT AUTHORITY\LocalService" start= auto
  • Note: Do not remove the spaces between the equals sign and parameters. This is an oddity of sc command and is required
  • If this works you should see something like the screenshot below:

image

If you get the “Access is denied” error then you are not running as administrator.

Step 7: Configure the SRVANY.EXE service

  • If you want to perform this step manually you will need to know about regedit. Here are the steps:
  • Run regedit
    • Navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\uTorrent\Parameters
    • Create the Parameters key if it does not exist
    • Under the Parameters Key, add a new String Value named Application
    • Set the value to be C:\Program Files (x86)\uTorrent\uTorrent.exe
    • If you have done everything correctly it should look like the screenshot below:

image

Step 8: Modify permissions on your downloads directory

By default Windows will not allow your uTorrent service to read or write to the disk. In order for uTorrent to work you need to add read & write permissions on the directory or directories you specified in Step 2.

  • Navigate to the directory
  • View the directory properties
  • Select the Security tab
  • Click the Edit… button
  • Click the Add… button
  • Enter LOCAL SERVICE (including the space) then click OK
  • Ensure “Allow Modify” is ticked, and OK everything
  • It should look something like the screeshot below:

image

Step 9: Ensure the uTorrent service is running

  • Load the services control panel (Start->Run->Services.msc)
  • Locate the service named uTorrent and verify the Status column says “Started”.
  • If it does not say “Started”, then click the Start Service button

Finally…

  • Log off your Windows session and repeat Step 3 to verify that the web UI is still working and you can download torrents successfully.

General trouble shooting:

  • Double check that uTorrent.exe is not running on your desktop.
    • Note: By default clicking the close button in top right of the uTorrent window will not actually exit the application
  • Double check that uTorrent.exe is running as a service.
    • In task manager, “Show processes from all users”, ensure you can see uTorrent.exe running with LOCAL SERVICE displaying in the User Name column
  • Please leave a comment if you have any issues with this guide

Using d:DesignSource for design-time DataGrid grouping with sample data

I recently had the need to use the row grouping feature of the WPF DataGrid.

As you know, in order to design with Blend effectively, you really need to have data displayed at design-time. It’s fairly straight forward to use combinations of d:DesignContext and d:DesignData to achieve that goal. In the case of DataGrid, you can bind ItemsSource directly to a collection in your design-time model.

The question is: How do you use design-time data and grouping at the same time?

The reason the solution is not obvious is because the DataGrid’s grouping feature relies on having a PropertyGroupDescription configured for the CollectionView that the DataGrid’s ItemSource is bound to. If you bind ItemsSource directly to a collection, you do not have access to the CollectionView at design-time.

Just to confuse things, if you Google for DataGrid grouping you will find a plethora of out-of-date articles suggesting you can configure the grouping by using the DataGrid.GroupingDescriptions in Xaml, which you can’t (it only worked on older/beta versions). On the other hand there are several articles which describe how to configure grouping programmatically. The problem with the programmatic approach is it does not run at design-time, and is in conflict with the design-time attributes. I want to use the well supported design-time sample data tool chain, and keep designers free from having to write code.

While Googling for a solution I came across the new design-time attribute documentation (note: it applies equally well to WPF in spite of the Silverlight bias!), which included an attribute I had never seen before: d:DesignSource. According to MSDN d:DesignSource

Specifies a design-time data source for a CollectionViewSource. This makes the designer aware of the shape of your types. This enables you to use the data binding builder to create bindings.

<CollectionViewSource x:Key="CustomerViewSource"
  d:DesignSource="{d:DesignInstance
  local:Customer, CreateList=True}" /> 

The description was intriguing but after looking at the code sample it seemed to be mistakenly underselling the capability. The sample code shows that it does more than make the “designer aware of the shape of your types” – it’s actually allowing sample data to be injected into a CollectionViewSource using the well know d:DesignInstance … and presumably d:DesignData too.

As it turns out, the only way to specify the DataGrid grouping in Xaml is to use the CollectionViewSource. I figured by combining CollectionViewSource and d:DesignSource I could achieve my goals.

After some experimentation I got it working exactly as I hoped it would. Here is the code:

    <Grid>

        <Grid.Resources>
            <CollectionViewSource x:Key="groupedCollectionView"
                                  d:DesignSource="{d:DesignData Source=./SampleData/BookingRowCollectionSampleData.xaml }" 
                                  Source="{Binding RuntimeBookingRowCollection}">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="PropertyToGroupBy"/>
                </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
        </Grid.Resources>

        <DataGrid AutoGenerateColumns="True"
                  ItemsSource="{Binding Source={StaticResource groupedCollectionView}}" >
            <DataGrid.GroupStyle>
                <x:Static Member="GroupStyle.Default"/>
            </DataGrid.GroupStyle>
        </DataGrid>

    </Grid>

There are a couple of things to point out:

  • I used “Create sample data from class…” in Blend to create my BookingRowCollectionSampleData.xaml. The class which I generate from was defined below. I found I had to create this specialized collection in order to satisfy the d:DesignSource. Conversely my attempt at creating sample data based off my view model which in turn had a collection property was a dead end – d:DesignSource needs to be given a raw collection; there is no way to dereference the collection property within a view model.
        public class BookingRowCollection : List<BookingRow>
        {
        }
  • I wanted to make sure that I didn’t need multiple paths in my code behind to handle the differences between design-time and run-time, specifically with binding and MVVM. In this case the design-time “switch” is handled purely within the CollectionViewSource, where the Source is set differently depending on what mode we are in. Note that even though the CollectionViewSource is a resource, it will still correctly bind to our RuntimeBookingRowCollection.

Declaring the CollectionViewSource proxy within your Xaml will not suit all MVVM projects as sometimes you might want to define a CollectionView within your view model, but it worked in my case because the grouping was never going to change. For this project the grouping can be considered purely part of presentation so I am happy to declare it in Xaml, and as a bonus it works beautifully with design-time sample data!

I think this solution will work for Silverlight too, but I have not tested it yet.

d:DesignInstance in Depth

Update: I have contacted WPF “User education” team at Microsoft about the lack of documentation. The response was: “I’ve looked into this and there was some confusion around whether or not these were publicly exposed. Thanks for letting us know about this error. We are now working on getting these documented.”

There is currently no formal documentation for the DesignInstanceExtension (which you will see in XAML as d:DesignInstance).

The best two articles are by Unni and Karl but there are a few things they don’t cover.

This is what I have worked out by trial and error:

According to Intellisense DesignInstance has got 3 parameters: Type, IsDesignTimeCreatable and CreateList.

Type This is the type of the object for which the design-time data binding “shape” will be derived
IsDesignTimeCreatable (Defaults to false)

If this is true then a new instance of your type will be created at designtime. If you want data to actually appear in the designer you will need to make sure suitable properties are being set in your constructor. The best way to do this is to create a derived type of your model type, where you are free to set properties to default values without polluting your real types. If your model type implements an interface even better – you can create a design time model that way.

If this is false VS/Blend will use reflection to create a dummy type with the same shape as your specified Type. The problem with this is the dummy type will have no instance data in it thus you will not see anything in the designer. When this is false you are really only getting the benefit of assisted type-aware data binding. (If you need lots of sample data you are better off using the DesignData extension)

CreateList (Defaults to false)

If true the DesignInstance will actually be created as a list of the specified Type. From what I can tell this is the only way to specify your design instance as a collection (I briefly tried to pass a generic list as the Type parameter but could not get it to work, hence why I expect this parameter exists).

Note that DesignInstance and DesignData are mutually exclusive mark-up extensions. You cannot set both DesignInstance and DesignData extensions when setting your DataContext.

In general the main use of DesignInstance extension is to allow you to use the data binding tools within Blend and Visual Studio. It can give you some sample data if you set properties in your constructor.

To be able to design effectively you really need plentiful and varied sample data. For the best design experience you should consider using the DesignData extension – the drawbacks being the slightly increased upfront cost of creating a XAML file containing your sample data, and the increased complexity of refactoring the XAML whenever your classes change.