Отображение представления в строку с последующим перенаправлением приводит к исключению

Итак, вот в чем проблема: я создаю электронные письма для отправки моим приложением, отображая страницы полного просмотра в строки и отправляя их. Это работает без каких-либо проблем до тех пор, пока я не перенаправляюсь на другой URL-адрес на сайте впоследствии. Всякий раз, когда я пытаюсь, я получаю «System.Web.HttpException: невозможно выполнить перенаправление после отправки заголовков HTTP».

Я считаю, что проблема связана с тем, что я повторно использую контекст действия контроллера, откуда исходит вызов для создания электронной почты. В частности, HttpResponse из контекста. К сожалению, я не могу создать новый HttpResponse, который использует HttpWriter, потому что конструктор этого класса недоступен, а использование любого другого класса, производного от 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;
        }
    }

person Chris Charabaruk    schedule 19.07.2009    source источник


Ответы (3)


Вам нужно будет инициировать новый запрос. Бит, вы действительно хотите отправлять электронные письма таким образом синхронно? Если почтовый сервер не работает, пользователь может ждать некоторое время.

Я всегда помещаю электронные письма в офлайн-очередь и получаю их от службы поддержки. Вы можете использовать для этого шаблонизатор Spark.

Еще один подход - не перенаправлять, а записывать страницу с мета-тегом перенаправления.

person Haacked    schedule 19.07.2009
comment
Я хочу использовать движок WebForms для создания самих тел электронной почты. Spark выглядит неплохо, но мне все же гораздо удобнее использовать WebForms на всех этапах. Кстати, по новому запросу я предполагаю, что HttpServerUtility.Execute - это хорошо? Что касается синхронной отправки, то этого не должно быть, все зависит от настроек SmtpClient, не так ли? Поскольку у меня есть возможность сбрасывать почту в папку для последующей отправки, это не проблема. - person Chris Charabaruk; 21.07.2009

Вот альтернативный метод рендеринга представления в строку, который никогда не приводит к выводу данных в ответ (поэтому он должен избегать вашей проблемы): http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/

Чтобы отобразить обычное представление вместо частичного, вам необходимо изменить ViewEngines.Engines.FindPartialView на ViewEngines.Engines.FindView.

person Kevin Craft    schedule 15.05.2010

Взгляните на MVC Contrib EmailTemplateService, который делает именно то, что вам нужно.

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

Извини, Крис, не совсем понимаю, о чем я думал, но, очевидно, я не читал вопрос. Хотя я не могу объяснить это, но могу объяснить, почему вы получаете ошибку - HttpResponse.Flush () отправляет заголовки перед сбросом содержимого в ваш фильтр. Это устанавливает флаг внутри ответа, так что при попытке перенаправления вы получаете исключение.

Используя рефлектор для просмотра кода внутри Flush, я не вижу никакого чистого способа обойти это без большого количества размышлений и других неприятностей.

person Neal    schedule 20.07.2009
comment
Нет, это будет та же проблема. EmailTemplateService.RenderMessage () - это практически тот же код, который я уже использую, за исключением создания MailMessage вместо строки. - person Chris Charabaruk; 21.07.2009
comment
Я знаю, что причиной этого является звонок Флашу. Фил прав, единственный способ обойти это - создать совершенно новый запрос. - person Chris Charabaruk; 24.07.2009
comment
МЕРТВАЯ ССЫЛКА: Попробуйте это вместо этого! github.com/mvccontrib/MvcContrib/blob/master/ src / MVCContrib / - person Dai Bok; 04.02.2010