いくつかの奇妙な理由から、コントローラアクションからレスポンスストリームに直接HTMLを書きたいと思います。 (私はMVC分離を理解していますが、これは特殊なケースです)アクションからの出力ストリームへの書き込み
ストリームに直接書き込むことはできますか?HttpResponse
?その場合、コントローラーのアクションはどのIView
オブジェクトに返されるべきですか? 「null」を返すことはできますか?
いくつかの奇妙な理由から、コントローラアクションからレスポンスストリームに直接HTMLを書きたいと思います。 (私はMVC分離を理解していますが、これは特殊なケースです)アクションからの出力ストリームへの書き込み
ストリームに直接書き込むことはできますか?HttpResponse
?その場合、コントローラーのアクションはどのIView
オブジェクトに返されるべきですか? 「null」を返すことはできますか?
return Content(...);
私が正しく覚えていれば、...
は出力ストリームに直接書き込むか、まったく何も書き込まないようにすることができます。
はController
上Content
方法を見てみましょう:http://aspnet.codeplex.com/SourceControl/changeset/view/22907#266451
そしてContentResult
:http://aspnet.codeplex.com/SourceControl/changeset/view/22907#266450
はい、あなたは応答に直接書き込むことができます。完了したら、CompleteRequest()を呼び出すことができ、何も返す必要はありません。例えば
:
// GET: /Test/Edit/5
public ActionResult Edit(int id)
{
Response.Write("hi");
HttpContext.ApplicationInstance.CompleteRequest();
return View(); // does not execute!
}
は、独自のアクション結果を書きます。ここで鉱山の一例は次のとおり
public class RssResult : ActionResult
{
public RssFeed RssFeed { get; set; }
public RssResult(RssFeed feed) {
RssFeed = feed;
}
public override void ExecuteResult(ControllerContext context) {
context.HttpContext.Response.ContentType = "application/rss+xml";
SyndicationResourceSaveSettings settings = new SyndicationResourceSaveSettings();
settings.CharacterEncoding = new UTF8Encoding(false);
RssFeed.Save(context.HttpContext.Response.OutputStream, settings);
}
}
今回用いた通常のMVCパターンを達成するために、FileResult
から派生したクラスを使用する:
/// <summary>
/// MVC action result that generates the file content using a delegate that writes the content directly to the output stream.
/// </summary>
public class FileGeneratingResult : FileResult
{
/// <summary>
/// The delegate that will generate the file content.
/// </summary>
private readonly Action<System.IO.Stream> content;
private readonly bool bufferOutput;
/// <summary>
/// Initializes a new instance of the <see cref="FileGeneratingResult" /> class.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="content">Delegate with Stream parameter. This is the stream to which content should be written.</param>
/// <param name="bufferOutput">use output buffering. Set to false for large files to prevent OutOfMemoryException.</param>
public FileGeneratingResult(string fileName, string contentType, Action<System.IO.Stream> content,bool bufferOutput=true)
: base(contentType)
{
if (content == null)
throw new ArgumentNullException("content");
this.content = content;
this.bufferOutput = bufferOutput;
FileDownloadName = fileName;
}
/// <summary>
/// Writes the file to the response.
/// </summary>
/// <param name="response">The response object.</param>
protected override void WriteFile(System.Web.HttpResponseBase response)
{
response.Buffer = bufferOutput;
content(response.OutputStream);
}
}
制御方法は次のようになるであろう:
public ActionResult Export(int id)
{
return new FileGeneratingResult(id + ".csv", "text/csv",
stream => this.GenerateExportFile(id, stream));
}
public void GenerateExportFile(int id, Stream stream)
{
stream.Write(/**/);
}
バッファリングをオフにすると、
stream.Write(/**/);
は非常に遅くなります。解決方法は、BufferedStreamを使用することです。 1つのケースでは、パフォーマンスが約100倍向上しました。あなたがあなた自身の結果の型を派生させたくない場合は、あなたは、単にResponse.OutputStream
への書き込みとnew EmptyResult()
を返すことができ
を参照してください。
Response.End()を避ける必要があります。http://stevesmithblog.com/blog/use-httpapplication-completerequest-instead-of-response-end/ –
CompleteRequest()を使用するように更新しました。 – womp
ビューの欠落に関するエラーを避けるために、 "return View()"を "return Content(" ")に置き換えると便利です。しかし、このアプローチは安全ですか? –