.NET Dojo: ASP.NET MVC
July 22, 2008 @ 05:37 PM

First, what's this .Net Dojo stuff? Well, here it is ... it is a new series of events (I'm hoping monthly) that we will be having monthly to help developers hone and sharpen their .Net Kung Fu. It will be a combination of lecture and hands-on labs ... lecture to explain the concepts (of course) and hands-on to let you get your fingers dirty playing with the technology. Since it is hands-on, you will need to bring a laptop to do the labs and (possibly) install some additional prerequisites before the session (these will be listed, of course). They will be held at the Houston Microsoft office from 1:00 PM to 5:00 PM and cover a wide range of .Net topics. I'm also hoping to be able to get some of the technical leaders here in Houston to deliver some of the sessions ... so that you'll be learning from the best around.

Ben Scheirman of Sogeti has volunteered to deliver the very first .Net Dojo on the ASP.NET MVC Framework. (Didn't I tell you that I wanted to get the best around?) Here are the details:

Overview: ASP.NET MVC is one of the key new features that will be included in .NET Framework 3.5 Service Pack1. It provides a framework that enables you to easily implement the model-view-controller (MVC) design pattern in your web applications, helping you build loosely-coupled, pluggable components for application design, logic and display. While not a replacement for traditional ASP.NET WebForms, ASP.NET MVC does provide a compelling alternative for developing web applications and better facilitates test driven development (TDD) in web applications. This workshop will dig into what ASP.NET MVC is, what it does, and how it is different from WebForms.

What you will learn: Through a combination of lecture and hands-on labs, attendees will learn how to create ASP.NET MVC applications using Visual Studio 2008 and how to work with the key components of an ASP.NET MVC application. Additionally, they will learn how to test their MVC components and applications using TDD principles.

Prerequisites: To fully participate in this workshop, attendees will need the following:

  • An open mind
  • A working knowledge of ASP.NET, C#, HTML and CSS.
  • A laptop with:

Sign up here ... but hurry ... space is limited!

Hope to see you there ...
 
C# SIG Presentation
July 22, 2008 @ 09:59 AM

I have uploaded (finally) the presentation that I delivered to the C# SIG last Wednesday, July 16 to my SkyDrive. You can download it here.

I did make some little modifications to it though ... and they address one of the outstanding questions of the evening ... how does ASP.NET Role-based security work with ASP.NET Dynamic Data? Well, it's pretty simple and straightforward, actually.

Some background first. ASP.NET Dynamic Data uses SP1's UrlRoutingModule to map requests to the correct table ... with the name of the table appearing as a directory on the web site. So, when editing the "Products" table, the URL will be http://mydatasite/Products/[NameOfView]. Adding authentication and authorization for the entire site is a no-brainer; just add the authorization element into the web.config with the proper entries and you're done. Doing it for individual tables is just about as easy; in this case, you just need to add a location element to your web.config and configure the settings for the location. For example:

<location path="products">
  <system.web>
    <authorization>
      <allow roles="Products"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>

In this case, we have defined a role called "Products" that can edit (and view, of course) the products table, but no one else can. This will behave exactly as would a "real" folder in any ASP.NET web site using role-based authorization with the built-in RoleManager (regardless of where the roles are actually coming from!).

As I said, I added this to the demos that I uploaded. All access to the site is authenticated; no anonymous users are allowed. There are 2 roles - Products, which can edit the Products table and HR, which can edit the Employees table - and 3 users. All users have the same password (Pass@word1). Here's the breakdown:

User ID Role
User1 HR
User2 Products
User3 <No Role>

 

You can, of course, get a bit more complicated than this, but you'd have to do some additional customization of the different pages to do that.


 
CORRECTION: C# SIG Tomorrow
July 14, 2008 @ 03:05 PM

In my previous post, I said that I'd be talking about ADO.NET Data Service. I'm not sure what happened to my brain, but that's not what I told Harry. I will actually be talking about ADO.NET Dynamic Data. Hope to see you there tomorrow!!


 
Cool way to do ASP.NET Caching with Linq
July 11, 2008 @ 06:18 PM

OK, well, I think it's cool (and since the mind is its own place ...). I've been a big fan of ASP.net's cache API since I found out it way back in the 1.0 beta. It certainly solves something that was problematic in ASP "Classic" in a clean, elegant and darn easy to use way. Unfortunately, not a lot of folks seem to know about it. So I'll start with a little overview of ASP.net caching.

As the name implies, it's a cache that sits server side. All of the relevant, .Net-supplied classes are in the System.Web.Caching namespace and the class representing the cache itself is System.Web.Caching.Cache. You can access it from the current HttpContext (which you'll see). The management of the cache is handled completely by ASP.net ... you just have to add objects to it and then read from it. When you add to the cache, you can set options like dependencies, expiration, priority and a delegate to call when the item is removed from the cache. Dependencies are interesting ... they will automatically invalidate (and remove) the cache item based on notification from the dependency. ASP.net 1.x had only 1 cache dependency class (System.Web.Caching.CacheDependency) that allowed you to have a dependency on a file, another cache item, and array of them or another CacheDependency. Framework 2.0 introduced System.Web.Caching.SqlCacheDependency for database dependencies and System.Web.Caching.AggregateCacheDependency for multiple, related dependencies. With the AggregateCacheDependency, if one of the dependencies changes, it item is invalidated and tossed from the cache. Framework 2.0 also (finally) "unsealed" the CacheDependency class, so you could create your own cache dependencies. With expiration, you can have an absolute expiration (specific time) or a sliding expiration (TimeSpan after last access). Priority plays into the clean-up algorithm; the Cache will remove items that haven't expired if the cache taking up too much memory/resources. Items with a lower priority are evicted first. Do yourself a favor and make sure that you keep your cache items reasonable. Your AppDomain will thank you for it.

ASP.net also provides page and partial-page caching mechanisms. That, however, is out of our scope here. For the adventurous among that don't know what that is ...

So ... the cache ... mmmmm ... yummy ... gooooood. It's golly-gee-gosh-darn useful for items that you need on the site, but don't change often. Those pesky drop-down lookup lists that come from the database are begging to be cached. It takes a load off the database and is a good way to help scalability - at the cost of server memory, of course. (There ain't no free lunch.) Still, I'm a big fan of appropriate caching.

So ... what's the technique I mentioned that this post is title after? Well, it's actually quite simple. It allows you to have 1 single common method to add and retrieve items from the cache ... any Linq item, in fact. You don't need to know anything about the cache ... just the type that you want and the DataContext that it comes from. And yes, it's one method to rule them all, suing generics (generics are kewl!) and the Black Voodoo Majick goo. From there, you can either call it directly from a page or (my preferred method) write a one-line method that acts as a wrapper. The returned objects are detached from the DataContext before they are handed back (so the DataContext doesn't need to be kept open all) and returned as a generic list object. The cache items are keyed by the type name of the DataContext and the object/table so that it's actually possible to have the same LinqToSql object come from two different DataContexts and cache both of them. While you can load up the cache on application start up, I don't like doing that ... it really is a killer for the app start time. I like to lazy load on demand. (And I don't wanna hear any comments about the lazy.)

Here's the C# code:

/// <summary>
/// Handles retrieving and populating Linq objects in the ASP.NET cache
/// </summary>
/// <typeparam name="LinqContext">The DataContext that the object will be retrieved from.</typeparam>
/// <typeparam name="LinqObject">The object that will be returned to be cached as a collection.</typeparam>
/// <returns>Generic list with the objects</returns>
public static List<LinqObject> GetCacheItem<LinqContext, LinqObject>()
    where LinqObject : class
    where LinqContext : System.Data.Linq.DataContext, new()
{
    //Build the cache item name. Tied to context and the object.
    string cacheItemName = typeof(LinqObject).ToString() + "_" + typeof(LinqContext).ToString();
    //Check to see if they are in the cache. 
    List<LinqObject> cacheItems = HttpContext.Current.Cache[cacheItemName] as List<LinqObject>;
    if (cacheItems == null)
    {
        //It's not in the cache -or- is the wrong type. 
        //Create a new list.
        cacheItems = new List<LinqObject>();
        //Create the contect in a using{} block to ensure cleanup. 
        using (LinqContext dc = new LinqContext())
        {
            try
            {
                //Get the table with the object from the data context.
                System.Data.Linq.Table<LinqObject> table = dc.GetTable<LinqObject>();
                //Add to the generic list. Detaches from the data context. 
                cacheItems.AddRange(table);
                //Add to the cache. No absolute expirate and a 60 minute sliding expiration
                HttpContext.Current.Cache.Add(cacheItemName, cacheItems, null,
                    System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60),
                    System.Web.Caching.CacheItemPriority.Normal, null);
            }
            catch (Exception ex)
            {
                //Something bad happened.
                throw new ApplicationException("Could not retrieve the request cache object", ex);
            }
        }
    }
    //return ... 
    return cacheItems;
}

And in VB (see, I am multi-lingual!) ...

''' <summary>
''' Handles retrieving and populating Linq objects in the ASP.NET cache
''' </summary>
''' <typeparam name="LinqContext">The DataContext that the object will be retrieved from.</typeparam>
''' <typeparam name="LinqObject">The object that will be returned to be cached as a collection.</typeparam>
''' <returns>Generic list with the objects</returns>
Public Shared Function GetCacheItem(Of LinqContext As {DataContext, New}, LinqObject As Class)() As List(Of LinqObject)
    Dim cacheItems As List(Of LinqObject)

    'Build the cache item name. Tied to context and the object.
    Dim cacheItemName As String = GetType(LinqObject).ToString() + "_" + GetType(LinqContext).ToString()
    'Check to see if they are in the cache. 
    Dim cacheObject As Object = HttpContext.Current.Cache(cacheItemName)

    'Check to make sure it's the correct type.
    If cacheObject.GetType() Is GetType(List(Of LinqObject)) Then
        cacheItems = CType(HttpContext.Current.Cache(cacheItemName), List(Of LinqObject))
    End If

    If cacheItems Is Nothing Then
        'It's not in the cache -or- is the wrong type. 
        'Create a new list.
        cacheItems = New List(Of LinqObject)()
        'Create the contect in a using   block to ensure cleanup. 
        Using dc As LinqContext = New LinqContext()
            Try
                'Get the table with the object from the data context.
                Dim table As Linq.Table(Of LinqObject) = dc.GetTable(Of LinqObject)()
                'Add to the generic list. Detaches from the data context. 
                cacheItems.AddRange(table)
                'Add to the cache. No absolute expirate and a 60 minute sliding expiration
                HttpContext.Current.Cache.Add(cacheItemName, cacheItems, Nothing, _
                    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60), _
                   CacheItemPriority.Normal, Nothing)
            Catch ex As Exception
                'Something bad happened.
                Throw New ApplicationException("Could not retrieve the request cache object", ex)
            End Try
        End Using
    End If

    'return ... 
    Return cacheItems
End Function

 

The comments, I think, pretty much say it all. It is a static method (and the class is a static class) because it's not using any private fields (variables). This does help performance a little bit and, really, there is no reason to instantiate a class if it's not using any state. Also, note the generic constraints - these are actually necessary and make sure that we aren't handed something funky that won't work. These constraints are checked and enforced by the compiler.

Using this to retrieve cache items is now quite trivial. The next example shows a wrapper function for an item from the AdventureWorks database. I made it a property but it could just as easily be a method. We won't get into choosing one over the other; that gets religious.

public static List<StateProvince> StateProvinceList
{
    get
    {
        return GetCacheItem<AdvWorksDataContext, StateProvince>(); 
    }
}

And VB ...

Public ReadOnly Property StateProvinceList() As List(Of StateProvince)
    Get
        Return GetCacheItem(Of AdvWorksDataContext, StateProvince)()
    End Get
End Property

Isn't that simple? Now, if you only have one DataContext type, you can safely code that type into the code instead of taking it as a generic. However, looking at this, you have to admit ... you can use this in any ASP.net project where you are using Linq to handle the cache. I think it's gonna go into my personal shared library of tricks.

As I think you can tell, I'm feeling a little snarky. It's Friday afternoon so I have an excuse. BTW ... bonus points to whoever can send me an email naming the lit reference (and finish it!) in this entry. Umm, no it isn't Lord of the Rings.


 
Presenting at the C# SIG
July 11, 2008 @ 01:44 PM

Boy, I'm on a blogging roll today, eh? I've got one more in the works that'll go out by the end of the day too.  The ol' keyboard is taking quite the pounding. :-)

I announced this last night at HDNUG, but Bill reminded me that some folks may not remember it all (there was a lot going on last night) and besides, I meant to blog it anyway.

Bobby Schaffer's Beginning C# SIG and Harry Nystrom's C# SIG will be meeting at the Microsoft offices on Tuesday, July 15. Bobby's SIG will be kicking off at 6:00 PM, where he will be talking about Inheritance in C#. Harry's SIG kicks off, I think, at 7 (maybe 7:30) and I will be there talking about ADO.NET Data Services, a killer-cool piece of .NET Framework and Visual Studio SP1, currently in beta. For each SIG, I'll also be giving away a copy of Visual Studio 2008 Professional ... so, yes, that's 2 copies of Visual Studio 2008 Pro!!!

Food? Hmmm ... yeah ... typically it's BYOF (that's bring your own food). But ... ya know ... yeah, what the hell ... I'll spring for pizza & drinks.


 
 
"