ASP.NET MVC: Como posso renderizar um controle para um fluxo?
-
25-09-2019 - |
Pergunta
Portanto, estou fazendo uma visão parcial na memória para direcionar os dados XSL-FO na visualização para um renderizador de PDF.
O renderizador do PDF pode pegar uma string, xmldocument ou fluxo como entrada.
Aqui está o que eu gostaria de fazer: (Editado para clareza)
Solução tirada de: http://thriftybliss.spaces.live.com/blog/cns!58da805f37f31f20!170.entry?wa=wsignin1.0&sa=362921628
var viewPage = new ViewPage();
var viewData = new ViewDataDictionary(model);
viewPage.ViewData = viewData;
var control = viewPage.LoadControl(viewName);
viewPage.Controls.Add(control);
using (var inStream = new MemoryStream())
{
using (var sw = new StreamWriter(inStream))
{
using (var tw = new HtmlTextWriter(sw))
{
viewPage.RenderControl(tw);
}
using (var outStream = new MemoryStream())
{
driver.Render(inStream, outStream);
return outStream.ToArray();
}
}
}
Aqui está o que funciona, mas o que eu preferiria não fazer:
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
var xml = new XmlDocument();
xml.LoadXml(sb.ToString());
using (var ms = new MemoryStream())
{
driver.Render(xml, ms);
return ms.ToArray();
}
Infelizmente, o htmltextwriter não parece querer escrever para o streamwriter, ou talvez eu apenas estrague outra coisa.
Se eu substituir o StreamWriter pelo StringWriter, ele funcionar bem, mas não posso usar o StringWriter porque, quando chamo de .toString (), recebo todos os tipos de caracteres de fuga que atrapalham o XSL-Fo e o renderizador lança uma exceção "caracteres ilegais".
Eu adquiri isso criando um XMLDocument e carregando a string nisso, mas parece uma maneira muito indireta de fazer as coisas. Eu realmente gostaria de apenas capturar a saída do htmltextwriter e alimentá -lo diretamente no renderizador. Há alguma maneira de fazer isso?
Obrigado!
Solução
Quando você diz "htmltextwriter não parece querer escrever para o streamwriter" isso significa que isso significa que driver.Render
Não consegue tirar bytes do encontro? Duas possibilidades que eu consigo pensar ...
Primeiro é que o htmltextwriter não está descarregando o fluxo depois que terminar de escrever, nesse caso, você pode precisar de um sw.Flush()
lá antes de entregar o encontro a driver.Render
.
O segundo é que, depois de escrever para o MemoryStream, o ponteiro de localização estará no final do fluxo, e qualquer tentativa de ler dele produzirá zero bytes (pois está no final).
Nesse caso, configuração inStream.Position
para 0, ou chamando inStream.Seek(0, SeekOrigin.Begin)
antes de ligar driver.Render
deve consertar isso.
Eu já encontrei a segunda situação algumas vezes antes, então esse é o meu melhor palpite.
Outras dicas
Eu não testei nada disso... mas é uma versão modificada de um Método RenderViewToString que eu fiz e uso em outro lugar:
public static Stream RenderViewToStream<T>(string viewPath, T model, ControllerContext controllerContext)
{
var ms = new MemoryStream();
using (var writer = new StreamWriter(ms))
{
var view = new WebFormView(viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(controllerContext, view, vdd, new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
}
return ms;
}