Need help adding download feature to MVC application - c#

I have a web MVC application that I would like to add feature that gives users the ability to download large files from my server. The users have a combination of Mac and Windows PC. I was thinking along the lines of javasripts or silverlight.
Can someone advice me on how to implement this feature?
Do you have any code examples?

Use the File method of Controller class.
So Create a Controller called FilesController and have an action method called DownLoad
public class FilesController : Controller
{
public ActionResult Download(string fileId)
{
var fullFilePath=FileService.GetFullPath(fileId); // get the path to file
return File(fullFilePath,"application/pdf","yourDownLoadName.pdf");
}
}
This Will return a PDF file from the specified path(fullFilePath) with the MimeType/ContentType as PDF and "yourDownLoadName.pdf" as the Downloadable file name
Users can access this like http://yourdomainname.com/Files/Download?fileId=somefileId
This method has got a bunch of overloads using file path, byte array ,stream etc..

Create a controller action with a FileStreamResult return type.

Related

How to apply security permissions to static files with ASP.NET MVC?

I'm trying to use ASP.NET MVC to have a web app that will take details about a parent item and allow uploads and sharing of files which are associated with and stored under the name of the parent item.
The files I want to protect are stored in this way:
~/Files/{Item-GUID}/{Filename}.{ext}
The Item-Guid can be used to query the db for security permissions for the item. (users are logged as AD SIDs)
I need to know how to have ASP.Net respond to file requests for these files in the path ~/Files/ and use the /Item-GUID/ to check security permissions before serving the file to the user, and throw authentication errors if the user is not logged in or does not have access to the parent item.
I would appreciate any links or advice on where should I start here.
Thanks In Advance.
I use often create a custom permission class that derives from the AuthorizeAttribute class. This is one way you can create a custom permissions filter on any controller action.
public MyPermissionsFilter : AuthorizeAttribute
{
private readonly string _permissionName;
public PermissionsFilter(string permissionName)
{
_permissionName = permissionName;
}
}
Override the OnAuthorization method.
public override void OnAuthorization(AuthorizationContext filterContext)
{
//Perform Check with _permissionName
//Redirect to error / unauthorised
}
Then decorate your controller action.
[HttpPost]
[PermissionsFilter("PermissionName")]
public void SaveFile(HttpPostedFileBase file)
{
//Do file stuff
}
I hope that's what you want and is of some help.
Addition : I've renamed GetFile to SaveFile.. and this is what is should have been.
I've also been thinking about this again and it may not be the best solution for you. If you need to check a users permissions to access a single file based upon it's GUID, you might be better having the security check called in the SaveFile method that receives the file base parameter. You can get the guid from the file name then to pass to the permissions check. If it fails then simply redirect to the appropriate view.

Can a ActionResult open a specific folder on a server?

For example, I need only documents from a folder on the server drive X:\Docs for an online web application. Is there a way that a button on the website will open X:\Docs by default? I have tried this to open specific folders with no luck:
[HttpPost]
public ActionResult Index(HttpFileCollection file)
{
var path = System.IO.Path.GetDirectoryName("X:\Docs");
return RedirectToAction("Index");
}
I am new to C# and MVC. Is this achievable?
You can enable directory browsing of that folder and then having the button (or href) to point to the url. You don't event need a controller method for it.
Updated: if the folder is not under your website's root you will need to do some work by yourself. For example
#foreach (string path in Directory.GetFiles("X:\Docs"))
{
<div>
<!--doc link-->
</div>
}
You will need to have read permission for that drive ofc
As Luke pointed out you could alo do this inside your controller and pass it into your View which I also think it might be a better approach since View should be responsible for reading and rendering data

asp.net MVC secure root folder only for authorized users

I am having this small extranet service where users can log in, get all sorts of info and download few files.
Is it possible to secure root folder in MVC asp.net project? I am having a project where users have to log in before using any material. How ever if I use for example "/material" folder for every pdf, jpg, etc. files, other unauthorized users can see those files also.
For example everybody can see this file if they type www.example.com/material/pdf-file.pdf So I want only authorized / logged users to see this file. Is this possible?
I managed to get it work. Here is how I did it.
The first I added this line to Web.config file:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
This allows dot chars in .pdf, .png, etc... in url's.
I added to RouteConfig.cs new routing for controller.
routes.MapRoute(
name: "Material",
url: "Material/Download/{file}",
defaults: new { controller = "Material", action = "Download", file = UrlParameter.Optional }
);
I created a new controller "Material".
// GET: Material
[Authorize]
public ActionResult Download(string file)
{
string path = Server.MapPath(String.Format("~/App_Data/Material/{0}", file));
if(System.IO.File.Exists(path))
{
string mime = MimeMapping.GetMimeMapping(path);
return File(path, mime);
}
return HttpNotFound();
}
And also transfered material folder inside app_data.
This seems to work nicely. Only authorized users can access to material folder.
It's possible to do that, but there are a lot ways to accomplish that.
A simplified scenario could be:
Disable directory listing on IIS
Create a custom "download wrapper" controller+action for the purpose of serving of those files.
Then wherever you create Action links, generate them using a HtmlHelper which would redirect the client to the "wrapper" controllers action. You can pass the filename in a parameter.
On the "wrapper" controller you could utize the [Authorize] attribute or better yet, without using such attributes everywhere you could use FluentSecurity for handling the authorization.
After you create the "wrapper" controller your URL for getting a file could look like:
www.example.com/download/file/pdf-file.pdf
This example URL assumes controller name is 'download' and action name is 'file'.

ASP.NET WebAPI multiple actions were found

I have a web api controller and two GET methods:
public class ImagesController : ApiController {
[HttpGet]
public HttpResponseMessage GetImages() { }
[HttpGet]
public HttpResponseMessage Download([FromUri]int[] ids) { }
}
Why I'm getting multiple actions found error, when trying to reach /api/Images, why both actions are the same?
When you created controller, you have assigned HttpGet to two different methods. Making that you have confused web server when it tries to process your request. Since you are sending GET verb to the controller it self, instead directly to the method, web server can not determinate what method should be invoked.
You can try with /api/Images/GetImages in order to directly hit a method, or remove one of listed.
If you see the Web API feature it work for the selected httm methods like GET,PUT,POST,DELETE.
So if you create two action method with same name it will give error. To avoid this error you have to redefine the DefaultAPI path in route.config file.
Change it to
API/{controller}.....
After changing this acces your API from browser like
Or
Mark as a answer if this resolve your issue.

How to get incoming InputStream, in controller in ASP.NET MVC

I need to get an incoming input stream for an uploaded file from the front-side in an ASP.NET controller and then forward it elsewhere, can anyone tell me how to access it? I saw some comments that say that I can get the way below but I get a compile error if I do that:
var requestStream=HttpContext.Current.Request.InputStream;
Thank you
If you're in a controller, then this.Request.InputStream should have what you need.
if the use uploaded a file you can added a HttpPostedFileBase to the action to access the file.
public ActionResult Upload(HttpPostedFileBase file)
{
using(var stream = file.InputStream)
{
...
}
}

Categories