Загрузка файла приводит к выходу пользователя из системы - PullRequest
0 голосов
/ 14 марта 2020

У меня есть ASP. NET MVC 4.5.2 веб-сайт (из-за ограничений хостинга), где есть область администратора с ссылкой для действий, которая загружает файл .csv или .xlsx для пользователя. при щелчке.

Локально это работает абсолютно нормально.

Однако при выходе в рабочий режим нажатие кнопки загрузки приводит к тому, что пользователь выходит из системы и отображается на экране входа в систему, как если бы он ушел. не был аутентифицирован. Затем, вход в систему приводит к тому, что загрузка фактически начинается (из-за returnUrl, установленной для ссылки действия кнопки загрузки).

Следующие фрагменты кода являются урезанными версиями того, что у меня есть:

AdminController

[Authorize(Roles = "Admin")]
    public class AdminController : BaseController
    {
         ...

        [HttpGet]
        public ActionResult Users()
        {
            var users = _context.PreSignups
                                .Where(x => x.IsDeleted == false)
                                .OrderBy(x => x.DateCreated).ToList();

            CheckMessages();

            return View(users);
        }

        [HttpGet]
        public ActionResult Download_PreSignupUsersToExcel()
        {
            var users = _context.PreSignups
                                .Where(x => x.IsDeleted == false)
                                .OrderBy(x => x.DateCreated).ToList().ToDataTable();

            DocumentService.WriteToSpreadsheet(users, $"PreSignupUsers_{DateTime.UtcNow.ToString("yyyy_MM_dd_hh_mm_ss")}.xlsx", true, Response);

            // NOTE: Due to the Response being sent back in DocumentService.WriteToSpreadsheet() the below is mostly redundant as the response has already closed by this point.

            TempData["Message"] = "Download started";

            return RedirectToAction("Logs", "Admin");
        }

DocumentService.cs

public static void WriteToSpreadsheet(DataTable dt, string filename, bool hasHeaders, HttpResponseBase response, enFileType fileType = enFileType.Xlsx)
        {

            ... // Build the data

            // Write the data
            using (var exportData = new MemoryStream())
            {
                response.Clear();
                workbook.Write(exportData);
                if (fileType == enFileType.Xlsx) //xlsx file format
                {
                    response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                    response.AddHeader("Content-Disposition", $"attachment;filename={filename}");
                    response.BinaryWrite(exportData.ToArray());
                }
                else if (fileType == enFileType.Xls)  //xls file format
                {
                    response.ContentType = "application/vnd.ms-excel";
                    response.AddHeader("Content-Disposition", $"attachment;filename={filename}");
                    response.BinaryWrite(exportData.GetBuffer());
                }
                response.End();
            }
        }

Представление Содержит следующую ссылку действия в некоторый момент сделать GET вызов выше. Нажатие этого приводит к тому, что пользователь, по-видимому, выходит на экран входа в систему с "admin/Download_PreSignupUsersToExcel" в качестве returnUrl.

@Html.ActionLink("Export .Xlsx", "Download_PreSignupUsersToExcel", "Admin", null, new { @class="btn btn-primary" })

Для справки, BaseController наследуется от класса Controller и предоставляет удобный способ хранения ApplicationDbContext. и LoggingService, и он не должен влиять на вышесказанное.

Я потерял код.

Есть идеи?

1 Ответ

0 голосов
/ 05 апреля 2020

Хорошо, так как оказывается, что браузер будет прослушивать только один ответ на указанный c запрос.

Я переместил часть кода для загрузки в собственный API AdminDownloadController. Затем, удалив response.End(); и вернув HttpResponseMessage со всеми соответствующими данными и заменив им стандартный контроллер ActionResult, загрузка начинается в том же аутентифицированном и авторизованном сеансе без выхода пользователя из системы.

Предостережение заключается в том, что вы не можете многое сделать с ответом на стороне клиента, например с отображением сообщений, без каких-либо JS маги c. AJAX вызывает текущие проблемы с аутентификацией и авторизацией, так что выбирайте путь наименьшего сопротивления ... если только вы не увлекаетесь такими вещами! :

AdminDownloadController.cs

[Authorize(Roles = "Admin")]
    public class AdminDownloadController : BaseApiController
    {

        // GET: api/AdminDownload/PreSignupUsersToExcel
        public HttpResponseMessage Get(string downloadName)
        {
            var response = new HttpResponseMessage(HttpStatusCode.NotFound);

            switch (downloadName)
            {
                case "PreSignupUsersToExcel":
                    var users1 = _context.PreSignups
                                .Where(x => x.IsDeleted == false)
                                .OrderByDescending(x => x.DateCreated).ToList().ToDataTable();

                    response = DocumentService.WriteToSpreadsheet(users1, $"PreSignupUsers_{DateTime.UtcNow.ToString("yyyy_MM_dd_hh_mm_ss")}.xlsx", true);
                    break;

                    ...

            }

            return response;
         }
     }

DocumentService.cs

public static HttpResponseMessage WriteToSpreadsheet(DataTable dt, string filename, bool hasHeaders, enFileType fileType = enFileType.Xlsx)
{            

    // Build Data
    ...

    // StreamData
    using (var exportData = new MemoryStream())
    {
        workbook.Write(exportData);

        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new ByteArrayContent(exportData.ToArray());
        response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentDisposition.FileName = filename;

        if (fileType == enFileType.Xlsx)
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        else if (fileType == enFileType.Xls)
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel");

        return response;
    }
}

WhwhatView.cs html

...

@Html.ActionLink("Export .Xlsx", "AdminDownload", "Api", new { downloadName = "PreSignupUsersToExcel" }, new { @class = "btn btn-primary" })

...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...