2

在 ASP.NET MVC 操作中,我试图返回包含用户信息的 CSV 文件:

  IList<UserModel> users = _repository.GetUsers();

  MemoryStream stream = new MemoryStream;
    using (StreamWriter writer = new StreamWriter(stream)) {
      using (CsvWriter csv = new CsvWriter(writer)) {
        csv.Configuration.With(x => {
          x.AutoMap<UserModel>();
          x.RegisterClassMap<UserModelCsvMapper>();
        });            
        csv.WriteRecords(reply.Users);
        writer.Flush();
        return File(stream, "text/csv", "Users.csv");
      }
    }

我有以下映射器:

public class UserModelCsvMapper : CsvClassMap<UserModel> {
  public override void CreateMap() {
    Map(x => x.Name).Name("Name");
    Map(x => x.Email).Name("Email");
    Map(x => x.Linked).Name("Linked");
  } // CreateMap
} // UserModelCsvMapper

我的 CSV 编写器似乎是空的,当我返回 Stream 时出现错误:

((System.IO.Stream)(stream)).WriteTimeout' threw an exception of type 'System.InvalidOperationException'

我得到错误页面:

Cannot access a closed Stream.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ObjectDisposedException: Cannot access a closed Stream.

更新:添加堆栈跟踪

无法访问已关闭的 Stream。说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.ObjectDisposedException:无法访问已关闭的流。

源错误:

在执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常起源和位置的信息。

堆栈跟踪:

[ObjectDisposedException:无法访问已关闭的流。] System.IO._ Error.StreamIsClosed() +57 System.IO.MemoryStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 计数) +10909062 System.Web.Mvc.FileStreamResult .WriteFile(HttpResponseBase 响应) +157 System.Web.Mvc.FileResult.ExecuteResult(ControllerContext 上下文) +296 System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive (IList 1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +116 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 过滤器,Int32 filterIndex,ResultExecutingContext preContext,ControllerContext controllerContext,ActionResult actionResult)+529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList1 个过滤器,ActionResult actionResult) +106 System.Web.Mvc.Async.<>c _DisplayClass2b.b_1c () +321 System.Web.Mvc.Async.<>c _DisplayClass21.b_1e (IAsyncResult asyncResult) +185 System. Web.Mvc.Async.WrappedAsyncResult 1.CallEndDelegate(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标记) +56 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) + 40 System.Web.Mvc.Controller.b _1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +70 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +139 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web .Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44 System.Web.Mvc.Controller.b_ 15(IAsyncResult asyncResult, Controller controller) +39 System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +62 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +139 System.Web .Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39 System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39 System.Web.Mvc.MvcHandler.b_5(IAsyncResult asyncResult, ProcessRequestState innerState) +39 System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +70 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +139 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web. Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult 结果) +38 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9514928 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

谢谢你,米格尔

4

1 回答 1

4

您的 using 语句正在关闭您在 FileResult 中返回的内存流。

这应该解决它。声明MemoryStream块的外部。一旦流被完全写入流,它将由框架关闭Response(尽管目前关闭不是必需的MemoryStream。当它们被垃圾收集时,它们会被正确清理。

IList<UserModel> users = _repository.GetUsers();

var stream = new MemoryStream();
using (StreamWriter writer = new StreamWriter(stream)) {
  using (CsvWriter csv = new CsvWriter(writer)) {
      csv.Configuration.With(x => {
      x.AutoMap<UserModel>();
      x.RegisterClassMap<UserModelCsvMapper>();  
    });            
    csv.WriteRecords(reply.Users)
    writer.Flush();
    return File(stream, "text/csv", "Users.csv");
  }
}

或者,您可以使用 FileResponse 的 Byte[] 重载。

using (var stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (CsvWriter csv = new CsvWriter(writer) {
  csv.Configuration.With(x => {
    x.AutoMap<UserModel>();
    x.RegisterClassMap<UserModelCsvMapper>();  
  })        

  //use the users that you just retrieved from the repository
  csv.WriteRecords(users)
  writer.Flush();

  return File(stream.ToArray(), "text/csv", "Users.csv");
}
于 2014-03-07T14:12:41.017 回答