#c# #asp.net-mvc #asynchronous #asp.net-web-api
#c# #asp.net-mvc #асинхронный #asp.net-веб-api
Вопрос:
Я экспортирую файл Excel с помощью WebAPI, но он выдает исключение, и я не знаю почему. Я погуглил и не нашел никакого решения.
Исключение:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>Error while copying content to a stream.</ExceptionMessage>
<ExceptionType>System.Net.Http.HttpRequestException</ExceptionType>
<StackTrace>
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.<HandleCompression>d__17.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.<SendAsync>d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>Cannot access a closed Stream.</ExceptionMessage>
<ExceptionType>System.ObjectDisposedException</ExceptionType>
<StackTrace>
at System.IO.__Error.StreamIsClosed() at System.IO.MemoryStream.get_Position() at System.Net.Http.StreamToStreamCopy.StartAsync()
</StackTrace>
</InnerException>
</Error>
Мой код :
[AllowAnonymous]
[HttpGet]
[Route("api/AddPatient/ExportToExcel")]
public HttpResponseMessage ExportToExcel()
{
try
{
MemoryStream dataStream = Utility.GetFile();
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = "Test.xlsx";
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return httpResponseMessage;
}
catch (Exception ex)
{
throw;
}
}
Функция GetFile, как показано ниже, для получения потока памяти Excel
Примечание: используя NPOI, я создаю файл Excel
public static MemoryStream GetFile()
{
MemoryStream stream =null;
XSSFWorkbook wb = new XSSFWorkbook();
ISheet sheet = wb.CreateSheet("Test");
var row = sheet.CreateRow(0);
var cell = row.CreateCell(0);
cell.SetCellValue("Test");
using ( stream = new MemoryStream())
{
wb.Write(stream);
}
return stream;
}
Комментарии:
1. это кажется полезным. В GetFile получена ошибка, пожалуйста, вставьте ее.
2. Нет смысла иметь
try catch
блок, если вы просто повторно создаете исключение…3. Вы удаляете,
stream
а затем возвращаете его? Тогда вы получаетеObjectDisposedException
? Не совсем уверен, в чем здесь вопрос.4. Что
Utility.GetFile()
делает? Создает ли это файл в памяти или файл с диска? В любом случае вы можете использоватьreturn File(...)
для возврата либо сохраненного файла, либо потока. MemoryStream — это не что иное, как оболочка надbyte[]
массивом, и его удаление не освобождает никаких ресурсов
Ответ №1:
Вам нужно быть осторожным при работе с объектом stream.
Но я думаю, что ваша функция get dataStream
также неверна. Возможно, больше кода?
try
{
using(MemoryStream dataStream = Utility.GetFile())
{
// read from beginning
dataStream.Position = 0;
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = "Test.xlsx";
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return httpResponseMessage;
}
}
catch (Exception ex)
{
throw;
}
Вы GetFile
не можете обернуть оператор using, который закроет ваш объект потока памяти.
// try this
public static MemoryStream GetFile()
{
MemoryStream stream = new MemoryStream();
// do your thing
XSSFWorkbook wb = new XSSFWorkbook();
ISheet sheet = wb.CreateSheet("Test");
var row = sheet.CreateRow(0);
var cell = row.CreateCell(0);
cell.SetCellValue("Test");
wb.Write(stream);
// reset position here
stream.Position = 0;
return stream;
}
Комментарии:
1. Теперь возникает новая ошибка: не удается получить доступ к закрытому потоку
2. @JasminSolanki обычно это связано с тем, что вы обращаетесь к нему, когда он уже «закрыт», вам нужно обернуть с помощью инструкции using, чтобы ваш объект не удалялся, когда вы захотите его использовать
3. @JasminSolanki вы не можете использовать оператор using в своей функции GetFile, поэтому вы получаете ту же ошибку. Удалите этот оператор using.
4. Да, я изменил его, но поток все еще закрыт
5. Зачем использовать этот код вместо простого
return File(stream,..);
? Фактическое исправление заключается в том, чтобы избежать удаления MemoryStream или вместо этого использовать буфер byte[]. MemoryStream — это не что иное, как оболочка над байтом[]