# Monday, 23 April 2012

Having been a part of many large enterprise ASP.NET MVC application implementations using test driven development I learned early on that separating your controller classes into a their own project significantly reduces the noise in your web project.  It wasn’t until a recent talk I gave to user group in my region that I realized that this isn’t a widely adopted practice.  For large applications with a lot of developers and a complex architecture I highly recommend it. 

Putting your controllers in a separate assembly is very straight forward.  First create a controllers project in your solution and then you just need to update your route registrations to tell them where to look for the controllers.

  1. routes.MapRoute(name: "Default", url: "{controller}/{action}/{id}",
  2.                 namespaces: new[] {"[Namespace of the Project that contains your controllers]"},
  3.                 defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional});

In order to tell ASP.NET MVC where to look for your controllers when registering your routes you use the ‘namespaces’ parameter of the MapRoute method as illustrated above.

I know that the concept of putting controllers in a separate assembly is a bit controversial and everyone seems to have a strong opinion either for or against, so let me know what side of the fence you fall on.

posted on Monday, 23 April 2012 08:02:14 (Central Daylight Time, UTC-05:00)  #    Comments [12]
# Monday, 06 February 2012

I have been working a lot with MVC sites lately and experimenting with how to make them *usable* on mobile browsers.  This is post is about the single line of mark-up you can add to your sites Master Page, or in this case your _Layout.cshtml.

Before I get to that line I am going to show you a quick screen shot of a vanilla MVC 3 application, that can be downloaded here.

First is a screen shot of the site running in a desktop browser.

image

 

Next, is the site rendered on Windows Phone 7, Android, and iPhone.

Windows Phone 7

Opera Mobile (Android)

iPhone

image image image

 

The first thing you notice is that iOS does a fairly good job adaptively rendering the site, damn Apple!  Next you will notice that all WP7 and Android do is zoom out so the site fits on the device.  A site of any significant content or functionality would be almost useless because of the amount of panning and zooming that would be required.  I am sure we have all dealt with sites on our mobile devices like that.  So what can we do to make the site render better in WP7 and Android?

You can actually get a long way towards perfect mobile rendering of your site by adding one simple html tag.

  1. <meta name="viewport" />

The meta viewport tag can be used to control how HTML content is displayed in mobile browsers.  The meta viewport tag has properties like width, height, minimum-scale, and maximum-scale.  In this example the particular property we are concerned with is the width property.  We want to tell the the browser to render our content width at the width of device.

  1. <meta name="viewport" content="width=device-width">

Let’s see what happens when we add that tag to the head of our _Layout.cshtml file

image

As you can see above, because the meta viewport tag only effects mobile browsers our desktop version looks exactly the same.  Let’s check on the mobile browsers.

Windows Phone 7

Opera Mobile (Android)

iPhone

image image image

The site looks much better on Windows Phone 7 and Android, and still looks the same in Apple.  So by adding that single line of mark-up we where able to give our mobile users a much better user experience.

Stay tuned for a future post on using CSS Media Queries to improve the mobile experience even further.

posted on Monday, 06 February 2012 08:15:38 (Central Standard Time, UTC-06:00)  #    Comments [2]
# Monday, 21 November 2011

If you ever need to redirect to a custom page in ASP.NET MVC when a user is either not authenticated or not authorized here is how you do it.

  1. Create a custom attribute that inherits from AuthorizeAttribute.
  2. Override the OnAuthorization method.
    • call the base OnAuthorization
    • Handle user not being authenticated
    • Handle user not being authorized
  3. Use the newly created attribute in your controller in place of the ASP.NET Authorize attribute

 

The Custom Attribute
  1. public class CustomAuthorizeAttribute : AuthorizeAttribute {
  2.  
  3.     public override void OnAuthorization(AuthorizationContext filterContext) {
  4.         base.OnAuthorization(filterContext);
  5.         if (!filterContext.HttpContext.User.Identity.IsAuthenticated) {
  6.             filterContext.Result = new RedirectResult("~/Account/Logon");
  7.             return;
  8.         }
  9.  
  10.         if (filterContext.Result is HttpUnauthorizedResult) {
  11.             filterContext.Result = new RedirectResult("~/Account/AccessDenied");
  12.             return;
  13.         }
  14.     }
  15. }
Example Controller Usage
  1. [CustomAuthorize(Roles = ("Admin,Manager"))]
  2. public ActionResult Index() {
  3.     return View("Index");
  4. }
posted on Monday, 21 November 2011 09:46:18 (Central Standard Time, UTC-06:00)  #    Comments [9]
# Monday, 14 November 2011

ASP.NET MVC has an HTML Helper DropDownListFor that takes an IEnumerable and creates a drop down list for it.  Often you want to create a drop down list for an Enum.  Of course you can do this without using an HTML Helper and use standard HTML controls but you don’t have the standard clean view code that HTML Helpers give you.  Extending and creating your own HTML Helpers is rather easy, as demonstrated in my last post. With that in mind I created an extension to DropDownListFor that will create a drop down list for an Enum type.

 

Enum Html Helper
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Linq.Expressions;
  4. using DropDownListForEnumDemo.Extensions;
  5.  
  6. namespace System.Web.Mvc.Html {
  7.  
  8.     public static class EnumHtmlHelper {
  9.         
  10.         public static MvcHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression) {
  11.             return DropDownListFor(htmlHelper, expression, null, null);
  12.         }
  13.  
  14.         public static MvcHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string optionLabel) {
  15.             return DropDownListFor(htmlHelper, expression, optionLabel, null);
  16.         }
  17.  
  18.         public static MvcHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes) {
  19.             return DropDownListFor(htmlHelper, expression, null, htmlAttributes);
  20.         }
  21.  
  22.         public static MvcHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string optionLabel, object htmlAttributes) {
  23.             ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
  24.             Type enumType = Nullable.GetUnderlyingType(typeof (TEnum)) ?? typeof (TEnum);
  25.             IEnumerable<TEnum> enumValues = Enum.GetValues(enumType).Cast<TEnum>();
  26.             IEnumerable<SelectListItem> items = enumValues.Select(e => new SelectListItem {Text = e.ToString().FromCamelToProperCase(), Value = e.ToString(), Selected = e.Equals(metadata.Model)});
  27.             if (optionLabel != null) {
  28.                 new[] {new SelectListItem {Text = optionLabel}}.Concat(items);
  29.             }
  30.             return htmlHelper.DropDownListFor(expression, items, optionLabel, htmlAttributes);
  31.         }
  32.     }
  33. }

 

Enum
  1. namespace DropDownListForEnumDemo.Enumerations {
  2.  
  3.     public enum Cars {
  4.         FerrariItalia = 0,
  5.         LamborghiniGallardoLP560,
  6.         LamborghiniAventador,
  7.         AstonMartinVantage,
  8.         Porsche911GT2,
  9.     }
  10. }

 

Model
  1. namespace DropDownListForEnumDemo.Models {
  2.  
  3.     public class CarsModel {
  4.         [Display(Name = "Select A Car:")]
  5.         [Required(ErrorMessage = "* Required")]
  6.         public Cars? SelectedCar { get; set; }
  7.     }
  8. }

 

View
  1. @{ViewBag.Title = "Home Page";}
  2. @using DropDownListForEnumDemo.Models
  3. @model CarsModel
  4. <h2>@ViewBag.Message</h2>
  5. @using (Html.BeginForm()) {
  6.     <div>
  7.         <fieldset>
  8.             <div class="editor-label">
  9.                 @Html.LabelFor(m => m.SelectedCar)
  10.             </div>
  11.             <div class="editor-field">
  12.                 @Html.DropDownListFor(m => m.SelectedCar, "-- Select --")
  13.                 @Html.ValidationMessageFor(m => m.SelectedCar)
  14.             </div>
  15.         </fieldset>
  16.         <input type="submit" value="Click Me"/>
  17.     </div>
  18. }

 

image

 

Note:  Because enumeration values have to adhere to the same naming conventions as variables I had to work some magic to get the display values formatted correctly.  OK, it’s really not magic…just a little RegEx Voo-Doo.

The code is available on GitHub

posted on Monday, 14 November 2011 08:46:32 (Central Standard Time, UTC-06:00)  #    Comments [3]
# Monday, 07 November 2011

ASP.NET MVC provides a lot of HTML Helpers that allow you to more easily with less code create your views.  Typically navigation in MVC is done using the ActionLink HTML Helper that allows you easily generate an html anchor tag that will redirect to a specified controller and action.  I found cases where I wanted my navigation to be done via a button rather than a link so I created my own HTML Helper to make this easier.

Code:

  1. using System.Web.Routing;
  2.  
  3. namespace System.Web.Mvc.Html {
  4.  
  5.     public static class ActionLinkButtonHelper {
  6.        
  7.         public static MvcHtmlString ActionLinkButton(this HtmlHelper htmlHelper, string buttonText, string actionName, string controllerName, RouteValueDictionary routeValues) {
  8.             string href = UrlHelper.GenerateUrl("default", actionName, controllerName, routeValues, RouteTable.Routes, htmlHelper.ViewContext.RequestContext, false);
  9.             string buttonHtml = string.Format("<input type=\"button\" title=\"{0}\" value=\"{0}\" onclick=\"location.href='{1}'\" class=\"button\" />",buttonText,href);
  10.             return new MvcHtmlString(buttonHtml);
  11.         }
  12.     }
  13. }

Example Usage:

  1. @Html.ActionLinkButton("Add", "AddSiteFromDistrict", "SiteMaintenance", new RouteValueDictionary(new { districtID = @Model.DistrictID }))
posted on Monday, 07 November 2011 08:53:15 (Central Standard Time, UTC-06:00)  #    Comments [2]