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.

Reset Identity Column Value in MSSQL Server

One of those simple tips....

While setting up some test data on two different machines my row data became out of synch, a quick Google and "hey presto"

The following line resets the Identity value for the Customer table to 0 so that the next record added starts at 1.

 

DBCC CHECKIDENT('Product', RESEED, 0)

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";
 }

The SQL DISTINCT clause is case insensitive by default

Solution:  The COLLATE clause can make any string operation case sensitive.

The solution turned out to be pretty easy, use a COLLATE clause with a case sensitive collation.  Here's a sample query with both case senstive and case insensitve collations.

Case insensitive:

select distinct (Item) COLLATE sql_latin1_general_cp1_cs_as
    FROM (
           select  'abcd' item
 union all select  'ABCD'
 union all select  'defg'
 union all select  'deFg') items

 

Case sensitive:

All that is different in the next query is the name of the collation:

select distinct (Item) COLLATE sql_latin1_general_cp1_ci_ai
    FROM (
           select  'abcd' item
 union all select  'ABCD'
 union all select  'defg'
 union all select  'deFg') items

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!
 

Microsoft JScript runtime error: Object doesn't support property or method 'createContextualFragment'

While working on a project that used Coolite extensions I was getting frustrated trying to build a new VM dev environment.

I couldn't get the projects to run because of the error in the subject. It turned out to be quite simple. I had upgraded to IE 9 and it doesn't support it.

Thanks to Stack Overflow

Un-installing IE 9 and installing Firefox sorted out this issue.