The ASP.Net 3.5 Extensions CTP (PKA [Previously Known As] ASP.Net MVC) is out.
The MVC Contrib project was created by smart people on CodePlex as "...a series of assemblies that add functionality to Microsoft's ASP.NET MVC Framework and make the framework easier to use."
My early prediction is that the View IntelliSense and possibility of ReSharper refactorings keeping my Controller/View relationship in sync will be a huge draw for those already already enlightened by MVC. With the exception of some superfluous 'var's and 'new's, the current ViewPage syntax looks very Brailish.
I've got two patches in the queue. The first is an implementation of a Windsor ControllerFactory. Not a whole lot of thought put into this one. Came pretty much out of the MonoRail repository.
The second is slightly more interesting and required some brain power. The MVCTookit (which is currently released separately from the CTP, but will probably be incorporated in the future) provides a method to hydrate an object from a NameValueCollection. The NameValueCollection is most likely going to be Form, QueryString, or Cookie data that comes as part of an HTTP request. Pretty neat, fairly useful, but has some specific limitations (array support and complex object graphs are two big ones for me). This is a CTP though so I only cried a little.
That other MVC framework has a sweet Binder component that has a slew of features including support for arrays, generic lists, complex object graphs. The implementation uses an intelligent tree style parser to enable some of the cooler features. It was too much to wrap my head around so I went with a simpler implementation that addresses my current needs in the form of the NameValueDeserializer. The syntax is demonstrated in the code below:
[Test]
public void DeserializeComplexGenericList()
{
NameValueCollection collection = new NameValueCollection();
collection["emp.OtherPhones[0].Number"] = "800-555-1212";
collection["emp.OtherPhones[1].Number"] = "800-867-5309";
collection["emp.OtherPhones[1].AreaCodes[0]"] = "800";
collection["emp.OtherPhones[1].AreaCodes[1]"] = "877";
NameValueDeserializer nvd = new NameValueDeserializer();
Employee emp = nvd.Deserialize<Employee>(collection, "emp");
Assert.IsNotNull(emp);
Assert.AreEqual(2, emp.OtherPhones.Count);
Assert.AreEqual("800-555-1212", emp.OtherPhones[0].Number);
Assert.AreEqual("800-867-5309", emp.OtherPhones[1].Number);
Assert.AreEqual(2, emp.OtherPhones[1].AreaCodes.Count);
Assert.AreEqual("800", emp.OtherPhones[1].AreaCodes[0]);
Assert.AreEqual("877", emp.OtherPhones[1].AreaCodes[1]);
}
private class Employee
{
public int Id
{
get;
set;
}
private readonly Phone _phone = new Phone();
public Phone Phone
{
get { return _phone; }
}
private readonly List<Phone> _otherPhones = new List<Phone>();
public IList<Phone> OtherPhones
{
get { return _otherPhones; }
}
}
public class Phone
{
public string Number
{
get;
set;
}
private readonly List<string> _areaCodes = new List<string>();
public IList<string> AreaCodes
{
get { return _areaCodes; }
}
}
You provide the collection of values, the prefix that identifies items applicable to your object, and the type of object you are looking for. I haven't yet made any mature optimizations but I have made a few premature optimizations. I'd love some feedback on optimizing the handling of arrays. I'm sure there are some edge cases I missed so please submit patches.
posted @ Monday, December 10, 2007 9:21 AM