Saturday, April 23, 2011

Validation: set maxlength of a text box using MVC validation

Given a view model as below:
public class EmployeeFormViewModel
{
[Required(ErrorMessage = "*")]
    [StringLength(20,ErrorMessage = "Max length 20 characters")]
    public string Name { getset; }
}
And when client validation and unobtrusive JavaScript are enabled in a MVC 3 app in web.config in the root directory:

  <appSettings>
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/> 
  appSettings>



A view:

<h2>Employee Formh2>
@using (Html.BeginForm("Employee","SaveEmployeeForm","Home",FormMethod.Post)){
    @Html.TextBoxFor(model=>model.Name)
    <br />
    <input type="submit" value="Submit" />
}

renders into Html on the client side:



<form action="/SaveEmployeeForm/Home?Length=4" method="post">
 <input data-val="true" 
  data-val-length="Name must not be longer than 20 characters long" 
  data-val-length-max="20" 
  data-val-required="*" 
  id="Name" 
  name="Name" 
  type="text" 
  value="" />    
 <br />
    <input type="submit" value="Submit" />
form>


This works great: it shows the error message when the user types a name longer than 20 characters and leaves the text box.  But it still allows the user to type in more than 20 letters before the focus leaves the text box.
  
What if I want to keep the user from keying in 20 characters? 

Well, the maxlength attribute of the input tag is the answer.  When it is set to 20, the user is only allowed to type in 20 characters.  I really don't want to keep setting "maxlength" to every single text box that I create and more importantly I want validation attribute "StringLength" to control this value.  But the generated code does not set the "maxlength" attribute.  How do I set the value of maxlength attribute using the value of data-val-length-max attribute?
A little JQuery sweetness does the trick:
<script language="javascript" type="text/javascript">
    $(document).ready
    (
        function () {
            $('input[data-val-length-max]').each
            (
                function (index) {
                    $(this).attr('maxlength', $(this).attr('data-val-length-max'));
                })
        });
script>
What the code above says is that for every input tag with the attribute of "data-val-length-max", use the value of it to set the value of "maxlength" attribute.

Friday, April 22, 2011

Double Meaning or Entendre

Double Meaning or Double Entendre can be very funny when used in jokes.  Read the following jokes from this site:
Old Timer 1 : You know what I miss?
Old Timer 2 : And what might that be?
Old Timer 1 : Really small targets that are miles away.




Teacher 1 : You know what makes me mad?
Teacher 2 : What?
Teacher 1 : Changing the 'e' to an 'a' and adding a 'd'.



Ha-ha-ha, he-he-he, wasn't that funny!


In the first example above, "miss" could mean thinking of something sentimental wishing you still have it or could mean when I shoot a target I don't hit it.  Same thing in the second one where "me" could me myself or the word "me".  This is all funny and silly until you start coding that way.


During a recent design session, a team member suggested reusing existing properties for different purposes.  This reminded me of a story I heard some years back, during another design session,  a team discovered  that they needed a new field in the database for their application.  The app had been released and it was in production at a major client's site.  The client operated on 24/7 schedule, taking down the database would mean longer downtime therefore losing money.  So the team decided to use an existing field but use it differently depending the format of the value in the field.  It sounded like a good solution, all they had to do is re-deploy the application which took less then 5 minutes.  The client gets new features without much of downtime.  Great news, right?  

To the client, yes.  How about for the developers and the long term maintenance of the application?  Subsequently, the property of the class that the field was mapped to had to be handled differently. Wherever the property was used, a helper extension method was used to parse the value so the new value is can be put to work while making sure not to break the old code.  Suddenly, we created a lot of work for ourselves which meant higher cost to develop the feature.  More importantly, it had a long term implication for maintenance.  As we know people change jobs, developers come and go, now there was additional cost for maintenance because we had to document what the field really meant so we could educate new developers to use it properly.  In the end, it really wasn't worth saving the client's downtime of maybe 10 hours the most.

The moral of the story: do not give double meaning to a property, field.  Do it properly using S.O.L.I.D principles. 

Sunday, April 17, 2011

A mystery solved

Today, I was trying to solve a problem where on our French site, a specification number (which is a decimal number) of the same product  was toggling between 1.3 and 1,3 intermittently.  It should be 1,3 for French.  It turned out the problem was in two folds.


First of all, the following code is being used to convert decimal to string:
//specNumber = 1.3;
specNumber.ToString();


Secondly, the app is running on two load balanced servers.  One server's region and language is set up as:

 while the other is set up as below:

That explains why the value is appearing as 1.3 or 1,3 intermittently.


To address this problem, we need to fix it in code.  When the site is being browsed in French we'll use:

   var fr = CultureInfo.CreateSpecificCulture("fr-CA");
   specNumber.ToString(fr.NumberFormat);

That way, the code is not dependent on the server region and language settings.

Wednesday, April 13, 2011

Asp.net View (Webform View) to Razor View Translator



If you need to have asp.net views translated to Razor views, you might be interested in checking out Teleriks 

Tuesday, April 12, 2011

Custom Routing in MVC

In MVC, by default, out of the box routing pattern is {controller}/{action}/{id} where id is optional as defined in the Global.asax.cs:

            routes.MapRoute
                (
                    "Default"// Route name
                    "{controller}/{action}/{id}"// URL with parameters
                    new {controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
                );


However, this will not always meet your needs.  In such case, you can create custom routes.  For instance, let's say it is a requirement that the "HR (Human Resource)"  department of your company should have their own unique URL in a pattern like this: "Hr/PersonalProfile/Display/1234".  Custom route can be utilized to make this work:

            routes.MapRoute
                (
                    "Hr"// The name must be unique in a route table
                    "Hr/PersonalProfile/{action}/{id}"// URL with parameters
                    new {controller = "PersonalProfile", action = "Display", id = UrlParameter.Optional} // Parameter defaults                );

Now you can display a personal profile using this URL: http://{yourdomian}/Hr/PersonalProfile/Display/1234

One very important thing to note is that MVC tries to find matching route in the order of the routes registration.

In our example, the custom route "Hr" must be registered before the default route is.  Otherwise, when the site is accessed with the URL "http://{yourdomian}/Hr/PersonalProfile/Display/1234", it matches the default route and it will try to look for a controller named "Hr" which doesn't exist.  This, of course, results in an error as below:

Server Error in '/' Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Requested URL: /Hr/PersonalProfile/Display

Phil Haack created a very useful tool for debugging MVC routing: route debugger and you can get it through NuGet package management tool.  Just type in the following command in Package Manager Console:
PM> install-package routedebugger

If you're not familiar with NuGet, read about it here.  And download it from here.



Tuesday, March 22, 2011

Hide MVC version # and Asp.Net version # from HTTP Header


By default, Asp.Net and Mvc emit the version numbers in the HTTP header as below:


In the figure above, X-AspNet-Version is the Asp.net version and X-AspNetMvc-Version is version number of System.Web.Mvc version number as shown below:
























But for some reason that you don't want the world know that you're running your app on Asp.net and MVC, you can turn them off.

To remove  X-AspNet-Version from the header, set the value of enableVersionHeader of httpRuntime tag to false the web.config as follows:
  <system.web>
    <httpRuntime enableVersionHeader ="false" />

To remove X-AspNetMvc-Version from the header, you can modify the application_start event in Global.asax.cs as follows:
 protected void Application_Start()
        {
            MvcHandler.DisableMvcResponseHeader = true;

After making above changes in my app, the end result of the header looks like this:






About Cullen

My photo
Christian, Father, Software Developer/Architect who enjoys technology and using it to make people's lives easier!

Followers