I have a form which binds a model and a file upload using the default binder for HttpPostedFileBase.
This works fine when using Html.BeginForm(). However, I wanted to perform the same action using AJAX so I replaced this with Ajax.BeginForm() changing the parameters accordingly.
The model still binds correctly, however I can't get the file upload to bind to the HttpPostedFileBase.
This binds the model and the file upload:
<% using (Html.BeginForm("MapUpdateColumns", "RepositoryAdmin", FormMethod.Post, new { id = "UpdateDataset", enctype = "multipart/form-data" })) {%>
This only binds the model:
<% using (Ajax.BeginForm("MapUpdateColumns", "RepositoryAdmin", new AjaxOptions { UpdateTargetId = "columnMappings" }, new { id = "UpdateDataset", enctype = "multipart/form-data" })) {%>
The controller action:
public ActionResult MapUpdateColumns(DatasetViewModel model, HttpPostedFileBase sourceFile)
Should this be possible, and if so what am I doing wrong? Thanks.
You cannot upload files with AJAX. One way to achieve this is to use a hidden iframe which will simulate an AJAX call and perform the actual file upload or use Flash. Here's a very nice jQuery Form plugin using a hidden iframe which is capable of transparently ajaxifying a form submission containing file fields.
It is possible, the answer is here:
https://stackoverflow.com/a/13522052/1067149
I did it myself and it's guaranteed it works.
ADD id="file" in your tag input
IN YOUR ACTIONRESULT PARAMETER
HttpPostedFileBase 'file' name and view tag name should be same
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(tbl_products tbl_products,HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
tbl_products.phototype = file.ContentType;
tbl_products.photo =new byte[file.ContentLength ];
file.InputStream.Read(tbl_products.photo,0, file.ContentLength);
if(obj.insert(tbl_products))
{
return RedirectToAction("Index");
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
}
}
return View(tbl_products);
}
IT WORKS FOR ME
Yes I also agree. You can definately upload files using 'Ajax.BeginForm'.Add 'enctype = "multipart/form-data"' to the AjaxOptions object.
Related
I have two Asp.Net MVC Websites. The first one is inside the root domain domain.com, and the second one is a subdomain sub.domain.com.
Everything works fine inside the root domain, but I'm having trouble submitting a form to a controller on the subdomain. Whatever I try to send seems never to get to the controller.
It may seem strange but this problem does not happen when I try to start the application locally in debug mode. (locally is not a subdomain, just plain localhost).
Just for testing purposes I've build a simple model:
public class TestModel
{
public string test_text { get; set; }
}
And this is the CSHTML partial view:
#using (Html.BeginForm("TryModel", "Home", new { }, FormMethod.Post, new { }))
{
<input type="text" name="test_text" />
<button type="submit">Test</button>
}
Even with this simple configuration, on my local copy I've no problem, but as soon as I start the application on the remote machine, the posted data is always empty.
What do you think could be the problem?
EDIT
This is the controller methods
[HttpGet]
public ActionResult TryModel()
{
return View();
}
[HttpPost]
public ActionResult TryModel(TestModel model)
{
// code removed
return View(model);
}
And yes, the action is called correctly. Even the Request.Form is empty.
Html.BeginForm takes only 4 Parameter,
Parameters: string actionName, string controllerName, FormMethod method, object htmlAttributes
you should change the your parameter
from:
#using (Html.BeginForm("TryModel", "Home", new { }, FormMethod.Post, new { }))
to:
#using (Html.BeginForm("TryModel", "Home", FormMethod.Post, new { }))
I hope it will helps.
My Controller
public ActionResult Edit(int id)
{
return this.EditDefault(id);
}
[HttpPost]
public ActionResult Edit(int id, Models.Company model)
{
return this.EditDefault(id, model);
}
My Model
pulbic class Company
{
... Many other Propeties
public HttpPostedFileBase File { get; set; }
}
My View
#using (Html.BeginForm(new { enctype = "multipart/form-data" }))
{
... Many other Properties
#Html.TextBoxFor(m => m.File, new
{
type = "file", style = "display:none"
})
... Submit
}
So my problem now is when I submit the page the infos in the model are right, but the File Property is still null.
I found some solutions where people added HttpPostedFileBase as parmeter in the controller (tried it doesn't work too), but I would like to avoid that anyway because the model and the controller are generated with T4. So has someone an idea why the File Property is always null?
Would be really happy about some help :)
Update: Found the solution thx to Matt Tabor.
For me the solution looks like this because I use a shared Edit page.
The javascript part is to hide the actual file upload element and use a span instead, because the file upload isn't style able.
//Shared Part
#{
RouteData routeData = this.ViewContext.RouteData;
string currentController = routeData.GetRequiredString("controller");
}
#using (Html.BeginForm("Edit", currentController, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
//Special Part
... Many other Properties
//File upload which is hidden
#Html.TextBoxFor(m => m.File, new
{
type = "file", style = "display:none"
})
//Span which forwards the clicks to the file upload
<span id="fake-file-name">Kein Bild</span>
... Submit
}
<script type="text/javascript">
$(function () {
//forward the click from the span to the file upload
$("#fake-file-name").click(function () {
$("#File").click();
});
//display the chosen file name to the user with the styled span
$("#File").bind('change', function () {
//we don't want the C:\fakepath to show
var displayFileName = this.value.replace("C:\\fakepath\\", "");
$("#fake-file-name").text(displayFileName);
});
});
</script>
you need to specify your form method as post
#using (Html.BeginForm("Edit", "CONTROLLER", null,FormMethod.Post, new { enctype = "multipart/form-data" }))
#Html.TextBoxFor(m => m.File, new
{
type = "file", style = "display:none"
})
Instead have a Input type file as shown below -
<input type="file" name="File" id="File"/>
PS: Name should match to Model property name.
UPDATE
Remove display:none from your code and it should work fine.
I have an MVC app and I've run into a problem with modern multitab browsers.
I have a screen that creates a model and stores it in this.TempData["MyViewModel"]
I then open the same screen in a 2nd tab and as it calls the same controller methods this.TempData["MyViewModel"] is once again set.
If I then go back to Tab 1 and refresh the page, I am presented with the data I entered in Tab 2.
Is there a way to store data in TempData uniquely per browser tab ?
I have toyed with the idea of creating a unique TempData key and persist it between requests using either the querystring or a hidden field but this seems messy.
Any ideas / advice would be most welcome. :o)
What I have so far is a concept of a 'ProcessID'.
In my first partial view I have a form with a hidden field which is loosely bound to my Model.ProcessID. When the form is posted this hidden field ProcessID is used as the TempData key...
Example:
public sealed class MyViewModel
{
public MyViewModel()
{
this.ProcessID = Guid.NewGuid().ToString();
}
public string ProcessId { get; set; }
// other fields
}
Partial View 1:
#model Models.MyViewModel
#using (Ajax.BeginForm("PartialView1", "Home", new { }, new AjaxOptions() { UpdateTargetId = "myDivToUpdate" }, new { }))
{
#Html.HiddenFor(m => m.ProcessId);
// other fields...
<input type="submit" value="next" />
}
public ActionResult PartialView1(FormCollection form)
{
return this.PartialView("PartialView1", new Models.MyViewModel());
}
[HttpPost]
public ActionResult PartialView1(FormCollection form)
{
Models.MyViewModel vm = new Models.MyViewModel();
this.UpdateModel(vm, form);
this.TempData[vm.ProcessId] = vm;
return this.PartialView("PartialView2", vm);
}
In my 2nd partial view form I once again have a hidden field loosely bound to the same Model.ProcessID. When this form is posted I can use the Model.ProcessID to retrieve my viewmodel from TempData and update it:
Partial View 2:
#model Models.MyViewModel
#using (Ajax.BeginForm("PartialView2", "Home", new { }, new AjaxOptions() { UpdateTargetId = "myDivToUpdate" }, new { }))
{
#Html.HiddenFor(m => m.ProcessId);
// other fields (different to partial view 1)...
<input type="submit" value="finish" />
}
[HttpPost]
public ActionResult PartialView2(FormCollection form, Models.MyViewModel vm)
{
vm = (this.TempData[vm.ProcessId] as Models.MyViewModel);
this.UpdateModel(vm, form);
return this.Json(new { result = true, message = "success" }, JsonRequestBehavior.AllowGet);
}
By default I believe MVC uses session state to store TempData using the SessionStateTempDataProvider and therefore each TempData will be stored in the same place for that session. Using session the only around this that I can see is to use some identifier as you suggested.
However you can implement the ITempDataProvider interface to use your own provider that could then store this data in some other form of storage (such as cookies or sql).
I have have a View where I add products to a simple WebStore. I want to have multiple images with one product. That's why I use FileUpload from Microsoft.Web.Helpers. The use of FileUpload in my View is like this:
#FileUpload.GetHtml("Upload", 5, true, true, addText: "Add more", uploadText: "Upload files")
Then I have some labels and fields for other product attributs like this:
<div class="editor-field"><br>
#Html.EditorFor(model => model.Title)<br>
#Html.ValidationMessageFor(model => model.Title)<br>
</div>
The problem is that when I use post method, my controller does not get anything. I use controller like this:
[HttpPost]
public ActionResult Create(Product product, IEnumerable<HttpPostedFileBase> fileUpload)
{
foreach (var file in fileUpload)
{
var fileName = Path.GetFileName(file.FileName);
}
return RedirectToAction("Index");
}
So does anyone have any idea what I am doing wrong. Because my FileUpload object is always empty.
Most likely your BeginForm is missing the required field. It should look like this:
using(Html.BeginForm("Index", "Home", FormMethod.Post,
new { enctype="multipart/form-data" })) {
}
Now using HttpPostedFileBase in mvc 4 easy to upload multiple files, EditorFor FileUpload in asp.net mvc 4 razor
I had this problem last night FileUpload control and the parameter name should be the same
Change:
public ActionResult Create(Product product, IEnumerable<HttpPostedFileBase> **fileUpload**)
to
public ActionResult Create(Product product, IEnumerable<HttpPostedFileBase> **upload**)
<%:ViewData["galleryId"]%>
<% using (Html.BeginForm(
"FinishEdit" ,
"GalleryManager" ,
FormMethod.Post ,
new { enctype = "multipart/form-data" }
)
)
{%>
<%:Html.Hidden("galleryId" , ViewData["galleryId"])%>
<% } %>
The view data outside of the form renders correctly, but the viewdata inside the form does not. What is going on?
Try clearing the model state in your controller action if you intend to modify any of the POSTed variables and render the same view:
[HttpPost]
public ActionResult FinishEdit()
{
...
ModelState.Remove("galleryId");
ViewData["galleryId"] = "some new gallery id";
return View();
}
Html helpers are first looking in the model state dictionary values before ViewData and Model.
Html.Hidden helper looks first ModelState dictionary. This could be a reason.