I came across a situation where I wanted to use MvcContrib’s Pagination features.  My project consists of an AutoMapper Attribute that performs the actual mapping of my domain to its view model counterpart.

Given that my view is of type IEnumerable<TagDisplayModel>, and my controller passes LazyPagination<Tag> to View(), something like Html.Grid(Model).AutoGenerateColumns().Render() works as expected.  However, adding Html.Page((IPagination)Model) to our view fails.

AutoMapper is a delicate worker, doing only as it knows how to do.  It knows how to handle IEnumerable just fine, performing a mapping for each item in the enumeration.  However, it knows nothing about MvcContrib’s IPagination interface, nor how to map to a concrete one.  When we try to specify a mapping from IPagination<Tag> to IPagination<TagDisplayModel>, nothing seems to happen (or a type casting error… I forget).

Luckily, AutoMapper’s API provides a hook for such occasions.  Enter: ConstructUsing().  This method provides a hook for us to specify how it should resolve the destination class.  MvcContrib Pagination, by default, uses LazyPagination<T>.  It works, but the translation gets hairy if we try to keep up with it.  If the source does not execute the contained IQueryable and perform the actual pagination, it will be lost during the mapping process.  Instead, we can use CustomPagination, whose constructor takes an IEnumerable<T>, as well as paging information.

Because the actual code is too ugly (and the method signature too long to fit in this blog), I have put it up on CodePaste.NET. (BEWARE:  The resulting generic code is not for the faint of heart)

Using this extension method, create a map for your paginated types:

AutoMapper.Mapper

    .CreateMap<IPagination<Tag>, IPagination<TagDisplayModel>>()

    .ConstructPagination();

 

Then, the following action method will work as you would expect it to:

[AutoMap(typeof(IPagination<Tag>),typeof(IPagination<TagDisplayModel>))]

public ActionResult Index(int page = 1)

{

    var tags = _readonlySession.All<Tag>().AsPagination(page);

    return View(tags);

}

 

Thus, allowing you to call <%= Html.Pager((IPagination)Model) %> inside the view without error (also remember that your view is IEnumerable<TagDisplayModel>.

Tuesday, August 10, 2010 9:35:00 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
ASP.NET MVC | AutoMapper | MvcContrib

I’m sure we’ve all experienced this error, and even wasted time on trying to pick apart what is actually happening:

The model item passed into the dictionary is of type 'MvcApplication3.Models.ClassA', but this dictionary requires a model item of type 'MvcApplication3.Models.ClassB'.

At first glance, you say “Gee, must have passed the wrong type to my view,” naively double checking your handy work:

<% Html.RenderPartial("ClassB", Model.B); %>

Yup, that’s what you wanted.  Render the darn partial for ClassB using Model.B.  This should work, but why is it throwing the error?  So, you check the partial itself to make sure it’s strongly typed:

Inherits="System.Web.Mvc.ViewUserControl<MvcApplication3.Models.ClassB>"

Nope, that’s right too.  How could this be?  You’re certainly bordering on apoplexy at this point, so you check the class declaration for Model (which is type ClassA):

public class ClassA
{
public string Name { get; set; }
public ClassB B { get; set; }
}

Clearly, something has gone awry.  B absolutely is the correct type.  What is the value of Model.B at runtime?  So you fire up the debugger, and realize that B is null.

A quick search on StackOverflow, and I found this solution:

“…I think the problem you are getting is a result of the RenderPartial method using the calling (view)'s model to the partial view when the model you pass is null.. you can get around this odd behavior by doing:”

<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %>

 

That solution doesn’t sit right with me, though.  It doesn’t make any sense.  For one, it’s a kludge.  Second, the way I see it, if the model passed into RenderPartial is null, then I wouldn’t expect it to render anything.  As such, I came up with some helper methods that wrap RenderPartial, and include that behavior.

The helper methods have kind of a wide range of syntax, mainly to accommodate various coding styles.  They all do about the same thing.

This call arbitrarily checks the model being passed in, and only calls RenderPartial if it is not null:

<% Html.TryRenderPartial("ClassB", Model.B); %>

The next two calls are basically identical, and you can choose to use whichever you want. One takes a lambda, and passes in the Model for you to base the condition off of, or you can provide a boolean expression:

<% Html.RenderPartialIf(Model.B != null, "ClassB", Model.B); %>
<% Html.RenderPartialIf(m => m.B != null, "ClassB", Model.B); %>

I chose to add a condition parameter to this concept in favor of business rules that are represented in the views.  The value can be predetermined ahead of time (i.e. ClassB has a “DisplayForUser” property, and call render partial if m => m.B.DisplayForUser).  Best of all, this call helps to keep pesky if blocks out of the view.

RenderPartialHelpers.zip (.61 KB)
Sunday, August 08, 2010 8:53:13 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
ASP.NET MVC

I added the new build of MvcContrib to OpenIdPortableArea today, and committed the new embedded resource routes.  It worked great, and I’m working on some other things with the portable area.

I noticed that the newly embedded images started displaying slightly slower than before.  Maybe it’s all in my head, but it got me thinking about caching nonetheless.  The embedded JavaScript, images, and CSS files are never going to change.  As implemented right now, each request for embedded content requires that the mime type be determined, then locate the resource in the assembly, and then returns a FilePathResult() from the stream of the extracted resource.  With caching, we can prevent this operation from happening on every request.

After thinking of this, I quickly pitched it to Steve Michelotti.  I suggested the possiblity of including [OutputCache(CacheProfile="EmbeddedResource")] on the EmbeddedResourceController’s Index action.  He thought this was an interesting approach, because it leaves the actual cache settings up to the programmer using this particular feature.

So, as with any good idea I gave it a shot.  I found that it worked great, but there was a catch.  Using the OutputCache.CacheProfile property means you absolutely must provide that cache profile in the web.config.  You get a yellow screen of death without it.  With this in mind, adding such a cache profile requirement is just one more mandatory configuration to remember.  How can we make it just work.  Maybe the programmer using this code has some insane reason not to cache these resources.  Whatever the case may be, it would be nice to allow the consumer to opt into the caching mechanism and allow everything to work without it.

First Idea

I quickly created a class called OptionalOutputCacheAttribute, which inherited directly from System.Web.Mvc.OutputCacheAttribute.  The OutputCacheAttribute class uses OnResultExecuting() to serve the cached version of the page.  My plan was to check and see if that particular cache profile exists, and bail if it doesn’t.  Sounds good in theory, but fails in practice.  Why, you say?  Because the OutputCacheAttribute.CacheSettings property is marked internal.  Crap.  So much for that idea.

EDIT: On second thought, this is probably not the real reason. The OutputCacheAttribute doesn't expose its internal OutputCacheParameters object, nor does it expose an Enabled property. It is more likely that ASP.NET deals with caching a little deeper than we can get to, and I suspect it just doesn't support the idea of "maybe cache...". If the OutputCache attribute exists, then cache it. Period.

Second Idea

I have a backup plan, because there just has to be a way to make this work.  Keeping the OptionalOutputCacheAttribute class, what else is there to work with?  I found a way to make it work, but some might find it… unsavory.

The attribute takes a moment and inspects the application’s web.config.  Here’s the code:

/// <summary>

///     Provides optional chaching

/// </summary>

public class OptionalOutputCacheAttribute : OutputCacheAttribute

{

    /// <summary>

    ///     Contains a record of what CacheProfiles have been looked for

    /// </summary>

    protected static Dictionary<string, bool> CacheProfiles { get; set; }

 

    /// <summary>

    ///     Constructor

    /// </summary>

    public OptionalOutputCacheAttribute()

    {

        CacheProfiles = new Dictionary<string, bool>();

    }

 

    /// <summary>

    ///     Determines if the target CacheProfile exists before trying

    ///     to handle the caching of the page.

    /// </summary>

    /// <param name="filterContext"></param>

    public override void OnResultExecuting(ResultExecutingContext filterContext)

    {

        if (!CacheProfiles.Keys.Contains(CacheProfile))

        {

            XDocument xdoc =

                XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "\\web.config");

 

            var profileExists =

                xdoc.Descendants("outputCacheProfiles")

                    .Descendants(XName.Get("add"))

                    .Any(node => node.Attribute(XName.Get("name")).Value == CacheProfile);

 

            CacheProfiles.Add(CacheProfile, profileExists);

        }

 

        if (CacheProfiles[CacheProfile])

            base.OnResultExecuting(filterContext);

    }

}


Using Linq to Xml, it’s fairly trivial to parse the web.config.  It loads perfectly into an XDocument.  Then, it’s easy to see if the “outputCacheProfiles” node has any “add” nodes with a “name” attribute equivalent to the name of the cache profile.

As a way of reducing the frequency of web.config parses, the attribute keeps a static Dictionary.  The first thing to check is if this particular cache profile has been looked up.  If it hasn’t, we need to load the web.config and do the search.  The result is added to the dictionary for later use.

After all of this parsing nonsense, we index into the dictionary and use the bool value.  If the dictionary says that the cache profile exists, we allow the base class (System.Web.Mvc.OutputCacheAttribute) to execute its OnResultExecuting() method.

The Outcome

Using this new OptionalOutputCacheAttribute, we can decorate the EmbeddedResourceController with it:

[OptionalOutputCache(CacheProfile="EmbeddedResource")]

public ActionResult Index(string resourceName, string resourcePath)

{

    // ....

}


My initial tests for this code have proved successful.  What does everyone else think of this?  I was a little iffy on the whole web.config parsing thing (still am).  However, I think this point of extensibility or configurability is more favorable than either A) not providing any support for caching embedded resources, or B) arbitrarily determining cache settings.

Thursday, April 15, 2010 12:48:35 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
ASP.NET MVC | Caching | MvcContrib | OpenIdPortableArea

While working with areas I found that there was some occasional unexpected behavior with the order that routes get mapped.  Calling AreaRegistration.RegisterAllAreas() doesn’t give you any control over which area gets registered first.  If this becomes an issue, you may be so inclined to individually register routes.  Here is an approach:

public static void RegisterAreas(RouteCollection routes)

{

    routes.RegisterArea<BlogAreaRegistration>();

}

 

protected void Application_Start()

{

    //AreaRegistration.RegisterAllAreas();

    RegisterAreas(RouteTable.Routes);

    RegisterRoutes(RouteTable.Routes);

}


I created a RegisterAreas method just like RegisterRoutes.  Here, I can clearly register each Area one by one in the order that I choose.  This is done via an extension method on the RoutesCollection type.

public static class Extensions

{

    public static void RegisterArea<T>(this RouteCollection routes)

        where T : AreaRegistration

    {

        // instantiate the area registration

        AreaRegistration area = Activator.CreateInstance<T>();

 

        // create a context, which is just the name and routes collection

        AreaRegistrationContext context =

            new AreaRegistrationContext(area.AreaName, routes);

 

        // register it!

        area.RegisterArea(context);

    }

}


This extention method creates an instance of the AreaRegistration, and then creates an AreaRegistrationContext, and then calls RegisterArea on the area.

I find that this approach demystifies RegisterAllAreas and focuses on intention over convenience.  Registering areas individually is not always necessary, but it can be helpful to reduce routing confusion.

Wednesday, March 31, 2010 9:55:01 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
Areas | ASP.NET MVC | Routing

Frankly, I’m surprised that it took until page 12 of the jQuery Cookbook to mention putting JavaScript at the bottom of the page before the closing tag.  Pages load faster with the JavaScript at the bottom, and it removes the need to use the ready() function.  This is great advice.  Using a ContentPlaceHolder helps keep the scripts in their optimal location.

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</head>
<body>
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
<asp:ContentPlaceHolder ID="ScriptContent" runat="server" />
</body>
</html>

Then, I’m able to include an element inside of my View and use it freely.  Notice that I was able to include jquery.min.js above the ContentPlaceHolder, which means jQuery will already be warm for any JavaScript in my ScriptContent.
 
<asp:Content ID="Content3" ContentPlaceHolderID="TitleContent" runat="server">
About
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="MainContent" runat="server">
<h2>About</h2>
<div class="about-message"></div>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="ScriptContent" runat="server">
<script type="text/javascript">
      $('.about-message').text("This is the About Page!");
</script>
</asp:Content>

Another added perk to this ContentPlaceHolder approach is that it lets me include other JavaScript libraries that individual Views might depend on.  Pretty simple, but I hope you enjoy it!
Thursday, January 21, 2010 10:00:41 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET MVC | JavaScript | jQuery

Last Saturday, Steve and I attended Philly.NET Code Camp 2009.2. There were about 475 attendees and 12 separate tracks, each with 5 sessions. Here is the list of tracks that I attended:

8:30 AM – Len Smith, “Test Driven Development and Dependency Injection”

10:00 AM – Jess Chadwick, “What’s New and Hot in .NET 4.0”

12:30 PM – Al Katawazi, “Enterprise ASP.NET MVC Application Development”

2:00 PM – Steve Bohlen, “Refactoring to a S.O.L.I.D. Foundation”

3:30 PM – Sara Chipps, “Making Your Personal Projects a Reality”

Overall, the tracks were great. I felt like I was able to get something out of each one. My interests were split, attending two new and upcoming topics and two craftsmanship* topics.

On the topic of all things new and exciting, here are some .NET 4.0 points of interest:

  • DLR (Dynamic Language Runtime)
  • Lazy (lazy instantiation of the generic type)
  • Code Contracts, with Runtime and Compile time checking
  • Covariance and Contravariance
    • IEnumerable b = new IEnumerable();
    • DoSomething(Action func); DoSomething(Base b => b.Value);
  • Named & Optional Parameters
    • A(B b, int i = 0); A(i: 5, b: new B());
  • PLINQ
    • Parallel.ForEach, parallelizes a task across a collection
  • MEF (Managed Extensibility Framework)
    • Provides Extensibility, and Dependency Management
    • Similar to IoC, but not quite there.

Enterprise ASP.NET MVC was interesting because it demonstrated true reuse of components in an MVC application. I was particularly interested in how he set up the MVC application, separating it into several projects. Each project had an extremely specific task:

  • Demo
  • Communication
  • QA
  • Security
  • Static Content

The presenter, Al Katawazi also mentioned referencing a separate project for all Static Content. He referenced a post by Nick Berardi about the Google App Engine that I found very interesting.

More bloggy goodness to come…

Monday, October 19, 2009 11:22:06 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
.NET 4.0 | ASP.NET MVC | Code Camp | Philly.NET

I must say that being able to use the Routing engine in ASP.NET MVC is liberating.  In the traditional web model, your browser is making a request for a file on some remote web server.  The server looks for that file, processes it, and makes a response.  This model works great, but what if you don’t want “.aspx” on the end of your Url?  Beyond that, relative paths on the server can take away from any readability your Urls may have had.  Ever tried explaining query string parameters to the average user?  Painful.

Routing isn’t a new thing by any means, but has recently become a reality in the world of .NET.  There’s a whole namespace dedicated to it in System.Web.Routing.  It allows you to create cognitive, user friendly, and meaningful Urls.  Time for an example.

Sam is on a project, and his program manager instructs him to create a user profile page for their application.  With some special permission, Sam is able to try out ASP.NET MVC.  Does he start coding at the drop of a hat?  Never.  Ever.  Requirements first!  One of the general requirements says “The average user knows what page the Url represents.”  Sam is a good programmer, so his gut reaction is a question: “How would the user know that a Url points to their own profile?”  He writes out on his whiteboard (because all good programmers write things out on a whiteboard):

Traditional ASP.NET Web Forms Way:

http://localhost:1234/Users/UserProfile.aspx?UserID=1&Username=johncoder
http://localhost:1234/Users/UserProfile.aspx?UserID=1

Ideal Ways in ASP.NET MVC:

http://localhost:1234/Users/1/johncoder
http://localhost:1234/Users/1
http://localhost:1234/Users/johncoder <- Possible naming conflicts, but previous two work fine.

Now that Sam knows how he wants to accomplish his goal.  He fires up Visual Studio and creates a new ASP.NET MVC Web Application.  He uses his company’s existing data access layer, which uses LINQ to SQL classes.  Routes point to Action Methods on Controllers, which means that Sam needs a UsersController:

public class UsersController : Controller
{
    public ActionResult Details(int id)
    {
        UserRepository repository = new UserRepository();
        User user = repository.FindUserById(id);
        return View(user);
    }
}


The Details Action Method finds the target User, and a View for the user model.  By default, it will use “Views\Users\Details.aspx”.  There’s more!

public class MyMvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = "" }
        );
    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}


The above code appears in the Global.asax.cs file an MVC application by default.  “Default” is the name being assigned to this given route, and “{controller}/{action}/{id}” is the Url.  The anonymous object in the next line serves as the default values for this route.  Using this route, the Url to a user would look like this:

http://localhost:1234/Users/Details/1

This isn’t quite what he had in mind.  Sam needs to create a new route to facilitate his need.  Here’s what he came up with:

routes.MapRoute(
    "UserProfile",
    "Users/{id}/{username}",
    new { controller = "Users", action = "Details", username = "" }
);


There's a little trickery going on here. Notice that he made no mention of a controller, or even an action method in the Url. Instead, he is taking advantage of the default parameter values by using an anonymous type. Since he didn’t include “{controller}” in his Url, the anonymous object needs to specify which controller to use.  MVC is built to look for "controller" and "action" keywords, and allows you to add your own. In this case, he added "id" and "username" parameters. If the user does not specify an "id" value, the request will not match against this route, and continue searching the RouteCollection until it finds a match.  Since he specified a default “username” as an empty string, the user is not required to enter a username.  The Url in this route has “Users” hard coded into it.  That literally means that the Url has to have “Users” in it.

Another feature of the Routing engine is that it can be used to generate Urls, too.  Sam can change any View in his application to use an HtmlHelper method like so:

<%= Html.RouteLink(user.FullName, "UserProfile", new { id = user.Id, username = user.Username } ) %>


The first parameter is the anchor text. The second is the name of the Route that the engine should use. The properties of the anonymous object are the parameters in the Url.

Don’t you agree that this is much more flexible than relying on the file system to create Urls?  It is my honest opinion that attention to usability details (even as transparent as a Url) produces a professional, high quality product.  By taking advantage of newer features, like the Routing engine, we can escalate our standards to the next level.

Thursday, October 08, 2009 12:11:37 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
ASP.NET MVC | C# | Routing | Usability

John Nelson

mugshot I am a passionate C# Developer working in ASP.NET on an e-commerce solution for ticketing software. I work across all of the application layers, including server side functionality, and client side programming with jQuery and MS Ajax. Although my full time job is in WebForms, I spend many of my off hours working with MVC. I am especially interested in productivity and good programming practices.

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
johncoder.com
Statistics
Total Posts: 41
This Year: 17
This Month: 0
This Week: 0
Comments: 4