Олицетворение в ASP.NET MVC - PullRequest
       20

Олицетворение в ASP.NET MVC

6 голосов
/ 15 апреля 2010

У меня есть действие, которое требует чтения файла из безопасного места, поэтому я должен использовать олицетворение для чтения файла.

Этот код РАБОТАЕТ:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult DirectDownload(Guid id)
{
    if (Impersonator.ImpersonateValidUser())
    {
        try
        {
            var path = "path to file";
            if (!System.IO.File.Exists(path))
            {
                return View("filenotfound");
            }

            var bytes = System.IO.File.ReadAllBytes(path);
            return File(bytes, "application/octet-stream", "FileName");
        }
        catch (Exception e)
        {
            Log.Exception(e);
        }finally
        {
            Impersonator.UndoImpersonation();
        }
    }
    return View("filenotfound");
}

Единственная проблема с приведенным выше кодом заключается в том, что мне нужно прочитать весь файл в память, и я собираюсь иметь дело с ОЧЕНЬ большими файлами, так что это не хорошее решение. Но если я заменю эти 2 строки:

var bytes = System.IO.File.ReadAllBytes(path);
return File(bytes, "application/octet-stream", "FileName");

с этим:

return File(path, "application/octet-stream", "FileName");

Это НЕ работает, и я получаю сообщение об ошибке:

Доступ к пути «C: \ Проекты \ загрузки \ 1 \ aa2bcbe7-ea99-499d-add8-c1fdac561b0e \ Без названия 2.csv 'отказано.

Я полагаю, что, используя файл File Results с путем, пытается открыть файл позднее в конвейере запросов, когда я уже "отменил" олицетворение.

Помните, что код олицетворения работает, потому что я могу прочитать файл в массиве байтов. Что я хочу сделать, так это передать файл клиенту.

Есть идеи, как мне обойти это?

Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 15 апреля 2010

Вы можете попробовать написать пользовательский FilePathResult:

public class ImpersonatingFileResult : FilePathResult
{
    public ImpersonatingFileResult(string fileName, string contentType) 
        : base(fileName, contentType)
    { }

    protected override void WriteFile(HttpResponseBase response)
    {
        // TODO : Start impersonation
        response.TransmitFile(FileName);
        // TODO : Rollback impersonation
    }
}

и в вашем контроллере:

return new ImpersonatingFileResult(path, "application/octet-stream");
1 голос
/ 20 мая 2015

Мне нравится Ответ Дарина , но он пропускает логику олицетворения и выдает ошибку в IIS 7 ...

Итак, я добавил код олицетворения, как вы могли бы, используя Пакет Nuget SimpleImpersonation .

Кроме того, в IIS 7 было внесено несколько изменений для предотвращения ошибки недопустимого дескриптора.

public class ImpersonatingFileResult : FilePathResult
{
    public ImpersonatingFileResult(string fileName, string contentType)
        : base(fileName, contentType)
    { }

    protected override void WriteFile(HttpResponseBase response)
    {
        using (SimpleImpersonation.Impersonation.LogonUser(domain: "SomeDomain", username: "SomeUser", password: "SomePassword", logonType: SimpleImpersonation.LogonType.NewCredentials))
        {
            response.Clear();
            response.ContentType = base.ContentType;
            response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(base.FileName));
            response.TransmitFile(FileName);
            response.Flush();
        }
    }

А затем с помощью контроллера:

        return new ImpersonatingFileResult(someFilePath, "Application/pdf");

Выше указано для загрузки файла, но если вы хотите отобразить его, вам нужно указать «inline».

            response.Clear();
            response.ContentType = base.ContentType;
            response.AddHeader("Content-Disposition", "inline; filename=\"" + System.IO.Path.GetFileName(base.FileName) + "\"");
            response.TransmitFile(FileName);
            response.Flush();
...