将视图渲染为字符串,然后重定向会导致异常

发布于 2024-07-27 04:32:38 字数 1988 浏览 6 评论 0原文

所以问题是:我正在通过将完整视图页面渲染为字符串并发送它们来构建要由我的应用程序发送的电子邮件。 只要我之后不重定向到该网站上的另一个 URL,此操作就不会出现任何问题。 每当我尝试时,都会收到“System.Web.HttpException:发送 HTTP 标头后无法重定向”。

我相信问题来自于我正在重用来自创建电子邮件的调用的控制器操作的上下文。 更具体地说,来自上下文的 HttpResponse。 不幸的是,我无法创建一个使用 HttpWriter 的新 HttpResponse,因为该类的构造函数无法访问,并且使用从 TextWriter 派生的任何其他类都会导致 response.Flush() 本身引发异常。

有人有解决方案吗?

    public static string RenderViewToString(
        ControllerContext controllerContext,
        string viewPath,
        string masterPath,
        ViewDataDictionary viewData,
        TempDataDictionary tempData)
    {
        Stream filter = null;
        ViewPage viewPage = new ViewPage();

        //Right, create our view
        viewPage.ViewContext = new ViewContext(controllerContext,
            new WebFormView(viewPath, masterPath), viewData, tempData);

        //Get the response context, flush it and get the response filter.
        var response = viewPage.ViewContext.HttpContext.Response;
        //var response = new HttpResponseWrapper(new HttpResponse
        //    (**TextWriter Goes Here**));
        response.Flush();
        var oldFilter = response.Filter;

        try
        {
            //Put a new filter into the response
            filter = new MemoryStream();
            response.Filter = filter;

            //Now render the view into the memorystream and flush the response
            viewPage.ViewContext.View.Render(viewPage.ViewContext,
                viewPage.ViewContext.HttpContext.Response.Output);
            response.Flush();

            //Now read the rendered view.
            filter.Position = 0;
            var reader = new StreamReader(filter, response.ContentEncoding);
            return reader.ReadToEnd();
        }
        finally
        {
            //Clean up.
            if (filter != null)
                filter.Dispose();

            //Now replace the response filter
            response.Filter = oldFilter;
        }
    }

So here's the issue: I'm building e-mails to be sent by my application by rendering full view pages to strings and sending them. This works without any problem so long as I'm not redirecting to another URL on the site afterwards. Whenever I try, I get "System.Web.HttpException: Cannot redirect after HTTP headers have been sent."

I believe the problem comes from the fact I'm reusing the context from the controller action where the call for creating the e-mail comes from. More specifically, the HttpResponse from the context. Unfortunately, I can't create a new HttpResponse that makes use of HttpWriter because the constructor of that class is unreachable, and using any other class derived from TextWriter causes response.Flush() to throw an exception, itself.

Does anyone have a solution for this?

    public static string RenderViewToString(
        ControllerContext controllerContext,
        string viewPath,
        string masterPath,
        ViewDataDictionary viewData,
        TempDataDictionary tempData)
    {
        Stream filter = null;
        ViewPage viewPage = new ViewPage();

        //Right, create our view
        viewPage.ViewContext = new ViewContext(controllerContext,
            new WebFormView(viewPath, masterPath), viewData, tempData);

        //Get the response context, flush it and get the response filter.
        var response = viewPage.ViewContext.HttpContext.Response;
        //var response = new HttpResponseWrapper(new HttpResponse
        //    (**TextWriter Goes Here**));
        response.Flush();
        var oldFilter = response.Filter;

        try
        {
            //Put a new filter into the response
            filter = new MemoryStream();
            response.Filter = filter;

            //Now render the view into the memorystream and flush the response
            viewPage.ViewContext.View.Render(viewPage.ViewContext,
                viewPage.ViewContext.HttpContext.Response.Output);
            response.Flush();

            //Now read the rendered view.
            filter.Position = 0;
            var reader = new StreamReader(filter, response.ContentEncoding);
            return reader.ReadToEnd();
        }
        finally
        {
            //Clean up.
            if (filter != null)
                filter.Dispose();

            //Now replace the response filter
            response.Filter = oldFilter;
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

貪欢 2024-08-03 04:32:38

您必须发起新的请求。
位,你真的想用这种方式同步发送电子邮件吗? 如果邮件服务器宕机,用户可能会等待很长时间。

我总是将电子邮件放入离线队列中并让服务邮寄它们。 您可以考虑为此使用 Spark 模板引擎。

另一种方法是不重定向,而是写出带有元重定向标记的页面

You'd have to initiate a new request.
Bit, do you really want to send emails synchronously this way? If the mail server is down, the user could be waiting a good while.

I always put emails in an offline queue and have a service mail them. You might consider using the Spark template engine for this.

One other approach is to not redirect but write out a page with a meta redirect tag

面如桃花 2024-08-03 04:32:38

这是将视图渲染为字符串的另一种方法,该方法永远不会导致数据输出到响应(因此它应该避免您的问题): http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view- to-string/

要渲染常规视图而不是部分视图,您需要将“ViewEngines.Engines.FindPartialView”更改为“ViewEngines.Engines.FindView”。

Here is an alternative method for rendering a view to a string that never results in data being output to the response (therefore it should avoid your problem): http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/

To render a regular view instead of a partial view, you'll need to change "ViewEngines.Engines.FindPartialView" to "ViewEngines.Engines.FindView".

花期渐远 2024-08-03 04:32:38

看一下 MVC Contrib EmailTemplateService ,它正是您所追求的。

http://mvccontrib.googlecode.com/svn/trunk/ src/MVCContrib/Services/EmailTemplateService.cs

抱歉克里斯,不太清楚我在想什么,但我显然没有阅读这个问题。 虽然我无法为您提供解决此问题的方法,但我可以告诉您为什么会收到错误 - HttpResponse.Flush() 在将内容刷新到过滤器之前发送标头。 这会在响应中设置一个标志,以便当您尝试重定向时会收到异常。

使用反射器查看 Flush 内部的代码,我看不到任何干净的方法可以让您在没有大量反射和其他讨厌的情况下解决这个问题。

Have a look at the MVC Contrib EmailTemplateService which does exactly what you are after.

http://mvccontrib.googlecode.com/svn/trunk/src/MVCContrib/Services/EmailTemplateService.cs

Sorry Chris, not quite sure what I was thinking but I obviously didn't read the question. While I cannot give you a way around this, I can tell you why you are getting the error - HttpResponse.Flush() sends the headers before flushing the content to your filter. This sets a flag inside the response so that when you try to redirect you get the exception.

Using reflector to look at the code inside Flush, I can't see any clean way for you to get around this without a lot of reflection and other nastiness.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文