find a location for property in a new city

Thursday, 25 August 2011

Azure Table Storage One of the request inputs is out of range

While trying to insert an entity into a Windows Azure Table Storage table I got the rather ambiguous "An error occurred while processing this request." error message from a System.Data.Services.Client.DataServiceRequestException. The inner exception help a message of "One of the request inputs is out of range."

The error message wasn't terribly helpful but I finally found what was causing the problem. It was because of my Row Key. The RowKey property that comes from the TableServiceEntity abstract class has specific requirements which I was unintentionally breaching.

My RowKey was calculated from another property of my Entity. In this particular instance this meant the string included a '/' symbol. This is not allowed by Table Storage for RowKeys.

Solution

When calculating the RowKey from the other property I am now removing special characters that the Azure Storage does not allow. This includes forward slash (/) character, backslash (\) character, number sign (#) character, question mark (?) character.

Old code:
private string productName;
public string ProductName
{
   get { return productName; }
   //setting the RowKey and productName to the same value in one go
   set { RowKey = productName = value; }
}
New code:
private string productName;
public string ProductName
{
   get { return productName; }
   set { RowKey = Regex.Replace(productName = value, @"[\ /?#]", ""); }
}
I actually already knew about this from when I read Apress's Windows Azure Platform but the confusing error message threw me off on a tangent and hoped it hadn't done the same to anyone else.

Follow britishdev on Twitter

Saturday, 13 August 2011

ASP.NET MVC Checkbox has a hidden input too

I noticed strange behaviour whilst coding and ASP.NET MVC CheckBox Html Helper. I noticed that the field which was in part of a GET form was creating the query string with the same field in it twice. When the box was checked one parameter was true and the other was false.

Say I have a boolean field, MyField, that I am creating a checkbox for. I would write this: @Html.CheckBox("MyField"). You would expect this to output a single check box but if you actually look at the HTML that is generated you will notice that is also creates a hidden field.



I found out the the reason for this is written within the ASP.NET MVC source code:
if (inputType == InputType.CheckBox) {
    // Render an additional  for checkboxes. This
    // addresses scenarios where unchecked checkboxes are not sent in the request.
    // Sending a hidden input makes it possible to know that the checkbox was present
    // on the page when the request was submitted.
    StringBuilder inputItemBuilder = new StringBuilder();
    inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));

    TagBuilder hiddenInput = new TagBuilder("input");
    hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
    hiddenInput.MergeAttribute("name", name);
    hiddenInput.MergeAttribute("value", "false");
    inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing));
    return inputItemBuilder.ToString();
}

I appreciate the reasoning behind this but in my scenario MyField is part of a ViewModel that is being sent with the form and of course boolean values are False by default so this is wasted on my scenario.

Another reason I do not like this is because I am using the GET method on my form the user will see this oddity in the querystring. Worse still, they be a developer and judge my code as rubbish not knowing it is the doing of ASP.NET MVC. I can't have that! ;)

Solution

Simple solution really. Write the HTML you want in HTML, forget about the HtmlHelper:
<input type="checkbox" name="MyField" value="true" id="MyField"
@Html.Raw((Model.MyField) ? "checked=\"checked\"" : "") />

Remember the value="true" because the default value to be sent is "on" if it is checked, which obviously can't be parsed to a Boolean.

Obviously, this doesn't look that clean but I will continue to do this on forms that use the GET method.

Follow britishdev on Twitter

Thursday, 21 July 2011

RazorEngine TemplateCompilationException Unable to compile template

When using the RazorEngine for the first time for email templating I ran into a "TemplateCompilationException" with the error message "Unable to compile template. Check Errors list for details." Looking further into the error I found further details "error CS0103: The name 'model' does not exist in the current context."

It turns out that your Razor views are not to be writen in exactly the same way as when running within an ASP.NET web context. I suppose I should have guessed this from the way I was used to declaring the model for the WebFormsViewEngine.

Solution

Instead of using the @model declaration at the the top I should have been using @inherits. An example:

Regular Razor view for web:
@model Models.ContactDetailsViewModel
<!DOCTYPE html>
<html>
 <body>
  <div>
   <p>Hello @Model.FullName,</p>
   <p>We will call you at @Model.CallTime on @Model.PhoneNumber</p>
   <p>Thanks</p>
  </div>
 </body>
</html>

Razor view for use as a template:
@inherits RazorEngine.Templating.TemplateBase<Models.ContactDetailsViewModel>
<!DOCTYPE html>
<html>
 <body>
  <div>
   <p>Hello @Model.FullName,</p>
   <p>We will call you at @Model.CallTime on @Model.PhoneNumber</p>
   <p>Thanks</p>
  </div>
 </body>
</html>

Hope this helps and well done for using such an awesome feature of the RazorEngine!

Follow britishdev on Twitter

Wednesday, 6 July 2011

Custom Model Binder for binding drop downs into a DateTime in MVC

I have a Nullable DateTime Property in my Model I want to bind painlessly with three drop down select boxes I have for Day Month and Year respectively.

First thing to do is to make a new shiny custom model binder. I have done mine by inheriting from DefaultModelBinder (which you will need to include System.Web.Mvc to access).
using System;
using System.ComponentModel;
using System.Web.Mvc;

namespace Infrastructure.OFP.ModelBinders
{
    public class MyUserModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext,
            ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.PropertyType == typeof(DateTime?)
                && propertyDescriptor.Name == "DateOfBirth")
            {
                var request = controllerContext.HttpContext.Request;
                var prefix = propertyDescriptor.Name;
    
//remember I am a Brit so this will give me dd/mm/yyyy format - this may not work for you :)
//also since this is a binder specific for one particular form the hardcoding of
//    MyUser.DateOfBirth is suitable
//AND... I am using Value because I am using a Nullable
                var date = string.Format("{0}/{1}/{2}",
                           request["MyUser.DateOfBirth.Value.Day"],
                           request["MyUser.DateOfBirth.Value.Month"],
                           request["MyUser.DateOfBirth.Value.Year"]);

                DateTime dateOfBirth;
                if (DateTime.TryParse(date, out dateOfBirth))
                {
                    SetProperty(controllerContext, bindingContext,
                                propertyDescriptor, dateOfBirth);
                    return;
                }
                else
                {
                    bindingContext.ModelState.AddModelError("DateOfBirth",
                           "Date was not recognised");
                    return;
                }
            }
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }
}

This new Model Binder will need to be registered to be used when binding a MyUser object. You do this in the Global.asax Application_Start() like so:
protected void Application_Start()
{
    ModelBinders.Binders[typeof(MyUser)] = new MyUserModelBinder();
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

For reference the drop downs I created to populate the nullable DateTime property of DateOfBirth is as follows:
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Day,
                      new SelectList(Model.Days, "Key", "Value"))
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Month,
                      new SelectList(Model.Months, "Key", "Value"))
@Html.DropDownListFor(m => m.MyUser.DateOfBirth.Value.Year,
                      new SelectList(Model.Years, "Key", "Value"))
@Html.ValidationMessageFor(m => m.MyUser.DateOfBirth)

This works as I expected it to. It validates the property as expected using the DataAnnotations that I have defined for it.

Follow britishdev on Twitter

Monday, 20 June 2011

Azure SDK enable IIS 7.0 with ASP.NET support

Trying to install Windows Azure SDK and Windows Azure Tools for Microsoft Visual Studio on Windows 7 running IIS 7.5 throws an error that states, "... enable internet information services 7.0 with asp.net support ..."

I do not have IIS 7.0 - I am using IIS 7.5. Surely the Windows Azure SDK and Windows Azure Tools are compatible with 7.5 though? Well, they are! So why do I need IIS 7.0?

Well, you don't. The clue is in the message "with ASP.NET support." I needed to edit my IIS in control panel to do this.

Enabling IIS 7+ with ASP.NET

Go to Control Panel > Programs > Turn Windows features on or off.

Then find Internet Information Services. Expand it then go to World Wide Web Services, then Application Development Features and then check ASP.NET. This will check a few other dependent features and after a short wait should be able to run the installation for Windows Azure SDK again.

Follow britishdev on Twitter

Tuesday, 14 June 2011

Two bugs in ASP.NET MVC 3 and a workaround for both

So I spent an hour today arsing about with a couple of ASP.NET MVC 3 bugs. One was a Routing issue that caused it to act differently to MVC 2. The second I found was a FormsAuthentication issue that insisting on sending me to /Account/Login.

Amazing how this crept in really given that it was community tested to death with such a massive ASP.NET MVC following so it is a wonder they weren't weeded out and fixed before RTM. Oh well, don't pretend you don't like a challenge.

Routing doesn't work the same in MVC3 from MVC2

Here is an example of this bug in action

My current route is:
routes.MapRoute("groups", "groups/{groupSlug}/{action}/{id}/{urlTitle}",
                new
                {
                    controller = "groups",
                    groupSlug = UrlParameter.Optional,
                    action = "index",
                    id = UrlParameter.Optional,
                    urlTitle = UrlParameter.Optional
                });

I am using this route in an ActionLink like this (well obviously I've changed it for clarity - but I was totally using T4MVC!):
<%: Html.ActionLink(item.Group.Title, "index", new { groupSlug = "something" })%>

In MVC2 it that produces the URL /groups/something. But in MVC3 it produces the URL /groups?groupSlug=something.

MVC3 Routing UrlParameter.Optional workaround

I struggled with this for a good few hours, many a time exclaiming that, "my route IS there! What the hell is wrong with you?!" I took it apart piece by piece to discover that MVC3 no longer likes multiple UrlParameter.Optional's in a row.

A rather ugly workaround for this is to put in a new route for each of these problem routes that have no reference to the following UrlParameter.Optional's. So AFTER the above route you I need to put in another route like this:
//workaround for MVC3 bug
routes.MapRoute("groupsFix", "groups/{groupSlug}/{action}",
                new
                {
                    controller = "groups",
                    groupSlug = UrlParameter.Optional,
                    action = "index"
                });

Since writing this I have discovered it is a known issue and Phil Haack has a much better explanation than me! Obviously.

FormsAuthentication.LoginUrl is always /Account/Login

I have setup my forms authentication in web.config to register the LoginUrl as "~/login" but since upgrading to MVC3 it has decided to ignore that and now FormsAuthentication.LoginUrl returns "~/Account/LogIn" regardless of what I set in web.config.

There is a workaround for this though. You simply need to add this line to your AppSettings:

and everything works how it used to. Strangeness indeed.

Conclusion

Live with it. Fix up your errors as explained above and continue staying up to speed with ASP.NET MVC. It's worth it if even just for Razor alone.

Follow britishdev on Twitter

Monday, 13 June 2011

Adding MVC dependencies to a project for deployment

Deployment of new web applications has been a bit annoying since the birth of ASP.NET MVC. Production servers with .NET 4 or 3.5 installed will still be missing key assemblies such as System.Web.Mvc.dll. This will cause errors such as "Could not load file or assembly 'System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies" and "Could not load file or assembly 'System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies." when your project is deployed to production.

It is confusing for two reasons: Why does it work on your development machine? Well, when you install all the tools required to make MVC application you get all the necessary assemblies with it. Which assemblies are your production servers missing? Well there were 3 in ASP.NET 1, 1 in ASP.NET MVC 2 but now with ASP.NET MVC 3 + Razor there are loads. I've found out which ones I actually need before but it is still confusing.

With Visual Studio 2010 SP1 there is a new feature that does all the hard work for you. You can right click your ASP.NET MVC web application project and select 'Add Deployable Dependencies...':

Then you select the type of features you are using so Visual Studio can decide which references are needed:


It will then create a _bin_deployableAssemblies directory for you with all the assemblies included:


Now if you publish using Web Deploy it will include those files as expected and your deployed solution will be happy once more.

Important note:
If you are not using the 'Web Deploy' as your publish method though - this will NOT work. You will need to reference the assemblies and make them bin deployable yourself.

Follow britishdev on Twitter

Wednesday, 8 June 2011

Why WatiN tests are slow with the IE browser

I found opening and closing of the IE browser in WatiN a massive overhead when I was having to dispose of IE at the end of each of NUnit's tests. I found a way though to speed the whole process up.

I really wanted to open one instance of IE in my NUnit TestFixture and use that for the duration. This would save the huge huge cost of opening and disposing of WatiN's IE browser. As a sidenote it was a lot quicker in FireFox but since most users use IE best stick to that!

There were a couple of hurdles to jump to enable me to use just one IE browser for all my NUnit TestFixture's WatiN tests though.

1. Initialise and Dispose of IE at either end of the TestFixture

This is fairly obvious if you are familiar with NUnit. You just need to utilise the TestFixtureSetUp and TestFixtureTearDown attributes to initialise and dispose of your IE browser like so:
[TestFixture]
public class MyTests : IDisposable
{
    IE Browser;
 
    [TestFixtureSetUp]
    public void Init()
    {
        Browser = new IE();
    }

    [TestFixtureTearDown]
    public void Dispose()
    {
        if (Browser != null)
        {
            Browser.Dispose();
        }
    }

    ...

TestFixtureTearDown will run regardless of any fails in Assertions or even Exceptions so you can be confident that the browser will close on any unmaned CI machines.

2. Solving the weird STA problem (in NUnit)

You need to add to your app.config to ensure the tests run in an single thread apartment (STA) so that the non thread safe Internet Explorer browser can run safely.

I have written separately about how to solve the STA threading problem in Internet Explorer for WatiN.

The overhead of opening and closing the Internet Explorer browser should now be reduced to a one off. I have seen tests times of my NUnit powered WatiN tests reduce from 12 mins down to just 51 secs!

Follow britishdev on Twitter

ThreadStateException thown in WatiN with Internet Explorer

I was using NUnit to Assert some responses from a suite of WatiN tests whilst using the IE browser. Running them caused a ThreadStateException with an error message of 'The CurrentThread needs to have its ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer'

Internet Explorer is not thread safe so WatiN should use a single threaded apartment (STA). To ensure you abide by this WatiN will throw a ThreadStateException if it is not. This can be rectified by setting the ApartmentState to ApartmentState.STA as the error message suggests for Internet Explorer.

How set your CurrentThread to ApartmenState.STA for WatiN in NUnit

If you've haven't already create an App.config in your NUnit testing assembly. You will need to add the following to it:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
   <sectionGroup name="NUnit">
    <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
   </sectionGroup>
  </configSections>
  <NUnit>
   <TestRunner>
    <!-- Valid values are STA,MTA. Others ignored. -->
    <add key="ApartmentState" value="STA" />
   </TestRunner>
  </NUnit>
</configuration>

If you are having problems with different runners other than NUnit you can find tips on how to set STA on them too.

Follow britishdev on Twitter

Thursday, 19 May 2011

Image resizing, cropping and compression using .NET

If you need to resize an image or crop an image or compress an image or even do all three you will find you can do all of those things using the .NET framework's System.Drawing classes. In this tutorial I will talk you through the steps required to do all three to transform an large image to an image fit for your website.

This is the example scenario. You have been asked to make a page that enables a user to upload any image they want so that it can be manipulated to ensure it is 200px x 200px and compressed to a smaller file size. I won't talk you though how to make the uploading part as there are a plethora of blogs discussing that already. What I will discuss is how to resize crop and compress that image.

Say you have an image that is 1000px x 800px. There are 3 main steps to converting it to a compressed 200px x 200px image:

Resizing an image

To resize it the key is that it needs to keep the same aspect ratio whilst being a lot smaller.

So the expected outcome of this stage will be that the shortest of the two dimensions will be 200px, the other will be larger and the aspect ratio will remain the same. Begin code:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format)
{
    using (var streamOriginal = new MemoryStream(originalBytes))
    using (var imgOriginal = Image.FromStream(streamOriginal))
    {
        //get original width and height of the incoming image
        var originalWidth = imgOriginal.Width; // 1000
        var originalHeight = imgOriginal.Height; // 800

        //get the percentage difference in size of the dimension that will change the least
        var percWidth = ((float)size.Width / (float)originalWidth); // 0.2
        var percHeight = ((float)size.Height / (float)originalHeight); // 0.25
        var percentage = Math.Max(percHeight, percWidth); // 0.25

        //get the ideal width and height for the resize (to the next whole number)
        var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250
        var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200

        //actually resize it
        using (var resizedBmp = new Bitmap(width, height))
        {
            using (var graphics = Graphics.FromImage((Image)resizedBmp))
            {
                graphics.InterpolationMode = InterpolationMode.Default;
                graphics.DrawImage(imgOriginal, 0, 0, width, height);
            }
        }
    }
}

Cropping an image

After the last step you are left with an image that is 250px x 200px. As you will notice that is still an aspect ratio of 5:4 so it does not look squashed. However this still isn't the right size so you will now need to crop it.

You are now intending to cut off the excess from both sides to reduce the width whilst leaving the height the same. This will leave you with a 200px x 200px image. Code on:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format)
{
    using (var streamOriginal = new MemoryStream(originalBytes))
    using (var imgOriginal = Image.FromStream(streamOriginal))
    {
        //get original width and height of the incoming image
        var originalWidth = imgOriginal.Width; // 1000
        var originalHeight = imgOriginal.Height; // 800

        //get the percentage difference in size of the dimension that will change the least
        var percWidth = ((float)size.Width / (float)originalWidth); // 0.2
        var percHeight = ((float)size.Height / (float)originalHeight); // 0.25
        var percentage = Math.Max(percHeight, percWidth); // 0.25

        //get the ideal width and height for the resize (to the next whole number)
        var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250
        var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200

        //actually resize it
        using (var resizedBmp = new Bitmap(width, height))
        {
            using (var graphics = Graphics.FromImage((Image)resizedBmp))
            {
                graphics.InterpolationMode = InterpolationMode.Default;
                graphics.DrawImage(imgOriginal, 0, 0, width, height);
            }

            //work out the coordinates of the top left pixel for cropping
            var x = (width - size.Width) / 2; // 25
            var y = (height - size.Height) / 2; // 0

            //create the cropping rectangle
            var rectangle = new Rectangle(x, y, size.Width, size.Height); // 25, 0, 200, 200

            //crop
            using (var croppedBmp = resizedBmp.Clone(rectangle, resizedBmp.PixelFormat))
            {
            }
        }
    }
}

Compressing the image

You now have the image to the correct size but for the web it is not really optimised.

You now want to compress the image down from the current 4 bytes per pixel (32bit) image, which would be ~156KB (for a 200x200 image!). Time to compress:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format)
{
    using (var streamOriginal = new MemoryStream(originalBytes))
    using (var imgOriginal = Image.FromStream(streamOriginal))
    {
        //get original width and height of the incoming image
        var originalWidth = imgOriginal.Width; // 1000
        var originalHeight = imgOriginal.Height; // 800

        //get the percentage difference in size of the dimension that will change the least
        var percWidth = ((float)size.Width / (float)originalWidth); // 0.2
        var percHeight = ((float)size.Height / (float)originalHeight); // 0.25
        var percentage = Math.Max(percHeight, percWidth); // 0.25

        //get the ideal width and height for the resize (to the next whole number)
        var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250
        var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200

        //actually resize it
        using (var resizedBmp = new Bitmap(width, height))
        {
            using (var graphics = Graphics.FromImage((Image)resizedBmp))
            {
                graphics.InterpolationMode = InterpolationMode.Default;
                graphics.DrawImage(imgOriginal, 0, 0, width, height);
            }

            //work out the coordinates of the top left pixel for cropping
            var x = (width - size.Width) / 2; // 25
            var y = (height - size.Height) / 2; // 0

            //create the cropping rectangle
            var rectangle = new Rectangle(x, y, size.Width, size.Height); // 25, 0, 200, 200

            //crop
            using (var croppedBmp = resizedBmp.Clone(rectangle, resizedBmp.PixelFormat))
            using (var ms = new MemoryStream())
            {
                //get the codec needed
                var imgCodec = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == format.Guid);

                //make a paramater to adjust quality
                var codecParams = new EncoderParameters(1);

                //reduce to quality of 80 (from range of 0 (max compression) to 100 (no compression))
                codecParams.Param[0] = new EncoderParameter(Encoder.Quality, 80L);

                //save to the memorystream - convert it to an array and send it back as a byte[]
                croppedBmp.Save(ms, imgCodec, codecParams);
                return ms.ToArray();
            }
        }
    }
}

There you go. Your massive image is looking good to the correct size whilst being a much leaner version of former self. Congratulations!

Update

In line 24, you can see I have set the InterpoltionMode of the graphics object to InterpolationMode.HighQualityBicubic before doing the initial resize. I previously had this set to Default but I noticed that straight diagonal lines in resized images were coming out jagged and they didn't look pretty. HighQualityBicubic is meant to be "the best" form of interpolation according to Microsoft so I sided with that. I can see a big improvement in the quality so I would recommend it too.

Follow britishdev on Twitter