Posts tagged with asp.net - page 3

Observations on Microsoft MVC for ASP.NET

Anyone who’s tried to develop large complex web sites with ASP.NET has likely run into many problems covering the page and control life cycle, view state and post backs and subsequent maintainability including the difficulty in creating automated unit tests.

Microsoft, taking a cue from the popularity of Ruby on Rails and subsequent .NET related efforts such as MonoRail, are embracing the model-view-controller (MVC) pattern and developing something more suited to web development than WebForms which aimed to make web development as similar to Windows development as possible (despite the major underlying differences in architecture).

The prototype, currently named System.Web.Mvc or Microsoft.Web.Scalene depending on where you look, is headed by Scott Guthrie with both Phil Haack and Scott Hanselman involved (sounds like a dream project and team to be involved with) and a preview release (“drop”) is due within the coming weeks.

Guthrie and Hanselman presented Microsoft MVC at the ALT.NET conference which revealed some interesting details buried in the video, my rough observations and notes based on the prototype they showed follows:

Philosophy

  • Don’t repeat yourself
  • Highly extensible & pluggable
  • Use generics to achieve strong-typing without code generation
  • Good performance, fast enough for large-scale sites
  • Separation of concern for maintainability
  • Clean URLs in and out
  • Clean HTML

Extensible

  • Interfaces used extensively
  • No sealed classes
  • Plug-in points for view engines (e.g. MonoRail’s NVelocity, Brail)
  • Support for Inversion of Control (IoC) engines (e.g. Windsor, StructureMap, Spring.NET)

Compatibility

  • Runs on the .NET 2.0 CLR
  • Some helper classes require .NET 3.5 (extension methods)
  • Normal Request, Response objects (via interfaces for mocking)
  • Does not support postback form runat="server"
  • Supports MasterPages, DataBinding, CodeBehind
  • Existing .aspx’s are blocked using web.config

Visual Studio

  • Solution templates for web project and unit testing
  • Full designer & IntelliSense integration

Flow

  • Route -> ControllerFactory -> Controller -> Action -> ViewEngine -> View

Routing

  • Routes can be defined dynamically and support RegEx URL matching
  • IControllerFactory pops out the required IController
  • Routing is case insensitive by default
  • Support REST, blog engine, Jango style mappings etc. default is /controller/action/parameters

Controllers

  • FrontController style
  • IController exposes:
    • Execute(IHttpContext context, RouteData routeData)
    • IViewEngine ViewEngine property
  • Some implementations available, all with virtual methods:
    • ControllerBase (adds dispatching)
    • Controller (Populate parameters into ViewData["key"])
    • Controller (Populates parameters by making ViewData type T)
  • Attributes
    • [ControllerAction] attribute to expose methods as actions (secure default behavior by not exposing helper methods)
    • Attribute for output caching
    • [ControllerAction(DefaultAction=true)] to override default method of Index

Parameters (to the controller)

  • Automatically parsed where a TypeConverter exists
  • Future versions will support more complex serialization of types
  • Can be nullable – use null coalesce operator for defaults

View Engine

  • IViewEngine
    • IView LoadView(string viewName)
  • Implementations include:
    • WebFormViewEngine

Views

  • IView
    • virtual void RenderView(object data)
  • Implementations include:
    • ViewPage – pick up parameters from ViewData[""] in conjunction with Controller
    • ViewPage pick up parameters from ViewData as type T in conjunction with Controller

HTML

  • Clean HTML generation (have they sorted out the id mangling by MasterPages/INamingContainer?)
  • Static HTML class supports Link, PagingLinks and Url methods
  • Map to action names using Lambda expressions to ensure follows refactoring, e.g. string url – Html.Link<ProductController>(controller =>controller.Edit(4);
  • Is there a way to follow the default action?

Model/data

  • Pagination extension methods extend IQueryable for getting pages of data (skip, limit)
  • Pattern for view-update-view cycle
  • Object property to form field id mapping available and pluggable, allows
    • product.UpdateFrom(Request.Form)

Testing

  • Easy to write tests by using mock objects (request, response)
  • Unit testing framework project (NUnit, MBUnit, xUnit.NET)

Finally

  • What’s with ScottGu’s nametag, can the show’s organizers not afford anything more than a Post It note?
  • What cool software is Scott Hanselman using to do the screen-cast video/zoom/overlay/highlighting?

[)amien

Web Application Security for Developers presentation

Last nights Guernsey Software Developers Forum meeting was sparsely attended with a number of the regulars attendees absent. There were however two new faces including Kezzer who I’d been chatting to on-line for years.

Hopefully the low numbers were down to the seasonal summer holidays and the subsequent knock-on effect that we couldn’t get email out to the BCS Guernsey division to gather sufficient awareness.

I did a short presentation on Web Application Security for Developers that covered HTML injection, SQL injection and cross-site scripting including some live demonstrations on sample code. Slides and sample are available although without audio or screen cast of the demonstrations until I work out how to do that with Keynote.

Downloads

I’ve come to the conclusion that putting presentations together takes me around 1 hour of preparation to 1 minute of presentation…

[)amien

Typed session data in ASP.NET made easier still

Philippe Leybaert is unimpressed with Microsoft’s Web Client Software Factory approach for typed session data and offers his own Typed session data made (very) easy which still seems overkill to me comprising as it does of generics, a delegate a helper class to achieve the desired effect. (Whilst you are there check out his very interesting MVC project for ASP.NET called ProMesh)

The solution which I have been using since my .NET 1.1 days is much simpler still and involves nothing more than creating a plain class with properties for every session variable and a static get accessor that obtains or creates it on the HttpContext similar to a singleton.

Here’s an example with the important Current property (slightly cleaned up and improved for this post ;-)

public class MySession {
  public string Name;
  public int LoginID;
  public int CustomerID;

  public static MySession Current {
    get {
      MySession currentSession = HttpContext.Current.Session["_session"] as MySession;
      if (currentSession == null) {
        currentSession = new MySession();
        HttpContext.Current.Session["_session"] = currentSession;
      }
      return currentSession;
    }
  }
}

Using the session data then simply involves operations like:

MySession.Current.Name = NameTextBox.Text;
NameLabel.Text = MySession.Current.Name;

This solution is a lot clearer however all of these solutions use HttpContext.Session which is actually supposed to be there for compatibility with ASP.

Ideally Microsoft would provide us with an option in web.config whereby we can choose our session class and it would just instantiate and track it as part of the session life-cycle.

[)amien

Rails-style controllers for ASP.NET

Rob Conery has been putting together some great screen casts on SubSonic and his latest on generating controllers pointed out that ASP.NET doesn’t support the Rails-style http://site//controller/method style of execution.

This got me quite excited and I’ve put together a proof-of-concept web project that demonstrates mapping the path to controller methods using an IHttpHandler and reflection.

How it works

It registers the ControllerHttpHandler via the web.config:

<httpHandlers>
  <add path="/ctl/\*/\*" verb="POST,GET,HEAD" type="ControllerHttpHandler" />
</httpHandlers>

There is a very basic Controller abstract base class that just provides a simple way of accessing the context for dealing with request/response for now.

public abstract class Controller
{
  protected System.Web.HttpContext context;

  internal Controller(System.Web.HttpContext context) {
    this.context = context;
  }
}

We then have a test controller or two that implement from this with a couple of methods and the required constructor:

public class TestController : Controller
{
  public TestController(System.Web.HttpContext context) : base(context) { }

  public void Index() {
    context.Response.Write("This is the index");
  }

  public void Welcome() {
    context.Response.Write("Welcome to the TestController");
  }
}

Finally the magic that joins them up is the ControllerHttpHandler:

using System;
using System.Web;
using System.Reflection;

public class ControllerHttpHandler : IHttpHandler
{
  public void ProcessRequest(HttpContext context) {
    string[] parts = context.Request.Path.Split('/');
    if (parts.Length < 4) {
      context.Response.Write("No controller & member specified");
      return;
    }

    string controllerName = parts[2];
    string methodName = parts[3];
    Type potentialController = Type.GetType(controllerName);
    if (potentialController != null && potentialController.IsClass && potentialController.IsSubclassOf(typeof(Controller))) {
      MethodInfo potentialMethod = potentialController.GetMethod(methodName);
      if (potentialMethod != null) {
        Controller controller = (Controller) Activator.CreateInstance(potentialController, context);
        potentialMethod.Invoke(controller, null);
      }
      else
        context.Response.Write(String.Format("Method '{0}' not found on controller '{1}'", methodName, controllerName));
    }
    else
      context.Response.Write(String.Format("Controller '{0}' not found", controllerName));
  }

  public bool IsReusable {
    get { return false; }
  }
}

That’s it!

Limitations

The controllers and methods are mapped at run-time using reflection. This would probably be too slow for production. Also it currently has to be in a top-level folder because I can’t figure out how to pass the HTTP request back to ASP.NET to try with the rest of the stack if we don’t have a matching controller/method.

One option might be to have no httpHandlers in the web.config and add the exact controller/method maps at build or run-time. This solves both the top-level problem and potentially the speed.

Another option to address just the speed of reflection would be to cache the path/method strings to the actual method and type so the only reflection would be the Activator.CreateInstance. If that is slow then we could look at pooling the controller instances themselves.

Going forward

Parameters for a method could be extracted and parsed from the query-string – they are currently ignored.

Response is raw output – we could do something very similar to rhtml.

I’m going to chat things over with the Subsonic team and see if we can come up with anything from here.

[)amien