ASP.NET MVC + Entity Framework + IIS 7.0 + DI + REST + Ajax + Dojo = SlipStream 2

by msimpson 5/2/2008 10:18:00 AM

For the past few weeks I've been experimenting with a number of new and not-so-new technologies that seem to combine very well.  The technologies include:

  • ASP.NET MVC:  This is a new framework from Scott Guthrie's team at Microsoft that provides a real model-view-controller implementation for ASP.NET.  The framework includes a robust URL routing engine that is flexible enough to do real RESTful routing, and can generate URLs from the routes (allowing you to change your routing later without breaking your app).  You don't need to use MVC to use the routing engine either.
  • IIS 7.0: The new version of IIS is lean and modular, and supports integration with ASP.NET applications.  This allows individual apps to plug into the processing pipeline and completely take over processing from IIS.  For me, this allows custom authentication plus clean RESTful URLs with no file extensions.
  • ADO.NET Entity Framework:  This is the new ORM tool from Microsoft.  It can reverse-engineer your database and generate a data model with mapping between the physical database, logical data model and entity objects.  I and a colleague of mine have written a handful of serious ORM frameworks, and although so far I've really only kicked EF's tires, it seems to do everything I need.  A key feature for me is that it supports querying using LINQ to SQL (among other methods).
  • DI: Dependency Injection is a technique for decoupling the components of an application to enable future extensibility and better testing.  I haven't started implementing this yet in this app, but I plan to very soon.  A couple of frameworks I'm looking at are Unity and NInject.
  • REST: Not so much a technology as a mindset, REST has intrigued me ever since I read RESTful Web Services a few months ago.  Microsoft tools haven't supported it well at all - until now.  I thought this was a good time to explore an alternative (OK, "non-Microsoft") way to design and build web applications.
  • Ajax:  I've used Ajax in web apps for several years now, but only for specific, narrowly-defined purposes.  I wanted to build an app that leveraged it to the hilt, and an app based on RESTful design seemed to present the best opportunity to do so.
  • Dojo:  This is a client-side Javascript framework that provides a cornucopia of capabilities including Ajax support, widgets, fancy UI effects, event wiring, etc. etc.  In many cases it can eliminate the need for server-side controls.
  • CSS:  OK, this is not new, and I've used CSS for years; but I wanted to create an app that leverages CSS for all style information, and avoids cluttering the document with it.  In particular, I wanted to avoid using tables for layout, except for tabular data.

For my guinea pig, I chose to reimplement the web application that supports my audio product for Second Life, SlipStream.  The new version will be completely web-driven, eliminating almost all notecard configuration within the device in-world.  The system must do the following:

  • Allow management of customers, plus their devices, playlists, managers, etc. from both a browser-based web UI and scripts in Second Life (SL);
  • Allow indirect but real-time searching of the Shoutcast directory;
  • Provide configuration and stream information to device scripts in SL;
  • Track the current state of devices in SL, based on the calls they make to the application.

The requirement to support both SL script clients and web browsers causes some issues.  First, the scripting language in Second Life, LSL, is pretty limited when it comes to making HTTP calls, despite being compiled to and run on Mono (this feature is currently in an almost-production stage).  You can't, for example, set custom request headers or check the response headers, and there's no facility for parsing JSON or XML data returned by the call.  Plus, the size of data that can be sent and received is severely restricted, to 255 bytes per call last time I checked.  And HTTP requests are throttled to 100 per 100 seconds per object in SL.

I'm dealing with most of this by carefully designing the resources I expose and the representation formats I use when talking to a script client in SL.  But another wrinkle is authentication - SL scripts will need to authenticate on every call by passing the appropriate query string parameters.  Browser clients, however, are asked to log in only when they try to access a restricted resource, and they will get an authentication token they can send back on subsequent requests.  The authentication scheme is pretty much completely custom as a result.  It consists of an HTTPModule that checks for the necessary credentials, and establishes a custom security principal and identity for the current request. 

Authorization is done pretty much the normal way.  The app only has three classes of users:  anonymous users, authenticated normal users, and administrators.  For simple, "static" authorization, the controller action methods use a PrincipalPermission attribute to check membership in a role.  However, this type of checking is rarely enough.  Typically I would provide another layer of mapping for static authorization: instead of Users <-> Roles, I would have Users <-> Groups <-> Permissions.  This can be done using the .NET administrative tools, but most people aren't aware of that and don't use them.  Anyway, for this app, the simple role-based authorization suffices for static authorization.

But many apps also have what I call "dynamic" authorization - that is, authorization that is dependent on current application state, typically the resource that the user is trying to access.  An example of this would be a system where user Fred can only access documents he created, but not other people's documents.  In this case, a simple role check won't cut it - you need to find out who authored the document being requested, and then see if that matches the current user.  Anyway, this application has some scenarios like that, and so I have some helper code built into my controllers to do this type of checking.

Just for grins, I also want to support conditional HTTP GET on the resources and actions where it's appropriate (which as it turns out, aren't that many, but hey).  So, I wrote some code in a base class for my views that tacks on the appropriate response headers based on the timestamp of the current resource from my database, and examines incoming headers to see if it can optimize the response body away. 

The default routes provided in the MVC templates from Microsoft are not (IMHO) completely RESTful - they include the action in the URL:  for example /{controller}/{action}.  I felt that the action should be expressed by the HTTP method used to make the request, so I reworked the routes accordingly:  /{controller}/{id}/{format}, for example. 

The application is completely stateless; that is, it does not use session state at all.  This allows it to keep working through a restart - the user's authentication token will be accepted on the next request after a restart, and the user never knows the difference.  The user cannot fake an authentication token because it's encrypted on the server using the server's private key;

On the client side, the app uses CSS for all styling except tabular data, including form layout.  All the forms submit via Ajax, eliminating postbacks and allowing things like password fields to retain their values when you submit.  I'm using Dojo for the Ajax calls and for a few other things here and there... I'll be looking at expanding to use it for all my form widgets, but whether I stick to that approach will depend on whether the resulting code is XHTML- and CSS-compliant.

So far, I have the basics of the application working:  authentication, authorization, fetching data, supplying forms, handling form submissions, etc.  I need to do some more styling and finish building out the rest of the features, but it's starting to come together.  When I get the app done, then it will be time to build out the device scripts in LSL, package the product and start selling! 

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , , , , , , ,

Software | Second Life

Related posts

Comments

5/3/2008 4:34:13 AM

Josh Gough

Mike, this is a great post. I have toyed around with many of those technologies as well like Dojo and RESTful design and am (still) reading that RESTful Web Services book. Web Services will be a big topic for us at GB soon.

Here are some additional links about MVC and RESTful design:

Polymorphic Podcast MVC Resources and interview:
http://polymorphicpodcast.com/shows/mvcresources/

ASP.NET MVC in Action book by Jeff Pallermo:
http://www.manning.com/palermo/

Follow the MVC Contrib (http://www.mvccontrib.org) project on twitter:
http://twitter.com/mvccontrib

Follow and add links to the del.ici.ous tag cloud for ASP.NET MVC:
del.icio.us/.../

Aaron Lerch on Unifying Web "Sites" Web Services with ASP.NET MVC:
www.aaronlerch.com/.../
-- This is exactly the situation you and I exchanged emails about. He discusses also practical reasons why you would not necessarily want to do such a thing. I chatted with him on his blog widget. Perhaps a viable solution is to strive for uniformity of the URL design, allowing deviations where needed, but not necessarily run them on the same code-base or same server.

Roy Fielding on Web Architecture:
roy.gbiv.com/.../on-software-architecture

I think you could actually write a book on this the way you are writing this application in a very real-world way, mixing and matching "official" Microsoft technologies with third party components.

As far as the gripes you have about {action}, I expressed this concern to Scott Hanselman and Scott Guthrie. Here is what Scott Guthrie wrote back to me on the subject:

-----

Hi Josh,

Yep - you will definitely be able to enable RESTful based applications using ASP.NET MVC. We are actually looking to add a routes.MapResource() helper method in a future preview that will make automatically wiring up REST based route resources easy with ASP.NET MVC (you can use the MVCContrib project today to also help with this).

Hope this helps!

Scott
________________________________________
From: Joshua Gough
Sent: Wednesday, April 23, 2008 9:37 PM
To: Scott Guthrie
Subject: Functionality in ASP.NET MVC to support Web HTML and Web Services on a single URL strcuture, similar to Rails?

Hello Scott,

Just reading through your notes on your blog about the MVC refresh.

I wanted to call out one part and ask you a question:

Quote:

"Returning ActionResult Objects from Action Methods

It enables some nice composition scenarios where a FilterActionAttribute can take the result of an action method and modify/transform it before executing it. For example: a "Browse" action on a ProductCatalog controller might return an RenderActionResult that indicates it wants to render a "List" view of products. A FilterActionAttribute declaratively set on the controller class could then have a chance to customize the specific "List" view template rendered to be either List-html.aspx or List-xml.aspx depending on the preferred MIME type of the client. Multiple FilterActionAttributes can also optionally be chained together to flow the results from one to another."

I had sent the following links to ScottHa about how some folks are supporting both HTML Web Apps and Web Services on a single URL structure with their RoR apps. It sounds like what you describe is definitely going to help in that respect as well.

I've been reading the book "RESTful Web Services" as well as reading up on Roy Fielding's blog and thoughts lately and it seems to me that ASP.NET<http://ASP.NET> MVC is primed to support many very nice scenarios for "linkable" applications, or "Hypertext as the Engine of Application State" as Fielding would say.
-----

Josh Gough us

Add comment


(Will show your Gravatar icon)  

  Country flag





Live preview

8/27/2008 4:48:31 PM

Powered by BlogEngine.NET 1.2.0.0
Theme by Mads Kristensen


Calendar

<<  August 2008  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar

Pages

    Recent posts

    Recent comments

    Disclaimer

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

    © Copyright 2008

    Sign in