Buffer too many uploads? - asp.net-mvc

I am trying to upload a large video file. I am using Azure Storage blob. Reading documentation there is warning about using IFormFile at https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1
It suggests that I stream my data.
Is the follow code creating a buffer there will crash my server , or streaming directly to the storage?
From the View
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<input asp-for="VideoAsFile" class="form-control" />
<span asp-validation-for="VideoAsFile" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
From the controller
public async Task<IActionResult> Create([Bind(" Name,Description,VideoAsFile")] VideoWithFileViewModel video)
{
if (ModelState.IsValid)
{
string imageId;
using (var stream = video.VideoAsFile.OpenReadStream())
{
imageId = videoServices.SaveVideo(stream);
}
var newVideo = new Video()
{
Name = video.Name,
Description = video.Description,
URL = imageId
};
repository.AddVideo(newVideo, User);
repository.SaveAll();
return RedirectToAction(nameof(Index));
}
From the VideoServices
public string SaveVideo(Stream videoStream)
{
CloudBlobClient blobClient=new CloudBlobClient(new Uri(baseUri), credentials);
var imageId = Guid.NewGuid().ToString();
var container = blobClient.GetContainerReference("videos");
var blob = container.GetBlockBlobReference(imageId);
blob.UploadFromStreamAsync(videoStream);
return imageId;
}

IFormFile causes issues because the model binder can only do its thing once the request body has been entirely spooled into memory, which if you have a large upload, could mean using up many gigabytes of RAM or potentially maxing out your RAM utilization entirely.
To buffer the upload, you have to work with the request stream directly, which means turning off model binding entirely on the action. That means you cannot get anything from the action params.
The request body stream will be encoded as multipart/form-data, so you will have to manually parse this into its constituent parts, and bind the data to your entity/model directly, and then read the file part in a buffered way, passing the blocks you read on to your Azure blob storage piece by piece. Microsoft has an example of doing a buffered upload. However, it writes the upload file to disk. Getting it into Azure blob storage is on you.

Related

ASP.NET MVC - IHtmlFormElement's GetSubmission returns null

I'm making a POST request through an MVC controller using ASP.NET MVC and while unit testing I'm getting 'Object reference not set to an instance of an Object' from an IHtmlFormElement's GetSubmission() method. The test finds the button and the button itself is not null, but when the test calls the GetSubmission() with the submit button as a parameter it returns null.
Everything works fine from browser.
This is my Add.cshtml file content:
#model MVCPhones.Data.Phone
<form method="post" asp-action="Add">
<div class="form-group">
<label asp-for="Make" class="control-label">Make</label>
<input asp-for="Make" type="text" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Model" class="control-label">Model</label>
<input asp-for="Model" type="text" class="form-control" />
</div>
<div class="form-group">
<label asp-for="RAM" class="control-label">RAM</label>
<input asp-for="RAM" type="number" class="form-control" />
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-label">PublishDate</label>
<input asp-for="PublishDate" type="date" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Here is my PhonesController post method:
public async Task<IActionResult> Add(Phone phone)
{
try
{
phone.Created = DateTime.Now;
phone.Modified = DateTime.Now;
await _context.Phones.AddAsync(phone);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
Here is the section that gives the error:
Error

The Image uploading functionality is not working properly for me

I am using this code with the help of one tutorial, but still i am unable to upload the image, i mean the image is not appearing, please someone help me on this
This is the code I have used:-
<div class="col-md-6">
<div class="form-group">
#Html.LabelFor(model => model.ImgPath, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<img src="#Url.Content(Model.ImgPath)" style="margin:10px" height="200" width="200" id="imagePreview" />
<input type="file" name="ImageUpload" accept="image/jpeg, image/png" onchange="ShowImagePreview(this, document.getElementById('imagePreview')" />
</div>
</div>
</div>
If your image is not uploading, i think you should check you form tag and make it something like this
<form method="post" enctype="multipart/form-data">
//your image upload
<input type="file" name="ImageUpload" accept="image/jpeg, image/png" />
</form>
then you can use the
Request.Files
and access all the files sent or if you want it strongly embedded use
//this for Asp.Net Core
public IActionResult(IFormFile ImageUpload)
{
//Everything here
}
//Or this for Asp.Net
public ActionResult(HttpPostedFileBase ImageUpload)
{
//Everything else here
}
Read this stackoverflow post to understand about it

Asp.Net MVC - Data permutator

I have searched for hours for this without finding an answer, so I'm asking your help (I'm a beginner in web development (and in Asp.Net MVC)).
I want to create a simple data permutator (for example you enter 3 datas "a, b, and c", and I give you the possible permutations between these 3 datas : "abc; acb; bac; bca; cab; cba").
I have tried the following code, but it does not work (I have an HTTP 404 error).
<form method="post">
<div class="col-md-4 input-group">
<div class="input-group-addon">1</div>
<input type="text" name="firstData" class="form-control" placeholder="First Data" maxlength="50" required />
</div>
<div class="col-md-4 input-group">
<div class="input-group-addon">2</div>
<input type="text" name="secondData" class="form-control" placeholder="Second Data" maxlength="50" required />
</div>
<div class="col-md-4 input-group">
<div class="input-group-addon">3</div>
<input type="text" name="thirdData" class="form-control" placeholder="Third Data" maxlength="50" required />
</div>
<div class="col-md-12 mainAction centerbloc">
<input type="submit" value="Permutate the data" class="btn btn-success register-button-slider" href="">
</div>
</form>
And then below, I want to display the result in the same page, like this :
#{ if (IsPost)
{
string firstdata = Request.Form["firstData"];
string seconddata = Request.Form["secondData"];
string thirddata = Request.Form["thirdData"];
<p>
#firstdata #seconddata #thirddata<br />
#seconddata #firstdata #thirddata<br />
</p>
}
}
I haven't put anything special in my controller (maybe the mistake is here?) :
namespace Blogs.Controllers
{
public class ToolsController : Controller
{
[Route("tools/datapermutator", Name = "DataPermutator"), HttpGet]
public ActionResult DataPermutator()
{
return View();
}
}
}
If you have a way to do it, it would be very helpful, thank you in advance!

How can I export data in pdf using MVC?

This is My Index method by which I am getting the list of data in webgird.How can I write a method for exporting this list of data when I click on button?
public ActionResult Index(string eMailId)
{
var refEntry = _moneyReport.GetAll().Where(a => a.EmailId == eMailId).ToList();
var credittotal = _moneyReport.GetAll().Where(a => a.EmailId == eMailId && a.PromoValue < 0).Sum(a => a.PromoValue);
decimal TotalCredit = Convert.ToDecimal(credittotal * -1);
var debittotal = _moneyReport.GetAll().Where(a => a.EmailId == eMailId && a.PromoValue >0).Sum(a => a.PromoValue);
decimal TotalDebit = Convert.ToDecimal(debittotal);
ViewBag.TotDebit = TotalDebit;
ViewBag.TotCredit = TotalCredit;
if(TotalCredit>TotalDebit)
{
decimal FinalTotal = TotalCredit - TotalDebit;
ViewBag.Total = FinalTotal;
}
else
{
decimal FinalTotal = TotalDebit - TotalCredit;
ViewBag.Total = FinalTotal;
}
return View(refEntry);
}
This is my View page where I am entering an emailid,load and Export button`enter code here.
#using (Html.BeginForm())
{
<div class="container-fluid form-row">
<div class="col-md-12 no-padding">
<div class="col-md-3 no-padding">
<input type="text" name="eMailId" id="eMailId" />
<span class="highlight"></span>
<span class="bar"></span>
<label class="no-left">Enter Email Id <sup class="star">*</sup></label>
</div>
<div class="col-md-3">
<input type="text" id="gName" name="gName" readonly="readonly" />
<span class="highlight"></span>
<span class="bar"></span>
<label>Name</label>
</div>
<div class="col-md-3">
<input type="submit" id="btnLoad" class="btn btn-md pm-create" value="Load" />
<input type="submit" id="btnLoad" class="btn btn-md" value="Export To PDF" />
</div>
<input type="hidden" id="HdnEmail" value='#TempData["MailID"]' />
</div>
</div>
}
<div id="report-grid">
#{Html.RenderPartial("ImportMoneyReport", Model);}
</div>
ImPortMoneyReport is my partial page where i ve the webgrid.
To export model data to PDF you will have to use one of third party pdf export libraries such as few below. You will find sample examples on respective sites or google them. You will need to implement code to export pdf in and add that file/stream into Response.OutputStream by setting respective content type in ImportMoneyReport action. Also you will have to invoke ImportMoneyReport method on post/event you can not use Html.RenderPartial to export; otherwise you can put export code in Index action only.
PDF Sharp
iTextSharp
It you want something that's working and very easy to use. Take a look at https://github.com/andyhutch77/MvcRazorToPdf
Just read the documentation.
For sample code. Take a look at this.
https://github.com/andyhutch77/MvcRazorToPdf/tree/master/MvcRazorToPdfExample
If you encounter some issues go to their github page and click the Issues tab, maybe some of your questions are already resolved there.
P.S.
Some of the PDF libraries like Rotativa will require an executable program to run that will not work when your app is deployed to Azure because Azure doesn't support exe files (I guess for security purposes) else you'll create a webjob just for the exe file.

Submitting a form to ASP.NET MVC from Knockout does not bring in all the values

Here is what I have in my view in ASP.NET MVC 5
#model Entities.Coupon
#using (Html.BeginForm("coupon", "marketing", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="scsm-18 scmd-16 sclg-14">
<div class="form-group">
<label>Codes</label>
#Html.TextBoxFor(p => p.Code, new { #class = "form-control", #data_bind = "value: Code", #autofocus = true, #maxlength = "50" })
</div>
<input type="radio" name="IsPerCentOrDollar" value="1" data-bind="checked: IsPerCentOrDollar" />
<span>PercentageAmount</span>
<input type="radio" name="IsPerCentOrDollar" value="2" data-bind="checked: IsPerCentOrDollar" />
<span>DollarAmount</span>
<input type="radio" name="IsPerCentOrDollar" value="3" data-bind="checked: IsPerCentOrDollar" />
<span>FreeShipping</span>
</div>
<div class="panel-footer text-right">
<input type="submit" name="commandType" id="btnSave" class="btn btn-primary" data-bind="click:submit" value="Save" />
</div>
}
In the script:
$(document).ready(function () {
var viewModel = new CouponViewModel(couponModel);
ko.applyBindings(viewModel);
function CouponViewModel(data) {
self.Code = ko.observable(data.Code);
self.IsPerCentOrDollar = ko.observable("1");
self.DiscountLevel = ko.computed(function () {
return self.IsPerCentOrDollar();
});
};
}
Code in MVC:
[HttpPost, ActionName("coupon")]
public ActionResult coupon(Coupon coupon)
{
try
{
// some logic not yet in
}
catch (Exception ex)
{
}
return View();
}
That's all I have in there now.
In Developer tools inside the browser I can see values for self.DiscountLevel change on the selection of radio buttons.
On Submit, at MVC front the value of Code comes in but the values for DiscountLevel are not.
Any help is greatly appreciated.
Regards.
Let me expand on #StephenMuecke's comment (which has the gist of it I think).
ASP.NET MVC's default model binding will fill the argument (Coupon) with values found in the request. Only form elements are sent along with the request. You seem to expect that DiscountLevel is sent along, but it's just a JavaScript function that exists in the user's browser.
Adding something like this may solve your immediate problem:
<input type="hidden" name="DiscountLevel" data-bind="value: DiscountLevel" />
To note a related issue though: the property you have trouble with is a computed observable. However, you probably do not want to send it along as it depends entirely on IsPerCentOrDollar. Just have your server side Coupon class derive the discount level from that property too. That would also prevent users from hacking the hidden input and sending in a malicious value.

Resources