Not able to return CSV file in MVC action. Not Cannot access a closed Streamable
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(IList 1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +116 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList
1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList 1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList
1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList
1 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.WrappedAsyncResult 1.CallEndDelegate(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.WrappedAsyncResultBase
1.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.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +70 System.Web.Mvc.Async.WrappedAsyncResultBase
1.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.WrappedAsyncResultBase
1.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.WrappedAsyncResultBase
1.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");
}
链接地址: http://www.djcxy.com/p/85126.html