maandag 17 oktober 2011

MaxLength attribute doesn't work anymore!


To spare the rest of you the headache; MVC 3 does not support the MaxLength attribute any longer.

In stead you can now use the StringLength attribute which also replaces the MinLength attribute through a named parameter.

Some examples:
  • Set the maximum string length to 50:
       1:  [StringLength(50, ErrorMessage = "{0} has a maximum of {1} characters")]
  • Set the maximum and minimum string length:
       1:  [StringLength(50, MinimumLength=10, ErrorMessage = "{0} has a maximum of {1} and a minimum of {2} characters")]

Seems you still need to use MaxLength attribute for Entity Framework though.

zaterdag 18 juni 2011

Denote required fields in asp.net MVC 3

I'm a big fan of the asp.net MVC framework.

The "convention over configuration" idea makes your projects more easily to understand by other developers looking into your code.
Maybe it's just me, but I think that MVC helps a lot in matching the pieces in your architectural design; it makes you write better code.

The true power of the MVC framework lies in its extensibility.
You can get very far using the "out of the box" features, but the asp.net team made it very easy to extend that standard functionality.

This post is an example of this extensibility.

I'm going to show you how you can automatically denote required fields on a form using an asterix (*).

So let's fire up Visual Studio and create a new MVC 3 project.


Step 1: The model

Right-click you Model folder, choose Add -> Class and name it QuestionModel.cs.

Add some properties: Id, LastName, FirstName, Company, JobTitle, Email, Question.
Tip: for simple properties you can type "prop" and hit tab twice.

Mark the required properties as "Required" using DataAnnotations (System.ComponentModel.DataAnnotations).

   1:      public class QuestionModel
   2:      {
   3:          [Key]
   4:          public int Id { get; set; }
   5:   
   6:          [Required]
   7:          public string LastName { get; set; }
   8:   
   9:          [Required]
  10:          public string FirstName { get; set; }
  11:   
  12:          public string Company { get; set; }
  13:   
  14:          public string JobTitle { get; set; }
  15:   
  16:          [Required]
  17:          public string Email { get; set; }
  18:   
  19:          [Required]
  20:          public string Question { get; set; }
  21:      }

Build your project (ctrl + shift + b), so MVC picks up your model.



Step 2: The controller

Starting from the "HomeController", create a new ActionResult methode called "Question" which returns a View with an instance of our QuestionModel as a parameter.

   1:  public class HomeController : Controller
   2:      {
   3:          // ...
   4:   
   5:          public ActionResult Question()
   6:          {
   7:              var model = new QuestionModel();
   8:   
   9:              return View(model);
  10:          }
  11:      }

Still in your controller class, right click the Question ActionResult method and choose "Add View..." to create your view.

Make it a "stongly-typed" view with it's "Model class" set to the "QuestionModel" and "Razor" as it's "view engine".


Step 3: The Extension

Our extension will check if a field is required and if so, place an asterix (*) after the textbox.

Create a new folder in your project and call it "Extensions".
Add a class to this folder calling HtmlExtensions.
   1:  public static class HtmlExtensions
   2:      {
   3:          public static MvcHtmlString RequiredFieldFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
   4:          {
   5:              // Get the metadata for the model
   6:              var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
   7:   
   8:              // Check if the field is required
   9:              var isRequired = metadata
  10:                                  .ContainerType.GetProperty(metadata.PropertyName)
  11:                                  .GetCustomAttributes(typeof(RequiredAttribute), false)
  12:                                  .Length == 1;
  13:   
  14:              // If the field is required generate label with an asterix
  15:              if (isRequired)
  16:              {
  17:                  var labelText = "*";
  18:   
  19:                  var tag = new TagBuilder("label");
  20:                  tag.MergeAttributes(new Dictionary<string, object> { { "style", "color: red; margin-left: -5px; margin-right: 5px; vertical-align: top;" } });
  21:                  tag.SetInnerText(labelText);
  22:                  
  23:                  return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
  24:              }
  25:   
  26:              return null;
  27:          }
  28:      }

Again build your project so mvc can pick up the changes.


Step 4: The View

Open the view created at the end of step 2.

Reference your extension class:

   1:  @using RedAsterixExample.Extensions;

Call the extension method for every field (required an not required field):

   1:  @Html.RequiredFieldFor(model => model.LastName)

The complete view could look something like:

   1:  @model RedAsterixExample.Models.QuestionModel
   2:   
   3:  @{
   4:      ViewBag.Title = "Question";
   5:  }
   6:   
   7:  @using RedAsterixExample.Extensions;
   8:   
   9:  <h2>Question</h2>
  10:   
  11:  <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  12:  <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
  13:   
  14:  @using (Html.BeginForm())
  15:  {
  16:      @Html.ValidationSummary(true)
  17:      <fieldset>
  18:          @Html.HiddenFor(m => m.Id)
  19:   
  20:          <div class="editor-label">
  21:              @Html.LabelFor(model => model.LastName)
  22:          </div>
  23:          <div class="editor-field">
  24:              @Html.EditorFor(model => model.LastName)
  25:              @Html.RequiredFieldFor(model => model.LastName)
  26:              @Html.ValidationMessageFor(model => model.LastName)
  27:          </div>
  28:   
  29:          <div class="editor-label">
  30:              @Html.LabelFor(model => model.FirstName)
  31:          </div>
  32:          <div class="editor-field">
  33:              @Html.EditorFor(model => model.FirstName)
  34:              @Html.RequiredFieldFor(model => model.FirstName)
  35:              @Html.ValidationMessageFor(model => model.FirstName)
  36:          </div>
  37:   
  38:          <div class="editor-label">
  39:              @Html.LabelFor(model => model.Company)
  40:          </div>
  41:          <div class="editor-field">
  42:              @Html.EditorFor(model => model.Company)
  43:              @Html.RequiredFieldFor(model => model.Company)
  44:              @Html.ValidationMessageFor(model => model.Company)
  45:          </div>
  46:   
  47:          <div class="editor-label">
  48:              @Html.LabelFor(model => model.JobTitle)
  49:          </div>
  50:          <div class="editor-field">
  51:              @Html.EditorFor(model => model.JobTitle)
  52:              @Html.RequiredFieldFor(model => model.JobTitle)
  53:              @Html.ValidationMessageFor(model => model.JobTitle)
  54:          </div>
  55:   
  56:          <div class="editor-label">
  57:              @Html.LabelFor(model => model.Email)
  58:          </div>
  59:          <div class="editor-field">
  60:              @Html.EditorFor(model => model.Email)
  61:              @Html.RequiredFieldFor(model => model.Email)
  62:              @Html.ValidationMessageFor(model => model.Email)
  63:          </div>
  64:   
  65:          <div class="editor-label">
  66:              @Html.LabelFor(model => model.Question)
  67:          </div>
  68:          <div class="editor-field">
  69:              @Html.TextAreaFor(model => model.Question)
  70:              @Html.RequiredFieldFor(model => model.Question)
  71:              @Html.ValidationMessageFor(model => model.Question)
  72:          </div>
  73:   
  74:          <p>
  75:              <span>Fields denoted with a (*) are required </span>
  76:              <br />
  77:              <input type="submit" value="Create" />
  78:          </p>
  79:      </fieldset>
  80:  }
  81:   
  82:  <div>
  83:      @Html.ActionLink("Back to List", "Index")
  84:  </div>

When you run the application, you will see that the red asterix (*) is only added for the required fields.

maandag 6 juni 2011

Welcome

Hi there!

Welcome to my brand new blog.

Who am I?
My name is Koen Luyten and I work as a .net developer since August 2008.
For a summary of my professional life, you can take a look at LinkedIn

What will this blog be about?
I created this blog mainly to post about my findings and experiences with .net, both in the form of written text and tutorials.
Besides that, I will try to frequently post links to other blog posts that I find interesting.

Why this blog?
There are 2 main reasons why I have created this blog:
  1. Being a young developer, I still have to discover a lot in the world of Microsoft development.
    Having a blog somehow makes me obliged to do some research and testing.
  2. I would like to share my findings with the rest of you.
How will this blog differ from any other technical blog?
In most cases it probably won't. It will just be another perspective on certain topics.
I can say that I always try to keep my writing and examples as easy to understand as possible.

I hope you'll enjoy reading my blog.
I'll be sure to enable the commenting part, so you can reply to any of my writing.

-- To be continued --