Custom Error View and Elmah

I added Elmah you my MVC 4 web portal that I had been working on. I had Custom Error controller and view configured to handle the general public error messages, which worked perfectly.

I noticed that on a live deployment that I received an occasional exception

System.InvalidOperationExceptionThe view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/Account/Error.cshtml ~/Views/Account/Error.vbhtml ~/Views/Shared/Error.cshtml ~/Views/Shared/Error.vbhtml ~/Views/Account/Error.aspx ~/Views/Account/Error.ascx ~/Views/Shared/Error.aspx ~/Views/Shared/Error.ascx

The problem occurs because Elmah adds the HandleErrorAttribute in the Global.asax.cs file

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

This filter is executed when an un-handled exception is thrown. It sets the view as Error. The MVC runtime tries to render that view. But in this case, there is no such view. So it again throws another exception which is handled by ASP.NET runtime.

There are two solutions to this:

1) Add an Error.cshtml view in the Shared folder to display the exception thrown by the runtime.

2) Add/edit the key in web.comnfig appSettings

    <add key="elmah.mvc.disableHandleErrorFilter" value="true" />
This allows the exception to propagate to the configured Error controller using the existing routing rules.

The required anti-forgery cookie “__RequestVerificationToken” is not present

I have had a problem with the AntiforgeryToken exception on an MVC4 website.

Everything was correctly configured i.e.

view code:

using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    //some code
}

 

Controller code:

[HttpGet]
[ValidateAntiForgeryToken]
public ActionResult Index()
{
    //some code
}

What made things worse was that only random users had this issue.

The problem turned out to be a poorly configured load balanced server, and the web.config setting

<httpCookies requireSSL="true" />

one server had a wild card SSL installed and the second server did not.

The result being that some users were being served by the server with the SSL installed with provided an encrypted cookie containing the anti-forgery token. Other users are served by the other server which was unable to provided the encrypted cookie.

Hence the anti-forgery token exception is thrown.

ASP.NET MVC CurrencyBinder

Recently I have been working on an MVC 4 web portal. I had been bought on-board to help complete a live site. A problem was identified where a customer form would allow the user to enter a currency value, but the value would not persist.

The to test the binding I created a view model something like this

namespace TestWebApp.Models
{
	public class TestViewModel
	{
		[StringLength(30, MinimumLength = 3, ErrorMessage = "Invalid")]
		[Required(ErrorMessage = "Required")]
		public string StringData { get; set; }

		[Range(1, 9999, ErrorMessage = "Invalid value")]
		public int IntData { get; set; }

		[Required(ErrorMessage = "Required")]
		public decimal DecimalData { get; set; }

		[DataType(DataType.Currency)]
		[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:C2}")]
		[Required(ErrorMessage= "Required")]
		public decimal CurrencyData { get; set; }
	}
}

Usually MVC will infer the correct binding provider for each view model property and perform the correct validation for each data member. If, as in this case you are using something like jQuery client side validation, the user is provided with a really nice culture dependent currency formatted value

e.g.

£1,234.56 (en-GB)

$1,234.56 (en-US)

1 234,56 € (fr)

The problem is that the databinding tries to validate a numeric value, and throws an "invalid value" exception, this is beacuse the currency symbol is not recognised. The way to resolve this is to add a "custom" data binder for the currency data type.

#region Using
using System.Globalization;
using System.Web.Mvc;
#endregion
namespace TestWebApp.Helpers
{
    public class CurrencyBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            decimal value;
            var valueProvider = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (string.IsNullOrEmpty(valueProvider?.AttemptedValue))
                return null;
            if (bindingContext.ModelMetadata.DataTypeName == "Currency")
            {
                if (decimal.TryParse(valueProvider.AttemptedValue, NumberStyles.Currency, CultureInfo.CurrentCulture, out value))
                    return value;
            }
            else
            {
                if (decimal.TryParse(valueProvider.AttemptedValue, out value))
                    return value;
            }
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Invalid Currency");
            return null;
        }
    }
}
You will need to tell your application to use your custom binding in the application start-up.
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
            ModelBinders.Binders.Add(typeof(decimal), new CurrencyBinder());
        }

WPF PNG image DPI

While wrestling with a problem of scaling a WPF window background image, I came across an issue which I had not thought about for ages.

The PNG had been created by a colleague and he set the image to 72dpi. 
It turns out the WPF defaults to 96dpi and therein lay the start of my problem.

Also part of my problem was that I was being a 'plank' as I had set ResizeMode to NoResize to prevent and user scaling the window and I had also set SizeToContent to Manual which screwed up the layout when the application was run. 
Although things looked great in the designer, the window rendering tries to re-calculate the layout of all the controls but the SizeToContent prevented the calculation to complete. The result being that the controls looked out of place in relation to the background image on  the window.

Invalid object name 'dbo.CustomerRoles'.

Recently i have been building a website for a customer using NopCommerce v2.80. (This platform is implemented using ASP.NET MVC 4 and Entity FrameWork)

This project required me to build some plugins to extend the core functionality.

Here is a great blog by Skyler Severns showing how to build a plugin with data access.

While adding new DTO's and mapping table data I fell fowl of 

Invalid object name 'dbo.CustomerRoles'.

I was confused as I had created several plugins each with ther own data models, connected to the database and all had been fine. It was only when I extended the existing data scheme that the problem arose.

It took a while for the penny to drop that each plugin had its own data context (which I had hand crafted) and had missed the fact that the nopCommerce datacontect had used 'Non Pluralisation'

So to fix this on each data context simply add the following code to OnModelCreating() method.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Remove the pluralisation
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    // Other initialistion
    modelBuilder.Configurations.Add(new RoleAccessCodeMap());

    base.OnModelCreating(modelBuilder);
}

Xml Serialization

To automatically create support classes to help with Xml serialization, you can use a great tool Xsd2Code.

While using the tool I came across a feature which I vaguely remember reading a while ago, ‘hiding xml elements’.

Eg 

public class Contact
{
    public string Name { get; set; }
}

The class above will generate the following xml scheme. Note the 'minOccurs' attrubute.

<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Contact" nillable="true" type="Contact" />
  <xs:complexType name="Contact">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="Name" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

However to generate the correct scheme that I needed, I wanted the Name element to be Nullable

<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Contact" nillable="true" type="Contact" />
  <xs:complexType name="Contact">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The way to achieve this with Xmlserialization is to use the ‘propertySpecified’ convention.

public class Contact
{
    public string? Name { get; set; }

    [XmlIgnore]
    public bool NameSpecified { get { return Name.HasValue; } }
}

The public property is made Nullable.

Add the ‘Specified’ property. The property name must match the public property plus the string ‘Specified’, this will instruct the Xmlserializer not to serialise the member.

How to work with Razor _layout menu items

While using Razor in an MVC4 application I was working on, I needed to 'enable' the menu item for the current page.

The solution turned out to be quite simple (when I thought about it)

in the _Layout.cshtml add the following script

<script>
        @functions 
        { 
            public string Selected(string PageTitle)
            {
                if (ViewBag.Title == PageTitle)
                    return "current";
                else
                    return "";
            } 
       } 
    </script>
Then call the function from  HTML
<li class="@Selected("Dashboard")">
                            <a href='@Url.Action("Index", "Dashboard")'>
                                <img src="~/img/computer.png" width="25" height="25">Dashboard</a>
</li>
<li class="@Selected("Reports")">
                            <a href='@Url.Action("Index", "Reports")'>
                                <img src="~/img/chart.png" width="25" height="25">Reports</a>
</li>
Finally in each view you will can define the page title
e.g. in Dashboard view
@{
    ViewBag.Title = "Dashboard";
 }

read-only ConfigurationElement

I had written a custom section manager to allow the configuration for FTP logon credentials.

All was going well, I had written a class to model the credentials by inheriting from ConfigurationElement. The customer section was derived from ConfigurationSection.

So now I can write a custom section in the application config file and read the values at runtime, great I thought. the problem is that when I try to edit an element I get an "The element is read-only" exception.
After adding setter accessors to the credentials class (obvious) the problem was this little gem....

 

protected override void SetReadOnly()
{
    //do nothing!
}

 
Hope this helps!