ANSWERED
See answers section below
I've been struggling for hours with this problem and I haven't found anything that relates, so apologies if this post is a duplicate.
I'll start by constructing a problem related to my own.
Let's say we create a ViewModel:
public class XmlViewModel(){
[Required]
public string Code { get; set; }
public string XML { get; set; }
}
and a constructor method which loads the View and as well as another that gets called when the submit is registered on the View.
public class Extractor{
public ActionResult Index()
{
XmlViewModel xmlVM = new XmlViewModel ()
{
XML = "Sample XML";
};
return View(xmlVM);
}
public ActionResult GetXml(XmlViewModel xmlVM){
xmlVM.XML = GetXMLByCode();
return View ("Index", xmlVM)
}
}
Then the view Index as below
#model Project.ViewModel.XmlViewModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("GetXml", "Extractor", Model))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Code, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(Model.XML))</pre>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Generate XML" class="btn btn-default"/>
</div>
</div>
</div>
}
So in this scenario I'm starting the page with:
When the user clicks Submit using a XML Code, I want the Code to be run against some collection of XML, then that returned XML replaces the "SampleXML"
Problem is when the form gets submitted again(Twice) (Now with the XML field holding a few hundred characters) it overloads the Query and returns this:
Because yep you guessed it, the XML fills up the Request with the XML from the previous Form result.
So my question is, is there any way to clear the ViewModel Property so it isn't passed in the Query, or some attribute to add that will tell the ViewModel to not pass the property through the Html.BeginForm()?
If possible I would like to stay away from passing the ViewModel properties individually as the actual problem's ViewModel is more complicated and it would be troublesome going down that route.
After my suggestions, if you are still getting header to large, I can help diagnose.
Add an xml file to your project. Add tons of xml to it. Right click to get properties. For build action, change to embedded resource.
Where I have WebApplication2.XMLFile1.xml, you should have your assembly name dot then your file name. You can right click on your project, and see properties to get assembly name.
Here is my code
namespace WebApplication2.Controllers
{
public class XmlViewModel
{
[Required]
public string Code { get; set; }
public string XML { get; set; }
}
public class HomeController : Controller
{
public static string GetXMLByCode()
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "WebApplication2.XMLFile1.xml";
string result = String.Empty;
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
return result;
}
public ActionResult GetXml(XmlViewModel xmlVM)
{
xmlVM.XML = GetXMLByCode();
return View("Index9", xmlVM);
}
public ActionResult Index9()
{
XmlViewModel xmlVM = new XmlViewModel { XML = "Sample XML" };
return View(xmlVM);
}
here is my view
#model WebApplication2.Controllers.XmlViewModel
#{
ViewBag.Title = "Index9";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("GetXml", "Home", Model))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Code, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(Model.XML))</pre>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Generate XML" class="btn btn-default" />
</div>
</div>
</div>
}
ANSWERED
I eventually figured it out by doing the following in the view:
#{
ViewBag.Title = "Index";
ViewBag.XML= XmlViewModel.XML;
XmlViewModel.XML = "";
}
---
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(ViewBag.XML))</pre>
</div>
</div>
Now when the view is loaded, the Viewbag will hold the XML being returned and I can safely empty the model data before returning it to the Html.BeginForm()
Keeping for anyone in the same situation
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I have the following problem with passing data to metod create in controller.
First I display view for method create (GET)
public ActionResult Create(string id)
{
RolesUser RolesUser = new RolesUser(id,repository.GetUserById(id).Roles, repository.GetRoles().ToList());
return View(RolesUser);
}
I use the following ViewModel
public class RolesUser
{
public RolesUser()
{
}
public RolesUser(string id,ICollection<IdentityUserRole> userRoles,List<IdentityRole> Roles)
{
userId = id;
this.Roles = GetNewRolesForUser(userRoles.ToList(), Roles.ToDictionary(x => x.Id, x => x.Name)).ConvertAll(
role =>
{
return new SelectListItem()
{
Text = role.ToString(),
Value = role.ToString(),
Selected = false
};
});
}
public IEnumerable<SelectListItem> Roles { get; set; }
public string userId { get; set; }
private List<string> GetNewRolesForUser(List<IdentityUserRole> UserRoles,Dictionary<string,string> Roles)
{
List<string> AvaiableRoles = new List<string>();
List<string> IdUserRoles = new List<string>();
UserRoles.ForEach(item => IdUserRoles.Add(item.RoleId));
foreach(KeyValuePair<string,string> Role in Roles)
{
if (!IdUserRoles.Contains(Role.Key))
{
AvaiableRoles.Add(Role.Value);
}
}
return AvaiableRoles;
}
}
It displays me essential information on my view in Create.cshtml, when I execute Submit it shows me following error
Object reference not set to an instance of an object.
The metod create (POST) looks like this
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles ="Admin")]
public ActionResult Create([Bind(Include ="userId")] RolesUser user)
{
if (ModelState.IsValid)
{
try
{
repository.AssignToRole(user.userId, "Klient");
repository.SaveChanges();
}
catch
{
ViewBag.exception = true;
return View();
}
}
ViewBag.exception = false;
return RedirectToAction("Index");
}
Code for Create.cshtml
#model Repository.ViewModels.RolesUser
#{
ViewBag.Title = "Create";
}
<h2>Dodaj poziom dostępu</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>#Model.userId</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.userId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.userId, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.Label("Poziomy dostępu", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.userId, Model.Roles)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Dodaj" class="btn btn-default" />
</div>
</div>
</div>
}
It looks like viewmodel is not passing to method, so I have null exception. But I don't understand why, if GET metod render properly view.
The NullReferenceException is likely hit inside the repository.AssignToRole() method because user.userId is null. You should add a hidden input for the userId somewhere inside the form so the userId value is posted to the parameter object on the Create action. If you add it after the #Html.AntiForgeryToken() the start of the form would look like
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.userId)
...
I am trying to read a value from a view in aps.net mvc: I am aware that this seems like a very basic issue, however, i could not find any solution for this, so i am turning to you: In my case, it seems as if the parameter playlistModel.Model.Name is never sent, or at least is null.
My controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PlaylistViewModelDetails playlistModel)
{
if (!String.IsNullOrEmpty(playlistModel.Model.Name))
{
//this is never called due to playlistModel.Model.Name being null.
return RedirectToAction("Index");
}
return View(playlistModel);
}
#model Orpheus.Models.ViewModels.PlaylistViewModelDetails
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Erstellen" class="btn btn-default" />
</div>
</div>
</div>
}
public class PlaylistViewModelDetails
{
public PlaylistModel Model = new PlaylistModel(); //a seperate class containing a string value, which must be read from the form
}
Thank you for helping me to solve this issue!
Your PlaylistViewModelDetails contains only a field for Model. The DefaultModelBinder only binds properties, not fields.
Change your model to
public class PlaylistViewModelDetails
{
public PlaylistModel Model { get; set; }
}
and add a parameter-less constructor if you want to initialize PlaylistModel
public PlaylistViewModelDetails()
{
Model = new PlaylistModel();
}
Note also Name in PlaylistModel also need to be a property.
I'm trying to upload images to my application but it always returns null. I'm unable to find the issue here. Can you help me out? Here's my code.
Model
[Table("Slider")]
public partial class Slider : BaseModel
{
[Required]
[StringLength(200)]
public string FileName { get; set; }
[StringLength(200)]
public string Title { get; set; }
[StringLength(1000)]
public string Description { get; set; }
public int? Order { get; set; }
}
[NotMapped]
public class SliderImage : Slider
{
public HttpPostedFileBase ImageFile { get; set; }
}
View
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.FileName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.FileName, new { #class = "form-control", #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.FileName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ImageFile, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.ImageFile, new { #class = "form-control", type = "file" })
//This is Same as below
//<input class="form-control" id="ImageFile" name="ImageFile" type="file" value="">
</div>
</div>
Controller
public ActionResult Edit(int id)
{
Slider slider = _db.Sliders.Find(id);
if (slider == null)
{
return HttpNotFound();
}
Mapper.CreateMap<Slider, SliderImage>();
SliderImage sliderImage = Mapper.Map<Slider, SliderImage>(slider);
return PartialView("_Edit", sliderImage);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditSlider([Bind(Include = "Id,FileName,Title,Description,Order,IsActive,Name,ImageFile")] SliderImage sliderImage)
{
if (ModelState.IsValid)
{
Mapper.CreateMap<SliderImage, Slider>();
Slider slider = Mapper.Map<SliderImage, Slider>(sliderImage);
_db.Entry(slider).State = EntityState.Modified;
_db.SaveChanges();
return Json(new { success = true });
}
return PartialView("_EditSlider");
}
What am I doing wrong i this?
Found The Issue
I'm binding the partial view inside the bootstrap modal popup. When I upload from the popup, the upload returning null. Instead if I open the partial View directly in browser, then the file is present in the model. So there is no problem with file upload. The problem is with modal popup or something.
When Using Bootstrap model
When using partial View Directy
Check the difference found when using fiddler between the Bootstrap Modal Submit and Using the partial View Directly in the following image respectively
When posting from the modal popup, the content type is changed to application/x-www-form-urlencoded where as when using the partial view directly it is multipart/form-data
Found the root Issue.
$('form', dialog).submit(function () {
var $form = $(this);
var enctype = $form.attr('id');
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$('#myModal').modal('hide');
//Refresh
location.reload();
} else {
$('#myModalContent').html(result);
bindForm();
}
}
});
return false;
});
I'm using AJAX posting to submit the data from my form. When using $(this).serialize() the ajax success is being called but the file is not returning as the content type is different. How can I change this??
I think I have been able to identify your problem, Ajax does not support file serialization, you should use the following method in the script:
$('form', dialog).submit(function () {
var formData = new FormData($(this)[0]);
$.ajax({
url: this.action,
type: this.method,
contentType: this.enctype,
data: formData,
success: function (result) {
if (result.success) {
$('#myModal').modal('hide');
$('#replacetarget').load(result.url); // Load data from the server and place the returned HTML into the matched element
} else {
$('#myModalContent').html(result);
bindForm(dialog);
}
}
});
return false;
});
Ok, I think your current issue is related to the default settings for the jQuery.ajax method. By default, the content type for the jQuery.ajax() method is 'application/x-www-form-urlencoded; charset=UTF-8'. So, in a sample project, I modified your javascript function to specify the contentType as a paramter to the ajax method: contentType: this.enctype
I think there also may be a couple additional issues. The next issue that I noticed is that on submission, I was connecting to another actions, so I updated this line in the view:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
To this:
#using (Html.BeginForm("EditSlider", "<Your Controller Name>", FormMethod.Post, new { enctype = "multipart/form-data" }))
Lastly, when the ajax submitted, I was being redirected to the partial view. I believe this can be fixed by adding preventDefault to the ajax function:
$('form', dialog).submit(function (event) {
event.preventDefault();
var $form = $(this);
$.ajax({
url: this.action,
type: this.method,
contentType: this.enctype,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$('#myModal').modal('hide');
//Refresh
location.reload();
} else {
$('#myModalContent').html(result);
bindForm();
}
}
});
});
This is how I was able to get this example working in a sample project; please post an update if you have additional issues.
Usually, modal pop-ups are rendered at the end of the body. I'm pretty sure that bootstrap does the same thing. This, in turn, means that the content of the modal is moved to a new location and is taken out of your form element. I would recommend a reordering: move the form inside the modal window:
<div class="modal-body">
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
...
}
</div>
This will move the entire form (and not just the form elements) when the modal gets built.
Only the file uploaded return null? or the other textbox return null as well?
As #Andrei comments, usually the modals is moved to a new location and the form is not present or your partialview could be moved to make the modal works.
With jqueryUI I had a similar problem. I couldn't find in your question if you are using ajax to submit your data, you could use .ajax() to send your form and see if the image was upload
$.ajax({
url: "#Url.Action("Action", "Controller")",
type: "POST",
cache: false,
data: $("#YourFormID").serialize(),
success: function (result) {
//your success data
},
error: function (jqXHR, textStatus, errorThrown) {
//your error handler
},
});
return false;
If you don't want to use $.ajax(), you could try to use .appendTo() with jquery, wrap everything what it is inside your form in a div with an ID, then after you have all your data try to sepecify that you want to appendTo("#YourFormID") on a button click, or as you like. This work for me when I was using modal, hope it helps you with something. Good luck
If I understand you make the form in a partial View, and this partial is used in a modal popup, it's right.
1) make a model for used in the form with all elements for the form,
2) declare the model in the first line in the partial view
3) pass as parameter the model to the post function.
4) you use a Partial view, well is possible use this view in differents pages, you need specify the control to treatement the form. in code:
MODEL
public partial class SliderModel
{
[Required]
[StringLength(200)]
public string FileName { get; set; }
[StringLength(200)]
public string Title { get; set; }
[StringLength(1000)]
public string Description { get; set; }
public int? Order { get; set; }
[NotMapped]
public HttpPostedFileBase ImageFile { get; set; }
}
VIEW
#model YOURNAMESPACE.Models.SliderModel
<form method="post" class="form-horizontal" role="form" id="sendMail"
enctype="multipart/form-data" action="/CONTROLLERNAME/EditSlider">
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.FileName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.FileName, new { #class = "form-control", #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.FileName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ImageFile, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.ImageFile, new { #class = "form-control", type = "file" })
//This is Same as below
//<input class="form-control" id="ImageFile" name="ImageFile" type="file" value="">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-1">
<button type="submit" class="btn btn-success"><b><i class="fa fa-envelope"></i> Envoyer</b> </button>
</div>
</div>
</form>
CONTROLLER
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditSlider(SliderModel obj)
{
if (ModelState.IsValid)
{
your options
}
return PartialView("_EditSlider");
}
Try with following way this worked for me :
VIEW :
#using (Html.BeginForm("ComplaintAndSuggestion", "RegisterComplaints", FormMethod.Post, new { enctype = "multipart/form-data", id = "ajaxUploadForm" }))
{
:
:
:
<div class="row mb10">
<div class="col-sm-3 col-md-3">
<label for="file1">Upload Image 1</label>
<input type="file" name="images" id="file1" accept="image/*" />
</div>
<div class="col-sm-3 col-md-3">
<label for="file2">Upload Image 2</label>
<input type="file" name="images" id="file2" accept="image/*" />
</div>
<div class="col-sm-3 col-md-3">
<label for="file3">Upload Image 3</label>
<input type="file" name="images" id="file3" accept="image/*" />
</div>
<div class="col-sm-3 col-md-3">
<label for="file4">Upload Image 4</label>
<input type="file" name="images" id="file4" accept="image/*" />
</div>
</div>
<input type="submit" value="Create" />
}
Controller :
[HttpPost]
public ActionResult ComplaintAndSuggestion(Register register, IEnumerable<HttpPostedFileBase> images, IEnumerable<HttpPostedFileBase> videos)
{
foreach (var file in images)
{
if (file != null)
{
string filenameWithDateTime = AppendTimeStamp(file.FileName);
file.SaveAs(Server.MapPath(Path.Combine("~/Images/", filenameWithDateTime)));
fileUploadModel.FilePath = (Server.MapPath(Path.Combine("~/Images/", filenameWithDateTime)));
fileUploadModel.FileName = filenameWithDateTime;
fileUploadModel.FileType = "Image";
fileUploadModel.RegisterId = register.RegisterId;
mediaRepository.Add(fileUploadModel);
mediaRepository.Save();
}
}
}
Let me know.
I use jquery validation in my MVC application and after selecting and leaving an input, it is automatically validated. On the other hand, if user does not select an input, they are not validated even if submitting the form. So, I want to validate all the related fields after pressing submit button on MVC Razor page. How can I do this?
I created a simple example. It's just to give you a start, you still have to modify this code to your needs. This example is using jquery form validation.
Model
public class Vehicle
{
public int Id { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
Controller & Action
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
View
#model JqueryValidationDemo.Models.Vehicle
#{
ViewBag.Title = "Jquery Form Validation Demo";
}
<script src="~/Scripts/jquery-2.0.3.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script>
$(document).ready(function () {
$('#myform').validate({ // initialize the plugin
rules: {
Make: {
required: true,
minlength: 2
},
Model: { required: true }
},
messages: {
Make: {
required: "Make is required!",
minlength: "Make Name at least 2 characters long!"
},
Model: {
required: "Modl is required!"
}
},
submitHandler:
$("#myform").on('submit', function () {
if ($("#myform").valid()) {
//Do something here
alert("Validation passed");
}
return false;
})
})
});
</script>
#using (Html.BeginForm("Index", "Home", FormMethod.Get, new { #id = "myform" }))
{
<fieldset>
<legend>Vehicle</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Make)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Make)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Model)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Model)
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
}
Note: Be careful with your jquery reference, you don't need to use jquery.validate.unobtrusive.js.
Hope it will give you a good start.
Update:
Remove keyup or keypress
Remove keypress
$("#youElementId").bind('keypress', function (e) {
if (e.keyCode == 13) {
return false;
}
return true;
});