asp.net, asp.net mvc, code comments suggest edit

Not long ago, my compadre Scott Hanselman related the following story

In a recent MVC design meeting someone said something like “we’ll need a Repeater control” and a powerful and very technical boss-type said:

“We’ve got a repeater control, it’s called a foreach loop.”

I beg to differ. I think we can do better than a foreach loop. A foreach loop doesn’t help you handle alternating items, for example. My response to this story is, “The foreach loop is not our repeater control. Our repeater control is an iterating extension method with lambdas!”. Because who doesn’t love lambdas?

Not many people realize that within an ASPX template, it’s possible to pass sections of the template into a lambda. Here, let me show you the end result of using my Repeater<T> helper method. It’s an extension method of the HtmlHelper class in ASP.NET MVC.

<table>
  <% Html.Repeater<Hobby>("Hobbies", hobby => { %>
  <tr class="row">
    <td><%= hobby.Title %></td>
  </tr>
  <% }, hobbyAlt => { %>
  <tr class="alt-row">
    <td><%= hobbyAlt.Title %></td>
    </tr>
  <% }); %>
</table>

This renders a table with alternating rows. The Repeater method takes in two lambdas, one which represents the item template, and another that represents the alternating item template.

This particular overload of the Repeater method takes in a key to the ViewData dictionary and casts that to an IEnumerable<T>. In this case, it tries to cast ViewData["Hobbies"] to IEnumerable<Hobby>. I’ve included overloads that allow you to explicitly specify the items to repeat over.

This isn’t very remarkable when you think a bout it. What the above template code translates to is the following (roughly speaking)…

Response.Write("<table>");

Html.Repeater<Hobby>("Hobbies", hobby => {
    Response.Write("  <tr class=\"row\">");
    Response.Write("    <td>");
    Response.Write(hobby.Title);
    Response.Write("    </td>");
    Response.Write("  </tr>");
  }, hobbyAlt => { 
    Response.Write("  <tr class=\"alt-row\">");
    Response.Write("    <td>");
    Response.Write(hobbyAlt.Title);
    Response.Write("    </td>");
    Response.Write("  </tr>");
  });

Response.Write("</table>");

The code for the Repeater method is simple, short, and sweet.

public static void Repeater<T>(this HtmlHelper html
  , IEnumerable<T> items
  , Action<T> render
  , Action<T> renderAlt)
{
  if (items == null)
    return;

  int i = 0;
  items.ForEach(item => {
    if(i++ % 2 == 0 ) 
      render(item);
    else
      renderAlt(item); 
  });
}

public static void Repeater<T>(this HtmlHelper html
  , Action<T> render
  , Action<T> renderAlt)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  html.Repeater(items, render, renderAlt);
}

public static void Repeater<T>(this HtmlHelper html
  , string viewDataKey
  , Action<T> render
  , Action<T> renderAlt)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  var viewData = html.ViewContext.ViewData as IDictionary<string,object>;
  if (viewData != null)
  {
    items = viewData[viewDataKey] as IEnumerable<T>;
  }
  else
  {
    items = new ViewData(viewData)[viewDataKey] as IEnumerable<T>;
  }
  html.Repeater(items, render, renderAlt);
}

Some of the ViewData machinations you see here is due to the fact that ViewData might be a dictionary, or it might be an unknown type, in which case we perform the equivalent of a DataBinder.Eval call on it using the supplied view data key.

It turns out that the regular <asp:Repeater /> control works just fine with ASP.NET MVC, so there’s no need for such an ugly method call. I just thought it was fun to try out and provides an alternative approach that doesn’t require databinding.

UPDATE: I wanted to end this post here, but my compadre and others took exception to my implementation. Read on to see my improvement…

As astute readers of my blog noted, the example I used forces me to repeat a lot of template code in the alternative item case. The point of this post was on how to mimic the repeater, not in building a better one. Maybe you want to have a completely different layout in the alternate item case. I was going to build a another one that relied only on one template, but I figured I would leave that to the reader. But noooo, you had to complain. ;)

So the following is an example of a repeater method that follows the most common pattern in an alternating repeater. In this common case, you generally want to simply change the CSS class and nothing else. So with these overloads, you specify two CSS classes - one for items and one for alternating items. Here’s an example of usage.

<table>
  <% Html.Repeater<Hobby>("Hobbies", "row", "row-alt", (hobby, css) => { %>
  <tr class="<%= css %>">
    <td><%= hobby.Title%></td>
  </tr>
  <% }); %>
</table>

And here’s the source for the extra overloads. Note that I refactored the code for getting the enumerable from the ViewData into its own method.

public static void Repeater<T>(this HtmlHelper html
  , IEnumerable<T> items
  , string className
  , string classNameAlt
  , Action<T, string> render)
{
  if (items == null)
    return;

  int i = 0;
  items.ForEach(item =>
  {
    render(item, (i++ % 2 == 0) ? className: classNameAlt
  });
}

public static void Repeater<T>(this HtmlHelper html
  , string viewDataKey
  , string cssClass
  , string altCssClass
  , Action<T, string> render)
{
  var items = GetViewDataAsEnumerable<T>(html, viewDataKey);

  int i = 0;
  items.ForEach(item =>
  {
    render(item, (i++ % 2 == 0) ? cssClass : altCssClass);
  });
}

static IEnumerable<T> GetViewDataAsEnumerable<T>(HtmlHelper html, string viewDataKey)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  var viewData = html.ViewContext.ViewData as IDictionary<string, object>;
  if (viewData != null)
  {
    items = viewData[viewDataKey] as IEnumerable<T>;
  }
  else
  {
    items = new ViewData(viewData)[viewDataKey] 
      as IEnumerable<T>;
  }
  return items;
}

Hopefully that gets some people off my back now. ;)

Technorati Tags: aspnetmvc,asp.net

asp.net mvc, code comments suggest edit

File this one away for the next time your boss comes in and asks,lumberg[1]

Yeaaah, I’m going to need you to make that little change to the code. It’ll only take you a couple hours, right?

Software has this deceptive property in which some changes that seem quite big and challenging to the layman end up being quite trivial, while other changes that seem quite trivial, end up requiring a lot of thought, care, and work.

Often, little changes add up to a lot.

I’m going to walk through a change we made that seemed like a no-brainer but ended up having a lot of interesting consequences that were invisible to most onlookers.

The Setup

I’ll provide just enough context to understand the change. The project I work on, ASP.NET MVC allows you to call methods on a class via the URL.

For example, a request for /product/list might call a method on a class named ProductController with a method named List. Likewise a request for /product/index would call the method named Index. We call these “web callable” methods, Actions. Nothing new here.

There were a couple rules in place for this to happen:

  • The controller class must inherit from the Controller class.
  • The action method must be annotated with the [ControllerAction] attribute applied to it.

We received a lot of feedback on the requirement for having that attribute. There were a lot of good reasons to have it there, but there were also a lot of good reasons to remove it.

Removing that requirement should be pretty simple, right? Just find the line of code that checks for the existence of the attribute and change it to not check at all.

The Consequences

Ahhh, if only it were that easy my friend. There were many consequences to that change. The solutions to these consequences were mostly easy. The hard part was making sure we caught all of them. After all, you don’t know what you don’t know.

Base Classes

So we removed the check for the attribute and the first thing we noticed is “Hey! Now I can make a request for /product/gethashcode, Cool!

Not so cool. Since every object ultimately inherits from System.Object, every object has several public methods: ToString(), GetHashCode(), GetType(), and Equals(), and so on… In fact, our Controller class itself has a few public methods.

The solution here is conceptually easy, we only look at public methods on classes that derive from our Controller class. In other words, we ignore methods on Controller and on Object.

Controller Inheritance

One of the rationales for removing the attribute is that in general, there isn’t much of a reason to have a public method on a controller class that isn’t available from the web. But that isn’t always true. Let’s look at one situation. Suppose you have the following abstract base controller.

public abstract class CoolController : Controller
{
  public virtual void Smokes() {...}

  public virtual void Gambles() {...}

  public virtual void Drinks() {...}
}

It is soooo cool!

You might want to write a controller that uses the CoolController as its base class rather than Controller because CoolController does some cool stuff.

However, you don’t think smoking is cool at all. Too bad, Smokes() is a public method and thus an action, so it is callable. At this point, we realized we need a [NonAction] attribute we can apply to an action to say that even though it is public, it is not an action.

With this attribute, I can do this:

public class MyReallyCoolController : CoolController
{
  [NonAction]
  public override void Smokes()
  {
    throws new NotImplementedException();
  }
}

Now MyReallyCoolController doesn’t smoke, which is really cool.

Interfaces

Another issue that came up is interfaces. Suppose I implement an interface with public methods.  Should those methods by default be callable? A good example is IDisposable. If I implement that interface, suddenly I can call Dispose() via a request for /product/dispose.

Since we already implemented the [NonAction] attribute, we decided that yes, they are callable if you implicitly implement them because they are public methods on your class and you have a means to make them not callable.

We also decided that if you explicitly implement an interface, those methods would not be callable. That would be one way to implement an interface without making every method an action and would not require you to annotate every interface method.

Special Methods

Keep in mind that in C# and VB.NET, property setters and getters are nothing more than syntactic sugar. When compiled to IL, they end up being methods named get_PropertyName() and set_PropertyName(). The constructor is implemented as a method named .ctor(). When you have an indexer on a class, that gets compiled to get_Item().

I’m not saying it was hard to deal with this, but we did have to remember to consider this. We needed to get a list of methods on the controller that are methods in the “typical” sense and not in some funky compiler-generated or specially named sense.

Edge Cases

Now we started to get into various edge cases. For example, what if you inherit a base controller class, but use the new keyword on your action of the same name as an action on the base class? What if you have multiple overloads of the same method? And so on. I won’t bore you with all the details. The point is, it was interesting to see all these consequences bubble up for such a simple change.

Is This Really Going To Help You With Your Boss?

Who am I kidding here? Of course not. :) Well…, maybe.

If your boss is technical, it may be a nice reminder that software is often like an iceberg. It is easy to see the 10% of work necessary, but the other 90% of work doesn’t become apparent till you dig deeper.

If your boss is not technical, we may well be speaking a different language here. I need to find an analogy that a business manager would understand. A situation in their world in which something that seems simple on the surface ends up being a lot of work in actuality. If you have such examples, be a pal and post them in the comments. The goal here is to find common ground and a shared language for describing the realities of software to non-software developers.

Technorati Tags: Software,Software Design,ASP.NET MVC

asp.net, asp.net mvc, code comments suggest edit

In a recent post I expressed a few thoughts on using a DSL instead of an XML config file. I followed that up with a technical look at monkey patching CLR objects using IronRuby, which explores a tiny bit of interop.

These posts were precursors to this post in which I apply these ideas to an implementation that allows me to define ASP.NET MVC Routes using IronRuby. Also included in this download is an incomplete implementation of an IronRuby view engine. I haven’t yet implemented layouts.

IronRubyMvcDemo.zip Download (4.93 MB)

This implementation works with the latest CodePlex drop of MVC.

To use routes written in Ruby, reference the IronRubyMvcLibrary from your MVC Web Application and import the IronRubyMvcLibrary.Routing namespace into your Global.asax code behind file. From there, you can just call an extension method on RouteCollection like so…

public class GlobalApplication : System.Web.HttpApplication
{
  protected void Application_Start()
  {
    RouteTable.Routes.LoadFromRuby();
  }
}

This will look for a Routes.rb file within the webroot and use that file to load routes. Here’s a look at mine:

$routes.map "products/{action}/{id}"
  , {:controller => 'products', :action => 'categories', :id => ''}
$routes.map "{controller}/{action}/{id}", {:id => ''}
$routes.map "{controller}", {:action => 'index'}, {:controller => '[^\.]*'}
$routes.map "default.aspx", {:controller => 'home', :action => 'index'}

That’s it. No other cruft in there. I tried experimenting with lining up each segment using tabs so it looks like an actual table of data, rather than simply code definitions.

Also included in this download is a sample web app that makes use of the IronRubyViewEngine. You can see how I applied Monkey Patching to make referencing view data cleaner. Within an IronRuby view, you can access the view data via a global variable, $model. The nice part is, whether you pass strongly typed data or not to the view, you can always reference view data via $model.property_name.

In the case where the view data is a view data dictionary, this will perform a dictionary lookup using the property name as the key.

Be sure to check out the unit tests which provide over 95% code coverage of my code if you want to understand this code and improve on it. Next stop, Controllers in IronRuby…

Technorati Tags: ironruby,ruby,aspnetmvc,aspnet,dsl

code comments suggest edit

In my last post I set the stage for this post by discussing some of my personal opinions around integrating a dynamic language into a .NET application. Using a DSL written in a dynamic language, such as IronRuby, to set up configuration for a .NET application is an interesting approach to application configuration.

With that in mind, I was playing around with some IronRuby interop with the CLR recently. Ruby has this concept called Monkey Patching. You can read the definition in the Wikipedia link I provided, but in short, it is a way to modify the behavior of a class or instance of a class at runtime without changing the source of that class or instance. Kind of like extension methods in C#, but more powerful. Let me provide a demonstration.

I want to pass a C# object instance that happens to have an indexer to a Ruby script via IronRuby. In C#, you can access an indexer property using square brackets like so:

object value = indexer["key"];

Being able to use braces to access this property is merely syntactic sugar by the C# language. Under the hood, this gets compiled to IL as a method named get_Item.

So when passing this object to IronRuby, I need to do the following:

value = $indexer.get_Item("key");

That’s not soooo bad (ok, maybe it is), but we’re not taking advantage of any of the power of Ruby. So what I did was monkey patch the method_missing method onto my object and used the method name as the key to the dictionary. This method allows you to handle unknown method calls on an object instance. You can read this post for a nice brief explanation.

So this allows me now to access the indexer from within Ruby as if it were a simple property access like so:

value = $indexerObject.key

The code for doing this is the following, based on the latest IronRuby code in RubyForge.

ScriptRuntime runtime = IronRuby.CreateRuntime();
ScriptEngine rubyengine = IronRuby.GetEngine(runtime);
RubyExecutionContext ctx = IronRuby.GetExecutionContext(runtime);

ctx.DefineGlobalVariable("indexer", new Indexer());
string requires = 
@"require 'My.NameSpace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...'

def $indexer.method_missing(methodname)
  $indexer.get_Item(methodname.to_s)
end
";

//pretend we got the ruby script I really want to run from somewhere else
string rubyScript = GetRubyCode();

string script = requires + rubyScript;
ScriptSource source = rubyengine.CreateScriptSourceFromString(script);
runtime.ExecuteSourceUnit(source);

What’s going on here is that we instantiate the IronRuby runtime and script engine and context (I still need to learn exactly what each of these things are responsible for apart from each other). I then set a global variable and set it to an instance of a CLR object written in C#.

After that, I start constructing a string that contains the beginning of the Ruby script I want to execute. I will pre-append this beginning section with the actual script I want to run.

The beginning of the Ruby script imports the .NET namespace that contains my CLR type to IronRuby (I believe that by default you don’t need to import mscorlib and System).

I then added a missing_method method to that CLR instance within the Ruby code via this snippet.

def $indexer.method_missing(methodname);
  $indexer.get_Item(methodname.to_s)
end

At that point now, when I execute the rest of the ruby script, any calls from within Ruby to this CLR object can take advantage of this new method we patched onto the instance.

Pretty nifty, eh?

In my next post, I will show you the concrete instance of using this and supply source code.

Technorati Tags: DLR,IronRuby,DSL

code comments suggest edit

Disclaimer: My opinions only, not anyone else’s. Nothing official here. I shouldn’t have to say this, but past history suggests I should. P.S. I’m not an expert on DSLs and Dynamic Languages ;)

This week I attended a talk by John Lam on IronRuby in which he trotted out the Uncle Ben line, with great power comes great responsibility. He was of course referring to the power in a dynamic language like Ruby.

Another quip he made stuck with me. He talked about how his brain sometimes gets twisted in a knot reading Ruby code written using metaprogramming techniques for hours at a time. It takes great concentration comprehending code on a meta and meta-meta level in which the code is manipulating and even rewriting code at runtime. Perhaps this is why C# will remain my primary language in the near term while I try and expand my brain to work on a higher level. ;)

However, the type of code I think he is referring to is the code for implementing a DSL itself. Once a DSL is written though, the code on top of that DSL ought to be quite readable. This is the nook where I see myself adopting IronRuby prior to using it as my primary language.I can see myself creating and using mini-DSLs (Domain Specific Languages) here and there as replacement for configuration.

Ahhh… configuration. I sometimes think this is a misnomer. At least in the way that the Java and .NET community have approached config in practice. We’ve had this trend in which we started jamming everything into XML configuration.

So much so, we often get asked to provide XML to configure features I think ought to be set in code along with unit tests. We’ve turned XML into a programming language, and a crappy one at that. Ayende talks about one issue with sweeping piles of XML configuration under a tool. This is not an intractable problem, but it highlights the fact that XML is code, but it is code with a lot of ceremony compared to the amount of essence. To understand what I mean by ceremony vs essence read Ending Legacy Code In Our Lifetime.

With the ASP.NET MVC project, we’ve taken the approach of Code First, Config Second. You can see this with our URL Routing feature. You define routes in code, and we might provide configuration for this feature in a future version.

With this approach, you can write unit tests for your route definitions which is a good thing! Routes basically turn the URL into a method invocation, why wouldn’t you want to have tests for that?

The reason I write about this now is that I’ve been playing around with IronRuby lately and want to post on some of the interesting stuff I’ve been doing in my own time. This post sets the context for why I am looking into this, apart from it just being plain fun and coming from a haacker ethic of wanting to see how things work.

Technorati Tags: DLR,IronRuby,Configuration,DSL

asp.net, asp.net mvc, code comments suggest edit

UPDATE: Just to prove that this is a preview of a preview, we had a signing problem with the initial pre-built VSI download. If you tried building from source, everything should’ve been ok. We apologize for that. Even though this is meant to be a rough preview, we do want to have a high quality bar in that you should be able to try out the code. So if you run into that problem, please do download the VSI again.

It’s no secret that Microsoft can get better at naming non RTM (Release to Manufacturing) releases. We have terms like CTP, Preview, Alpha, Beta, RC (Release Candidate), and so on. On the other hand, at least Microsoft does try to move things along to RTM rather than keeping products in perpetual Beta.

With ASP.NET MVC, we also need to add yet another type of release. For now I’ve been calling this a CodePlex Source Release meaning it’s simply sharing source code that is in progress. ScottGu called it a “Preview of a Preview” in my office one day and that name stuck with me. This is really a preview of an upcoming preview. ;)

Speaking of ScottGu, he posted a detailed description of this release on his blog last night. I recommend taking a look at it because he covers most of the changes in good detail.

One aspect of this latest source release that I’m particularly happy about is that we released our unit tests. As Scott mentioned, we are using MoQ as a mock framework within our tests. Note that this is not some official endorsement of any particular mock framework. Originally we started out trying to port our tests to Rhino Mocks (which I’ve written a lot about). MoQ just happened to have a programming model that was closer to the way our internal mock framework works, so we switched over to MoQ.

I will write more about this release later. But for now, I will leave you with an updated Northwind Demo based on this release because there ain’t no party like a Northwind party.

Technorati Tags: aspnetmvc

personal comments suggest edit

If ever someone was undeserving of having others spend their valuable time translating his blog, it would be me. But hey, some people from the http://blog.joycode.com/ site went ahead and did it anyway. I must admit that I’m very flattered that anyone would put the effort in.

Before this, I learned that Subtext powers MySpace China’s blogs, and now my blog is translated to Chinese. As David Hasselhoff says, “I’m big in China”. (To my Chinese audience, that is a joke. I am quite small.)

david_coleman

Technorati Tags: Chinese,China,Blogging

asp.net, asp.net mvc, code comments suggest edit

Made a few corrections on having default.aspx in the root due to a minor bug we just found. Isn’t preview code so much fun?

We’ve been making some changes to routing to make it more powerful and useful. But as Uncle Ben says, with more power comes more responsibility. I’ll list out the changes first and then discuss some of the implication of the changes.

  • Routes no longer treat the . character as a separator. Currently, routes treat the . and / characters as special. They are separator characters. The upcoming release of routing will only treat the / as separator.
  • Routes may have multiple (non-adjacent) url parameters in a segment. Currently, URL parameters in a route must fill up the space between separators. For example, {param1}/{param2}.{param3}. With the upcoming release, a URL segment may have more than one parameter as long as they are separated by a literal. For example {param1}.{ext}/{param3}-{param4}is now valid.

Passing Parameter Values With Dots

With this change, the dot character becomes just another literal. It’s no longer “special”. What does this buy us? Suppose you are building a site that can present information about other sites. For example, you might want to support URLs like this:

  • http://site-info.example.com/site/www.haacked.com/rss
  • http://site-info.example.com/site/www.haacked.com/stats

That first URL will display information about the RSS feed at www.haacked.com while the second one will show general site stats. To make this happen, you might define a route like this.

routes.Add(new Route("site/{domain}/{action}" 
  , new MvcRouteHandler()) 
{ 
  Defaults=new RouteValueDictionary(new {controller="site"})  
});

Which routes to the following controller and action method.

public class SiteController : Controller
{
  public void Rss(string domain)
  {
    RssData rss = GetRssData(domain);
    RenderView("Rss", rss);
  }

  public void Stats(string domain)
  {
    SiteStatistics stats = GetSiteStatistics(domain);
    RenderView("Stats", stats);
  }
}

The basic idea here is that the domain (such as www.haacked.com in the example URLs above) would get passed to the domain parameter of the action methods. The only problem is, it does not work with the previous routing system because routing considered the dot character in the URL as a separator. You would have had to define routes with URLs like site/{sub}.{domain}.{toplevel}/{action} but then that doesn’t work for URLs with two sub-domains or no sub-domain.

Since we no longer treat the dot as special, this scenario is now possible.

Multiple URL Segments

What does adding multiple URL segments buy us? Well it continues to allow using routing with URLs that do have extensions. For example, suppose you want to route a request to the following action method: public void List(string category, string format)

With both the previous and new routing, you can match the request for the URL…

/products/list/beverages.xml

with the route

{controller}/{action}/{category}.{format}

To call that action method. But suppose you don’t want to use file extensions, but still want to specify the format in a special way. With the new routing, you can use any character as a separator. For example, maybe you want to use the dash character to separate the category from the format. You could then match the URL

/products/list/beverages-xml

with the route

{controller}/{action}/{category}-{format}

and still call that action method.

Note that we now allow any character (allowed in the URL and that is not a dash) to pretty much be a separator. So if you really wanted to, though not sure why you would, you could use BLAH to separate out the format. Thus you could match the route

/products/list/beveragesBLAHxml

with the route

{controller}/{action}/{category}BLAH{format}

and it would still route to the same List method above.

Consequences

This makes routing more powerful, but there are consequences to be aware of.

For example, using the default routes as defined in the ASP.NET MVC Preview 2 project template, a request for “/Default.aspx” fails because it can’t find a controller with the name “Default.aspx”. Huh? Well “/Default.aspx” now matches the route {controller}/{action}/{id} (because of the defaults for {id} and {action}) because we don’t treat the dot as special.

Not only that, what about a request for /images/jpegs/foo.jpg? Wouldn’t routing try to route that to controller=”images”, action=”jpegs”, id=”foo.jpg” now?

The decision we made in this case was that by default, routing should not apply to files on disk. That is, routing now checks to see if the file is on disk before attempting to route (via the Virtual Path Provider).

If the file is on disk, we pop out and don’t route and let the web server handle the request normally. If the file doesn’t exist, we attempt to apply routing. This makes sure we don’t screw around with requests for static resources on disk. Of course, this default can be changed by setting the property RouteTable.Routes.RouteExistingFiles to be true.

Why Blog This Now?

The Dynamic Data team is scooping the MVC team on these routing changes. ;) They are releasing a preview of their latest changes to Dynamic Data which includes using our new routing dll.

Check out ScottGu’s post on the subject. I really feel Dynamic Data is the most underrated new technology coming out from the ASP.NET team. When you dig into it, it is really cool. The “scaffolding” part is only the tip of the iceberg.

Installing the Dynamic Data preview requires installing the routing assembly into the GAC. If you install this, it may break existing MVC Preview 2 sitesbecause the assembly loader favors the GAC when the assembly is the same version. And the routing assembly is the same version as the one in Preview 2.

The Dynamic Data Preview readme has the steps to update your MVC Preview 2 project to work with the new routing. You’ll notice that the readme recommends having a Default.aspx file in the root which redirects to /Home. Technically, the Default.aspx file in the root won’t be necessary in the final release because of the suggested routing changes (it is necessary now due to a minor bug). Unfortunately, Cassini doesn’t work correctly when you make a request for “/” and there is no default document. It doesn’t run any of the ASP.NET Modules. So we kept the file in the root, but you can will be able to remove it when deploying to IIS 7. So to recap this last point, the Default.aspx in the project root is to make sure that pre-SP1 Cassini works correctly as well as IIS 6 without star mapping. It’s will not be needed for IIS 7 in the future, but is needed for the time being.

We will have a new CodePlex source code push in a couple of weeks with an updated version of MVC that supports the new routing engine.

Technorati Tags: ASP.NET MVC,ASP.NET,Routing,Dynamic Data

code, tdd comments suggest edit

When I build applications, I personally like to have my unit tests in a separate class library project than the application I am testing. That’s just how I roll.

I just assumed this is how everyone structures their unit tests, but I’ve talked with some people who have a deep history in TDD who put their code in the same project.

So I wanted to create a simple poll to find out how people are actually structuring their unit tests. I’ve been involved in various internal discussions looking at how Microsoft design, tools, code can better support unit testing across the board.

Note that this is not an opinion question. I don’t think one way is “more right” than another. I just want to make sure we have an accurate view of what the real practice is out there.

So please do answer this poll and encourage others to do so. I’d hate for internal teams to make choices based on a wrong assumption. Thanks!

How do you structure your unit tests? \ (polls)

Tags: TDD , Unit Testing

asp.net, asp.net mvc, code, tdd comments suggest edit

Way down the road, it would be nice to be able to build ASP.NET MVC applications using a DLR language such as IronRuby. However, enabling DLR language support isn’t free.

There are going to be places in our design that are specific to statically typed languages (such as Attribute based filters) that just wouldn’t work (or would be too unnatural) with a dynamic language.

Ideally we can minimize those cases, and for the ones we can’t, we need to make sure the extensibility of the framework allows for extending the system in such a way that we can provide a DLR friendly version of that feature.

How do we identify and minimize such hot spots? Design reviews help, but only goes so far. There is nothing like executing code to highlight issues. So in collaboration with some of the DLR team members, I’ve been exploring the minispec framework used to test IronRuby and wrote my first testspec tonight. Check it out. (NOTE: line breaks added in the require statements so it fits within the width of my blog)

require File.dirname(__FILE__) + '/../../spec_helper'
require 'System.Web.Abstractions
, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
require 'System.Web.Routing
, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
require 'System.Web.Mvc
, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

describe "Route#<<" do
 
  it "can create RouteCollection which is empty" do
    rc = System::Web::Routing::RouteCollection.new
    rc.count.should == 0
  end
  
  it "can add route to RouteCollection" do
    rc = System::Web::Routing::RouteCollection.new
    r = System::Web::Routing::Route.new "", nil
    rc.add "route-name", r
    
    rc.count.should == 1
  end

end

And here is the result so far.

Administrator
CWindowsSystem32cmd.exe

Yay! Two passing tests.

Yeah, the tests are really really simple so far, but hey, this is just my first step. I need to get familiar with the minispec framework. Not only that, but I haven’t written any Ruby code in a long while. Fortunately I do have a copy of The Ruby Way on my shelf, which should help.

I probably have much higher priority items on my plate that I could be working on, but sometimes you have to treat yourself to a little fun. Besides, I am doing this on my own time right now. :)

Tags: DLR , ASP.NET , ASP.NET MVC , TDD

code comments suggest edit

There’s a great interview on the How Software is Built blog with Brad Wilson, a developer in Microsoft’s OfficeLabs team, but probably better known for his work on xUnit.net, CodePlex, and ObjectBuilder.

brad What I particularly liked about this post was the insight Brad provides on the diverse views of open source outside and inside of Microsoft as well as his own personal experience contributing to many OSS projects. It’s hard for some to believe, but there are developers internal to Microsoft who like and contribute to various open source projects.

Another reason that Brad gets a thumbs up in my book (along with Jim Newkirk) is that xUnit.net recently updated their installer to include test project integration with ASP.NET MVC Preview 2.

Technorati Tags: Open Source,OSS,Microsoft

code comments suggest edit

Subtext Submarine
LogoIt’s been all quiet on the Subtext front for a while. While I think many open source projects face the occasional lull, Subtext was hit by a Perfect Storm of inactivity.

This was mostly because several of the key developers all ended up having job changes (and moves) around the same time. For me, the move to Microsoft and up to the Seattle area took up a lot of my time and energy.

I finally feel settled in so I fired up the old TortoiseSVN client and got latest from the tree excited to see what new goodness people checked in during my absence.

Dsvnsubtexttrunk - TortoiseSVN Update...
Finished!

Ok, that’s not exactly true, but captures the spirit of the truth.

In any case, now that I’m mostly settled into lovely Bellevue, WA, I decided to spend a bit of time last week working on Subtext. I’m now swamped again, but I got a few key fixes in already which I’m happy about.

We decided to scale back the 2.0 release a bit. We were a bit too ambitious with the feature set and supporting two branches became way to time consuming. So we replaced the trunk with the 1.9 branch and all new development is in the trunk where it should be.

The next version will still target ASP.NET 2.0, but after that, we want to have fun with this so we’ll start to target ASP.NET 3.5. I won’t go into the feature list for 2.0 right now. The bulk of the work is on bug fixes, small tweaks and improvements, and infrastructure improvements. I feel like one of the best parts of Subtext is our build process and continuous integration server.

Since we decided to label the next version 2.0, we will be adding a few new hotly requested features. It should be a nice release. Sorry it’s been so quiet for so long, but the engine is back up and running full speed ahead.

Tags: Subtext

personal comments suggest edit

UPDATE: This was an April Fool’s joke. I actually stated this in the bottom of the original post, but in a very small font, which some people noticed. :)

I’m totally done with blogging. Hanging my blogging hat and never looking back. I started blogging on http://haack.org/ way back when around 1998. I tried to include a Wayback Machine archive link, but some domain squatters put a robots.txt file onto haack.org. Bummer. Shoulda held onto that domain.

If you follow my twitter stream, you’ve probably noticed I’ve been lamenting about blogging lately. A lot of bloggers, myself included, put an unhealthy amount of pressure on themselves to continue producing content. It becomes a bit of a self imposed boilerroom.

When I read about Dare stopping his blog, unlike many people who felt sad, I felt envious. Think of all the free time he must’ve freed up. I can totally understand the reasons. He’s getting ready to have a kid. I recently had one (almost 10 months ago). All the time I spend on blogging, is time not spent with my wife and my kid. I do have hobbies other than software.

Not only that, but a lot of the fun in blogging is gone. I feel like discourse in the blogosphere has become so polarized lately, much like the political climate in this country. People seem content with “Drive By Commenting”, messing with someone’s day with a vitriolic comment without regard for conseqences. I’m happy that people vehemently disagree with each other and me, I wish we could keep the discourse civil and focused on finding common ground. Just because I disagree with you doesn’t mean I have to think your point is completely unreasonable or that you’re stupid.

I’ll still read blogs and be on Twitter. The discourse isn’t much higher on Twitter, but the time commitment is small enough to make it worth it. I predict blogging itself will be dead in a year anyway with everyone moving to Twitter or Twitter-like services.

Now that spring and summer is on its way to the Northwest, I think the timing for this move is good. I know this will disappoint many of my friends, but I have to do what’s right for me and my family. I hope you understand.

 

Yes, this is an April Fool’s Joke

personal comments suggest edit

LazyCoder (aka Scott Koon) is organizing a little drinky drink this Wednesday around 6:00 PM-ish at The Three Lions Pub. This is just an informal gathering, not the huge production like the Hanselman Geek Dinner which requires eating at a mall food court because some three hundred plus geeks show up. (Did you know his last geek dinner was covered by theSeattle Times online?).

No, this will be a smaller intimate affair. Here’s your chance to get me sloshed by buying me beers in order to slip your pet feature into ASP.NET MVC. If it’s a really crazy feature idea, you may have to move up to Scotch. ;)

Seriously though, if you’re looking to blow off some steam on a Wed night (aren’t we all?) swing by and throw back one or a few with us.

Tags: Geek Dinner

code, tdd comments suggest edit

UPDATE: I should have entitled this “Comparing Rhino Mocks and MoQ for State Based Testing”. I tend to prefer state-based testing over interaction based testing except in the few cases where it is absolutely necessary or makes the test much cleaner. When it is necessary, it is nice to have interaction based testing available. So my comparison is incomplete as I didn’t compare interaction based testing between the two frameworks.

For the longest time I’ve been a big fan of Rhino Mocks and have often written about it glowingly. When Moq came on the scene, I remained blissfully ignorant of it because I thought the lambda syntax to be a bit gimmicky. I figured if using lambdas was all it had to offer, I wasn’t interested.

Fortunately for me, several people in my twitter-circle recently heaped praise on Moq. Always willing to be proven wrong, I decided to check out what all the fuss was about. It turns out, the use of lambdas is not the best part of Moq. No, it’s the clean discoverable API design and lack of the record/playback model that really sets it apart.

To show you what I mean, here are two unit tests for a really simple example, one using Rhino Mocks and one using Moq. The tests use the mock frameworks to fake out an interface with a single method.

[Test]
public void RhinoMocksDemoTest()
{
  MockRepository mocks = new MockRepository();
  var mock = mocks.DynamicMock<ISomethingUseful>();
  SetupResult.For(mock.CalculateSomething(0)).IgnoreArguments().Return(1);
  mocks.ReplayAll();

  var myClass = new MyClass(mock);
  Assert.AreEqual(2, myClass.MethodUnderTest(123));
}

[Test]
public void MoqDemoTest()
{
  var mock = new Mock<ISomethingUseful>();
  mock.Expect(u => u.CalculateSomething(123)).Returns(1);

  var myClass = new MyClass(mock.Object);
  Assert.AreEqual(2, myClass.MethodUnderTest(123));
}

Notice that the test using Moq only requires four lines of code whereas the test using Rhino Mocks requires six. Lines of code is not the measure of an API of course, but it is telling in this case. The extra code in Rhino Mocks is due to creating a MockRepository class and for calling ReplayAll.

The other aspect of Moq I like is that the expectations are set on the mock itself. Even after all this time, I still get confused when setting up results/expecations using Rhino Mocks. First of all, you have to remember to use the correct static method, either SetupResult or Expect. Secondly, I always get confused between SetupResult.On and SetupResult.For. I feel like the MoQ approach is a bit more intuitive and discoverable.

The one minor thing I needed to get used to with Moq is that I kept trying to pass the mock itself rather than mock.Object to the method/ctor that needed it. With Rhino Mocks, when you create the mock, you get a class of the actual type back, not a wrapper. However, I see the benefits with having the wrapper in Moq’s approach and now like it very much.

My only other complaint with Moq is the name. It’s hard to talk about Moq without always saying, “Moq with a Q”. I’d prefer MonQ to MoQ. Anyways, if that’s my only complaint, then I’m a happy camper! You can learn more about MoQ and download it from its Google Code Page.

Nice work Kzu!

Addendum

The source code for MyClass and the interface for ISomethingUseful are below in case you want to recreate my tests.

public interface ISomethingUseful 
{
  int CalculateSomething(int x);
}

public class MyClass
{
  public MyClass(ISomethingUseful useful)
  {
    this.useful = useful;
  }

  ISomethingUseful useful;
    
  public int MethodUnderTest(int x)
  {
    //Yah, it's dumb.
    return 1 + useful.CalculateSomething(x);
  }
}

Give it a whirl.

Tags: TDD , MoQ , Rhino Mocks

personal comments suggest edit

My family and I recently moved into our new home after a two month stay in temporary housing. One of the perks of moving is when your stuff is delivered from storage, it feels like Christmas again. “Oooh! Look at all the boxes I get to unwrap. Hey! I have a Stereo just like this one!”.

I have a tendency to get distracted by the things I’m unwrapping. For example, I found a few of my old college Math textbooks. I started thumbing through the Complex Analysis, Abstract Algebra, and Number theory books and they seemed like total gibberish to me.

Artists and writers often get all the credit for creativity. It’s often why people call them creative types. Meanwhile, mathematicians are often unfairly portrayed and humorless, pencil pushing, uncreative types. This is so not true. Many mathematicians use computers now and love telling jokes like “Can you prove that the integral of e to the x is equal to f sub u of n?” Perhaps if I write out the equation the joke becomes more apparent.

∫e^x^ = f~u~(n)

Hey, I didn’t say mathematicians had a **good sense of humor. The fact is that this idea that mathematicians lack creativity comes from those who never made it to higher math. Once you hit abstract algebra, number theory, non-Euclidean geometry, etc… you start to wonder if perhaps the giants in the field were smoking a little something something to come up with this stuff.

The creativity involved in some of the proofs (or even the questions the proofs prove) just boggles the mind. I imagine that the proof of Fermat’s Last Theorem (which reportedly took 7 straight years of work to crack) is something that pretty much nobody in the world understands. Not unlike an abstract painting in a modern art museum. But I digress…

Number theory was my favorite class at the time so I thought I’d sit down, crack open the text, and see if I could understand one problem and even make progress on it.

No Dice.

I understood this stuff once, when I was in college, but now, when I’m older and wiser, I am slower to pick it up, even though I understood it once already. So I started thinking? What is different between the now me and the college me? Then it hit me…

Pizza Consumption!

 mmm-pizza

Think about it for a sec. They often say programmers are machines that turns coffee into code. I wonder if college math students are machines that turn Pizza into solved problem sets? And what about the mythical lore of those early Dot-Com boom startups which started off as a small group of recent college students, Pepsi, and a bunch of Pizzas and ended up selling for millions? Pizza was the common denominator.

I think I’m on to something here. Perhaps Pizza is brain food. I wonder if it’s the Mozzarella or the Pepperoni. Of course, the problem for me now is that college was a long time ago. While the question of whether Pizza is brain food is mere idle speculation, it is a well established fact that Pizza is definitely gut food. Food for thought.

Technorati Tags: Pizza,Humor,College,Math

asp.net, asp.net mvc, code comments suggest edit

Whew! I’ve held off writing about MVC until I could write a non-MVC post in response to some constructive criticism (It’s not just Sean, Jeff mentioned something to me as well). Now that I’ve posted that, perhaps I’ve bought myself a few MVC related posts in a row before the goodwill runs dry and I have to write something decidedly not MVC related again. ;)

As ScottGu recently posted, the ASP.NET MVC source code is now available via CodePlex. A move like this isn’t as simple as flipping a switch and *boom* it happens. No, it takes a lot of effort behind the scene. On the one hand is all the planning involved, and Bertrand Le Roy and my boss Simon played a big part in that.

Along with planning is the execution of the plan which requires coordination among different groups such as the Devs, PMs, QA and the legal team. For that, we have our newest PM Scott Galloway to thank for that effort. I helped a little bit with the planning and writing the extremely short readme (I didn’t know what to say) and roadmap. One part of this experience that went surprisingly well was the person from our legal department we worked with. I was expecting a battle but this guy just got it and really understood what we were trying to do and was easy to work with.

With that said, I’ve seen a lot of questions about this so I thought I would answer a few here.

Is this the live source repository?

No, the MVC dev team is not committing directly into the CodePlex source code repository for many reasons. One practical reason is that we are trying to reduce interruptions to our progress as much as possible. Changing source code repositories midstream is a big disruption. For now, we’ll periodically ship code to CodePlex when we feel we have something worth putting out there.

Where is the source for Routing?

As I mentioned before, routing is not actually a feature of MVC which is why it is not included. It will be part of the .NET Framework and thus its source will eventually be available much like the rest of the .NET Framework source. It’d be nice to include it in CodePlex, but as I like to say, baby steps.

Where are the unit tests?

Waitaminute! You mean they’re not there?! I better have a talk with Scott. I kid. I kid.  We plan to put the unit tests out there, but the current tests have some dependencies on internal tools which we don’t want to distribute. We’re hoping to rewrite these tests using something we feel comfortable distributing.

When’s the next update to CodePlex?

As I mentioned, we’ll update the source when we have something to show. Hopefully pretty often and soon. We’ll see how it goes.

As a team, we’re pretty excited about this. I wondered if the devs would feel a bit antsy about this level of transparency. Sure, anyone can see the source code for the larger .NET Framework, but that code has already shipped. This is all early work in progress. Can you imagine at your work place if your boss told you to publish all your work in progress for all the world to critique (if you’re a full time OSS developer, don’t answer that). ;) I’m not sure I’d want anyone to see some of my early code using .NET.

Fortunately, the devs on my team buy into the larger benefit of this transparency. It leads to a closer collaboration with our customers and creates a tighter feedback cycle. I am confident it will pay off in the end product. Of course they do have their limits when it comes to transparency. I tried suggesting we take it one step further and publish our credit card numbers in there, but that was a no go.

Technorati Tags: aspnetmvc,codeplex

asp.net, asp.net mvc, code comments suggest edit

UPDATE: I’ve added a NuGet package named “routedebugger” to the NuGet feed, which will make it much easier to install.

UPDATE 2: In newer versions of the NuGet package you don’t need to add code to global.asax as described below. An appSetting <add key="RouteDebugger:Enabled" value="true" /> in web.config suffices.

In Scott Hanselman’s wonderful talk at Mix, he demonstrated a simple little route tester I quickly put together.

Route Debugger
Screenshot

This utility displays the route data pulled from the request of the current request in the address bar. So you can type in various URLs in the address bar to see which route matches. At the bottom, it shows a list of all defined routes in your application. This allows you to see which of your routes would match the current URL.

The reason this is useful is sometimes you expect one route to match, but another higher up the stack matches instead. This will show you that is happening. However, it doesn’t provide any information why that is happening. Hopefully we can do more to help that situation in the future.

To use this, simply download the following zip file and place the assembly inside of it into your bin folder. Then in your Global.asax.cs file add one line to the Application_Start method (in bold).

protected void Application_Start(object sender, EventArgs e)
{
  RegisterRoutes(RouteTable.Routes);
  RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}

This will update the route handler (IRouteHandler) of all your routes to use a DebugRouteHandler instead of whichever route handler you had previously specified for the route. It also adds a catch-all route to the end to make sure that the debugger always matches any request for the application.

I’m also making available the full source (using the word full makes it sound like there’s a lot, but there’s not all that much) and a demo app that makes use of this route tester. Let me know if this ends up being useful or not for you.

Technorati Tags: aspnetmvc,ASP.NET,routing

asp.net, code, asp.net mvc comments suggest edit

UPDATE: I updated the sample to work with the final version of ASP.NET Routing included with ASP.NET 3.5 SP1. This sample is now being hosted on CodePlex.

Download the demo here

In my last post I described how Routing no longer has any dependency on MVC. The natural question I’ve been asked upon hearing that is “Can I use it with Web Forms?” to which I answer “You sure can, but very carefully.”

Being on the inside, I’ve had a working example of this for a while now based on early access to the bits. Even so, Chris Cavanagh impressively beats me to the punch in blogging his own implementation of routing for Web Forms. Nice!

One of the obvious uses for the new routing mechanism is as a “clean” alternative to URL rewriting (and possibly custom VirtualPathProviders for simple scenarios) for traditional / postback-based ASP.NET sites.  After a little experimentation I found some minimal steps that work pretty well:

  • Create a custom IRouteHandler that instantiates your pages
  • Register new Routes associated with your IRouteHandler
  • That’s it!

He took advantage of the extensibility model by implementing the IRouteHandler interface with his own WebFormRouteHandler class (not surprisingly my implementation uses the same name) ;)

There is one subtle potential security issue to be aware of when using routing with URL Authorization. Let me give an example.

Suppose you have a website and you wish to block unauthenticated access to the admin folder. With a standard site, one way to do so would be to drop the following web.config file in the admin folder…

<?xml version="1.0"?>
<configuration>
    <system.web>
        
        <authorization>
            <deny users="*" />
        </authorization>

    </system.web>
</configuration>

Ok, I am a bit draconian. I decided to block access to the admin directory for allusers. Attempt to navigate to the admin directory and you get an access denied error. However, suppose you use a naive implementation of WebFormRouteHandler to map the URL fizzbucket to the admin dir like so…

RouteTable.Routes.Add(new Route("fizzbucket"
  , new WebFormRouteHandler("~/admin/secretpage.aspx"));

Now, a request for the URL /fizzbucket will display secretpage.aspx in the admin directory. This might be what you want all along. Then again, it might not be.

In general, I believe that users of routing and Web Form will want to secure the physical directory structure in which Web Forms are placed using UrlAuthorization. One way to do this is to call UrlAuthorizationModule.CheckUrlAccessForPrincipal on the actual physical virtual path for the Web Form.

This is one key difference between Routing and URL Rewriting, routing doesn’t actually rewrite the URL. Another key difference is that routing provides a mean to generate URLs as well and is thus bidirectional.

The following code is my implementation of WebFormRouteHandler which addresses this security issue. This class has a boolean property on it that allows you to not apply URL authorization to the physical path if you’d like (in following the principal of secure by default the default value for this property is true which means it will always apply URL authorization).

public class WebFormRouteHandler : IRouteHandler
{
  public WebFormRouteHandler(string virtualPath) : this(virtualPath, true)
  {
  }

  public WebFormRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)
  {
    this.VirtualPath = virtualPath;
    this.CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
  }

  public string VirtualPath { get; private set; }

  public bool CheckPhysicalUrlAccess { get; set; }

  public IHttpHandler GetHttpHandler(RequestContext requestContext)
  {
    if (this.CheckPhysicalUrlAccess 
      && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(this.VirtualPath
              ,  requestContext.HttpContext.User
              , requestContext.HttpContext.Request.HttpMethod))
      throw new SecurityException();

    var page = BuildManager
      .CreateInstanceFromVirtualPath(this.VirtualPath
        , typeof(Page)) as IHttpHandler;
      
    if (page != null)
    {
      var routablePage = page as IRoutablePage;
      if (routablePage != null)
        routablePage.RequestContext = requestContext;
    }
    return page;
  }
}

You’ll notice the code here checks to see if the page implements an IRoutablePage interface. If your Web Form Page implements this interface, the WebFromRouteHandler class can pass it the RequestContext. In the MVC world, you generally get the RequestContext via the ControllerContext property of Controller, which itself inherits from RequestContext.

The RequestContext is important for calling into API methods for URL generation. Along with the IRoutablePage, I provide a RoutablePage abstract base class that inherits from Page. The code for this interface and the abstract base class that implements it is in the download at the end of this post.

One other thing I did for fun was to play around with fluent interfaces and extension methods for defining simple routes for Web Forms. Since routes with Web Forms tend to be simple, I thought this syntax would work nicely.

public static void RegisterRoutes(RouteCollection routes)
{
  //first one is a named route.
  routes.Map("General", "haha/{filename}.aspx").To("~/forms/haha.aspx");
  routes.Map("backdoor").To("~/admin/secret.aspx");
}

The general idea is that the route url on the left maps to the webform virtual path to the right.

I’ve packaged all this up into a solution you can download and try out. The solution contains three projects:

  • WebFormRouting - The class library with the WebFormRouteHandler and helpers…
  • WebFormRoutingDemoWebApp - A website that demonstrates how to use WebFormRouting and also shows off url generation.
  • WebFormRoutingTests- a few non comprehensive unit tests of the WebFormRouting library.

WARNING: This is prototype code I put together for educational purposes. Use it at your own risk. It is by no means comprehensive, but is a useful start to understanding how to use routing with Web Forms should you wish. Download the demo here.

Technorati Tags: aspnetmvc,Routing,ASP.NET

asp.net, code, asp.net mvc comments suggest edit

At this year’s Mix conference, we announced the availability of the second preview for ASP.NET MVC which you can download from here. Videos highlighting MVC are also available.

Now that I am back from Mix and have time to breathe, I thought I’d share a few (non-exhaustive) highlights of this release as well as my thoughts on the future.

New Assemblies and Routing

Much of the effort and focus of this release was put into routing. If you’ve installed the release, you’ll notice that MVC has been factored into three assemblies:

  • System.Web.Mvc
  • System.Web.Routing
  • System.Web.Abstractions

The key takeaway here is that MVC depends on Routing which depends on Abstractions.

MVC => Routing => Abstractions

Routing is being used by another team here at Microsoft so we worked on making it an independent feature to MVC. MVC relies heavily on routing, but routing doesn’t have any knowledge of MVC. I’ll write a follow up post that talks about the implications of that and how you might use Routing in a non-MVC context.

Because of the other dependencies on Routing, we spent a lot of time trying to make sure we got the API and code correct and making sure the quality level of routing meets an extremely high bar. Unfortunately, this investment in routing did mean that we didn’t implement everything we wanted to implement for MVC core, but hey, it’s a preview right? ;)

CodePlex Builds

At Mix this year Scott Hanselman’s gave a great talk (IMHO) on MVC. One thing he announced during that talk is the vehicle by which we will be making the MVC source code available. Many of you might recall ScottGu’s recent roadmap for MVC in which he mentioned we would be making the source available. At Mix, Scottha announced that we would be deploying our source to CodePlex soon.

Not only that, we hope to push source from our source control to a CodePlex Project’s source control server on a semi-regular basis. These builds would only include source (in a buildable form) and would not include the usual hoopla with associated with a full Preview or Beta release.

How regular a schedule we keep to remains to be seen, but Scott mentioned in his talk around every four to six weeks. Secretly, between you and me, I’d love to push even more regularly. Just keep in mind that this is an experiment in transparency here at Microsoft, so we’ll start slow (baby steps!) and see how it progresses. In spirit, this would be the equivalent to the daily builds that are common in open source projects, just not daily.

Unit Test Framework Integration

In a recent post, I highlighted some of the work we’re doing around integrating third party unit testing frameworks.

Unit Testing
Frameworks

I’ve been in contact with various unit testing framework developers about integrating their frameworks with the MVC project template. I’m happy to see that MbUnit released updated installers that will integrate MbUnit into this dropdown. Hopefully the others will follow suit soon.

One interesting approach I should point out is that this is a great way to integrate your own totally tricked out unit testing project template complete with your favorite mock framework and your own private assembly full of your useful unit test helper classes and methods.

If you’re interested in building your own customized test framework project which will show up in this dropdown, Joe Cartano of the Web Tools team posted an updated streamlined walkthrough on how to do so using NUnit and Rhino Mocks as an example.

Upcoming improvements

One area in this preview we need to improve is the testability of the framework. The entire MVC dev team had a pause in which we performed some app building and uncovered some of the same problems being reported in various forums. Problems such as testing controller actions in which a call to RedirectToAction is made. Other problems include the fact that you need to mock ControllerContext even if you’re not using it within the action. There are many others that have been reported by various people in the community and we are listening. We ourselves have encountered many of them and definitely want to address them.

Experiencing the pain ourselves is very important to understanding how we should fix these issues. One valuable lesson I learned is that a framework that is testable does not mean that applications built with that framework are testable. We definitely have to keep that in mind as we move forward.

To that end, we’ll be applying some suggested improvements in upcoming releases that address these problems. One particular refactoring I’m excited about is ways to make the controller class itself more lightweight. Some of us are still recovering from Mix so as we move forward, I hope to provide even more details on specifically what we hope to do rather than this hand-waving approach. Bear with me.

During this next phase, I personally hope to have more time to continuously do app building to make sure these sort of testing problems don’t crop up again. For the ones that are out there, I take responsibility and apologize. I am a big a fan of TDD as anyone and I hate making life difficult for my brethren. ;)

RTM

When do we RTM? This is probably the most asked question I get and right now, I don’t have a good answer. In part, because I’m still trying to sort through massive amounts of feedback regarding this question. Some questions I’ve been asking various people revolve around the very notion of RTM for a project like this :

  • How important is RTM to you?
  • Right now, the license allows you to go-live and we’ll provide the source, is that good enough for your needs?
  • Is it really RTM that you want, or is it the assurance that the framework won’t churn so much?
  • What if we told you what areas are stable and which areas will undergo churn, would you still need the RTM label?
  • Is there a question I should be asking regarding this that I’m not? ;)

I do hope to have a more concrete answer soon based on this feedback. In general, what I have been hearing from people thus far is they would like to see an RTM release sooner rather than later, even if it is not feature rich. I look forward to hearing from more people on this.

Closing Thoughts

In general, we have received an enormous amount of interest and feedback in this project. Please do keep it coming as the constructive feedback is really shaping the project. Tell us what you like as well as what is causing you problems. We might not respond to every single thing reported as quickly as we would like to, but we are involved in the forums and I am still trying to working through the massive list of emails accrued during Mix.

Technorati Tags: ASP.NET,aspnetmvc,software