Wednesday, April 29, 2015

Custom Action Results in ASP.NET 5 (VNEXT) (MVC6)

Before we start, you should be aware of this. This post is based on a the ASP.NET 5 version, Visual Studio 2015 CTP 6 pulls down, when it creates an ASP.NET 5 Project. Meaning it is a pre-release of ASP.NET 5. Things in ASP.NET 5 can change and outdate this post. It is highly unlikely, but it can happen.

Even thou I keep referring MVC 6, it is still a post regarding ASP.NET 5 or ASP.NET vNext, it's the same, and MVC 6 is a part of ASP.NET MVC 5.

Why would I write a custom ActionResult

Yes, good question. There is plenty supported in ASP.NET 5. But sometimes you ends up in a situation, where you need something special. When I developed Your Favorite Snippet Tool, I needed to transfer binary in a certain way, to provide best user experience. I created a custom ActionResult to handle it.

ActionResult in MVC 6 compared to earlier versions

ActionResults have changed a bit, since the prior versions of MVC. Yes, you still have to inherit from ActionResult and yes you still have to override a ExecuteResult method, when making custom ActionResults.

The most noticeable difference, is that in MVC 6 ExecuteResult have another signature compared to prior version, and there is also a ExecuteResultAsync added.

ExecuteResult for ASP.NET MVC 5 and Prior


public abstract void ExecuteResult(ControllerContext context)

ExecuteResult for ASP.NET MVC 6


public virtual Task ExecuteResultAsync(ActionContext context)
public virtual void ExecuteResult(ActionContext context)

Two thing you might notice, the methods in MVC 6 are using virtual methods, and ActionContext instead of ControllerContext. There is nothing much to say about the contexts, they are very similar. By using virtual method there is no override constrains. It means that you can override either ExecuteResultAsync, ExecuteResult or both, but are not forced to.

Which to override, ExecuteResultAsync or ExecuteResult

It depends, but preferly ExecuteResultAsync, because it is the one which is called. Inside ActionResult, which you have to inherit from, following logic is happening:

 public abstract class ActionResult : IActionResult  
   {  
     public virtual Task ExecuteResultAsync(ActionContext context)  
     {  
       ExecuteResult(context);  
       return Task.FromResult(true);  
     }  
     public virtual void ExecuteResult(ActionContext context)  
     {  
     }  
   }  

So you see, ExecuteResultAsync is still called even thou you just override ExecuteResult. Plus, it will not make sense, to enforce overrides of the 2 methods.


Show me some code

I have made a string writer result, not the most exciting example, but it proves the point.

The custom ActionResult

 using Microsoft.AspNet.Mvc;  
 using System.Text;  
 using System.Threading.Tasks;  
 namespace CustomActionResults  
 {  
   internal class StringWriterResult : ActionResult  
   {  
     private byte[] _stringAsByteArray;  
     public StringWriterResult(string stringToWrite)  
     {  
       _stringAsByteArray = Encoding.ASCII.GetBytes(stringToWrite);  
     }  
     public override Task ExecuteResultAsync(ActionContext context)  
     {  
       context.HttpContext.Response.StatusCode = 200;  
       return context.HttpContext.Response.Body.WriteAsync(_stringAsByteArray, 0, _stringAsByteArray.Length);  
     }  
   }  
 }  


String write ActionResult in action:

 using CustomActionResults;  
 using Microsoft.AspNet.Mvc;  
 namespace ActionHandlers.Controllers  
 {  
   public class ExampleController : Controller  
   {  
     public IActionResult Get()  
     {  
       return new StringWriterResult("Hello World!");  
     }  
   }  
 }  

Insert the code in some ASP.NET 5 project, and you should get Hello World!, when hitting ~/Example/Get.


No comments:

Post a Comment