Download file from link inside my webpage - asp.net-mvc

I have Webpage with table of objects.
One of my object properties is the file path, this file is locate in the same network. What i want to do is wrap this file path under link (for example Download) and after the user will click on this link the file will download into the user machine.
so inside my table:
#foreach (var item in Model)
{
<tr>
<th width ="150"><p><b>Download</b></p></th>
<td width="1000">#item.fileName</td>
<td width="50">#item.fileSize</td>
<td bgcolor="#cccccc">#item.date<td>
</tr>
}
</table>
I created this download link:
<th width ="150"><p><b>Download</b></p></th>
I want this download link to wrap my file path and click on thie link will lean to my controller:
public FileResult Download(string file)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(file);
}
What i need to add to my code in order to acheive that ?

Return FileContentResult from your action.
public FileResult Download(string file)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(file);
var response = new FileContentResult(fileBytes, "application/octet-stream");
response.FileDownloadName = "loremIpsum.pdf";
return response;
}
And the download link,
Download
This link will make a get request to your Download action with parameter fileName.
EDIT: for not found files you can,
public ActionResult Download(string file)
{
if (!System.IO.File.Exists(file))
{
return HttpNotFound();
}
var fileBytes = System.IO.File.ReadAllBytes(file);
var response = new FileContentResult(fileBytes, "application/octet-stream")
{
FileDownloadName = "loremIpsum.pdf"
};
return response;
}

In the view, write:
Download
In the controller, write:
public FileResult DownloadFile(string file)
{
string filename = string.Empty;
Stream stream = ReturnFileStream(file, out filename); //here a backend method returns Stream
return File(stream, "application/force-download", filename);
}

This example works fine for me:
public ActionResult DownloadFile(string file="")
{
file = HostingEnvironment.MapPath("~"+file);
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
var fileName = Path.GetFileName(file);
return File(file, contentType,fileName);
}
View:
< script >
function SaveImg()
{
var fileName = "/upload/orders/19_1_0.png";
window.location = "/basket/DownloadFile/?file=" + fileName;
}
< /script >
<img class="modal-content" id="modalImage" src="/upload/orders/19_1_0.png" onClick="SaveImg()">

Related

Multiple constructors accepting all given argument types have been found in type 'System.Collections.Generic.List`1[Portal.Models.FileDataModel]'

I'm using ASP.NET Core 3.1 with EF Core and Azure Storage (File Storage). I am using Microsoft.Azure.Storage.File version 11.2.2 for the Azure Storage file handling.
I'm not sure exactly what this error is referencing other than a Dependency Injection (DI) issue?
Most of the articles or SO articles that I've come across referencing this error message suggest a DI, but when they inject it in Startup.cs, they have an Interface to accompany their injection. I do not.
I'm using a Razor page for this view. This code was previously written for an MVC view that I'm trying to convert for cohesion. See original post HERE. The project in MVC works without any issues. Should I just give up trying to do this all in Razor pages and use MVC for my entire project or is there an obvious issue I'm missing??
Here is my setup:
namespace AzureFileShare.Pages.Files
{
public class IndexModel : PageModel
{
private readonly IConfiguration _configuration;
public IndexModel(
IConfiguration configuration)
{
_configuration = configuration;
}
public async Task<IList<FileModel>> OnGetAsync()
{
string fileStorageConnection = _configuration.GetValue<string>("fileStorageConnection");
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(fileStorageConnection);
CloudFileShare share = storageAccount.CreateCloudFileClient().GetShareReference("payreports");
CloudFileDirectory root = share.GetRootDirectoryReference();
CloudFileDirectory dir = root.GetDirectoryReference(#"E000002/stubs");
// list all files in the directory
var fileData = await list_subDir(dir);
return fileData;
}
public static async Task<List<FileModel>> list_subDir(CloudFileDirectory fileDirectory)
{
var fileData = new List<FileModel>();
FileContinuationToken token = null;
do
{
FileResultSegment resultSegment = await fileDirectory.ListFilesAndDirectoriesSegmentedAsync(token);
foreach (var fileItem in resultSegment.Results)
{
if (fileItem is CloudFile)
{
var cloudFile = (CloudFile) fileItem;
//get the cloudfile's properties and metadata
await cloudFile.FetchAttributesAsync();
// Add properties to FileDataModel
fileData.Add(new FileModel()
{
FileName = cloudFile.Name,
Size = Math.Round((cloudFile.Properties.Length / 1024f), 2).ToString(),
DateModified = DateTime.Parse(cloudFile.Properties.LastModified.ToString()).ToLocalTime().ToString()
});
}
if (fileItem is CloudFileDirectory)
{
var cloudFileDirectory = (CloudFileDirectory)fileItem;
await cloudFileDirectory.FetchAttributesAsync();
//list files in the directory
var result = await list_subDir(cloudFileDirectory);
fileData.AddRange(result);
}
// get the FileContinuationToken to check if we need to stop the loop
token = resultSegment.ContinuationToken;
}
} while (token != null);
return fileData.OrderByDescending(o => Convert.ToDateTime( o.DateModified)).ToList();
}
}
}
Model
public class FileModel
{
public string FileName { get; set; }
public string Size { get; set; }
public string DateModified { get; set; }
}
appsettings.json
{
"ConnectionStrings": {
"fileStorageConnection": "DefaultEndpointsProtocol=https;AccountName=navraereports;AccountKey=REMOVEDFORPUBLIC;EndpointSuffix=core.windows.net"
}
}
#page
#model List<FileModel>
#{
ViewData["Title"] = "Download Pay Stub Copies";
}
<h1>Pay Stub Copies</h1>
<table class="table table-bordered">
<thead>
<tr>
<th>File Name</th>
<th>File Size</th>
<th>File Date</th>
<th>Download</th>
</tr>
</thead>
<tbody>
#foreach (var data in Model)
{
<tr>
<td>#data.FileName</td>
<td>#data.Size</td>
<td>#data.DateModified</td>
<td>
<a class="btn btn-primary"
href="/File/DownloadStub?id=#data.FileName">Download</a>
</td>
</tr>
}
</tbody>
</table>
Stack Trace:
System.InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'System.Collections.Generic.List`1[AzureFileShare.FileModel]'. There should only be one applicable constructor.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.TryFindMatchingConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactory(Type instanceType, Type[] argumentTypes)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelActivatorProvider.CreateActivator(CompiledPageActionDescriptor actionDescriptor)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelFactoryProvider.CreateModelFactory(CompiledPageActionDescriptor descriptor)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvokerProvider.CreateCacheEntry(ActionInvokerProviderContext context, FilterItem[] cachedFilters)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.<CreateRequestDelegate>b__0(HttpContext context)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
UPDATE
In Razor view, replace
#model List<FileModel>
with
#model AzureFileShare.Pages.Files.IndexModel
In IndexModel.cshtml.cs you'll need a new property for the result
public List<FileModel> FileModels { get; private set; } = new List<FileModel>();
In addition to change of signature, you'll need some changes inside method as well.
public async Task OnGetAsync()
{
string fileStorageConnection = _configuration.GetValue<string>("fileStorageConnection");
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(fileStorageConnection);
CloudFileShare share = storageAccount.CreateCloudFileClient().GetShareReference("payreports");
CloudFileDirectory root = share.GetRootDirectoryReference();
CloudFileDirectory dir = root.GetDirectoryReference(#"E000002/stubs");
// list all files in the directory
FileModels = await list_subDir(dir);
}
Finally, go back to Razor view and change
#foreach (var data in Model)
witn
#foreach (var data in Model.FileModels)
Please try replacing
fileData.OrderByDescending(o => Convert.ToDateTime( o.DateModified));
with
return fileData.OrderByDescending(o => Convert.ToDateTime( o.DateModified)).ToList();
and remove
return fileData;
from the line right below.
You should also replace
Stream fileStream = file.OpenReadAsync().Result;
with
Stream fileStream = await file.OpenReadAsync();
Replace
await file.DownloadToStreamAsync(memoryStream);
with
await file.DownloadToStreamAsync(new MemoryStream());
and remove
MemoryStream memoryStream = new MemoryStream();

MVC Image - Dispaly in a Tab instead of downloading to a file

I have the following controller method which gets a PNG from a web api.
public async Task<ActionResult> RealTimeUpdate(string fundName)
{
string docPath = ConfigurationManager.AppSettings["RealTimeUpdate"].Replace("{fundname}",fundName).ToString();
docPath = docPath.Replace("\\\\", "\\");
docPath = docPath.Replace("\"", "");
string url = ServiceUrl + "api/RealTime/" + fundName;
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var dataStream = response.Content.ReadAsStringAsync().Result;
if (dataStream == null)
return HttpNotFound();
var _buffer = JsonConvert.DeserializeAnonymousType(dataStream, new { _buffer = (byte[])null })._buffer;
// If user decides to save the file, this will help...
//Response.AddHeader("content-disposition", "filename=" + Path.GetFileName(path));
return File(_buffer, "application/png");
}
return View("Error");
}
I call it like this:
Real Time Update
As you can see, I have target="_blank", however, instead of displaying the image in a new tab, it downloads it to my documents folder. How can I get it to display in a tab?
You need a ImageController to render that.
once you have a controller you can render as follows:
public class ImageController{
public ActionResult ShowImage(string path)
{
return File(path);
}
}
in your views:
<img src="#Url.Action("Render","Image", new {id =1 // or path })" />
this answer was taken from https://stackoverflow.com/a/16142574/5586581

Assign Path for each link in ASP MVC

I have multiple pdf documents that I have to show in a view .My code is opening the same document for all the links which is wrong.
In my contoller :
public ActionResult Docs()
{
var docModel = this._documentBuilder.Build(this.StateData);
foreach (var doc in docModel.OldEstimateFiles)
{
return this.File(doc.PdfUrl, "application/pdf");
}
return null;
}
and in the view :
foreach (var menuItem in Model.OldEstimateFiles)
{
<ul >
<li>
#using (Html.Anchor(new ststyle { URL = "/DocumentEstimate/Docs", Target = "_blank", Text = menuItem.Label }))
{
}
</li>
</ul>
}
what is wrong in my code knowing that oldestimatefiles is a list
I edited my action in the controller to take in the ID.
public ActionResult Docs(string id)
{
var docModel = this._documentBuilder.Build(this.StateData);
return docModel.OldEstimateFiles.Any() ? this.File(docModel.OldEstimateFiles.Find(p => p.ID == id).PdfUrl, "application/pdf") : null;
}
I added an entry in the routeConfig file taking in the URL the id of the document and In the view I edited my link :
#using (Html.Anchor(new ststyle
{
URL = "/DocumentEstimate/EstimateDocs/" + menuItem.ID,
Id = menuItem.ID
It resolved the issue.

Image not displaying in ASP.NET MVC

In an ASP.NET MVC application, file is successfully saved to a folder and its URL is saved to SQL database. Having problem in loading file in a browser from folder using this URL. Code implementation is:
[HttpPost]
[ActionName("UploadPhoto")]
public ActionResult UploadPhoto(HttpPostedFileBase photoPath)
{
var fileName = Path.GetFileName(photoPath.FileName);
string path;
if (photoPath.ContentLength > 0)
{
path = Path.Combine(Server.MapPath("~/Images/photos"), fileName);
photoPath.SaveAs(path);
return RedirectToAction("CreateWithImage", new { path = path });
}
return View();
}
public ActionResult CreateWithImage(string path)
{
employee em = new employee();
em.districts = new SelectList(hc.districts, "name", "name");
em.photoPath = path;
return View(em);
}
file (image) is rendered in a view as:
#model HRMS.Models.employee
<dd>
#Html.Image(#Model.photoPath)
</dd>
Extension method implementation for #Html.Image is:
namespace HRMS.CustomeHTMLHelper
{
public static class CustomHtmlHelper
{
public static IHtmlString Image(this HtmlHelper helper,string src)
{
TagBuilder tb = new TagBuilder("img");
tb.Attributes.Add("src", VirtualPathUtility.ToAbsolute(src));
return new MvcHtmlString(tb.ToString(TagRenderMode.SelfClosing));
}
}
}
When View is called, I see a broken link for the image. HTML(with correct file path) for the loaded page (View) is seen as:
<dd>
<img src="/App_Data/photos/1.png" />
</dd>
When I try to run the physical path to the image in the browser i.e., <b>Requested URL</b> http://localhost:57852/App_Data/photos/1.png, it is throwing HTTP Error 404.8 - Not Found Error.
Where could I be wrong? Please help.

File Upload in MVC 5

I am developing a MVC 5 application and using MS SQL Server as a database. I have form in this app, which will store the event details in database. in this form i have a file upload field. Actually i want to upload an image in a folder on the server and store its URL in the database so that URL could be used in my front end.
Following is my create action method
public ActionResult Create([Bind(Include = "Id,Event_Name,Event_Description,Event_Detail,Image_Url,Event_Date,User_Name,Date_Uploaded,Category_ID")] WASA_Events wASA_Events)
{
var filePath = FileUpload();//Function call to get the uploaded file path
wASA_Events.Image_Url = filePath;
if (ModelState.IsValid)
{
db.WASA_Events.Add(wASA_Events);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Category_ID = new SelectList(db.WASA_Events_Category, "id", "Event_Category", wASA_Events.Category_ID);
return View(wASA_Events);
}
and FileUpload Function which will return the file path is as under
public string FileUpload()
{
var filePath = "";
if(Request.Files.Count > 0)
{
var file = Request.Files[0];
if(file!=null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/images/uplods/"), fileName);
file.SaveAs(path);
filePath = path;
}
}
return (filePath);
}
and in my view i used the following
#using (Html.BeginForm("Create", "WASA_Events", FormMethod.Post, new { enctype = "multipart/form-data" }))
Now the problem is i got nothing in the Request.Files.Count, means its value is zero. So can't move ahead.
Any Help.
Check the below.,.,
Check whether you can get the files in the request in the Create Action itself. I am sure that the request will maintain state in the FileUpload method too. But check for if it's not.
Whether the file upload input is inside the form that you are using in the view ?
Whether the file upload input is any third party control ? If so, check if you have the file name is updated in the file upload input in the HTML after selecting the file in the browser.
A little crazy check would be whether you have selected a file and opted to upload the file in the browser.,.,
I just did the file upload by adding the following class
public class Pictures
{
public HttpPostedFileBase File { get; set; }
}
and then use it in my create Controller action method. Below is the code for controller action
if (picture.File.ContentLength > 0)
{
var fileName = Path.GetFileName(picture.File.FileName);
var path = Path.Combine(Server.MapPath("~/assets/uploads/events/"), fileName);
picture.File.SaveAs(path);
}
and in view
<input type="file" id="File" name="File" class="form-control"/>
this solvedmy problem

Resources