2010-04-15 18 views
6

Tengo una Acción que necesita leer un archivo desde una ubicación segura, así que tengo que usar la suplantación para leer el archivo.Personificación en ASP.NET MVC

Este código funciona:

[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"); 
} 

El único problema con el código anterior es que tengo que leer todo el archivo en la memoria y voy a estar tratando con archivos muy grandes, así que esto no es una buena solución. Pero si puedo reemplazar estas 2 líneas:

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

con esto:

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

NO funciona y me sale el mensaje de error:

acceso a la ruta 'c: \ projects \ uploads \ 1 \ aa2bcbe7-ea99-499d-add8-c1fdac561b0e \ Untitled 2.csv 'se deniega.

Supongo que al utilizar los resultados de Archivo con una ruta, intenta abrir el archivo más adelante en la interconexión de solicitud cuando ya he "deshecho" la suplantación.

Recuerde, el código de suplantación funciona porque puedo leer el archivo en la matriz de bytes. Lo que quiero hacer es transmitir el archivo al cliente.

¿Alguna idea de cómo puedo evitar esto?

Gracias de antemano.

Respuesta

4

Usted puede intentar escribir una costumbre 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 
    } 
} 

y en su controlador:

return new ImpersonatingFileResult(path, "application/octet-stream"); 
+0

Eso funcionó muy bien. Lo cambié un poco porque recibía una excepción ... Impersonator.ImpersonateValidUser(); response.WriteFile (FileName); respuesta.Enjuague(); response.End(); Impersonator.UndoImpersonation(); – Emad

+0

Sí, este es un buen comienzo.Sin embargo, lanzará errores de "Invalid Handle" en ciertas versiones de IIS, que se basan en servir el archivo (y no en la suplantación). – Greg

1

I como respuesta de Darin, pero se salta la lógica suplantación, y arroja un error en IIS 7 ...

Por lo tanto, agregué el código de suplantación como podría al utilizar N uget Package SimpleImpersonation.

Además, se produjeron un par de cambios en IIS 7 para evitar un error de manejo no válido.

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(); 
     } 
    } 

Y después de usarlo desde el controlador:

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

Lo anterior es para descargar el archivo, pero si quieres que aparezca y, a continuación, es necesario que especifique "en línea".

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

¡Esta es una excelente respuesta, gracias! –