-->

Extending WebFormView in MVC

2020-05-06 18:22发布

问题:

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

回答1:

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.



回答2:

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);
    }
}


回答3:

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
{
}