passing value via ajax to controller action having null httppostedbasefile - asp.net-mvc-4

My Razor html:
#using (Html.BeginForm("CreateTestinomialPage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Fill Form</legend>
#Html.HiddenFor(m => m.PostedTypeId)
<div class="editor-label">
#Html.DisplayName("Image Upload")
</div>
<div class="editor-field" >
#*<input type="file" name="file" id="file" />*#
#Html.TextBoxFor(m => m.file,new{type="file"})
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Message)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Message)
#Html.ValidationMessageFor(model => model.Message)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Postedby)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Postedby)
#Html.ValidationMessageFor(model => model.Postedby)
</div>
<p>
<input type="submit" value="Create" />
</p>
<div id="result"></div>
</fieldset>
}
My scripts:
<script type="text/javascript">
$(function () {
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$('#result').html(result);
},
complete: function () {
$('form').each(function () {
this.reset(); //Here form fields will be cleared.
});
},
});
}
return false;
});
});
</script>
my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateTestinomialPage(TestinomialsModels models,HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (file == null)
{
ModelState.AddModelError("File", "Please Upload Your file");
}
else if (file.ContentLength > 0)
{
int maxcontentlength = 1024 * 1024 * 3;
string[] AllowedExtension = new string[] { ".jpg", ".gif", ".png" };
if (!AllowedExtension.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
{
ModelState.AddModelError("File", "Please file of type: " + string.Join(", ", AllowedExtension));
}
else if (file.ContentLength > maxcontentlength)
{
ModelState.AddModelError("File", "Your file is too large, maximum allowed size is: " + maxcontentlength + " MB");
}
else
{
var filename = Path.GetFileName(models.file.FileName);
models.ImagePath = ConfigurationManager.AppSettings["ImagesavePath"].ToString() + filename;
postservices.AddTestinomailPost(models);
var path = Path.Combine(Server.MapPath("~/Content/Upload/Images"), filename);
models.file.SaveAs(path);
return Content("Successfully Submiited");
}
}
}
return Content("An error occur while saved Plese try again..");
}
There is controllerAction null httppostedbasefile..

Related

How fix not working ActionResult Update in NET Core?

I'm learning about .NET Core and I'm using code from this tutorial. But my update sql is not working.
Here is the index view code:
public ActionResult Index(int? id)
{
ViewBag.Operation = id;
ViewBag.Name = db.Chars.ToList();
Chars Chars = db.Chars.Find(id);
return View(Chars);
}
As for now it work I see results from sql and here is the updated part:
public ActionResult Update(Chars Chars)
{
if (ModelState.IsValid)
{
db.Entry(Chars).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index", new { id = 0 });
}
Here is index.cshtml part:
#using (Html.BeginForm()
{
#foreach (var item in (IEnumerable<MVC__test_2.Chars>)ViewBag.Name)
{
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(modelItem => item.CharName, new { htmlAttributes = new { #class = "form-control" } })
#Html.HiddenFor(modelItem => item.CharID, new { id = item.CharID })
</div>
</div>
#Html.ActionLink("Index", "Index", new { id = item.CharID })
<input type="submit" value="Update" name="Update"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:block" : "display:none") />
}
}
According to the tutorial you provided , I made a demo to test and it updated the data well. The following is the working example , you could refer to and make the modification as per your need .
Model
public class Description
{
public int Id { get; set; }
public string Display { get; set; }
}
Controller
public IActionResult Index(int? id)
{
ViewBag.Operation = id;
ViewBag.Name = _context.Description.ToList();
Description description= _context.Description.Find(id);
return View(description);
}
public ActionResult Update(Description description)
{
if (ModelState.IsValid)
{
_context.Entry(description).State = EntityState.Modified;
_context.SaveChanges();
}
return RedirectToAction("Index", new { id = 0 });
}
Index.cshtml , you should hide the id of the modified data in the modification section.
#model WebApplication1.Models.Description
#using (Html.BeginForm("Update", "Home", FormMethod.Post))
{
#foreach (var item in (IEnumerable<WebApplication1.Models.Description >)ViewBag.Name)
{
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(modelItem => item.Display, new { htmlAttributes = new { #class = "form-control" } })
#Html.HiddenFor(modelItem => item.Id, new { id = item.Id })
</div>
</div>
#Html.ActionLink("Edit", "Index", new { id = item.Id })
}
// Create or Update data
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<fieldset>
<legend> <b>Entry Screen</b></legend>
<div class="form-group">
#Html.LabelFor(model => model.Display, new { #class = "control-label col-md-2" })
#Html.HiddenFor(model => model.Id)
<div class="col-md-10">
#Html.EditorFor(model => model.Display)
#Html.ValidationMessageFor(model => model.Display)
</div>
</div>
<div class="form-group">
<p>
<input type="submit" value="Create" name="Create"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:none" : "display:block") />
<input type="submit" value="Update" name="Update"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:block" : "display:none") />
</p>
</div>
</fieldset>
</div>
}

File upload in MVC 5 when used in bootstrap modal returns null

I'm trying to allow file uploading on modal popup using bootstrap modal popup.
But it always returns null for type = "file"
I've tried following solutions but no luck:
File upload in MVC when used in bootstrap modal returns null
it always return null. If I run this directly as separate page then it works fine but only having problem with popup.
I tried to change the content type on ajax but then its giving me this error "required anti-forgery form field __requestverificationtoken is not present"
I've tested what does page post using development tools:
enter image description here
here are my codes:
controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Create([Bind(Include = "ID,FileName,Link,SourceType,Comments,SourceDate,DateCreated,DateModified,ProjectID")] ProjectSource projectSource, HttpPostedFileBase uploadFile)
{
if (ModelState.IsValid)
{
//upload method 1
var fileSavePath = "";
if (HttpContext.Request.Files.AllKeys.Any())
{
// Get the uploaded image from the Files collection
var httpPostedFile = HttpContext.Request.Files[0];
if (httpPostedFile != null)
{
// Validate the uploaded image(optional)
// Get the complete file path
fileSavePath = (HttpContext.Server.MapPath("~/xyz/") + httpPostedFile.FileName);
// Save the uploaded file to "UploadedFiles" folder
httpPostedFile.SaveAs(fileSavePath);
}
}
//upload method 2
if (uploadFile != null && uploadFile.ContentLength > 0)
{
try
{
string path = Path.Combine(Server.MapPath("~/xyz/"),
Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(path);
ViewBag.Message = "File uploaded successfully";
}
catch (Exception ex)
{
ViewBag.Message = "ERROR:" + ex.Message.ToString();
}
}
else
{
ViewBag.Message = "You have not specified a file.";
}
db.ProjectSources.Add(projectSource);
await db.SaveChangesAsync();
return " File : " + ViewBag.Message + " == " + fileSavePath;
}
return " File : " + ViewBag.Message +" === "+sb.ToString();
}
view:
#model CharterPortal.Models.ProjectSource
#{
Layout = "";
#Scripts.Render("~/Scripts/jquery-2.2.3.min.js")
#Scripts.Render("~/Scripts/moment.min.js")
#Scripts.Render("~/Scripts/bootstrap.min.js")
#Scripts.Render("~/Scripts/bootstrap-datetimepicker.min.js")
#Scripts.Render("~/Scripts/bootstrap.fd.js")
}
×
Add new Source
#using (Html.BeginForm("Create", "ProjectSource", FormMethod.Post, new { enctype = "multipart/form-data" , #id="ajaxForm"}))
{
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="form-horizontal">
#*#Html.ValidationSummary(true, "", new { #class = "text-danger" })*#
<div class="form-group">
#Html.Label("Source file", htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.FileName, new { htmlAttributes = new { #class = "form-control" } })
#*<input type="file" name="uploadFile" />*#
#Html.TextBox("uploadFile",null, new { #class = "form-control", type = "file" })
#*Add file*#
#Html.ValidationMessageFor(model => model.FileName, "", new { #class = "text-danger" })
</div>
</div>
#*<div class="form-group">
<div class="col-md-10" id="files" style="padding-left:40px;">
</div>
</div>*#
<div class="form-group">
#Html.LabelFor(model => model.Link, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.Link, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Link, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SourceType, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.SourceType, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SourceType, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Comments, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6" style="color:black;">
#Html.TextAreaFor(model => model.Comments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Comments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SourceDate, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6" style="color:black;">
#Html.EditorFor(model => model.SourceDate, new { htmlAttributes = new { #class = "form-control datepicker datefield" } })
#Html.ValidationMessageFor(model => model.SourceDate, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-med btn-orange" data-dismiss="modal">Cancel</button>
<input class="btn btn-med btn-orange" type="submit" name="submit" value="Add" />
</div>
}
ajax:
$('form', dialog).submit(function (event) {
event.preventDefault();
$.ajax({
url: this.action,
type: this.method,
async: true,
data: $(this).serialize(),
contentType:this.enctype,
success: function (result) {
if (result) {
alert(result)
//Refresh
} else {
alert(result)
}
}
});
return false;
});
I hope to get good working solution for this:
thanks in advance for your time.
Thanks
Ive been using this block of code to solve this problem and ModelState.IsValid in partials for about a year. cheers.
$(function () {
window.addEventListener("submit", function (e) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = xhr.responseText;
}
}
}
};
xhr.send(new FormData(form));
}
}
}, true);
$('#modal').on('shown.bs.modal', function () {
$.validator.unobtrusive.parse($(this));
});
$('#modal').on('hidden.bs.modal', function () {
$('#spinner').remove();
});
$.ajaxSetup({ cache: false });
});

ajax beginform mvc callback

I have a single page with multiple partials set up. I want to be able to validate and update each partial seperatly. The validation works BUT when I type in a correct value and press save the page goes to the partial view instead of staying on the single page. What am I doing wrong here?
This is my main page :
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Action("Detail", new { id = i })
</div>
}
The partial is created like this:
#{
var idTest = "Test_" + Model.Id;
var ajaxOptions = new AjaxOptions
{
UpdateTargetId = #idTest,
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace
};}
#using (Ajax.BeginForm("Detail", ajaxOptions))
{ #Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Test</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Gemeente, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Gemeente, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Gemeente, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
This is the simple model:
public class Test
{
public int Id { get; set; }
[Required(ErrorMessage = "Gelieve een gemeente op te geven")]
public string Gemeente { get; set; }
}
These are the actions:
[HttpGet]
public ActionResult Detail(int id)
{
Models.Test model = new Models.Test();
model.Id = id;
return View(model);
}
[HttpPost]
public ActionResult Detail(Models.Test model)
{
if(ModelState.IsValid)
{
return PartialView(model);
}
return PartialView(model);
}
Add these lines to your view and also use #Html.Partial as shown below
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
so that your main view is
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Partial("Detail", new Test { Id = i })}
</div>
}
Scripts would be for unobtrusive ajax so that your ajax button works and Html.Partial so that first time when you load your page in foreach only partial view is rendered (not the full view)

ListBoxFor is not fully updating the viewmodel on submit

I have been able to create viewmodel like this (please ignore that it includes another viewmodel, that will be fixed after I solve my current problem :) ):
public class UserViewModel
{
#region Variables
private SecUserViewModel user;
private string[] assignedRolesIds;
private List<SecRoleViewModel> availableRoles;
#endregion
#region Properties
public SecUserViewModel User
{
get { return this.user; }
set { this.user = value; }
}
public string Guid
{
get { return this.user.Guid.ToString(); }
set { this.user.Guid = value; }
}
public string UserName
{
get { return this.user.UserName; }
set { this.user.UserName = value; }
}
public string Email
{
get { return this.user.Email; }
set { this.user.Email = value; }
}
public byte[] AuthDigest
{
get { return this.user.AuthDigest; }
set { this.user.AuthDigest = value; }
}
public bool IsUsingTempPasswd
{
get { return this.user.IsUsingTempPasswd; }
set { this.user.IsUsingTempPasswd = value; }
}
public DateTime? LastLogin
{
get { return this.user.LastLogin; }
set { this.user.LastLogin = value; }
}
public DateTime? PasswordChanged
{
get { return this.user.PasswordChanged; }
set { this.user.PasswordChanged = value; }
}
public string[] AssignedRolesIds
{
get { return this.assignedRolesIds; }
set { this.assignedRolesIds = value; }
}
public List<SecRoleViewModel> AvailableRoles
{
get { return this.availableRoles; }
set { this.availableRoles = value; }
}
#endregion
#region Constructor
public UserViewModel()
{
User = new SecUserViewModel();
AssignedRolesIds = null;
AvailableRoles = new List<SecRoleViewModel>(0);
}
public UserViewModel(SecUserViewModel secUser, List<SecRoleViewModel> roleList, List<SecRoleViewModel> availableList)
{
User = secUser;
AssignedRolesIds = roleList.Select(r => r.Role.Guid.ToString()).ToArray();
AvailableRoles = availableList;
}
#endregion
}
My controller has an edit action. On "GET" I pass viewmodel and it is displayed properly including the multiselect list and preselected values. But when I "POST" the "Edit", UserViewModel that is passed back has "AssignedRolesIds" and "AvailableRoles" Empty, although everything else is filled. When I check FormCollection object, there are "AssignedRolesIds" present as a key.
My view looks like this:
#model DocuLive.ViewModels.UserViewModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_AdminPage.cshtml";
}
<h2>Edit</h2>
<div class="error-message">#TempData["Fail"]</div>
<div class="success-message">#TempData["Success"]</div>
#using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>SecUser</legend>
<div class="editor-label">
#Html.LabelFor(model => model.User.Guid)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.Guid)
#Html.HiddenFor(model => model.User.Guid)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.UserName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.UserName)
#Html.HiddenFor(model => model.User.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.User.Email)
#Html.ValidationMessageFor(model => model.User.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.IsUsingTempPasswd)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.User.IsUsingTempPasswd)
#Html.ValidationMessageFor(model => model.User.IsUsingTempPasswd)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.LastLogin)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.LastLogin)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.PasswordChanged)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.PasswordChanged)
</div>
<div class="hidden-field">
#Html.HiddenFor(model => model.User.AuthDigest)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssignedRolesIds)
</div>
<div class="editor-field">
#Html.ListBoxFor(x => x.AssignedRolesIds, new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"), new { Multiple = "multiple", #class = "multi-select-list" })
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Users")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Can anyone advise why only values related to ListBoxFor are not passed back (there is a null value)?
Thanks in advance
It seems that the problem is binding the string array values to string id value of complex object (in my case Role) - but I figured out a way around it eventually. The trick is to have this signature of the method:
[HttpPost]
public ActionResult Edit(UserViewModel user, string [] assignedRolesIds)
And then you have this in view:
#Html.ListBox("AssignedRolesIds",new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"),new { Multiple = "multiple", #class = "multi-select-list"})
With this solution, you have to reassign "assignedRolesIds" back to "AssignedRolesIds" property on UserViewModel, but that is only two lines (including check that the array is not emppty or null).

how to submit a form after jquery dialog

I have a mvc4 web application a page with form
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>News</legend>
<div class="editor-label">
#Html.LabelFor(model => model.title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.summery)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.summery)
#Html.ValidationMessageFor(model => model.summery)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I want after form is valid to call a function that will show a confirm dialog (jquery)
$("#dialog-message").dialog({
modal: true,
resizable: false,
draggable: false,
title: title, closeOnEscape: false,
buttons: {
"OK submit": function () {
},
"Cancel Submit": function () {
}
}
});
what is the best whay to do so ?
I want the form to be validated ,next step if valid to show confirm message ,next step if "OK submit"
pressed to submit the form.
Try this:
$(formSelector).submit(function(){
var frm = $(this);
if (frm.validate()) {
$("#dialog-message").dialog({
buttons: {
"OK submit": function () {
//not sure - here can be a mistake
frm.unbind('submit');
frm.sumbit();
},
"Cancel Submit": function () {
}
}
});
}
return false;
});
If you want to show not a custom dialog you can use this:
$(formSelector).submit(function(){
var frm = $(this);
if (frm.validate()) {
return confirm("Want to submit?");
}
return false;
});