Refactoring the ASP.NET MVC project template authentication – Part 3
In part 3 I wanted to clean up a few small details. And once again I’ll be focusing on the server side .net code and saving the client side javascript for another post.
In this post I’ll be making use of the ASP.NET MVC Futures codebase which you can get here.
One of the complaints that is heard about MVC summed up by the following comment over at Los Techies “…I‘m not ready to start putting clunky C# code in my views, like asp.net MVC is using, feels like legacy asp all over again”. And yes many examples of this coding style exist including the LoginUserControl.ascx in the example MVC project.
1: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="LoginUserControl.ascx.cs" Inherits="MvcApplication1.Views.Shared.LoginUserControl" %>
2: <% if (Request.IsAuthenticated) { %>
3: Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>!
4: [ <%= Html.ActionLink("Logout", "Logout", "Account") %> ]
5: <% } else { %>
6: [ <%= Html.ActionLink("Login", "Login", "Account") %> ]
7: <% } %>
And I have to agree with the commenter this code is noisy and far from ideal. First we have a lot of that clunky code and second we have some Magic Strings for creating links to controller methods. Those magic strings can be dealt with using the generic ActionLink in the MVC Futures. Lets take a look at the refactored example.
1: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="LoginUserControl.ascx.cs" Inherits="MvcApplication1.Views.Shared.LoginUserControl" %>
2:
3: <%= Html.IfAuthenticated("Welcome <b>{0}</b>!", Html.Encode(Page.User.Identity.Name)) %>
4: [ <%= Html.LoginLink<LoginController>(x => x.Login(), x => x.Logout(), "Login", "Logout") %> ]
Now lets look at these extensions methods:
1: public static class LinkExtensions {
2: public static string LoginLink<T>(this HtmlHelper Html, Expression<Action<T>> loginAction, Expression<Action<T>> logoutAction, string loginText, string logoutText) where T : System.Web.Mvc.Controller {
3: if(Html.ViewContext.HttpContext.Request.IsAuthenticated) {
4: return Html.ActionLink<T>(logoutAction, logoutText);
5: }
6:
7: return Html.ActionLink<T>(loginAction, loginText);
8: }
9:
10: public static string IfAuthenticated(this HtmlHelper Html, string output, params object[] parameters) {
11: return (Html.ViewContext.HttpContext.Request.IsAuthenticated) ? String.Format(output, parameters) : string.Empty;
12: }
13: }
As you can see by using Html Extension methods we are able to move the if statements out of the view. Also by using generics we have eliminated the magic strings that configure what controller and actions to call. Now if we use our refactoring tools to rename any of our action methods the views will be updated as well.
If you are looking for something that looks even cleaner you might want to check out the Spark ViewEngine.
Let me know your thoughts…
Be sure to check out the rest of this series of posts: