How to use FILESTREAM in MVC 5 and EF6 - c#

This might be a silly question but I got confuse on the use of FileStream.
At first I thought FileStream is just an System.IO implementation for reading and saving files but there is also FILESTREAM for MSSQL or Database Storage.
https://msdn.microsoft.com/en-us/library/bb933993%28v=sql.100%29.aspx
My problem here is I would like to implement FILESTREAM on my application since I am just going to store profilepictures but what I dont get is the implementation part.
There are no examples or mention on how to use it in Entity Framework like what Filetype to be use or do I need to install a nuget. If I search for implementation of FileStream what I get is System.IO which does not have any reference for saving in database since it is use for file system
I am so confused. Please help.

It looks like that SQL Server FileStream is an over engineering solution for just keeping users avatars on oyour server. You can easily store the avatars on your server as files in some particular folder with having a corresponding record in your avatars reference table that keep the file path or store the avatar as a VARBINARY field in an avatars table.
Storing avatars as files seems to me a more straight forward solution because later on you can add an url of the file in some <img/> in purpose to display the avatar.
As for the rest I would suggest the following:
1) In your MVC view please reffer a model like that
public class AvatarModel
{
public int UserId { get; set; }
public HttpPostedFileBase AvatarFile { get; set; }
}
2) Start your Avatar View with the following statement
using (
Html.BeginForm("Avatar", "UserManagement", FormMethod.Post, FormMethod.Post, new { enctype = "multipart/form-data" } )
)
3) In the View define the inputs and submit button
<input type="hidden" id="UserId" value="#Model.UserId" />
<input type="file" id="AvatarFile" />
<button type="submit"/>
4) In your UserManagement controller implement the following method
[HttpPost]
[ActionName("Avatar")]
public ActionResult AvatarPost(AvatarModel model)
{
...
}
5) in the body of the method you will acess your file over the model argument
model.AvatarFile. The object model.AvatarFile gives you two possibilities either save as a file https://msdn.microsoft.com/en-us/library/system.web.httppostedfilebase.saveas(v=vs.110).aspx or you can read the file as a stream https://msdn.microsoft.com/en-us/library/system.web.httppostedfilebase.inputstream(v=vs.110).aspx convert it to a byte[] and then assign the byte array to a particular model of your entityt framework model.
Please keep in mind that by uploading the file you should keep the POST message <=64 Kbytes. In other case you will have customize your application config and the config of IIS on your server.
But 64 Kbytes should be enought for a avatat isn't it?

Related

Reading static files on ASP.NET

I'm on a solution with multiple projects, and I'm having issues accessing a project outside the one I'm currently on. Here's a very simplified structure of my codebase:
-ProjectA
-Pages
Index.razor
-ProjectB
- Images
-image.jpg
I'm on ProjectA using Blazor Server and I need to read an image outside my directory in ProjectB. I created a static file using the following code:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"./../ProjectB/Images/")),
RequestPath = new PathString("/MyImages")
});
The thing is, when I use "/MyImages" inside of an html img tag followed with the filename, it works fine and I can view any image in ProjectB. However, this does not work when I'm using System.IO code such as:
#code{
File.ReadAllBytes("/MyImages/image.jpg");
}
Can someone let me know what I'm doing wrong?
EDIT: I should have been a bit more clearer on the purpose of my project.
I have three classes that I'm dealing with, Product, CreateProduct and EditProduct. Those classes have the same properties like Name, Price, etc. The only difference is that Product has the string ImagePath while CreateProduct and EditProduct have IFormFile Image.
When I want to create a new Product, I read the string values like name, price, etc, then for the image, I use InputFile which gives me a IBrowserFile, do some basic conversion process to an IFormFile then POST it as a CreateProduct. In the backend, the API will store the IFormFile in the file system (aka ProjectB) then create a Product record in the DB which has the ImagePath.
Here's the snippet of code for this process:
[HttpPost]
public async Task<ActionResult<Product>> PostProduct([FromForm] CreateProduct model)
{
try
{
if (!ModelState.IsValid)
return BadRequest();
// This function helpers.UploadFiles will just write the file to the file system, then return the url
// For example, it'll return "/product_1/image.jpg"
var ProductImagePath = await _helpers.UploadFiles(model.Image);
var product = new Product
{
//news
Name = model.Name,
Price = model.Price,
ImagePath = ProductImagePath,
CreatedDate = DateTime.Now
};
_context.Product.Add(Product);
await _context.SaveChangesAsync();
And this is how it looks on the frontend:
// Converting my IBrwserFile(imageFile) to bytes so that it can be posted as IForm (Probably could do it better but that's an issue for another day)
using Stream filestream = imageFile.OpenReadStream(1024 * 1024 * 15);
using MemoryStream ms = new();
await filestream.CopyToAsync(ms);
byte[] productImage = ms.ToArray();
var formContent = new MultipartFormDataContent
{
{new StringContent("SomeProductName"),"Name"},
{new StringContent("SomeProductPrice"),"Price" },
{
new ByteArrayContent(productImage), "Image", fileName
},
};
await client.PostAsync("Product/", formContent);
My PUT request follows the same structure. The tricky part is the EditProduct scenario. I first have to do a GET request and receive the Product instance which only has the image path. There are two scenarios that editing my product entails:
Scenario 1:
1- Make a GET request for the `Product` class which has the image path
2- View all information including the image on the browser using <img src="ImagePath">
3- Decide to use a different image, which then I just call InputFile
4- Process InputFile and convert it to IFormFile
5- Make a PUT request and post the updated information to `EditForm` class
This works out fine. However in Scenario 2:
1- Steps 1 & 2 as before
2- Decide not to change the image, but change other stuff like the Name and price
3- ????
Now I need to make a PUT request but since I didn't use InputFile, I don't have an IFormFile that I can send to the PUT request for EditForm class.
In order for the PUT process to work properly, I need to read the image I got from the ImagePath using File.ReadAllBytes then read it to memory and convert it to an IFormFile.
As I mentioned at the start I can view the image using <img src="/MyImages/#imagePath />, with /MyImages being the static file path I created on Startup.cs. That doesn't work when I apply it to File.ReadAllBytes or any other IO functions.
It seems to me that your two projects are compiled under different folder systems, but are hosted under the same domain (say, "localhost/A" and "localhost/B"). From your browser's point of view, there's no problem.
But if you are trying to access files in your physical system, there's a problem because they have different root paths, and aren't actually sharing any folders. (which is as it should be, since you don't want 2 apps struggling for control over the file system)
Why do you want direct access to the image files? Will you manipulate them from your other project somehow?

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

Using WebImage in asp.net core razor mvc

I'm following this sample for working with WebImage. However I'm using asp-net core mvc in vs code.
Since there is no System.Web.Helpers where should I reference WebImage from? I tried searching and there are no explanation in aspnet mvc github wiki.
If you are looking to replace WebImage with a more suitable alternative for asp.net core, then IFormFile is your friend.
You can bind directly to an IFormFile if the parameter name matches the name of your form input field. Or, you can use the below. (Note the change from Request.Files to Request.Form.Files when moving from .net framework to core)
IFormFile inputFile = Request.Form.Files["uploadInputFieldName"];
Instead of the ContentLength property, you may find you need to reference Length instead.
When it comes to saving the file to the local file system (if that is what you are after), then swap out the SaveAs method call for this:
using (var stream = new FileStream(filePathWithSecureName, FileMode.Create))
{
await inputFile.CopyToAsync(stream);
}
More information on file uploads in core, including security considerations, this page is worth a read: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1
to upload webimage
<input type="file" name="updoc" id="upoc" class="form-control" />
and retrieve in controller by
in Controller
HttpPostedFileBase casteCertificate = Request.Files["updoc"];
Add multipart on your html begin form to retrive stream data from view
#using (Html.BeginForm("controller", "action", FormMethod.Post, new { enctype = "multipart/form-data", name = "myForm", id = "myForm" }))
Passing image to View
ViewBag.pic = urlofwebimage;
in view
<img id="Userpic" class="pull-right" style="margin-bottom: 7px" width="180" height="100" src="#ViewBag.pic" />
else u can also do model binding of Image Url

Need help adding download feature to MVC application

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.

How to find /open file from PC

you experts probably knowing the easyiest ways to open/find a file from asp.net mvc application.
could you tell me please how to do that, if i want for example to find and upload a photo from my PC.
Thanks and take care,
Ragims
This article may help you.
The article will show how to upload a
file from client to server location in
ASP.Net MVC application in 5 easy
steps.
Two samples:
example one
example two with unit testing
Just a simple HTML file input in your view will suffice:
<input type="file" name="MyFile" id="MyFile" />
Then accept the file in your controller action:
public ActionResult Upload(HttpPostedFileBase myFile)
{
// save or process file here...
return View();
}
Also, remember to set <form enctype="multipart/form-data"> in your form.

Categories