MVC Related Posts

Site updated with MVC

In case you haven't been following along the recent posts, I've been exploring ASP.Net MVC recently using this site as a guinea pig. Today I deployed the updated bits and hope you find them to be an improvement on the older site. I've tried hard to keep backwards compatibility with the old site links via some tricks in the Routing engine. Please take a look around and let me know if you find any links that aren't quite working correctly. Please be patient as it may be a bit before all of the legacy kinks are worked out.

As with the previous versions of this site, I plan to make this code base available, but need to clean it up before releasing it.

Posted on 7/24/2009 10:29:00 AM - Comments(2)
Categories: MVC LINQ

MVC Sitemap Navigation with XML Literals

As I continue re-writing this site to use MVC, I find more substructures that I can refactor easily. In the original implementation for the menu, I used the asp:Menu control. As I was working to theme the site, I had problems getting it to work acceptably with CSS styles. I also didn't like the reliance on tables.

In an effort to improve on it, I found the method of using unordered lists with list items for the menus (<ul> <li>). I then moved to a modified version of the UL SiteMap menu discussed by Byant Likes.

In moving to MVC, I was looking for a better option and found one on the MVC tutorial site. This builds the menu with a StringBuilder. I had a couple problems with this implementation however:

  • By using a StringBuilder, you don't get compiler assistance in validating the markup.
  • The implementation doesn't handle security trimming.
  • It only handles a single level of menu items.
  • For Each loops seem to be an anti-pattern for me with my LINQ experience.

To fix these issues, I figured we could re-write this relatively easily using XML Literals and VB with a recursive call to handle the potential n-levels of SiteMenuItems possible in the SiteMap XML specification. Even without adding any of the additional functionality, we can drastically simplify the implementation in the MVC Tutorial by re-writing it in XML Literals in VB:


Dim xMenu1 = <div class="menu">
                <ul id="menu">
                   <%= From node In SiteMap.RootNode.ChildNodes _
                                    .OfType(Of SiteMapNode)() _
                       Select <li class=<%= if(SiteMap.CurrentNode Is node, _
                                               "active", _
                                               "inactive") %>>
                                 <a href=<%= % node.Url>>
                                    <%= helper.Encode(node.Title) %></a>
                     </li> %>
                 </ul>
              </div>
Return xMenu1.ToString()

There are a couple things to point out here. First, the SiteMap.RootNode.ChildNode property returns a list of Object rather than SiteMapNode items. We can fix that by purposely limiting the results and strongly typing it at the same type using the .OfType(Of T) extension method.

Second, We eliminate the for each loop by projecting the new li items in the select clause. In this, we use the ternary If to determine if the node in the iteration is the same as the one selected. If it is, we apply the "active" style. The rest is relatively straight forward.

At this point, we have fixed issues 1 and 4 from my objection list above. Next, let's deal with the n=levels of menu items. To do this, we will replace the LINQ query with a recursive function call. The Menu helper extension now looks like the following:


Imports System.Runtime.CompilerServices

Namespace Helpers
    Public Module MenuHelper
        <Extension()> _
        Public Function Menu(ByVal helper As HtmlHelper) As String
            Dim xMenu = <div class="menu">
                            <ul id="menu">
                                <%= AddNodes(SiteMap.RootNode, helper) %>
                            </ul>
                        </div>
    
            Return xMenu.ToString()
        End Function
    End Module
End Namespace

Now we have an extremely clean and concise XML building of the basic structure. The hard work comes in the AddNodes method.


Private Function AddNodes(ByVal currentNode As SiteMapNode, ByVal helper As HtmlHelper) _
                 As IEnumerable(Of XElement)

   Return From node In currentNode.ChildNodes.OfType(Of SiteMapNode)() _
          Select <li class=<%= If(SiteMap.CurrentNode Is node, "active", "inactive") %>>
                     <a href=<%= node.Url %>><%= helper.Encode(node.Title) %></a>
                     <%= If(node.ChildNodes.Count > 0, _
                          <ul class="child">
                              <%= AddNodes(node, helper) %>
                          </ul>, Nothing) %>
                  </li>
End Function

Essentially this function moves the LINQ projection we did in the original re-write into a separate method. This method takes a SiteMapNode and returns rendered lists of XElements. In addition to generating the HTML for the current node's children, we also check to see if the respective child in turn has  are any child nodes and if so, we create a new unordered list and recursively call back into AddNodes to render those children as well. By using a recursive function, we can handle any level of children nodes that the SiteMap throws at us.

In order to add security trimming, we simply need to add a where clause. The SiteMap contains a non-generic IList that happens to contain strings. To use LINQ on this, we use the .Cast method to turn it into a generic IEnumerable(Of String). With that in place, we can use the .Any extension method to find if any of the roles specified in the SiteMap source meet the criteria where the HttpContext's current user is in at least one of those roles. We'll also check to see if there are no roles specified for that node (which means that it is not trimmed and all users can access the node). Here is the revised body of the AddNodes method:


Return From node In currentNode.ChildNodes.OfType(Of SiteMapNode)() _
       Where node.Roles.Count = 0 OrElse _
             node.Roles.Cast(Of String).Any(Function(role) _
                                            HttpContext.Current.User.IsInRole(role)) _
       Select <li class=<%= If(SiteMap.CurrentNode Is node, "active", "inactive") %>>
                  <a href=<%= node.Url %>><%= helper.Encode(node.Title) %></a>
                  <%= If(node.ChildNodes.Count > 0, _
                      <ul class="child">
                          <%= AddNodes(node, helper) %>
                      </ul>, Nothing) %>
              </li>

That's it. The only thing left is to manage the css styles to handle the fly-outs. You should be able to find plenty of sites that demonstrate how to set that up. If you can thinq of any enhancements to this, let me know.

Posted on 7/22/2009 8:41:00 PM - Comments(2)
Categories: MVC VB Dev Center VB

Disable Historical Debugger when using MVC with VS 2010 beta1

I've had a bit of down time between contracts recently and have been taking the opportunity to learn some technologies that I haven't had time to get into before. Since I've read so much about it, I thought I would try out ASP.Net MVC. Since it was just for fun, I figured I'd bite the bullet and try it under VS 2010.

I build a small sample following the tutorials at http://www.asp.net/learn/mvc/, however when I try to run it in VS 2010, the app crashes on me. There's enough "Magic" going on inside MVC, including the routing engine and dynamic loading of the controllers and views that trying to debug MVC is challenging enough when the IDE behaves. When it doesn't it makes life significantly more problematic. Naturally VS hard crashes rather than breaking in my code to let me figure out what's going wrong.

It turns out there wasn't a problem in my code, but rather an issue with MVC and the Historical Debugger which is turned on by default in VS 2010. To fix the issue, open the Option dialog (under Tools - Options) and locate the Historical Debugger tab. Uncheck the "Enable Historic Debugging" option.

Historical Debugging Option Screen

Joe Cartano of the ASP team assures us that this will be fixed in Beta 2, so hopefully this is only a temporary situation. Maybe next time I'll remember to read the release notes completely before banging my head against the wall.

Posted on 7/8/2009 3:06:00 PM - Comments(0)
Categories: VS 2010 MVC