Thursday, 28 July 2011

MVC3/Razor - Global Error Handling


Here is a technique you can use within your MVC application to control global error handling. The technique is quite similar to aspx pages where you populate the Application_Error function within Global.asax, however, the routing is completely new!


Global.asax
Code Snippet
  1. /// <summary>
  2. /// Handle application error on a global level.
  3. /// Passes handling off to the ErrorController
  4. /// </summary>
  5. protected void Application_Error()
  6. {
  7.     var exception = Server.GetLastError();
  8.     var httpException = exception as HttpException;
  9.     Response.Clear();
  10.     Server.ClearError();
  11.     var routeData = new RouteData();
  12.     routeData.Values["controller"] = "Errors";
  13.     routeData.Values["action"] = "General";
  14.     routeData.Values["exception"] = exception;
  15.     Response.StatusCode = 500;
  16.  
  17.     if (httpException != null)
  18.     {
  19.         Response.StatusCode = httpException.GetHttpCode();
  20.  
  21.         switch (Response.StatusCode)
  22.         {
  23.             case 403:
  24.                 routeData.Values["action"] = "Http403";
  25.                 break;
  26.  
  27.             case 404:
  28.                 routeData.Values["action"] = "Http404";
  29.                 break;
  30.         }
  31.     }
  32.  
  33.     IController errorsController = new ErrorController();
  34.     var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
  35.     errorsController.Execute(rc);
  36. }
End of Code Snippet


Note: This will route our errors to the ErrorController. Lets take a look at the error controller...


ErrorController.cs
Code Snippet
  1. // <copyright file="ErrorController.cs" company="GinkoSolutions.com">
  2. // Copyright (c) 2011 All Right Reserved
  3. // </copyright>
  4. // <author>Sean Greasley</author>
  5. // <email>sean@ginkosolutions.com/sean@tutorialgenius.com</email>
  6. // <summary>Controller for handling errors within the application.</summary>
  7. namespace MVCEmailExample.Controllers
  8. {
  9.     using System;
  10.     using System.Collections.Generic;
  11.     using System.Linq;
  12.     using System.Web;
  13.     using System.Web.Mvc;
  14.     using MVCEmailExample.Models;
  15.  
  16.     /// <summary>
  17.     /// Controller for handling errors within the application.
  18.     /// </summary>
  19.     public class ErrorController : Controller
  20.     {
  21.         public ActionResult General(Exception exception)
  22.         {
  23.             return View("Error", new ErrorModel() { ErrorTitle = "General Error", ExceptionDetail = exception });
  24.         }
  25.  
  26.         public ActionResult Http404()
  27.         {
  28.             return View("Error", new ErrorModel() { ErrorTitle = "Not found" });
  29.         }
  30.        
  31.         public ActionResult Http403()
  32.         {
  33.             return View("Error", new ErrorModel() { ErrorTitle = "Forbidden" });
  34.         }
  35.     }
  36. }
End of Code Snippet

So now were handling our errors and throwing them out to the Error View (in Views/Shared!). However, were now using a strongly typed view and passing a custom class into it. This custom class contains details of our error!


ErrorModel.cs (Our custom error class!)
Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5.  
  6. namespace MVCEmailExample.Models
  7. {
  8.     public class ErrorModel
  9.     {
  10.         public string ErrorTitle { get; set; }
  11.         public Exception ExceptionDetail { get; set; }
  12.     }
  13. }
End of Code Snippet

Very simple! All it does it holds information really.
Now lets take a look at our error view...


Error View (This will already exist with a new MVC3 application) P.s. I'm using Razor syntax!
Code Snippet
  1. @using MVCEmailExample.Models
  2. @model ErrorModel
  3. @{
  4.     Layout = "~/Views/Shared/_Layout.cshtml";
  5. }
  6.  
  7.  
  8. <h2>@Model.ErrorTitle</h2>
  9.  
  10. Sorry, an error occurred while processing your request.
  11.  
  12. <br />
  13.  
  14. @if (Model.ExceptionDetail != null)
  15. {
  16.       @Model.ExceptionDetail.Message
  17. }
End of Code Snippet

This is our strongly typed view (Hint: @model ErrorModel). We simply extract the error info here and display it in a very (unstylish) form!

This sample below is for a sample email application. This uses the code described above. Just hit the button without entering any information and (assuming you don't have local mail server) u'll see some errors appearing!

MVC3 Razor - Global Error Handling

C# - Sending HTML Email template with linked resources and plain text fallback


Hi all,

If your reading this, then chances are you've looked how to create a simple email with C# and added some HTML in there. You might have then looked for including images and the documentation on the internet for this is kinda poor/bad/doesn't work. Well here's how!!

In this example, I have created a class library that can be used with any C# application. So it doesn't matter what kinda application you have (MVC, ASPX Web App, Client App, Command Line etc...).

Lets let on with it!! I've created this project in .NET 4.0 at time of writing and included a VS2010 MVC3 Web App with it for full example. I have also included some global MVC3 error handling!

Code Snippet
  1. // <copyright file="EmailHelper.cs" company="GinkoSolutions.com">
  2. // Copyright (c) 2011 All Right Reserved
  3. // </copyright>
  4. // <author>Sean Greasley</author>
  5. // <email>sean@ginkosolutions.com/sean@tutorialgenius.com</email>
  6. // <summary>Email helper class. Allows sending of html and plain text emails to a target email address.</summary>
  7. namespace MVCEmailExample.Helpers
  8. {
  9.     using System;
  10.     using System.Collections.Generic;
  11.     using System.Collections.Specialized;
  12.     using System.Configuration;
  13.     using System.Linq;
  14.     using System.Net.Mail;
  15.     using System.Net.Mime;
  16.     using System.Web;
  17.     using System.Web.UI;
  18.     using System.Web.UI.WebControls;
  19.     using MVCEmailExample.Exceptions;
  20.     using MVCEmailExample.Models;
  21.  
  22.     /// <summary>
  23.     /// Email helper class.
  24.     /// Allows sending of html and plain text emails to a target email address.
  25.     /// </summary>
  26.     public class EmailHelper
  27.     {
  28.         /// <summary>
  29.         /// Sends an email to a recipient. Provides HTML and plain text views.
  30.         /// The recipient will receive which one their client supports.
  31.         /// </summary>
  32.         /// <param name="templateDir">Directory of where the HTML email template is stored.</param>
  33.         /// <param name="recipient">Receipient information</param>
  34.         public static void SendEmail(string templateDir, Recipient recipient)
  35.         {
  36.             try
  37.             {
  38.                 // Build message
  39.                 MailMessage message = new MailMessage();
  40.                 message.To.Add(new MailAddress(recipient.Email));
  41.                 message.Subject = ConfigurationManager.AppSettings["EmailSubject"];
  42.  
  43.                 // Create plain text mode for alternative view
  44.                 AlternateView plainView = AlternateView.CreateAlternateViewFromString(ConfigurationManager.AppSettings["PlainTextEmail"], null, "text/plain");
  45.                 message.AlternateViews.Add(plainView);
  46.  
  47.                 // Create HTML email version
  48.                 MailDefinition mailDef = new MailDefinition();
  49.                 mailDef.BodyFileName = string.Format(@"{0}\{1}", templateDir, @"Email.html");
  50.                 mailDef.IsBodyHtml = true;
  51.                 mailDef.Subject = ConfigurationManager.AppSettings["EmailSubject"];
  52.  
  53.                 // Build replacement collection to replace fields in Email.htm file
  54.                 // Use fields anywhere in the template file. I.e.   <%FRIENDNAME%>
  55.                 ListDictionary replacements = new ListDictionary();
  56.                 replacements.Add("<%NAME%>", recipient.Name);
  57.  
  58.                 // Use dummy control as owner (I.e. new System.Web.UI.Control()) as were in a class library.
  59.                 // It's only use to determine where the access templates from as a relative base.
  60.                 MailMessage msgHtml = mailDef.CreateMailMessage(recipient.Email, replacements, new System.Web.UI.Control());
  61.  
  62.                 AlternateView htmlView = AlternateView.CreateAlternateViewFromString(msgHtml.Body, null, "text/html");
  63.  
  64.                 // Add linked resources
  65.                 AddLinkedResources(templateDir, ref htmlView);
  66.                
  67.                 // Add HTML view
  68.                 message.AlternateViews.Add(htmlView);
  69.  
  70.                 // Send message
  71.                 SmtpClient client = new SmtpClient();
  72.                 client.Send(message);
  73.             }
  74.             catch (Exception mailEx) { throw new MailerException("Error sending email.", mailEx); }
  75.         }
  76.  
  77.         /// <summary>
  78.         /// Adds linked resources to the email
  79.         /// Email template must contain the resource IDs in the following format: <img src="cid:CONTENTID" />
  80.         /// </summary>
  81.         /// <param name="templateDir">Directory of where the HTML email template images are stored.</param>
  82.         /// <param name="htmlView">A reference to the HTML view.</param>
  83.         private static void AddLinkedResources(string templateDir, ref AlternateView htmlView)
  84.         {
  85.             LinkedResource logo1 = new LinkedResource(string.Format(@"{0}\{1}", templateDir, @"Images\email.jpg"), MediaTypeNames.Image.Jpeg);
  86.             logo1.ContentId = "email";
  87.             htmlView.LinkedResources.Add(logo1);
  88.         }
  89.     }
  90. }
  91.  
End of Code Snippet


Note: This will attempt to send a HTML email with an embedded image (linked resource). If the client does not support HTML, then a plain text email will be used as backup. boom! (I've defined this in the application settings, as well as the email subject and "from" email address).


Configuration - App Settings (Optional, just didn't want to hard code them) [Web/App.config]
Code Snippet
  1. <appSettings>
  2.     <!-- Email App Settings -->
  3.     <add key="EmailSubject" value="GinkoSolutions.com Email Example"/>
  4.     <add key="PlainTextEmail" value="Hi There, You currently don't support HTML emails, but thats ok! I'm just saying hello anyway!"/>
  5. </appSettings>
End of Code Snippet


Configuration - Email server [App/Web.config]
Code Snippet
  1. <system.net>
  2.     <mailSettings>
  3.         <smtp from="Admin &lt;admin@ginkosolutions.com&gt;">
  4.             <network host="localhost" port="25"  />
  5.         </smtp>
  6.     </mailSettings>
  7. </system.net>
End of Code Snippet


Note: This won't work unless you have a local email server. Please provide the details to an SMTP email server here.


Create a sample recipient class (Just for storing recipient details)
Code Snippet
  1. public class Recipient
  2. {
  3.     public string Name { get; set; }
  4.     public string Email { get; set; }
  5. }
End of Code Snippet


Invoke the email static class
Code Snippet
  1. // Construct recipient from form
  2. Recipient recipient = new Recipient() { Name = FriendName, Email = FriendEmail };
  3.  
  4. // Send email
  5. EmailHelper.SendEmail(Server.MapPath("~/EmailTemplate"), recipient);
End of Code Snippet


Note: I have added an email template path as a parameter. This is so that if you execute the email helper from a web application, it knows where to find the templates!


Sample HTML Template File
Code Snippet
  1. <body style="background: #000000;">
  2. Hello <%NAME%>,
  3. <br /><br />
  4. I thought i'd send you a picture of some guy holding an envelope.
  5. <br /><br />
  6. <img src="cid:email" />
  7. <br /><br />
  8. I have no idea why though!
  9. <br /><br />
  10. Thanks!
  11. </body>
End of Code Snippet


Note:
Notice the cid prefix for the images. This indicates a contentID for a linked resource. If you look in the code for the email helper, you will notice that I am created 1 linked resource and setting the contentID to 'email'. This will simply embed the image.
Again, in this template, you will notice I have used a custom tag for the friend's name called NAME. This is replaced within the email helper when we construct a ListDictionary and add our replacements to it.


and thats it!!

If you stuck, or can't get it to compile, then download the full sample here

MVC3 Web Application - Full Email Example with Fallback

Friday, 22 July 2011

MVC3 JQuery Client Validation using Entity Model Framework 4.1 auto generated classes


Hi all,

This is a quick tutorial on how to perform client validation using the MVC framework with auto generated classes in the backend. You might have these auto-generated classes by using a data modelling framework such as: Entity Framework or Linq-To-Sql.

Prerequisites
Creating an MVC 3 Web Application with the Razor View Engine, HTML5 and IIS Express 7.5


Creating an entity model using EMF 4.1
1. Create a new Entity Data Model (.edmx) file within your Modules folder. Right click Modules and add a "ADO.NET Entity Data Model" item. Call this "MembershipModel.edmx"
2. If you have a database already, seelct "Generate from database". This will automatically create entities based on your tables. If not, select "Empty model".
3. Open the entity designer file (.edmx).
4. If you selected "Empty model", Right click the designer > Add > Entity...
5. Name the entity "User"
6. OK to create!
7. Right click the new entity > Add > Scalar Property
8. Call the property "Name"
9. Right click the new entity > Add > Scalar Property
10. Call the property "Email"
11. You can generate your database from your model. Once you have created your entities, right click the designer and select "Generate Database from Model". Don't worry if you need to update these at a later date, EMF does a good job of syncing these later.
12. Setup a new connection to your database
13. You will be presented with an SQL script for your entities, cool huh?
14. Execute this against your datastore.

Note: If you open the designer oce behind file (MembershipModel.Designer.cs), you can see that the classes have been created for us (one per entity), aswell as some properties and a method to create a new user (in our example). By default, the designer uses a code generater called T4 (Text Template Transformation Toolkit). You will notice that all classes using the default template implement the EntityObject base class. These classes provide a lot of functionality, but are quite cumbersome to work with. So we are going to use a different generator! (DbContext Generator)


Using the DbContext Generator
1. Right click the Entity Model .edmx designer > "Add Code generation"
2. Select "ADO.NET DbContext Generator" from the dialog and name it "Model1.tt".
3. OK to create!
4. You will receive a warning because template can potentially contain harmful content. Just click ok!

Note: You will notice that two files have been created under the Models folder: Model1.tt and Model1.Context.tt. Underneath the Model1.tt file, you will be a custom class representing your entity "User.cs". This is the class you will be using throughout this sample application to represent users! If you don't see this class here, then you have created your database!



ok, im a master at EMF, show me the validation already!

With MVC, a simple way to perform validation is to use the [Required] atrribute for properties of our class. Now the problem lies with the way our classes are generated by the code generator (We cannot change the designer fiels because we'll lose our changes, plus its stupid!). An easy way around this is to use Metadatatype!

Metadatatype and T4 class validation
1. Right click the Models folder > Add > Class..
2. Call it "UserValidation.cs"
3. Enter the following code...

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
 
namespace MvcApplication1.Models
{
    [MetadataType(typeof(UserValidation))]
    public partial class User
    {}
 
    public class UserValidation
    {
        [Required(ErrorMessage = "Your Full Name is required")]
        public string Name { get; set; }
 
        [Required(ErrorMessage = "Your Email Address is required")]
        [RegularExpression(@"^[\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$", ErrorMessage = "Your Email Address is invalid")]
        public string Email { get; set; }
    }
}



Note: You will notice that Metadatatype allows us to specify another class on behalf of an existing partial class, to append attribues to. These attributes will be our validation attributes! I have chosen the Name and the Email properties of our user entity to apply validation to.


Configuring the Controller
1. Add a new controller. I.e. HomeController
2. In the Index method, return the view with a new copy of the EMF generated User class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Models;
 
namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ActionResult Index()
        {
            return View(new User());
        }
    }
}



Creating the configuring the view
1. Right click the Index method in the controller and add the view.
2. Make this strongly typed, or we will have a problem with the dynamic operations we will be using in the view (Example error: CS1963: An expression tree may not contain a dynamic operation)
3. Enter the following form information into the view...

@using MvcApplication1.Models
@model User
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Sample EMF Class Validation</h2>
 
@using (Html.BeginForm())
{
    <fieldset>
    <p>
        @Html.LabelFor(Model => Model.Name)
        @Html.TextBoxFor(Model => Model.Name)
        @Html.ValidationMessageFor(Model => Model.Name)
    </p>
    <p>
        @Html.LabelFor(Model => Model.Email)
        @Html.TextBoxFor(Model => Model.Email)
        @Html.ValidationMessageFor(Model => Model.Email)
    </p>
    <p>
        <input type="submit" value="Submit" />
    </p>
    </fieldset>
}


We are almost there, but one more thing!! We need to add a reference to the jquery validation libraries. You can either do this in your view (using sections from the main layout page) or simply add the following into the head on the _Layout.cshtml page...

    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>



Download Sample Files Here


Enjoy!

Wednesday, 20 July 2011

Creating an MVC 3 Web Application with the Razor View Engine, HTML5 and IIS Express 7.5


This was originally going to be a few simple steps, but I decided to go the whole hog. Good first read if your getting started with MVC3! (Rough knowledge required, when I say rough, I mean VS, aspx and O-O knowledge)


Creating new MVC 3 Web Application in VS 2010
1. Create a new MVC 3 Web Application
2. Select an Empty template from the templates dialog (the others ship with authentication that were not goign to use).
3. View engine, select Razor (This will allow us to use the Razor view engine which has slightly different markup and uses .cshtml files rather than .aspx pages). Note: Razor view can be rendered inside unit tests, something that aspx pages cannot.
4. Use HTML5 semantic markup, check it!
5. OK to create.

Note: You can see that quite a lot of libraries are included by default. You will also notice that JQuery (JS and CSS) is included as standard and we have a good base setup to begin developing our web application.



WHAT IS MVC and Order of execution

Init
Within an MVC application, you have a list of routes and filters defined when the application starts. These are defined the the Global.asax.cs file (yes it still exists!). The routes are referenced everytime a page is requested (URL is entered that is associated with the application). The routes describe which Controller will serve the view's content.

Controller
The Controller is responsible for all the business logic. This is the "C" part of MVC. The Controller may utilise the Model ("M" in MVC) to manipulate the datastore is some way (basically ask the database to grab something). The Controller may do some casting or validation on the data, then render the View (may also pass data to the view when rendering).

Model
The Model is all about the database and the database layer. Usually you will have a framework here for managing access and control to your database. In this example, we are using the entity framework. So we will have our .edmx files and our template files here. Our classes will also be defined here as they will be generated automatically from our database content!

View
The "V" in MVC. View's should know nothing about how the data is constructed and how the data works internally. The view should be essentially be dumb and told nothing about the data, other than anything required to display the data to the user. The reason for this aides the seperation of concerns principle of O-O programming. This allows us to clearly seperate are busienss logic. The rewards consist of: Unit testable busienss layer, designers can work with views without worrying about learning C#/VB etc.


Razor View Engine
I don't want to explain everything in this post or were gonna be writing a novel. Here is a good link by ScottGu on the Razor view engine. Either than, or you can just trust me that it's great!


Note about Razor 'master' pages and entry points
_ViewStart.cshtml - Does what it says! This is executed first and initialises the view.
_Layout.cshtml - Razor's answer to aspx master pages.



Creating a Controller
1. Right click the Controllers directory.
2. Add > Controller.
3. Name the controller HomeController (We already have a route defined in the Global.asax as default that points to a Home Controller - So there is no extra work required to link it up yet).
4. Set the template as an empty template
5. OK to create!
6. You will notice that you controller contains an Index method. Will will be executed by default when the user hits the 'Home' directory for your application. I.e. http://localhost/Home


Creating a View based off the Controller
1. Each method in our controller can map to its own view page. This is what we will be doing in this example. Once the controller is created, then creating a view is simple!
2. Open the HomeController, and right click on the Index method.
3. Select 'Add View...'
4. The view name will be Index by default. This is fine...
5. THe view engine will be Razor, this again is fine...
6. Creating a strongly typed view just means that this view will only accept classes of a single type. So if you are ALWAYS passing a TEST class to this view, then it should be strongly typed.
7. Partial view can be compared to an aspx user control. It's a partial view, not a complete one! This can be re-used throughout the web application. We are not creatign one of these now...
8. "Use layout or master page". We are using this (as describes before). Set this as the _Layout.cshtml file. It will reside in the Shared folder within Views (~/Views/Shared/_Layout.cshtml).
9. OK to create!



Setting up test server and launching application

Note: I recommend using IIS Express (7.5 latest at time of writing) or something different to the visual studio server for this application. MVC uses URL Routing (aka URL rewriting before MVC), so sometimes the routing gets a little confusing with the visual studio development server. IIS7 handles URL routing out of the box (Whereas more steps were requried for IIS 6, and you can't install IIS7 on windows XP). However, IIS Express 7.5 solves all of these problems becaue it performs both nicely!


Setting up IIS Express 7.5
1. If you don't have it, its a lightweight seperate install. Simply get it via the web platform intaller
2. Right click the web application in Visual Studio > Properties.
3. Web tab
4. Use local IIS Web server
5. Check "Use IIS Express".
6. Click create virtual directory button
7. OK to execute application!


Now, simply execute the application and you'll be presented with a very blank dull webpage. Congratulations, you did it! It's the start of something good, trust me!



Reference Links
Building an MVC 3 App with Database First and Entity Framework 4.1
Creating an MVC3 Application with Razor and JS

Monday, 11 July 2011

Deploying an MVC application on IIS 6


http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx