Chcę wygenerować dwa różne widoki (jeden jako ciąg, który zostanie wysłany jako wiadomość e-mail), a drugi stronę wyświetlaną użytkownikowi.
Czy jest to możliwe w programie ASP.NET MVC w wersji beta?
Próbowałem wielu przykładów:
1. Renderuj na łańcuch w ASP.NET MVC Beta
Jeśli użyję tego przykładu, otrzymuję komunikat „Nie można przekierować po wysłaniu nagłówków HTTP”.
2. MVC Framework: Przechwytywanie danych wyjściowych widoku
Jeśli go użyję, wydaje mi się, że nie mogę wykonać operacji redirectToAction, ponieważ próbuje ona renderować widok, który może nie istnieć. Jeśli zwrócę widok, jest on całkowicie popsuty i wcale nie wygląda dobrze.
Czy ktoś ma jakieś pomysły / rozwiązania tych problemów, czy mam jakieś sugestie dotyczące lepszych?
Wielkie dzięki!
Poniżej znajduje się przykład. Próbuję utworzyć metodę GetViewForEmail :
public ActionResult OrderResult(string ref)
{
//Get the order
Order order = OrderService.GetOrder(ref);
//The email helper would do the meat and veg by getting the view as a string
//Pass the control name (OrderResultEmail) and the model (order)
string emailView = GetViewForEmail("OrderResultEmail", order);
//Email the order out
EmailHelper(order, emailView);
return View("OrderResult", order);
}
Zaakceptowana odpowiedź od Tima Scotta (zmieniona i sformatowana przeze mnie trochę):
public virtual 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;
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;
}
}
Przykładowe użycie
Przyjęcie połączenia z kontrolera w celu otrzymania wiadomości e-mail z potwierdzeniem zamówienia, przekazanie lokalizacji Site.Master.
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
źródło
Odpowiedzi:
Oto, co wymyśliłem i działa dla mnie. Dodałem następujące metody do mojej podstawowej klasy kontrolera. (Zawsze możesz wykonać te metody statyczne gdzie indziej, które akceptują kontroler jako parametr, jak sądzę)
Styl MVC2 .ascx
Styl Razor .cshtml
Edycja: dodano kod Razor.
źródło
Ta odpowiedź nie jest w drodze. Pochodzi z https://stackoverflow.com/a/2759898/2318354, ale tutaj pokazałem sposób użycia go ze słowem kluczowym „statycznym”, aby był wspólny dla wszystkich kontrolerów.
W tym celu musisz utworzyć
static
klasę w pliku klasy. (Załóżmy, że Twoja nazwa pliku klasy to Utils.cs)Ten przykład dotyczy For Razor.
Utils.cs
Teraz możesz wywołać tę klasę ze swojego kontrolera, dodając NameSpace do pliku kontrolera w następujący sposób, przekazując „this” jako parametr do kontrolera.
Zgodnie z sugestią @Sergey ta metoda rozszerzenia może również wywoływać z cotroller, jak podano poniżej
Mam nadzieję, że przyda ci się, aby kod był czysty i uporządkowany.
źródło
To działa dla mnie:
źródło
Znalazłem nowe rozwiązanie, które renderuje widok na ciąg bez konieczności bałagania w strumieniu odpowiedzi bieżącego HttpContext (co nie pozwala na zmianę ContentType odpowiedzi lub innych nagłówków).
Zasadniczo wszystko, co robisz, to stworzyć fałszywy HttpContext, aby widok sam się renderował:
Działa to na ASP.NET MVC 1.0, razem z ContentResult, JsonResult itp. (Zmiana Nagłówków na oryginalnej HttpResponse nie generuje wyjątku „ Serwer nie może ustawić typu zawartości po wysłaniu nagłówków HTTP ”).
Aktualizacja: w ASP.NET MVC 2.0 RC kod nieco się zmienia, ponieważ musimy przekazać dane
StringWriter
używane do zapisu widoku wViewContext
:źródło
StringWriter
którego używasz do zapisuStringBuilder
, a nie do nowej instancji, w przeciwnym razie wynik widoku zostanie utracony.W tym artykule opisano, jak renderować widok do łańcucha w różnych scenariuszach:
Rozwiązanie / kod jest dostarczane jako klasa o nazwie ViewRenderer . Jest częścią zestawu WestwindToolkit Ricka Stahla w GitHub .
Użycie (3. - przykład WebAPI):
źródło
Jeśli chcesz całkowicie zrezygnować z MVC, unikając w ten sposób całego bałaganu HttpContext ...
Wykorzystuje to niesamowity silnik Razor Open Source tutaj: https://github.com/Antaris/RazorEngine
źródło
CompilerErrors
własnością wyjątku.w ten sposób otrzymujesz widok w postaci ciągu
Nazywamy tę metodę na dwa sposoby
LUB
źródło
Dodatkowa wskazówka dla ASP NET CORE:
Berło:
Realizacja:
Rejestracja w
Startup.cs
I użycie w kontrolerze:
źródło
Używam MVC 1.0 RTM i żadne z powyższych rozwiązań nie działało dla mnie. Ale ten zrobił:
źródło
Widziałem implementację dla MVC 3 i Razor z innej strony, działało to dla mnie:
Więcej informacji o renderowaniu Razor - MVC3 Wyświetl renderowanie do łańcucha
źródło
Aby wyświetlić widok na ciąg w warstwie serwisowej bez konieczności przekazywania kontroleraContext, istnieje dobry artykuł Ricka Strahla tutaj http://www.codemag.com/Article/1312081, który tworzy ogólny kontroler. Podsumowanie kodu poniżej:
Następnie, aby wyrenderować widok w klasie usługi:
źródło
Szybka wskazówka
W przypadku silnie typowanego modelu wystarczy dodać go do właściwości ViewData.Model przed przekazaniem do RenderViewToString. na przykład
źródło
Aby powtórzyć z bardziej nieznanego pytania, spójrz na MvcIntegrationTestFramework .
To oszczędza ci pisania własnych pomocników w celu strumieniowego przesyłania wyników i udowodniono, że działa wystarczająco dobrze. Zakładam, że byłoby to w projekcie testowym, a jako bonus miałbyś inne możliwości testowania, gdy tylko dostaniesz tę konfigurację. Głównym problemem byłoby prawdopodobnie uporządkowanie łańcucha zależności.
źródło
Oto klasa, którą napisałem, aby to zrobić dla ASP.NETCore RC2. Używam go, aby generować e-maile HTML za pomocą Razor.
źródło
Znalazłem lepszy sposób na renderowanie strony widoku maszynki do golenia, gdy otrzymałem błąd w powyższych metodach, to rozwiązanie zarówno dla środowiska formularzy internetowych, jak i środowiska mvc. Kontroler nie jest potrzebny.
Oto przykład kodu, w tym przykładzie symulowałem akcję mvc za pomocą asynchronicznego modułu obsługi http:
źródło