質問

On a ASP.NET MVC action I am trying to return a CSV file with users info:

  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");
      }
    }

And I have the following mapper:

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

My CSV writer seems empty and when I return the Stream I get the error:

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

And I get the error page:

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.

UPDATE: Adding Stack Trace

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.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[ObjectDisposedException: Cannot access a closed Stream.] System.IO._Error.StreamIsClosed() +57 System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count) +10909062 System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response) +157 System.Web.Mvc.FileResult.ExecuteResult(ControllerContext context) +296 System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +116 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, 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 filters, 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.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +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.WrappedAsyncVoid1.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.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.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9514928 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Thank You, Miguel

役に立ちましたか?

解決

Your using statement is closing the memory stream that you're returning in your FileResult.

This should fix it. Declare the MemoryStream outside of the block. It will be closed by the framework once the stream has been fully written to the Response stream (although it's currently not essential to close MemoryStream. They get cleaned up properly when they're garbage collected.

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");
  }
}

Alternately you can use the Byte[] overload of the FileResponse.

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");
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top