Delegating Action Result

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

In my last post, I walked through a simple example of an ActionResult that you can use to transmit a file to the user’s browser along with a download prompt.

The MVC framework will include several useful action results for common tasks. However, we might not cover all results you might want to return. In this post, I walk through a simple result that will cover all remaining cases. With the DelegatingResult, you simply pass it a delegate. This provides ultimate control. Let’s see it in action.

public ActionResult Hello() {
  return new DelegatingResult(context => {
    context.HttpContext.Response.AddHeader("something", "something");
    context.HttpContext.Response.Write("Hello World!");
  });
}

Notice that we pass in a lambda to the constructor of the action result. This lambda is a delegate of type Action<ControllerContext>. By doing this, the lines of code within that block (Response.AddHeader and Response.Write) are deferred till later.

Here’s the code for this action result.

public class DelegatingResult : ActionResult {
    
  public Action<ControllerContext> Command {
    get;
    private set;
  }
    
  public DelegatingResult(Action<ControllerContext> command) {
    this.Command = command;
  }

  public override void ExecuteResult(ControllerContext context) {
    if (context == null) {
      throw new ArgumentNullException("context");
    }
        
    Command(context);
  }
}

I updated the sample I wrote in my last post to include this demo. Download the source.

Technorati Tags: aspnetmvc,actionresult,lambda

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

16 responses

  1. Avatar for Andrew Davey
    Andrew Davey May 10th, 2008

    How about having a ComposedActionResult as well?
    return new ComposedActionResult(
    RenderCookie("uid","123")
    RenderHeader("foo","bar"),
    RenderView("Index")
    )

  2. Avatar for Andrew Davey
    Andrew Davey May 11th, 2008

    Thinking about composition led me to...
    What about going back to having controller actions returning void?
    The difference being that the RenderView method only queues on operation in the controller. This queue can be played back by the MVC framework to generate output later. It can still be tested easily as well. Just expose an ResultOperations property for example.
    The controller methods will look cleaner without the "ActionResult" type and the "return". This is good! "return RenderBlah(...);" doesn't read very well IMO.
    P.S. An extra piece of testing syntax magic. The above technique allows for: Assert.That(controller.DidRenderView("Index"))
    By using an extension method that looks at the ResultOperations queue. :D

  3. Avatar for Steve
    Steve May 11th, 2008

    Andrew,
    I wonder why they don't just provide both.
    Either way, I'm happy with MS MVC :)

  4. Avatar for Dragan Panjkov
    Dragan Panjkov May 11th, 2008

    Even with this release I keep receiving error regarding assembly not signed or something like that...
    Could not load file or assembly 'System.Web.Mvc' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)

  5. Avatar for Dragan Panjkov
    Dragan Panjkov May 11th, 2008

    here are steps I am using to test this on pre-preview 3 build
    1. I create mvc project using vs template (pre-preview3) and run it to be sure it is working
    2. add actionresultlibrary project to the solution
    3. delete entire contents of bin folder in both projects
    4. add references to assemblies inside reference_assemblies folder
    5. build actionresultribrary and update reference to it inside mvc web app
    6. build mvc web app and run it... and voila... it is working perfectly

  6. Avatar for Andrew Davey
    Andrew Davey May 11th, 2008

    Steve,
    Whilst both options can live side-by-side. Would you really use the explicit ActionResult/return when void/no-return option is less effort?

  7. Avatar for Steve
    Steve May 11th, 2008

    Andrew,
    It depends on my testing strategies, or if I test at all.
    The framework an assist me for writing tests, that is great. But it assumes I'm writing tests

  8. Avatar for Haacked
    Haacked May 11th, 2008

    @Dragan nice!

  9. Avatar for Dragan Panjkov
    Dragan Panjkov May 12th, 2008

    @Haacked: I have one better solution... just replace dll's in dependencies folder with those created with my visual studio MVC template... I have resolved that early in monday morning (around 3 AM) when I wanted just to try these samples :)

  10. Avatar for Steve
    Steve May 12th, 2008

    That worked - thanks everyone

  11. Avatar for Kasper Pedersen
    Kasper Pedersen May 20th, 2008

    Hi Phil!
    Am I missing something? I still get the following error:
    "Could not load file or assembly 'System.Web.Mvc' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)"

  12. Avatar for Dragan Panjkov
    Dragan Panjkov May 22nd, 2008

    @Kasper Please try workaround I have posted in previous coment to this post

  13. Avatar for Kasper Pedersen
    Kasper Pedersen May 22nd, 2008

    @Dragan: Thanks I'll try it. I just wrongfully assumed that Phil had updated the solution to correct this error.

  14. Avatar for vakantie
    vakantie June 21st, 2008

    Great post. I think we will be able to use it on our website. Im looking forward to read more of your great tips from the trade

  15. Avatar for Andrey Skvortsov
    Andrey Skvortsov November 12th, 2008

    Is there any place for "Delegating Action Result" in beta1 with new find/render(view) separation? What does it look like for beta1?
    Thanks.

  16. Avatar for Peter Moresi
    Peter Moresi July 8th, 2010

    Excellent piece of work here! Thanks!