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

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)
{
...
}
}

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?

POST of IFormFile not making it to action

I've got a .NET Core application that has a controller named Documents with a POST signature like this:
[HttpPost]
public async Task<IActionResult> PostAsync(CreateDocumentRequest createDocumentRequest)
The CreateDocumentRequest looks like this:
public class CreateDocumentRequest
{
public string Name { get; set; }
public string Description { get; set; }
public IFormFile File { get; set; }
}
Pretty simple. I then have a POST request configured in Postman like this:
URL: http://localhost:9090/api/documents
Body: configured as form-data and I have Name, Description and File all configured in the key-value pair interface. Furthermore, File is set as a file type so it allowed me to browse for a file.
When executing this POST the DocumentsController executes the constructor and Application Insights indicates that PostAsync was matched:
Activated Event Time Duration Thread
Application Insights: Trace "Route matched with {action = "PostAsync", controller = "Documents"}. Executing action TdlLims.MediaService.Controller.DocumentsController.PostAsync (TdlLims.MediaService)"
However, it never enters the action. My gut tells me that model binding is failing. This is for two reasons. One, all other pieces of the routing work according the Application Insights. Two, if I remove the parameters entirely, it does enter the action. What I've tried:
Added [FromForm] to the createDocumentRequest
Accepted only an IFormFile into the action, dropping the complex object
Split up the CreateDocumentRequest into three different parameters
And some other things along the way with less signifigance
Now, I'm suspect that when we're setting up Mvc, we may be missing something. We are configuring a few things, but I feel like we're missing a formatter for multipart/form-data somehow. I feel that way because we're using AddMvcCore instead of AddMvc:
.AddAuthorization()
.AddJsonFormatters()
.AddApiExplorer()
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new OptionConverter());
options.SerializerSettings.Converters.Add(new StringEnumConverter());
});
Finally, I can confirm the controller is working in general, because I have a GET that is accessible and it makes it to the action:
[HttpGet("{id}")]
public async Task<IActionResult> GetAsync(int id)
In the end, the issue was the size of the file. It would be nice if .NET Core threw an error rather than returning a 200 when something like that happened. I was trying to upload some images, and I'm going to need to figure out the right way to increase the file size, but when I uploaded a small text file the POST worked and the file was deserialized properly into the IFormFile.
I believe the attributes RequestFormLimits and RequestSizeLimit are going to play a role in setting that max file size in the end.

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.

asp.net mvc controller method that returns jpeg given parameter

I would like to create a jpeg on the fly given some data from a database. The data is an array containing values which should be translated into a colour.
A asp.net mvc controller method should return a jpeg on the fly given one parameter.
This should be fairly straight forward. Could someone please point me to some existing code?
Thanks.
Here are a couple of possible options that may help you get started:
I think you will porbably need an handler and then call the handler from your controller.
SO POst
Bob Cravens post
Scott Hansleman's post
If you want this in pure mvc you can do this
Extending MVC: Returning an Image from a Controller Action
Another way is to create a HttpHandler that does that for you
HTTP Handlers for Images in ASP.NET
hope this helps
There is a tutorial on msdn on How to: Encode and Decode a JPEG Image.
Doing that in MVC3 is pretty similar, you just need a action in your controller like this:
public class YourController : Controller
{
[HttpGet]
public ImageResult GetImage(int whatever)
{
stream imageStream = yourJpgFactory.GetImage(whatever)
return (imageStream)
}
}
and in your view
<img src="YourController/GetImage?whatever=42" />

Retrieve URL for Action from Controller

I am calling a Controller Action from a view, within that controller I need to invoke another Action which I will invoke to save the view to a network location as either HTML or Image.
How do I retrieve the URL to an Action from within a Controller. Please note I need the actual URL, this means RedirectionToAction or View() wont work.
Why? I need to pass in a URL which will contain a call to a View. This view will be used to generate an image or HTML document using the System.Windows.Forms.WebBrowser.
.NET 3.5; C#; MVC 1;
I could do something like this, but its dirty ... well it leaves me with that dirty feeling.
using(Html.BeginForm("Action", "MyWorkflowController",
new {
MyId = "bla",
URLToGenerateImage = Url.Action("GenerateImage", "MyWorkflowController")
}))
I ended up using the MvcContrib.UI.BlockRenderer to convert to View to Html instead of generating the image. I proceeded to save the html string to a file system location.
Here is a link for further information
http://www.brightmix.com/blog/how-to-renderpartial-to-string-in-asp-net-mvc/
How about ContentResult - Represents a text result, so you could have
/Controller/GetUrl/id
Public ActionResult GetUrl(int id)
{
// builds url to view (Controller/Image/id || Controller/Html/id)
var url = BuildImageUrl(id);
return ContentResult(url);
}
in view you could have:
GenerateImage

Categories