Récupération de la sortie html d’une vue asp.net mvc

Pour pouvoir templater des emails pour un site web en utilisant asp.net mvc, j’avais besoin de pouvoir recuperer la sortie html d’une vue sans avoir à recrawler une page (ce qui provoque des problèmes de statistiques et autres), en cherchant je suis tombé sur cet article très interessant :

http://jwbs-blog.blogspot.com/2009/08/chaining-aspnet-mvc-actions.html

Je l’ai un peu modifié pour en faire une methode d’extension :

public static string GetActionOutput<T>(this System.Web.Mvc.Controller ctrl, Expression<Action<T>> action)
{
var body = action.Body as MethodCallExpression;

var responseFilter = ctrl.HttpContext.Response.Filter;
var memoryStreamFilter = new MemoryStreamFilter(ctrl.HttpContext.Response.Filter);
ctrl.HttpContext.Response.Filter = memoryStreamFilter;

var routeData = ctrl.ControllerContext.RequestContext.RouteData;
string controllerName = body.Object.Type.Name.Replace("Controller", "");
string actionName = body.Method.Name;
var orgAction = routeData.Values["action"];
var orgController = routeData.Values["controller"];
routeData.Values["action"] = actionName;
routeData.Values["controller"] = controllerName;

var parameters = body.Method.GetParameters();
if (parameters.Length > 0)
{
for (int i = 0; i < parameters.Length; i++)
{
var expression = body.Arguments[i];
object value = null;
var constantExpression = expression as ConstantExpression;
if (constantExpression != null)
{
value = constantExpression.Value;
}
else
{
var lambda = Expression.Lambda<Func<object>>(Expression.Convert(expression, typeof(object)), new ParameterExpression[0]);
value = lambda.Compile()();
}

routeData.Values.Add(parameters[i].Name, value);
}
}

var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
var c = controllerFactory.CreateController(ctrl.ControllerContext.RequestContext, controllerName);
c.Execute(ctrl.ControllerContext.RequestContext);

ctrl.HttpContext.Response.Flush();
memoryStreamFilter.Position = 0;
string result = null;
using (var r = new StreamReader(memoryStreamFilter))
{
result = r.ReadToEnd();
r.Close();
}

memoryStreamFilter.Close();
memoryStreamFilter.Dispose();

ctrl.HttpContext.Response.Filter = responseFilter;
routeData.Values["action"] = orgAction;
routeData.Values["controller"] = orgController;

return result;
}





voici la classe de wrapping pour recuperer la sortie en mémoire :




public class MemoryStreamFilter : MemoryStream
{
public MemoryStreamFilter(Stream stream)
{

}
}





pour utiliser cette methode d’extension, il suffit de faire un appel comme ceci :




public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";

var content = this.GetActionOutput<HomeController>(i => i.About());

return View();
}





il est possible de passer des paramètres, la methode est prevue pour ça.

Aucun commentaire: