Thursday, June 05, 2008

LINQ to CSV

I thought it would be nice to be able to produce a CSV file by doing something like this:

string ordersCsv = orderRepository.GetAll().Select(o => new 
{ 
    OrderId = o.OrderId,
    Email = o.Email,
    OrderStatus = o.OrderStatus.Name,
    CreatedDate = o.CreatedDate,
    Total = o.Basket.Total
}).AsCsv();

So here's an extension method to do just that:

public static string AsCsv<T>(this IEnumerable<T> items)
    where T : class
{
    var csvBuilder = new StringBuilder();
    var properties = typeof (T).GetProperties();
    foreach (T item in items)
    {
        string line = properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray().Join(",");
        csvBuilder.AppendLine(line);
    }
    return csvBuilder.ToString();
}

private static string ToCsvValue<T>(this T item)
{
    if (item is string)
    {
        return "\"{0}\"".With(item.ToString().Replace("\"", "\\\""));
    }
    double dummy;
    if (double.TryParse(item.ToString(), out dummy))
    {
        return "{0}".With(item);
    }
    return "\"{0}\"".With(item);
}

It's work with anything that implements IEnumerable<T>, that includes the results of LINQ-to-SQL queries , arrays, List<T> and pretty much any kind of collection. Here's it's unit test:

[TestFixture]
public class EnumerableExtensionsTests
{
    [Test]
    public void GetCsv_ShouldRenderCorrectCsv()
    {
        IEnumerable<Thing> things = new List<Thing>()
            {
                new Thing
                    {
                        Id = 12,
                        Name = "Thing one",
                        Date = new DateTime(2008, 4, 20),
                        Child = new Child
                                    {
                                        Name = "Max"
                                    }
                    },
                new Thing
                    {
                        Id = 13,
                        Name = "Thing two",
                        Date = new DateTime(2008, 5, 20),
                        Child = new Child
                                    {
                                        Name = "Robbie"
                                    }
                    }
            };

        string csv = things.Select(t => new { Id = t.Id, Name = t.Name, Date = t.Date, Child = t.Child.Name }).AsCsv();

        Assert.That(csv, Is.EqualTo(expectedCsv));
    }

    const string expectedCsv = 
@"12,""Thing one"",""20/04/2008 00:00:00"",""Max""
13,""Thing two"",""20/05/2008 00:00:00"",""Robbie""
";

    public class Thing
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Date { get; set; }
        public Child Child { get; set; }
    }

    public class Child
    {
        public string Name { get; set; }
    }
}

MVC Framework: Capturing the output of a view (part 2)

Yesterday I wrote about a technique for capturing the HTML output by a view so that you could do something else with it, like send it in an email. However there turned out to be serious problems with that technique. Because it used the current HttpResponse instance it set the internal _headersWritten flag of the Response. When I subsequently wanted to execute a redirect I got an error saying:

"System.Web.HttpException: Cannot redirect after HTTP headers have been sent."

I tried to find some way to reset this flag, but there didn't seem to be any way of doing it. However, after digging around the MVC source code and with a bit of help from Reflector I found an entirely different (and better I think) approach. Rather than use the MVCContrib BlockRenderer I simply replace the current HttpContext with a new one that hosts a Response that writes to a StringWriter.

I've wrapped it all up in an extension method on Controller called CaptureActionHtml, so you can write code like this example from Suteki Shop that I use to send an order email confirmation:

[NonAction]
public virtual void EmailOrder(Order order)
{
    string subject = "{0}: your order".With(this.BaseControllerService.ShopName);

    string message = this.CaptureActionHtml(c => (ViewResult)c.Print(order.OrderId));

    var toAddresses = new[] { order.Email, BaseControllerService.EmailAddress };

    // send the message
    emailSender.Send(toAddresses, subject, message);
}

There are also overloads that allow you to call an action on a different controller than the current one, here's an example from a test controller I wrote where the TestController is executing the Item action on the orderController, using an alternate master page, called  "Print", and then writing the HTML output to a log:

public class TestController : Controller
{
    private readonly OrderController orderController;
    private readonly ILogger logger;

    public TestController(OrderController orderController, ILogger logger)
    {
        this.orderController = orderController;
        this.logger = logger;
    }

    public ActionResult Index()
    {
        string html = this.CaptureActionHtml(orderController, "Print", c => (ViewResult)c.Item(8));

        logger.Info(html);

        // do a redirect
        return RedirectToRoute(new {Controller = "Order", Action = "Item", Id = 8});
    }
}

The best way of seeing this all in action is to get the latest code for Suteki Shop, There's a stand-alone Suteki.Common assembly that you can include in your project that provides these extension methods in the Suteki.Common.Extensions namespace.

But here is the code for the extension class if you want to just cut and paste:

using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

namespace Suteki.Common.Extensions
{
    public static class ControllerExtensions
    {
        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The controller</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this TController controller,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(controller, null, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The controller</param>
        /// <param name="masterPageName">The master page to use for the view</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this TController controller,
            string masterPageName,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(controller, masterPageName, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The current controller</param>
        /// <param name="targetController">The controller which has the action to execute</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this Controller controller,
            TController targetController, 
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(targetController, null, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The current controller</param>
        /// <param name="targetController">The controller which has the action to execute</param>
        /// <param name="masterPageName">The name of the master page for the view</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this Controller controller,
            TController targetController, 
            string masterPageName,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            if (controller == null)
            {
                throw new ArgumentNullException("controller");
            }
            if (targetController == null)
            {
                throw new ArgumentNullException("targetController");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            // pass the current controller context to orderController
            var controllerContext = controller.ControllerContext;
            targetController.ControllerContext = controllerContext;

            // replace the current context with a new context that writes to a string writer
            var existingContext = System.Web.HttpContext.Current;
            var writer = new StringWriter();
            var response = new HttpResponse(writer);
            var context = new HttpContext(existingContext.Request, response) {User = existingContext.User};
            System.Web.HttpContext.Current = context;

            // execute the action
            var viewResult = action(targetController);

            // change the master page name
            if (masterPageName != null)
            {
                viewResult.MasterName = masterPageName;
            }

            // we have to set the controller route value to the name of the controller we want to execute
            // because the ViewLocator class uses this to find the correct view
            var oldController = controllerContext.RouteData.Values["controller"];
            controllerContext.RouteData.Values["controller"] = typeof(TController).Name.Replace("Controller", "");

            // execute the result
            viewResult.ExecuteResult(controllerContext);

            // restore the old route data
            controllerContext.RouteData.Values["controller"] = oldController;

            // restore the old context
            System.Web.HttpContext.Current = existingContext;

            return writer.ToString();
        }
    }
}

Wednesday, June 04, 2008

More Windsor Love: Using log4net integration

Adopting an IoC container has been a software revelation for me. It just keeps on getting better. I just added logging to Suteki Shop simply by doing the following steps (thanks to Sean Chambers for the details)

1. Add a reference to the following Castle Project dlls:

Castle.Facilities.Logging.dll
Castle.Services.Logging.Log4netIntegration.dll

2. Configure the LoggingFacility:

<facilities>
  <facility
    id="loggingfacility"
    configfile="log4net.config"
    loggingapi="log4net"
    type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging" />
</facilities>

3. Add the log4net config file to the root of the web application:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>

  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="sutekishop.log" />
    <appendToFile value="true" />
    <maximumFileSize value="100KB" />
    <maxSizeRollBackups value="2" />

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%level %thread %logger - %message%newline" />
    </layout>
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="RollingFile" />
  </root>
</log4net>
</configuration>

And that's all. Isn't that cool, now I can simply add a dependcy for ILogger to any service in my application and log to my heart's content.

MVC Framework: Capturing the output of a view

Update: I found that this technique has problems because it changes the state of the HttpResponse by setting its internal _headersWritten flag which means you can't subsequently execute a redirect. I've developed a different and better technique which involves replacing the current HttpContext. See this post:

MVC Framework: Capturing the output of a view (part 2)

Sometimes it's useful to be able to capture the output of a view rather than simply have it streamed to the Response.OutputStream. A couple of things have made this quite easy to do. Firstly, from CTP 3 of the MVC Framework, controllers now return an ActionResult rather than just setting properties and leaving the infrastructure to act on them. This means we can take a ViewResult and call ExecuteResult on it before it's returned, allowing us to take control of the rendering.

The second innovation is a nice piece of work from the MVCContrib project. This is an open source add-on to the MVC Framework that provides lots of useful stuff like standard error handling, data binding, IoC container integration and lots more. If you're building MVC Framework applications you really should look at what this project can do for you. Deep in its bowels is the BlockRenderer class, this can take any action that renders to Response.OutputStream and divert it to a string. It does it by adding a custom filter to the Response filter chain.

Here's a silly example of it in action. I've created a test controller and in its Index action I'm calling the Item action on another controller called orderController. I'm then using the BlockRenderer to capture the rendering of the Item view in a string, which is then simply displayed.

using System.Web.Mvc;
using MvcContrib.UI;

namespace Suteki.Shop.Controllers
{
public class TestController : Controller
{
private OrderController orderController;

public TestController(OrderController orderController)
{
this.orderController = orderController;
}

public ActionResult Index()
{
// pass the current controller context to orderController
orderController.ControllerContext = ControllerContext;

// create a new BlockRenderer
var blockRenderer = new BlockRenderer(HttpContext);

// execute the Item action
var viewResult = (ViewResult) orderController.Item(1);

// change the master page name
viewResult.MasterName = "Print";

// we have to set the controller route value to the name of the controller we want to execute
// because the ViewLocator class uses this to find the view
this.RouteData.Values["controller"] = "Order";

string result = blockRenderer.Capture(() => viewResult.ExecuteResult(ControllerContext));

return Content(result);
}
}
}


Note that I change the name of the master page. You can imagine that the "Print" master page is a simple body tag container without any of the site furniture: menus and wotnot, that my standard master page might have. I also have to change the controller route value because the ViewLocator class of the MVC Framework uses it to find the view name.



The main reason I have for doing this, is so that I can send a view by email, but you can imagine how it might be useful to do other things like build up a page from multiple controllers and or views.

Developer Developer Developer Day 7

DDD7 (UK) has recently been announced. It's going to be held at the Microsoft campus in Reading on the 22nd of November. Submissions for talks have now opened. I've put forward two suggestions, both on IoC containers. The first will be an updated version of the IoC introductory talk I gave last year:

Why do I need an Inversion of Control Container

"Inversion of Control (IoC) containers such as Unity Windsor and Structure Map are a hot topic in the Microsoft Development world. What are they and why is there such a buzz about them? How will they help me build better applications? Join me on a trip to an parallel universe of application architecture where I show how IoC containers at last make component oriented software development a reality."

This is an introduction to IoC and IoC containers. It's a description of how the IoC design pattern is a simple way of building component oriented software and how IoC containers add a bit of magic to that party. The other talk I've suggested is a deeper look at the subject by examining its use in a real application:

Using an Inversion of Control Container in a real world application

"Going beyond an initial introduction to IoC containers, this talk shows their use in an open source eCommerce application, Suteki Shop. I will show how the IoC container helps us write component oriented software and can significantly simplify both our architecture and code. This will include a look at some nice techniques such as generic repositories, using IoC containers with the MVC Framework and how they can help us host services."

The idea here is to pass on my experience of building applications based around these techniques. There will be a lot of code and practical advice. I'm still on a steep learning curve myself with all this, so I expect that by November there will be a lot in this talk that I'm not even aware of yet.

Saturday, May 31, 2008

Interface + Extension Methods = Mixin

Mixins are a language idea similar to multiple inheritance, but rather than extending a class a mixin works by defining an interface plus various functionality associated with that interface. It avoids the pathologies of multiple inheritance and is a flexible way of providing add-on functionality.

In C# we can create a mixin with a combination of an interface plus extension methods. LINQ is the canonical example of this with two core interfaces IEnumerable<T> and IQueriable<T> and a collection of extension methods on those interfaces.

It's easy to create your own mixins. For example, say I want to provide location functionality to various entities. I can define an interface like this:

public interface ILocatable
{
   int Longitude { get; set; }
   int Latitude { get; set; }
}

And then some extension methods for that interface:

public static class LocatableExtensions
{
   public static void MoveNorth(this ILocatable locatable, int degrees)
   {
       // ...
   }

   public static void MoveWest(this ILocatable locatable, int degrees)
   {
       // ..
   }
}

Now, if we've got some entities like:

public class Ship : ILocatable
{
   public int Longitude { get; set; }
   public int Latitude { get; set; }
}

public class Car : ILocatable
{
   public int Longitude { get; set; }
   public int Latitude { get; set; }
}

We can use the mixin like this:

Ship ship = new Ship(); ship.MoveNorth(10); Car car = new Car(); car.MoveWest(23);

It's a very nice pattern for adding capabilities to entities.

Thursday, May 29, 2008

Upgrading Suteki Shop to MVC Framework CTP 3

I've just spent this morning upgrading Suteki Shop to the latest version of the MVC Framework; CTP 3. There are some nice touches in it, but not an awful lot has changed, especially if, like me, you've been using the Code Plex source that was recently made available. Scott Guthrie details most of the major changes with this release on his blog.

Action Result

Still, it wasn't all plain sailing, there have been a lot of API changes since the last code drop. The names of the new controller action return values have changed as have the properties on the Controller base class which return them. I had to do a global find and replace for those. I'd written some nice test helper extension methods around ActionResult which had to be upgraded.

View data changes

The changes to view data caused a lot of churn as well. Now, instead of two separate kinds of view data; dictionary and strongly typed, there's a single class ViewDataDictionary<T> that supports both, with a new Model property having the type of the type parameter. This means that every invocation of ViewData in your View has to change to ViewData.Model. Currently I factor all my view data into a strongly typed hierarchy that I can pass through to various html helpers I've written, but with the new style view data there might be an opportunity for some nice refactorings.

Select rendering changes

Anther change which brings up some nice possibilities is the separation of the DropDownList html helper extension (renamed from 'Select') from the actual building of the select list itself in a SelectList class that you can pass from the controller along with all its data. Providing select lists from an IoC container might be a nice way to factor the loading of lookup data out from the controller.

One thing caught me out though. They've changed the order of the 'value' and 'text' parameters from the old Select helper method. I got some nasty runtime errors because of this.

'Hidden' extension method changes

Another nasty was the Hidden html helper extension method that renders an '<input type="hidden">' tag. It now takes a string as its value parameter instead of an object. For some reason the aspnet compiler doesn't seem to catch this change and so my forms were failing at runtime with the value parameter as an empty string.

MVCContrib

Probably the biggest investment of time this morning was changing the MVCContrib code to work with CTP 3. No, I didn't upgrade the entire thing; I just ripped out anything I wasn't using and upgraded the rest. It wasn't too bad in the end which must be tribute to the quality of the code. Once Jeremy and co have got the whole thing working with CTP 3, I'll move back to the main branch.

It's really fun working with the MVC Framework. The pace of development has been swift and it's nice that the team don't have to bake in the API at this stage which has allowed them to progressively factor the framework with feedback from the community. Sure it means that you have to spend half a day changing your code to work with a new release every so often, but if that means the design can evolve rapidly, I'm all for it.

Monday, May 26, 2008

Compiling aspx templates using aspnet_compiler

The default build process for aspx files is a problem in web site development. By default they only build on request, so nasty compile time errors can lay hidden until you actually hit the problem page when looking at the site. This is a real pain; when I hit F6, I want everything to build.

I've only recently come across the command line tool aspnet_compiler. It simply pre-compiles all the aspx pages in your web application. You can run it as a post build event which means all your aspx templates get built each time:

aspnet_compiler_setup

Now when you build, you get aspx errors reported too. Clicking on the errors takes you to the correct place in the aspx file, just like with regular .cs code:

aspnet_compiler_errors

Now is this common knowledge that I've just somehow missed out on. It seems strange that I had to work out this trick by myself?

What is RSD? Making my Suteki Shop to Live Writer integration slicker.

I recently wrote about how nice it is to use the MetaWeblog API to allow tools like Live Writer update content on bespoke software like my Suteki Shop eCommerce application (which is now morphing into a generic CMS). The one thing I didn't like was the step that requires the user to enter the API their site exposes and it's endpoint:

3_SelectProvider

A little more digging around the Live Writer docs and various blogs led me to discover Really Simple Discovery (RSD). It's an XML schema for describing the APIs that your software exposes by Daniel Berlinger.

In the head of your homepage you have a link to the location of your rsd.xml file:

<link title="RSD" href="http://localhost:63638/rsd.xml" type="application/rsd+xml" rel="EditURI" />

And here's the file itself:

<?xml version="1.0" encoding="utf-8" ?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd" >
 <service>
   <engineName>SutekiShop</engineName>
   <engineLink>http://sutekishop.co.uk/</engineLink>
   <homePageLink>http://localhost:63638/home</homePageLink>
   <apis>
     <api name="MetaWeblog" preferred="true" apiLink="http://localhost:63638/metablogapi.aspx" blogID="1" />
   </apis>
 </service>
</rsd>

As you can see it simply contains the web site engine name (suteki shop), the URL of the engine's homepage and the URL of this instance's homepage. Then follows a list of APIs that the engine supports. In my case it's a single entry for MetaWeblog that shows the XML RPC endpoint.

In the case of Suteki Shop, since it's an MVC Framework based application the rsd.xml file itself is generated from a view that simply inserts the current application URL where, in this case, "http://localhost:63638" appears.

Wednesday, May 21, 2008

Using Live Writer to Post Content to a Web Site

I've just added the MetaWeblog API to the Content Management System (CMS) of Suteki Shop. It's most excellent. It means that an administrator can manage the content of the web site using a slick WSYWIG tool like Windows Live Writer. I simply ripped the code for the API from Subtext, a really nice open source blogging application. It took me most of today to get it working, but it'll be a major win for my users who I can't expect to write HTML straight into a web based admin interface.

It's really easy to set up. Simply open up Live Writer and add a new account saying you want to use 'Another weblog service':

1_chooseBlogType

Then enter the URL of the application, here I'm just giving it the URL of the Visual Studio Development Web Server. You also need to enter an admin username (email) and password.

2_HomepageAndLogin

The last step is to tell Live Writer that Suteki Shop uses the Metaweblog API and point it to the XmlRpc endpoint that hosts the API.

3_SelectProvider

After that it's all set up and you can write a post, including images in live writer:

LiveWriterEdit

When you click the 'Publish' button the content magically appears with a new menu item on the Suteki Shop site:

InSutekiShop

You can find my subtext's implementation of the MetaWeblog API the usual place:

http://code.google.com/p/sutekishop/source/checkout

The MetaWeblog API is implemented in the files:

MetaWeblogAPI.cs

MetaWeblog.cs

Note the additional handler in the web.config file:

<add type="Suteki.Shop.XmlRpc.MetaWeblog, Suteki.Shop" path="metablogapi.aspx" verb="*" />