Software Development

Opting out of Google Instant Browsing

I recently wrote about a new feature of Google Chrome called Instant Browsing. You can turn it on or off Basic tab of the  Options page in Chrome.

If you are a web site owner/administrator and are concerned about the impact it might have on your web server to have a deluge of requests going to your server that the end user is probably not really interested in, or having a number of requests going to your server that result in a 404 resource not found because the half formed URL in the “omnibox” does not actually resolve to a real page then you can opt out.

For folks running ASP.NET (both WebForms and MVC) I’ve created a simple HTTP Module that will opt your site out if it encounters requests from Chromes’ Instant Browsing.

You can download the Module here: Instant Browsing HTTP Module V1. And to activate it in your application you need to add the DLL file as a reference to your application and then add the bolded line to your web.config.

<configuration>
 <system.web>
  <httpModules>
   <add name="InstantBrowsingOptOut" type="InstantBrowsing.InstantBrowsingOptOut, InstantBrowsing"/>
  </httpModules>
 </system.web>
</configuration>

 

The Code

If you prefer, you can add the following source to your application and compile it yourself.

using System;
using System.Collections.Specialized;
using System.Web;

namespace InstantBrowsing
{
    public class InstantBrowsingOptOut : IHttpModule
    {
        public void Dispose()
        {
            // Nothing to dispose. Required by IHttpModule
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(BeginRequest);
        }

        void BeginRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;

            string headerValue = GetPurposeHeaderValue(application.Request);
            if (HeaderValueDoesntExist(headerValue))
                return;

            if (PreviewMode(headerValue))
                Issue403Forbidden(application.Response);
        }

        private bool PreviewMode(string value)
        {
            return value.ToLowerInvariant().Contains("preview");
        }

        private bool HeaderValueDoesntExist(string value)
        {
            return string.IsNullOrEmpty(value);
        }

        private string GetPurposeHeaderValue(HttpRequest request)
        {
            NameValueCollection headers = request.Headers;
            return headers["X-Purpose"];
        }

        private void Issue403Forbidden(HttpResponse response)
        {
            response.Clear();
            response.StatusCode = 403;
            response.End();
        }
    }
}

And to activate it in your application you need to add the bolded line to your web.config.

<configuration>
 <system.web>
  <httpModules>
   <add name="InstantBrowsingOptOut" type="InstantBrowsing.InstantBrowsingOptOut, InstantBrowsing"/>
  </httpModules>
 </system.web>
</configuration>

Note that the second “InstantBrowsing” in the type attribute is the assembly, so if you’ve put it in an assembly with a different name you’ll need to change the type attribute to reflect that.

Software Development

Parallel Tasks and the HttpContext

A few days ago I spotted a question on StackOverflow by someone trying to use a parallel loop in an ASP.NET application. It may have been an ASP.NET MVC application (I don’t recall) but the issue is the same.

This person had some code in a parallel task that was using the HttpContext object. I would be hesitant to use that object in the first instance as I don’t know how thread safe it is. I suspect that since it holds a lot of information about the state of a request/response that it would be quite dangerous to access an instance in many threads.

His main issue what that he was getting a null back from HttpContext.Current inside the parallel tasks.

ASP.NET is already multithreaded. It abstracts most of that away so that when you are writing against it you only really ever see the request you are currently dealing with. Many other requests are happening around you, but the framework does its best to shield you from that so that you can write code cleanly. It is also its downfall in some cases.

If you don’t realise what the framework is doing for you then you could very easily fall into a number of traps when you get to the edges of that abstraction. So, when someone uses HttpContext.Current inside parallel tasks not realising that there must already by multiple requests being handled, and therefore there must be multiple simultaneous HttpContext objects floating around masquerading as the Current context. It can become very difficult to track down bugs if you know what the constraints of what Current means in this… erm… context.

Ultimately, HttpContext.Current is only available on the thread that you started with in ASP.NET. If you create new threads then it is no longer available unless you explicitly set it yourself.

Software Development

Starting an ASP.NET MVC 3 application

In this post, I’m going to show the basics of starting an application with ASP.NET MVC 3. The demo application will be a simple calorie counter that takes in a number of values from the user that is then used to calculate the calorific intake. The original calculation can be found here here: How many calories should I be eating?

First, if you don’t have it already, you’ll need to download ASP.NET MVC 3. Remember to shut down Visual Studio 2010 for the installation. And if you don’t have it already, I’d also recommend downloading Visual Studio 2010 SP1 and upgrading to it.

Creating the project

In Visual Studio 2010, from the New Project Dialog, go to the Visual C#/Web templates section and select ASP.NET MVC 3 Web Application from the list in the middle. If you don’t see it, ensure that the drop down says .NET Framework 4.

For this project, the Name will be set to “HarrisBenedictCalculator” as that is the type of calculation that the application will be performing.

1 - Visual Studio 2010 New Project dialog

Once the appropriate details are entered the OK button takes you to a more specific dialog for ASP.NET MVC 3 projects.

Since I want to show everything rather than rely on existing templates where some of the ground work is already done, I’m selecting the Empty template. I’m also going to select the “Use HTML5 semantic markup” and set the view engine to Razor.

Because we are selecting the empty template, unit tests project creation is not available. We can do that later.

2 - New ASP.NET MVC 3 Project dialog

When the second dialog is OK’ed the project will be created. For all that I selected “Empty” Visual Studio has created an awful lot of files already.

What’s already in this “empty” project?

3 - What's in the empty ASP.NET MVC 3 project

The project contains a set of predefined folders, some of which are already populated with files.

  • Content: Contains static content files such as CSS, graphics and javascript files.
  • Scripts: Contains a profusion of javascript files.
  • Views:  This contains some files that act like Master files for the Razor engine, an error page Razor template and a web.config.

The top level folder also contains a global.asax file which defines a set of default routes and filters, a packages.config file which is used by NuGet and a set of web.config files.

If you attempt to run the application as is then it will compile, but you go directly to a error message that says “The resource cannot be found” because there are not controllers as yet, so the routing engine cannot find a route for the default resource.

4 - Resource Not Found

For the moment, we are going to have a simple static HTML page for the error. To that end the web.config will have the following added to it:

<customErrors mode="RemoteOnly" defaultRedirect="Error.htm" />

We will see error messages, but once deployed the end users won’t. If you want to learn more about error handling see this other post on custom error handling in ASP.NET MVC 3.

Creating the initial view and controller

First up we are going to create the model of the view, the ViewModel if you like. This will contains all the variables needed to generate the request and receive data back in the response.

public class HarrisBenedictViewModel
{
    public HarrisBenedictViewModel()
    {
        LifestyleRates = new List<KeyValuePair>();
    }

    public bool IsMale { get; set; }
    public double Weight { get; set; }
    public double Height { get; set; }
    public int Age { get; set; }
    public double BasalMetabolicRate { get; set; }
    public IList<KeyValuePair<string, int>> LifestyleRates { get; set; }
}

Incidentally, I always initialise lists so that I don’t have to do a null check. Normally most code will loop over the list, an empty list will loop the same number of times as a list that isn’t there.

Now, we are ready to create the controller. When you right click on the Controllers folder in the project structure, you get an “Controller…” option in the "Add” sub-menu.

5 - Add Controller

For this, I’m going to create a controller called Main and leave it empty. That gives us a class called MainController that is derived from Controller.

The controller is going to have two actions (this is a very simple application), one called CalculatorInput which will simply return a view for accepting the values, and the other called CalculatorResult which will display the results of the calculation. Both views use the view model we created earlier.

The CalculatorInput method looks like this:

public ActionResult CalculatorInput()
{
    HarrisBenedictViewModel viewModel = new HarrisBenedictViewModel();
    return View(viewModel);
}

The empty view model will be populated by the user. If we want to pre-populate values on the view then we can do so by setting the appropriate values in the view model.

ASP.NET MVC uses naming conventions to find things. So, by default, the view will be in a folder named after the controller (in this case “Main”) and the view will be named after the controller action (in this case “CalculatorInput”).

To create the View, create the appropriate folder in the Views folder (if it doesn’t already exist) and then right click the folder you’ve just created and select Add->View…

A dialog appears that looks like this:

6 - Add View

@model HarrisBenedictCalculator.Models.HarrisBenedictViewModel

@{
    ViewBag.Title = "Harris Benedict Calculator";
}

<h2>Harris Benedict Calculator</h2>

@using(Html.BeginForm("CalculatorResult", "Main", FormMethod.Post)){
    <fieldset>
        <legend>Information about you</legend>

        <div class="editor-label">Are you male?</div>
        <div class="editor-field">@Html.CheckBox("IsMale", Model.IsMale)</div>


        <div class="editor-label">Weight (in kilos)</div>
        <div class="editor-field"><input name="Weight" value="@Model.Weight" /></div>

        <div class="editor-label">Height (in centimetres)</div>
        <div class="editor-field"><input name="Height" value="@Model.Height" /></div>

        <div class="editor-label">Age (in years)</div>
        <div class="editor-field"><input name="Age" value="@Model.Age" /></div>

        <div class="submit"><input type="submit" value="Calculate!" /></div>
    </fieldset>
}

The view sets up the form for getting the user inputs.

The Html.BeginForm defines where the form will be sent to once it is complete and how it will be sent. In this case, the form will be sent by and HTTP POST to the CalculatorResult method on the MainController class. I’ll talk more about what that does in the next section.

The form consists of a number of inputs which, by convention, have the same name as properties on the Model. If the model is pre-populated then the initial values will be used to populate the values in each of the input elements.

The CheckBox is a special case. Because of the way HTML works, if the checkbox is unchecked then nothing is returned. The MVC application then does not know if the checkbox was not ticked, or if the checkbox simply didn’t exist at all. This may be an important distinction. Therefore an Html helper method is available that outputs the checkbox and an hidden field to go with it.

At this point we can run the application and get the initial view being displayed to us:

7 - Rendering first view

Submitting the answers

As I mentioned above, the Html.BeginForm helper method tells ASP.NET MVC what controller and method to return the result to when the user presses the submit button. So, we have to create a method to process that on the specified controller (in this case Main)

The Main.CalculatorResult method looks like this:

[HttpPost]
public ActionResult CalculatorResult(HarrisBenedictViewModel viewModel)
{
    double bmr = 0; // Base Metabolic Rate
    if (viewModel.IsMale)
    {
        bmr =
            66 +
            (13.7 * viewModel.Weight) +
            (5 * viewModel.Height) -
            (6.76 * viewModel.Age);
    }
    else
    {
        bmr =
            655 +
            (9.6 * viewModel.Weight) +
            (1.8 * viewModel.Height) -
            (4.7 * viewModel.Age);
    }

    viewModel.LifestyleRates.Clear();
    viewModel.LifestyleRates.Add(
        new KeyValuePair<string, int>("Sedentry", (int)(bmr * 1.2)));
    viewModel.LifestyleRates.Add(
        new KeyValuePair<string, int>("Lightly Active", (int)(bmr * 1.375)));
    viewModel.LifestyleRates.Add(
        new KeyValuePair<string, int>("Moderately Active", (int)(bmr * 1.55)));
    viewModel.LifestyleRates.Add(
        new KeyValuePair<string, int>("Very Active", (int)(bmr * 1.725)));
    viewModel.LifestyleRates.Add(
        new KeyValuePair<string, int>("Extra Active", (int)(bmr * 1.9)));

    return View(viewModel);
}

The above performs the calculation. The code may look a bit long, but the calculation is relatively simple. In a full business application this code would be separated out elsewhere.

The method is decorated with the HttpPost attribute which tells MVC that the method may only be called in response to an HTTP POST verb. The method also takes the view model class as a parameter. MVC will may the form inputs to the view model class as best it can. You can also specify a list of more primitive types (like int, string, double, etc.) that map to the input elements on the form.

The method itself performs the calculation then updates some items in the view model with the results of the calculation. The View is then returned with the view model.

The convention is that, unless specified otherwise, the view returned will be named after the controller method in a folder named after the controller class. So the view is in the ~ViewsMain folder in a file called CalculatorResult.cshtml

@model HarrisBenedictCalculator.Models.HarrisBenedictViewModel

@{
    ViewBag.Title = "Harris Benedict Calculator Result";
}

<h2>Result</h2>

<p>For a <em>@(Model.IsMale ? "man" : "woman")</em> aged <em>@Model.Age</em> years old,
weighing <em>@Model.Weight.ToString("0.0")</em> kg, and <em>@Model.Height</em> cm tall
should be taking in the following calories per day:
</p>

<div class="result">
@foreach (var lifestyle in Model.LifestyleRates)
{
    <div class="result-line">
        <span class="result-label">@lifestyle.Key</span>@lifestyle.Value Calories
    </div>
}
</div>

<p>@Html.ActionLink("Calculate another?", "CalculatorInput", "Main")</p>

This view extracts the data from the view model and renders it to the browser.

So, the answer I get looks like this:

8 - Final Result

The Razor syntax is quite easy to follow for the most part. Anything starting with an @ sign indicates the start of some C# code. The rendering engine is clever enough to detect HTML code and revert back when needed.

At the bottom of the page the HTML helper method ActionLink generates the URL to take the user back round to the start of the process again in case they want to calculate another set of calorie intakes.

Summary

In this post I’ve demonstrated some very basic initial steps to get going with ASP.NET MVC 3.

You can also download the sample code in order to have a play yourself.

Tip of the Day

Tip of the Day #23: Getting going with IIS Express

First, if you don’t have it already you need to download IIS Express (you can also use this link to get the full install, not via Microsoft’s web installer, if you are behind a proxy that is preventing the installation). And, I’d also recommend downloading Visual Studio 2010 SP1 and upgrading to it.

In your web project, open up the properties by right clicking the project and selecting properties, or pressing Alt+Enter while the project is selected.

You will then be presented with a view like this:

1 Initial Web Properties

By default, in the servers section of the Web tab the “Use Visual Studio Development Server” (aka Cassini) will be selected. Change this to “Use Local IIS Web Server”

2 Change to Local IIS Web Server

If you want to customise the settings you may do so. I tend to set a specific local port so that I know that all my applications don’t class with one another and that I can easily identify it later. My naming scheme to select 4 or 5 digits that are derived from the name of the project as if dialled into a telephone keypad. (Some people think that’s a bit weird but it makes it easy to avoid port clashes and to reverse the port into the project if you ever get lost.)

If necessary you can define the virtual directory in the Project URL and configure it by pressing “Create Virtual Directory”.

3 Setting a Virtual Directory

If you don’t “Create Virtual Directory” and you attempt to run the project, you’ll get a warning dialog that asks if you want to configure it. If you select yes, then Visual Studio will configure the virtual directory for you and start the application.

4 Not configuring a Virtual Directory

Finally, if you need to see what Sites IIS Express is running there is a tray icon you can right click on to see.

5 System Tray Icon for IIS Express

And if you click “Show all applications” you get to see all the sites that IIS Express is running. Clicking on a URL takes you to that site, anywhere else on the line will bring up details of the site in the lower part of the dialog.

6 IIS Express Running Applications

Clicking on the “Parent” name will take you to the instance of Visual Studio that the application is running from. This is a really nifty feature to get you back to the correct instance of Visual Studio if you are running many of them at once.

Clicking on the “Path” will open up Windows Explorer to show you the folder in which the site is located. And clicking “Config” will open the config file in Visual Studio.

Tip of the Day

Tip of the day #20: Don't spam your own email while developing apps that send email

When we develop applications, often there will be a requirement for that application to send out emails. While this is going on we usually end up with lots of emails being sent to our own email address for test purposes.

I got this fantastic tip from a colleague of mine, Andy Gibson, so here it is:

If you want to test the email an application sends out without spamming your inbox you can modify your web.config with the following code so that it will save the emails to your machine as flat files rather than sending them through the SMTP client. If you combine this with ASP.NET 4 build configurations (web.config.release, web.config.debug, etc,) then this becomes even niftier.

<system.net>
  <mailSettings>
    <smtp deliveryMethod="SpecifiedPickupDirectory">
      <specifiedPickupDirectory pickupDirectoryLocation="D:Email"/>
      <network host="localhost"/> <!-- Required for .NET 4.0! -->
    </smtp>
  </mailSettings>
</system.net>

There is an added benefit to this, .NET saves it as a .eml file so your default mail client (in my case Outlook 2007) will open it on double click, or if you need to see the raw email including headers, you can open it in notepad.

Software Development

Parser Error Message: Ambiguous match found

Symptom

On deploying a newly precompiled web site, the error message as displayed by ASP.NET is as follows:

Server Error in ‘/’ Application.


Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Ambiguous match found.

Source Error:

Line 1:  <%@ control language="C#" autoeventwireup="true" enableviewstate="false" inherits="WebSiteControls_Offers_TypeFilter, App_Web_typefilter.ascx.bd9a439f" %>

Line 2:
Line 3: <%--

Source File: /WebSiteControls/Offers/TypeFilter.ascx    Line: 1


Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

System Information

This may or may not be relevant, but it reflects my set up at the time I discovered this issue.

  • Web Site project
  • Visual Studio 2008
  • .NET 3.5
  • IIS 6.0

 

Reason

The reason for this is that a control, in this case a Repeater, in the User Control had a similar name as a field on the code behind. The only difference between the two the case. One was called “offerTypes” (in the code behind, an IEnumerable containing entities from the business layer), the other “OfferTypes” (a ASP.NET Repeater control).

Solution

Rename one or other so that the names differ by more that case alone. In my case, I renamed the field referring to the entities to offerTypeInformation.

Software Development

32bit ASP.NET App on 64bit Windows 7

Recently we all moved to Windows 7 (64bit) on our development machines. With that, we moved also to IIS7.
So that meant that development copies of websites that we are working on have to
be moved to IIS7. This should be simple. Right?

When I attempted to get the first site up and running I got hit by the error “Could not load file or assembly ‘System.Web’ or one of its dependencies. An attempt was made to load a program with an incorrect format.“.
(The full error message is below.)
After searching around I eventually managed to piece together that the reason
was that IIS was trying to run in 64 bit mode and this application was compiled
as a 32 bit application. Okay…. So how do you fix this?

It turns out the fix is rather easy. In the IIS Manager, open up the list of
Application Pools and select the pool for your application. Right-click and
select “Advanced Settings”. From that point you get this dialog:

32-bit application

Just set “Enable 32-bit applications” to “True”, then Okay the dialog. You then
have to recycle the Application Pool for the change to take effect.

 

 

Server Error in ‘/’ Application.


Could not load file or assembly ‘System.Web’ or one of its dependencies. An attempt was made to load a program with an incorrect format.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.BadImageFormatException: Could not load file or assembly ‘System.Web’ or one of its dependencies. An attempt was made to load a program with an incorrect format.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Assembly Load Trace: The following information can be helpful to determine why the assembly ‘System.Web’ could not be loaded.


WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLMSoftwareMicrosoftFusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLMSoftwareMicrosoftFusion!EnableLog].

Stack Trace:


[BadImageFormatException: Could not load file or assembly 'System.Web' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0
   System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +416
   System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +166
   System.Reflection.Assembly.Load(String assemblyString) +35
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +190

[ConfigurationErrorsException: Could not load file or assembly 'System.Web' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +11207304
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +388
   System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +232
   System.Web.Configuration.AssemblyInfo.get_AssemblyInternal() +48
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +210
   System.Web.Compilation.BuildProvidersCompiler..ctor(VirtualPath configPath, Boolean supportLocalization, String outputAssemblyName) +76
   System.Web.Compilation.CodeDirectoryCompiler.GetCodeDirectoryAssembly(VirtualPath virtualDir, CodeDirectoryType dirType, String assemblyName, StringSet excludedSubdirectories, Boolean isDirectoryAllowed) +11196482
   System.Web.Compilation.BuildManager.CompileCodeDirectory(VirtualPath virtualDir, CodeDirectoryType dirType, String assemblyName, StringSet excludedSubdirectories) +185
   System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +551

[HttpException (0x80004005): Could not load file or assembly 'System.Web' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Web.Compilation.BuildManager.ReportTopLevelCompilationException() +76
   System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +1012
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters) +1025

[HttpException (0x80004005): Could not load file or assembly 'System.Web' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +11301302
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +88
   System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +11174792


Version Information: Microsoft .NET Framework Version:2.0.50727.4927; ASP.NET Version:2.0.50727.4927