Send a view model from ajax to controller - asp.net

Is it possible to create an object in a view and send it to a controller through ajax?
using the
$.ajax({
type: "POST", etc....
???
I want to send an object of the type that I receive in the view as
#model Project1.ViewModels.ModelSample

It's possible
This is perfectly (and easily) possible.
What about complex objects?
#xixonia provided all the information you may need to do so. But those examples are rather basic and may not provide information in case you have some sort of complex objects as:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Person Spouse { get; set; }
public IList<Person> Children { get; set; }
}
Any object that has more than a single level of properties in its tree is regarded as a complex object. Using technique provided by #xixonia will fail to work in this case.
So if you'd like to also use this kind of scenario I suggest you read this blog post that describes the whole problem in detail as well as provides a rather simple jQuery plugin that makes it possible to send even complex objects to Asp.net MVC controller actions that will be model bound to your whatever complex strong type.
Other posts on the same blog may also prove to be helpful:
successfully model bind forms to IList<T> action parameters (or within complex type parameters)
handling validation errors with Ajax requests
If you'll be using Ajax along Asp.net MVC you will find these posts very useful and will save you much of your development time when you run against such issues.

This is the way it worked for me:
$.post("/Controller/Action", $("#form").serialize(), function(json) {
// handle response
}, "json");
[HttpPost]
public ActionResult TV(MyModel id)
{
return Json(new { success = true });
}

Is it possible to create an object in
a view and send it to a controller
through ajax?
Absolutely. You can use ASP.NET MVC's model binding for this.
var data =
{
Id: 5,
Value: "Hello, world!"
};
$.post('Home/MyAction', data);
And you should have a matching POCO:
public class MyPoco
{
public int Id { get; set; }
public string Value { get; set; }
}
And an Action which takes your model to bind:
public ActionResult MyAction(MyPoco myPoco)
{
if(ModelState.IsValid)
{
// Do stuff
}
}
This should automatically deserialize your request into a POCO.

Related

Passed data to asp.net core controller using ajax is null

I'm trying to call a asp.net core controller using ajax but the passed value is null.
I debug the javacript in order to check if the parameters in ajax is correct.
The OrderType is IR ID and the OrderKeyword is test
please see the screenshot
And this is the model
public class OrderSearchInfo
{
public int OrderType { get; set; }
public string OrderKeyword { get; set; }
}
And this is my controller
[HttpPost]
public async Task<ActionResult> SearchOrder([FromBody]OrderSearchInfo order)
{
return View();
}
while debugging and checking the value of the OrderSearchInfo order is null
What did i do wrong? And how can i solve this? Thank you
I assume there are some main points to check:
data types: in your model, there is int OrderType, but in JS you have OrderType: "IR_ID" which isn't a number and could not be mapped to int
if your form has RequestVerificationToken, you should pass it in the request's headers
routing (ensure request URL matches ASP.NET expected one
P.S. please add your suggestions for further checks in comments, to make this answer more applicable for many people.

Model Validation With Web API and JSON Patch Document

I'm using JsonPatchDocument with ASP.NET 4.5 and Web Api. My controller looks like this:
[HttpPatch]
[Route("MyRoute/{PersonItem1}/{PersonItem2}/")]
public IHttpActionResult ChangePerson([FromHeader]Headers, [FromBody]JsonPatchDocument<PersonDto> person)
{
// Do some stuff with "person"
}
And PersonDto:
public class PersonDto
{
public string Name { get; set; }
public string Email { get; set; }
}
Now, I may send a PATCH request that is something like:
{
"op": "op": "replace", "path": "/email", "value": "new.email#example.org"
}
Now let's say I add some data annotations:
public class PersonDto
{
public string Name { get; set; }
[MaxLength(30)]
public string Email { get; set; }
}
What is the best way to ensure this validation is honored without writing additional validation. Is it even possible?
There is the simple method:
Get your object from your repository.
Deep copy the object so you have object A and B.
Apply the change with person.ApplyUpdatesTo(objB).
Create an extension method to validate the difference between object A and B.
If the validation is good proceede, if not throw an error.
This would catch if the client was attempting to modify immutable fields or if the new information in object B violates your constraints.
Note that this is not a great solution in that you would have to change your code in two places if you happen to change your constraints.

ActionResult parameters with no default constructor

Obviously there are a number of ways to do this, but I thought I'd ask for a little feedback on benefits and drawbacks of the approaches.
First of all, the NerdDinner tutorial's Edit Action is in the form (say Form A):
[HttpPost]
public ActionResult Edit(int id, FormCollection collection) {
It seems to me that if you shape your ViewModels well to match your views, that the approach Form B:
[HttpPost]
public ActionResult Edit(MyViewModel mvm) {
just seems like a better, cleaner approach. I then just map the VM properties to the Model properties and save. However, if this ViewModel has other entities embedded in it that are initialized via the constructor (for example in the nerddinner tutorial), then this edit action fails if there is no default constructor and you'd have to use the first approach.
So, the first question is do you agree that generally Form B is usually better? Are there drawbacks?
Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel. Are there advantages of embedding entities in ViewModels and keeping the validation at the entity level only?
This is a pretty general SO question.
the first question is do you agree that generally Form B is usually better?
The only time I do not use Form B is when I upload files. Otherwise, I don't believe anyone should ever need to use Form A. The reason I think people use Form A is a lack of understanding of the abilities of ASP.Net's version of MVC.
Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel.
Sort of / it Depends. I'll give you an example:
public IValidateUserName
{
[Required]
string UserName { get; set; }
}
public UserModel
{
string UserName { get; set; }
}
[MetadataType(typeof(IValidateUserName))]
public UserValiationModel : UserModel
{
}
The validation decorator is in an interface. I'm using the MetadataType on a derived class to validate the derived type. I personally like this practice because it allows reusable validation and the MetadataType/Validation is NOT part of the ASP.NET core functionality, so it can be used outside of ASP.Net (MVC) application.
Are there advantages of embedding entities in ViewModels ..
Yes, I do my absolute best to never pass a basic model to the view. This is an example of what I don't do:
public class person { public Color FavoriteColor { get; set; } }
ActionResult Details()
{
Person model = new Person();
return this.View(model);
}
What happens when you want to pass more data to your view (for partials or layout data)? That information is not Person relevant most of the time so adding it to the Person model makes no sense. Instead, my models typically look like:
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
}
public ActionResult Details()
{
DetailsPersonViewModel model = new DetailsPersonViewModel();
model.Person = new Person();
return this.View(model);
}
Now I can add required data the DetailsPersonViewModel that view needs beyond what a Person knows. For example, lets say this is going to display a for with all the colors for the Person to pick a favorite. All the possible colors aren't part of a person and shouldn't be part of the person Model, so I'd add them to the DetailPersonViewModel.
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
public IEnumerable<Color> Colors { get; set; }
}
.. and keeping the validation at the entity level only?
System.ComponentModel.DataAnnotations weren't designed to validate properties' properties, so doing something like:
public class DetailsPersonViewModel()
{
[Required(property="FavoriteColor")]
public Person Person { get; set; }
}
Doesn't exist and doesn't make sense. Why ViewModel shouldn't contain the validation for the entity that needs validation.
this edit action fails if there is no default constructor and you'd have to use the first approach.
Correct, but why would a ViewModel or a Entity in a ViewModel not have a parameterless constructor? Sounds like a bad design and even if there is some requirement for this, it's easily solved by ModelBinding. Here's an example:
// Lets say that this person class requires
// a Guid for a constructor for some reason
public class Person
{
public Person(Guid id){ }
public FirstName { get; set; }
}
public class PersonEditViewModel
{
public Person Person { get; set; }
}
public ActionResult Edit()
{
PersonEditViewModel model = new PersonEditViewModel();
model.Person = new Person(guidFromSomeWhere);
return this.View(PersonEditViewModel);
}
//View
#Html.EditFor(m => m.Person.FirstName)
//Generated Html
<input type="Text" name="Person.FirstName" />
Now we have a form that a user can enter a new first name. How do we get back the values in this constructor? Simple, the ModelBinder does NOT care what model it is binding to, it just binds HTTP values to matching class properties.
[MetadataType(typeof(IPersonValidation))]
public class UpdatePerson
{
public FirstName { get; set; }
}
public class PersonUpdateViewModel
{
public UpdatePerson Person { get; set; }
}
[HttpPost]
public ActionResult Edit(PersonUpdateViewModel model)
{
// the model contains a .Person with a .FirstName of the input Text box
// the ModelBinder is simply populating the parameter with the values
// pass via Query, Forms, etc
// Validate Model
// AutoMap it or or whatever
// return a view
}
I have not yet taken a look at the NerDinner project, however, I generally try to avoid having a ViewModel in the POST of an action and instead, only have the elements of the "form" submitted.
For instance, if the ViewModel has a Dictionary that is used in some kind of dropdown, the entire dropdown will not be submitted, only the selected value.
My general approach is:
[HttpGet]
public ActionResult Edit(int id)
{
var form = _service.GetForm(id);
var pageViewModel = BuildViewModel(form);
return View(pageViewModel);
}
[HttpPost]
public ActionResult Edit(int id, MyCustomForm form)
{
var isSuccess = _service.ProcessForm(id);
if(isSuccess){
//redirect
}
//There was an error. Show the form again, but preserve the input values
var pageViewModel = BuildViewModel(form);
return View(pageViewModel);
}
private MyViewModel BuildViewModel(MyCustomForm form)
{
var viewModel = new MyViewModel();
viewModel.Form = form;
viewModel.StateList = _service.GetStateList();
return viewModel;
}

ASP.NET MVC 3 Razor- Get data from custom editor

I have an experience in work with ASP.NET forms, but new to MVC.
How can I get data from shared views on postback?
In ASP.NET Forms I can write something like this:
ASP.NET Forms:
Model code:
public class MyModelItem
{
// Just TextBox is enough for editing this
public string SimpleProperty { get; set; }
// For this property separate NestedItemEditor.ascx is required
public MyModelNestedItem ComplexProperty { get; set; }
}
public class MyModelNestedItem
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
}
Behavior:
Control for editing MyModelNestedItem is separate ASCX control NestedItemEditor.ascx
This is just for example, MyModelNestedItem can be much more complex, I just want to give idea what I mean.
Now when I showing this item for editing, I'm showing one asp:TextBox and one NestedItemEditor.ascx. On page postback I'm gathering data from both and that's it.
Problem with MVC:
When I'm trying to implement this scenario with MVC, I'm using customized EditorFor (through using UIHint and creating shared view). So this shared view Views\Shared\EditorTemplates\MyModelNestedItem.cshtml can now display data that is already in MyModelNestedItem property but I have no idea how to make it return new entered data.
When parent controller recieves a post request, data seems to be in Request.Form, but which is civilized way to reach it? Sure, the best solution will be if data will fetch automatically into the MyModelItem.ComplexProperty.
The action which is called on post needs to be something like:
[HttpPost]
public ActionResult Index(MyViewModel mdl)
Then all the properties of the model which have input controls (or hidden inputs) on the form will have the data which was entered on the form (or passed to it or modified by javascript, in the case of hidden inputs).
This assumes that MyViewModel is the model referenced in your view.
Writing an ActionResult method in the controller with the complex type simply worked for me:
public class Topic
{
public Topic()
{
}
public DetailsClass Details
{
get;
set;
}
}
public class DetailsClass
{
public string TopicDetails
{
get;
set;
}
}
The view:
#modelTopic
#using (Html.BeginForm("Submit","Default"))
{
#Html.EditorFor(m=>m.Details)
#:<input type="submit" />
}
The controller:
public ActionResult Index()
{
Topic topic = new Topic();
return View( topic);
}
public ActionResult Submit(Topic t)
{
return View(t);
}
When submited, the Topic t contains the value i ented within the editor (Assuming You have a custom editor for the complex type, DetailsClass in my sample)

ASP.net MVC create model with value with multiple options

I am wanting to create a Model that has a property of Service which then has multiple options that can either be true or false. So my Contact Class:
public class Contact
{
//My Properties
}
I want the Contact class to have a property of Services. I have a list of services available. How can I reference my services from my Contact class. I would like be able to access it in my view like: model.services.MyCustomService if it's even possible. I come from a javascript background so this is what I mean but written in javascript if it helps.
Javascript Example
var Contact = {
property: "",
services: {
MyCustomService: "",
MyCustomService2: "",
}
}
Here's how I'd do it:
In your Model:
public class Contact
{
//My Properties
public List<Service> Services
{
get;
set;
}
}
In your Controller:
public ActionResult Index()
{
var model = new Contact(); // Create model
// Create some sample services
var service = new Service();
var service2 = new Service();
// Add the services
model.Services.Add(service);
model.Services.Add(service2);
// Pass the model to the view
return View(model);
}
Then, in your view:
#model MySite.Models.Contact
#foreach (var service in Model.Services)
{
<text>Here's my service: #service.MyCoolProperty.ToString()</text>
}
In that simple example, I first declared the Services property of your Contact class as a List<Service>. That allows you to combine many Services into one property - perfect for passing along to a view.
Next, in the Controller, I added some Services to the List by using the Add() method. Therefore, in the View, you're now able to access those Services through Model.Services.
To me, that looks like one of the simplest ways to approach this common problem. Hope that helped!
In C#, every object has a type so Services property has to have an actual type if you want to reference MyCustomService and MyCustomService2 through dot notation:
class Contact {
public ServiceContainer Services { get; set; }
}
class ServiceContainer {
public Service1 Service1 { get; set; }
public Service2 Service2 { get; set; }
}
However, if container serves for no other purpose but to store a service (assuming it's some object), you should probably store them in a list or array (access by index) or in a dictionary (access by string).
To give you more information, I'll need to know what exactly these services are, whether you expect their set to change, do they have different types, etc.
To bind to a collection all you need is this:
<%# Page Inherits="ViewPage<IList<Book>>" %>
A complete explanation can be found here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

Resources