Extending WebFormView in MVC
Asked Answered
R

3

0

I want to extend the WebFormViewEngine so that I can perform some post-processing - I want it to do it's stuff, then hand me the Html back, so I can do put some final touches to it. It needs to be done as a View/ViewEngine because I need access to the ViewData.

Unfortunately there seems to be no way to get the Html back from the WebFormView, and no way to hand a custom HtmlTextWriter to the WebFormView or ViewPage.

Surely there's a way to do this? No?

Littlecharva

Roseliaroselin answered 4/3, 2009 at 14:48 Comment(0)
T
2

You can use Action Filters to do this. Check out this tutorial at asp.net/mvc. You want to use a ResultsFilter.

As an alternate, you can override the virtual OnResultExecuted method of the Controller.

Tubby answered 7/3, 2009 at 2:45 Comment(2)
Thanks, that gets me a little closer to where I want to be. I can obviously acheive what I want using Action Filters or overriding OnResultExecuted, but I feel the code I'm writing belongs in a ViewEngine, as it will be run on ALL views.Roseliaroselin
It may run on all views in THIS application, but not every application. You don't want to be changing the framework for every project.Tubby
F
1

You can capture output recevier before the View gets rendered by overriding Render method of the WebFormView class. The trick is that the output receiver is not the System.IO.TextWriter writer but the Writer property of the viewContext. Also, you have to extend WebFormViewEngine to return your views.

public class MyViewEngine : WebFormViewEngine
{
    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        return new MyView(partialPath, null);
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        return new MyView(viewPath, masterPath);
    }
}    

public class MyView : WebFormView
{
    public MyView(string inViewPath, string inMasterPath) : base(inViewPath, inMasterPath) { }
    public MyView(string inViewPath) : base(inViewPath) { }

    public override void Render(ViewContext viewContext, System.IO.TextWriter writer)
    {
        //make a switch to custom output receiver
        var oldWriter = viewContext.Writer;
        viewContext.Writer = new System.IO.StringWriter();
        base.Render(viewContext, null);
        viewContext.Writer.Close();

        //get output html
        var html = ((System.IO.StringWriter)viewContext.Writer).GetStringBuilder();

        //perform processing
        html.Replace('a', 'b');

        //retransmit output
        viewContext.Writer = oldWriter;
        viewContext.Writer.Write(html);
    }
}
Framing answered 24/10, 2011 at 9:0 Comment(0)
K
0

Okay, I have never done this before but I looked through reflector and the MVC assemblies. It appears as though you it might be possible to extend the ViewPage and the ViewPage and the ViewMasterPage object with your object. The in your own object you can override the render method and get a handle tot the HtmlTextWriter. Then just pass it on to the base and let it do it's thing. Something like this (this is un-tested and is only theoretical, there may be more methods you need to override.) I recommend using reflector to see how it is done now and even how other view engines like Spark do it.

public class MyPage : ViewPage
{
    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    {
        //Do custom stuff here
        base.Render(writer);
    }
}
public class MyPage<TModel> : MyPage where TModel : class
{
}
Krafftebing answered 4/3, 2009 at 18:26 Comment(1)
I had used reflector and investigated that route, the problem is that there appears to be no way to have the WebViewEngine instantiate my ViewPage instead of the default one. It seems to use a BuildManager, but there's no obvious way to control the BuildManager.Roseliaroselin

© 2022 - 2024 — McMap. All rights reserved.