Read multipart form data without saving files to disk? - c#

I have a form which looks, simplified, like this:
<form id="image-form" enctype="multipart/form-data">
<input type="text" name="imageEntryName" />
<input type="file" name="imageEntry" />
<input type="text" name="imageEntryAltText" />
<input type="submit" value="SEND INN" class="btn-ok" />
</form>
This is posted to this action:
[HttpPost]
[Route("~/api/Exhibition/SubmitImageEntry")]
public async Task<HttpResponseMessage> SubmitImageEntry()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var provider = new MultipartFormDataStreamProvider("C:/test");
var data = await Request.Content.ReadAsMultipartAsync(provider);
return new HttpResponseMessage(HttpStatusCode.OK);
}
And this works. I get the posted data. But is this possible without the MultipartFormDataStreamProvider saving files to C:/test? I possible, I can just keep the data in memory until the action is completed.
EDIT: With MultipartFormDataStreamProvider I get the .FormData["key"] option, which is what I want.

Use the MultipartMemoryStreamProvider.

Related

ASP.NET MVC app shuts down when i try uploading files

I have a form in my asp.net web app, which sends files uploaded by the user
<form method="post" asp-action="#((Model != null) ? "Update" : "Upload")" asp-controller="Materials" enctype="multipart/form-data">
<input id="cat" type="hidden" name="cat" />
<input id="subcat" type="hidden" name="subcat" />
<input type="file" name="file" max="1" title="#((Model != null) ? "Обновить" : "Загрузить")"/><br />
<input type="file" name="images" multiple title="Загрузить картинки"/><br />
<input id="name" type="text" name="name" maxlength="30" /><br />
<textarea id="desc" name="description" maxlength="199" ></textarea><br/>
<input type="submit" value="Сохранить"/>
</form>
There is one input for a file, and one input for image files, but as soon as I input any files the app just.... shuts down
Here is the method from the controller:
[HttpPost]
public IActionResult Upload(IFormFile file, IFormFileCollection images, string name, string description, string cat, string subcat)
{
FileUploadManager f = new FileUploadManager(environment.WebRootPath + '/');
f.Upload(file,images, name, description, cat + "-" + subcat);
return Redirect(Url.Action("Index", "Material"));
}
the browser does not shut down, the app itself in the VS does, and without any exceptions, it just stops debugger as soon as files contact with HTML
also, I am using Yandex browser

Post a form to api endpoint and get the response in a javascript callback

Here is my current setup to upload a file to my webapp:
HTML:
<iframe name="myframe" id="frame1" class="hidden"></iframe>
<form target="myframe" method="post" enctype="multipart/form-data" action="/api/User/collection">
<input type="file" name="file" />
<input type="submit" value="Upload" />
</form>
Controller:
// POST api/user/collection
[HttpPost("collection")]
public ActionResult<IResponse> SetCollection(IFormFile file)
{
var collection = fileDeflator.UnzipAndGetCollection(file);
if (collection == null)
return BadRequest(new BaseResponse("The collection file is invalid."));
return base.SetUserCollection(collection);
}
It's working, except that there is no feedback at all for the client.
I would prefer that the JSON returned by the server be caught in a javascript callback on the web page (not the iframe) and be parsed to refresh a section on the page.
Is that possible with the nature of form submit ?
I ended with something working as I wanted with the helpful resources that Amy provided.
Here is the solution:
<form id="formSendCollection">
<input type="file" id="fileCollection" name="fileCollection" />
<span onclick="submitCollection();" class="button is-primary">Submit</span>
</form>
function submitCollection() {
var fdata = new FormData();
var fileCollection = document.getElementById('fileCollection').files[0];
fdata.append("fileCollection", fileCollection);
sendAjax('/api/User/Collection', fdata, function (body) {
vueApp.modelUser.collection = JSON.parse(body);
});
}
function sendAjax(url, body, callback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE) {
callback(xmlhttp.responseText);
}
};
xmlhttp.open('POST', url, true);
xmlhttp.send(body);
}

How to keep my model data when do GET>POST>REDIRECT to upload a file?

I want to create a register form using MVC which include a profile photo. I don't want to add record for people before completing the form (including profile photo upload). Also I want my UploadImage view and controller to be re-usable for many forms (not just this form). I pass three variables to my upload form through ActionLink: RedirectAction (RA), RedirectController (RC), and dataname and the procedure goes like this:
I store RA, RC, dataname in ViewBag, then put them in hidden <input> tags to be submitted when POSTing the file
// GET: UploadImage/Upload
public ActionResult Upload(string RA, string RC, string dataname)
{
ViewBag.RedirectAction = RA;
ViewBag.RedirectController = RC;
ViewBag.DataName = dataname;
return View();
}
Put these lines in my Upload.cshtml (View):
#using (Html.BeginForm("Upload", "UploadImage", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="hidden" name="RA" value="#ViewBag.RedirectAction" />
<input type="hidden" name="RC" value="#ViewBag.RedirectController" />
<input type="hidden" name="dataname" value="#ViewBag.DataName" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
}
Store the filename in TempData with dataname as the Key and redirect to /RC/RA:
// POST: UploadImage/Upload/
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file, string RA , string RC , string dataname)
{
var filepath = "C:/myfilename.jpg";
TempData.Add(dataname, filepath);
return RedirectToAction(RA,RC);
}
And get my filepath by utilizing TempData in my register form:
#if (TempData.Keys.Contains("MyData")) {
<div class="form-group">
<p>#TempData["MyData"].ToString()</p>
</div>}
The code works just fine, but the essential caveat is that I don't want other completed fields to get lost when redirected to the register form. How can I solve this problem ?
One option is to stick the data in the session. Another option would be to use a separate database table to hold in-progress registration data.

Unable to receive file data in FormCollection object inside controller

I have following markup:
<form id="did" enctype="multipart/form-data">
<textarea name="description">Text</textarea>
<input name="files" id="files" type="file" accept="doc,pdf" />
...
</form>
And in controller its like this:
public int Edit_Submit(FormCollection oForm)
{
var attachedFiles = oForm["files"];
var description= oForm["description"];
....
}
I am posting the form through jQuery which look like this:
var formInfo = $("#did").serialize();
$.post('../../data/SubmitEdit', formInfo, function (serverResult) {
...
I am receiving other data fine but always null in attachedFiles.
Is it not possible through this way? What am I doing wrong please help.
I don't think your uploaded file will be in your form collection.
Try something like this maybe:
<form id="did" action="../../data/SubmitEdit" enctype="multipart/form-data">
<textarea name="description">Text</textarea>
<input name="files" id="files" type="file" accept="doc,pdf" />
...
</form>
[HttpPost]
public ActionResult SubmitEdit(FormCollection oForm, HttpPostedFileBase files) {
...
Make sure HttpPostedFileBase name is the same as the id of your input[type="file"]
$.post() method is essentially an ajax call, or in more technical terms, use of XMLHttpRequest object.
And by XMLHttpRequest object you can't send file stream back to the server. There are some ways to imitate that though.
Also, at server-side, you should use HttpPostedFileBase class, to get the file stream back to the server.

Get html items from view to control

Still kind of new to MVC, so please bear with me. I'm trying to grab some dynamically generated HTML. In this case, list items in my notifyList. I plan on looping through each one in the controller and adding them as database entries. Any help is appreciated, thanks.
View
#model _BaseViewModel
// The form it's within...
#using (Html.BeginForm("Create", "Leaf", FormMethod.Post, new { id = "createForm" }))
<div class="editor-label bottom-area bottom-header">
Notification List:
</div>
<div class="editor-field bottom-area">
<ul id="notifyList"></ul>
</div>
Controller:
[HttpPost]
public ActionResult Create(_BaseViewModel model)
{
// Some loop here
// get html here
db.UserItems.AddObject(model.user);
db.SaveChanges();
//
return RedirectToAction("Index");
}
As far as I understood, you use jQuery to fetch <li/> elements into notifyList. What you need to do here is to generate a hidden input as well. Sample:
$("#btnAppend").click(function() {
for(var i = 0; i < 4; i++) {
var _val = "Foo " + i;
var $li = $("<li/>").text(_val);
var $hidden = #("<input/>").
attr("type", "hidden")
attr("name", "foo").
val(_val);
$hidden.appendTo($li);
$li.appendTo("#notifyList");
}
});
This code will generate following output inside your DOM:
<ul id="notifyList">
<li>Foo 0<input type="hidden" value="Foo 0" name="foo" /></li>
<li>Foo 1<input type="hidden" value="Foo 1" name="foo" /></li>
<li>Foo 2<input type="hidden" value="Foo 2" name="foo" /></li>
<li>Foo 3<input type="hidden" value="Foo 3" name="foo" /></li>
</ul>
When you make a http form post, you can grab the values by the below controller action implementation:
public ActionResult Index(string[] foo) {
foreach(var item in foo) {
//Work with each individual item
}
//continue your code
}
it doesn't work this way. html only exists in the view. the controller has no concept of html (not should it). data sent to the controller comes in 1 of types (GET, POST). there are others, but these are the main to.
get is typically associated with the querystring www.domain.com/mypage.aspx?key=value
where post is the input values from form
<form action="mypage.aspx" method="post">
<input name="key" value="value"/>
<input type="submit" value="click me"/>
</form>
So adding items to a html list won't provide any meaning to the controller. javascript and ajax provide more options on how the data gets sent to the server, but the data is sent, not the markup. and the data is sent as key value pairs.

Categories

Resources