I have an Action that needs to read a file from a secure location, so I have to use impersonation to read the file.
This code WORKS:
[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");
}
The only problem with the above code is that I have to read the entire file into memory and I am going to be dealing with VERY large files, so this is not a good solution. But if I replace these 2 lines:
var bytes = System.IO.File.ReadAllBytes(path);
return File(bytes, "application/octet-stream", "FileName");
with this:
return File(path, "application/octet-stream", "FileName");
It does NOT work and I get the error message:
Access to the path 'c:\projects\uploads\1\aa2bcbe7-ea99-499d-add8-c1fdac561b0e\Untitled 2.csv' is denied.
I guess using the File results with a path, tries to open the file at a later time in the request pipeline when I have already "undone" the impersonation.
Remember, the impersonation code works because I can read the file in the bytes array. What I want to do though is stream the file to the client.
Any idea how I can work around this?
Thanks in advance.
You may try writing a custom 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
}
}
and in your controller:
return new ImpersonatingFileResult(path, "application/octet-stream");
I like Darin's answer, but it skips the impersonation logic, and it throws an error in IIS 7...
So, I added the impersonation code as you could by utilizing Nuget Package SimpleImpersonation.
Also, a couple changes were thrown in for IIS 7 to prevent an invalid handle error.
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();
}
}
And then using it from controller:
return new ImpersonatingFileResult(someFilePath, "Application/pdf");
The above is for downloading the file, but if you want to display it, then you need to specify "inline".
response.Clear();
response.ContentType = base.ContentType;
response.AddHeader("Content-Disposition", "inline; filename=\"" + System.IO.Path.GetFileName(base.FileName) + "\"");
response.TransmitFile(FileName);
response.Flush();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With