#c# #excel #asp.net-core #model-view-controller
#c# #excel #asp.net-core #модель-представление-контроллер
Вопрос:
Я пытаюсь загрузить файл Excel, для которого я указываю правильный путь. Но после загрузки, когда я пытаюсь открыть, я получаю сообщение об ошибке как
excel не может открыть файл, поскольку формат файла или расширение файла недопустимы. Убедитесь, что файл поврежден…
в этом отдельном классе я создал функцию экспорта для создания и записи данных в файл Excel
public static ExcelPackage ExportExcel(string fileName, decimal projectId, ModelContext context)
{
ExcelPackage pck = new ExcelPackage();
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Project");
var surveys = context.Survey.Where(x => x.ProjectId == projectId)
.Include(s=> s.Question);
#region datatable
ws.Cells["A1"].Value = "SURVEY_ID";
ws.Cells["B1"].Value = "PAGE";
ws.Cells["C1"].Value = "RANKING";
ws.Cells["D1"].Value = "PARENT_ID";
ws.Cells["E1"].Value = "ID";
ws.Cells["F1"].Value = "ITEMTYPE";
ws.Cells["G1"].Value = "CONTROLTYPE";
ws.Cells["H1"].Value = "DISPLAYTYPE";
ws.Cells["J1"].Value = "VARIABLE_DESCRIPTION";
ws.Cells["K1"].Value = "VARIABLE_NAME";
ws.Cells["L1"].Value = "VARIABLE_LABEL";
ws.Cells["M1"].Value = "VALUE_LABEL_ID";
ws.Cells["N1"].Value = "MISSING_VALUE_ID";
ws.Cells["O1"].Value = "IS_REQUIRED";
ws.Cells["P1"].Value = "DATA_TYPE";
ws.Cells["Q1"].Value = "VARIABLE_LENGTH";
ws.Cells["R1"].Value = "NR_OF_DECIMALS";
ws.Cells["S1"].Value = "COMMENT";
ws.Cells["T1"].Value = "COMMENT_TYPE";
ws.Cells["U1"].Value = "SHOW_ALL_FOR_STUDY";
ws.Cells["V1"].Value = "ANSWER_FONT";
ws.Cells["W1"].Value = "IS_DELETE_QUESTION";
ws.Cells["X1"].Value = "IS_STOP_QUESTION";
ws.Cells["Y1"].Value = "ROUTING_TYPE";
ws.Cells["Z1"].Value = "ROUTING_VALUE";
ws.Cells["AA1"].Value = "SHOW";
int rowStart = 2;
foreach (var survey in surveys)
{
foreach (var item in survey.Question)
{
ws.Cells[String.Format("A{0}", rowStart)].Value = survey.IdSurvey;
ws.Cells[String.Format("B{0}", rowStart)].Value = item.Page;
ws.Cells[String.Format("C{0}", rowStart)].Value = item.Ranking;
ws.Cells[String.Format("D{0}", rowStart)].Value = item.ParentId;
ws.Cells[String.Format("E{0}", rowStart)].Value = item.IdQuestion;
ws.Cells[String.Format("F{0}", rowStart)].Value = item.Itemtype;
ws.Cells[String.Format("G{0}", rowStart)].Value = item.Controltype;
ws.Cells[String.Format("H{0}", rowStart)].Value = item.Displaytype;
ws.Cells[String.Format("J{0}", rowStart)].Value = item.VariableDescription;
ws.Cells[String.Format("K{0}", rowStart)].Value = item.VariableName;
ws.Cells[String.Format("L{0}", rowStart)].Value = item.VariableLabel;
ws.Cells[String.Format("M{0}", rowStart)].Value = item.ValueLabelId;
ws.Cells[String.Format("N{0}", rowStart)].Value = item.MissingValueId;
ws.Cells[String.Format("O{0}", rowStart)].Value = item.IsRequired;
ws.Cells[String.Format("P{0}", rowStart)].Value = item.DataType;
ws.Cells[String.Format("Q{0}", rowStart)].Value = item.VariableLength;
ws.Cells[String.Format("R{0}", rowStart)].Value = item.NrOfDecimals;
ws.Cells[String.Format("S{0}", rowStart)].Value = item.Comment;
ws.Cells[String.Format("T{0}", rowStart)].Value = item.CommentType;
ws.Cells[String.Format("U{0}", rowStart)].Value = item.ShowAllForStudy;
ws.Cells[String.Format("V{0}", rowStart)].Value = item.AnswerFont;
ws.Cells[String.Format("W{0}", rowStart)].Value = item.IsDeleteQuestion;
ws.Cells[String.Format("X{0}", rowStart)].Value = item.IsStopQuestion;
ws.Cells[String.Format("Y{0}", rowStart)].Value = item.RoutingType;
ws.Cells[String.Format("Z{0}", rowStart)].Value = item.RoutingValue;
ws.Cells[String.Format("AA{0}", rowStart)].Value = item.Show;
rowStart ;
}
ws.Cells["A:AZ"].AutoFitColumns();
}
#endregion
return pck;
}
}
затем я вызываю эту функцию из контроллера:
[HttpGet("{Id}")]
public IActionResult Export(IFormCollection form, decimal? id)
{
var exportId = _context.Project.First(x => x.ProjectId == id).ProjectId;
var fileName = form["Codebook.xlsx"];
//var pck = Models.Export.ExportExcel(fileName, exportId, _context);
return File(Models.Export.ExportExcel(fileName, exportId, _context).Stream
, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Codebook.xlsx");
Комментарии:
1. Вы можете избежать большей части этого кода, если используете один из
Load
методов, напримерws.Cells.LoadFromCollection(questions)
. Вы можете получить вопросы из опросов с.SelectMany(s=>s.Question)
помощью . В этом случае нет необходимостиInclude()
2. Что касается основной проблемы, вы должны убедиться, что поток
Position
равен 0. Чтение из потока начинается сPosition
. После записи позиция потока находится в конце потока, и чтение из него ничего не прочитает3. @Panagiotis Kanavos Что касается первого предложения, то оно действительно удобно!! основная проблема заключается в том, что приложение видит только один каталог, независимо от того, что я пытаюсь, он этого не меняет, поэтому ошибка, которую я получаю до сих пор, заключается в том, что он не может найти указанный мной каталог, хотя я передал корневой каталог.
4. Нет, проблема в том, что после записи
Position
то, с чего начинается чтение, является концом потока. Вам нужно установить для него значение 0 :pck.Stream.Position=0;
. Как чтение , так и запись в поток начинаются сPosition
. Как чтение, так и запись перемещают позицию на количество байтов, которые были прочитаны или записаны. Если вы хотите прочитать весь файл целиком, вам нужно переместитьPosition
0
Ответ №1:
Я не знаю, важно это или нет: мы используем тот же contenttype, что и вы, но мы устанавливаем ContentEncoding в System.Text.Encoding.UTF8. Упрощенный код:
public System.Web.Mvc.ActionResult Export(string filename)
{
Response.AppendHeader("Content-Disposition", string.Format("attachment; filename*=UTF-8''{0}", Uri.EscapeDataString(filename)));
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Stream ms = <<Excel file content>>
return new FileStreamResult(ms, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
Ответ №2:
файл должен быть сначала сохранен в webroot, затем вернуть его в виде массива байтов, чтобы на контроллере добавить IwebHostEnviroment, а затем обновить метод действия
public IActionResult Export(IFormCollection form, decimal? id)
{
var project = _context.Project.First(x => x.ProjectId == id).ProjectId;
var fileName = form["Codeboek"];
var pck = Models.Export.ExportExcel(fileName, project, _context);
var contentRootPath = _env.ContentRootPath;
fileName = "exportFile.xlsx";
var filePath = contentRootPath "/" fileName;
pck.SaveAs(new FileInfo(filePath));
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
}