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:
Enregistrer un commentaire