Search code examples
stringasp.net-mvc-3renderwcf-rest

Render an MVC3 action to a string from a WCF REST service method


I have a WCF REST service that takes some parameters and sends an email. The template for the email is an MVC3 action. Essentially I want to render that action to a string.

If it were an ASP.NET WebForm, I could simply use Server.Execute(path, stringWriter, false). However when I plug in the path to my action, I get Error executing child request.

I have full access to HttpContext from my service (AspNetCompatibilityRequirementsMode.Allowed).

I know there are other answers out there for rendering actions to strings from within the context of a controller. How do I do this when I'm outside that world, but still on the same server (and, for that matter, in the same app)?


Solution

  • I cobbled together an answer based on several different google searches. It works, but I'm not 100% sure it's as lean as it could be. I'll paste the code for others to try.

    string GetEmailText(TemplateParameters parameters) {
        // Get the HttpContext
        HttpContextBase httpContextBase = 
            new HttpContextWrapper(HttpContext.Current);
        // Build the route data
        var routeData = new RouteData();
        routeData.Values.Add("controller", "EmailTemplate");
        routeData.Values.Add("action", "Create");
    
        // Create the controller context
        var controllerContext = new ControllerContext(
            new RequestContext(httpContextBase, routeData), 
            new EmailTemplateController());
    
        var body = ((EmailTemplateController)controllerContext.Controller)
                   .Create(parameters).Capture(controllerContext);
        return body;
    }
    
    // Using code from here:
    // http://blog.approache.com/2010/11/render-any-aspnet-mvc-actionresult-to.html
    public class ResponseCapture : IDisposable
    {
        private readonly HttpResponseBase response;
        private readonly TextWriter originalWriter;
        private StringWriter localWriter;
        public ResponseCapture(HttpResponseBase response)
        {
            this.response = response;
            originalWriter = response.Output;
            localWriter = new StringWriter();
            response.Output = localWriter;
        }
        public override string ToString()
        {
            localWriter.Flush();
            return localWriter.ToString();
        }
        public void Dispose()
        {
            if (localWriter != null)
            {
                localWriter.Dispose();
                localWriter = null;
                response.Output = originalWriter;
            }
        }
    }
    public static class ActionResultExtensions
    {
        public static string Capture(this ActionResult result, ControllerContext controllerContext)
        {
            using (var it = new ResponseCapture(controllerContext.RequestContext.HttpContext.Response))
            {
                result.ExecuteResult(controllerContext);
                return it.ToString();
            }
        }
    }