从Action写入输出流

Pal*_*ani 27 asp.net-mvc

出于某些奇怪的原因,我想从控制器操作直接将HTML写入Response流.(我理解MVC分离,但这是一个特例.)

我可以直接写入HttpResponse流吗?在这种情况下,IView控制器操作应该返回哪个对象?我可以退回'null'吗?

Kna*_*ģis 46

我使用派生的类FileResult来使用普通的MVC模式来实现这一点:

/// <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);
    }
}
Run Code Online (Sandbox Code Playgroud)

控制器方法现在是这样的:

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(/**/);
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果关闭缓冲,

stream.Write(/**/);
Run Code Online (Sandbox Code Playgroud)

变得极其缓慢.解决方案是使用BufferedStream.这样做可以在一种情况下将性能提高大约100倍.看到

无缓冲输出非常慢


wom*_*omp 9

是的,您可以直接写回应.完成后,您可以调用CompleteRequest(),您不需要返回任何内容.

例如:

// GET: /Test/Edit/5
public ActionResult Edit(int id)
{

    Response.Write("hi");
    HttpContext.ApplicationInstance.CompleteRequest();

    return View();     // does not execute!
}
Run Code Online (Sandbox Code Playgroud)

  • 用"返回内容("")"替换"返回View()"可能很有用,以避免有关缺少视图的错误.但这种方法安全吗? (2认同)

Joh*_*han 5

编写自己的行动结果.这是我的一个例子:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


G-W*_*Wiz 5

如果您不想派生自己的结果类型,您可以简单地写入Response.OutputStream并返回new EmptyResult()


Jor*_*nes 3

return Content(...);如果我没记错的话,您...可以在您想要直接写入输出流的地方执行操作,或者什么也不执行。

看看Content以下方法Controller: http: //aspnet.codeplex.com/SourceControl/changeset/view/22907#266451

还有ContentResulthttp://aspnet.codeplex.com/SourceControl/changeset/view/22907#266450