JSON to MVC Api Controller via AJAX - asp.net-mvc

So I'm trying to add a "like" function to some blog posts by POSTing some JSON through ajax to the MVC api controller.
Models:
public class Blog{
public int ID{get;set;}
public string Title{get;set;}
//Some more stuff
public virtual ICollection<Likes> Likes {get;set;}
}
public class Likes{
public int ID{get;set;}
public string UserName{get;set;}
//Some more stuff
public virtual Blog Blog{get;set;}
}
Controller:
public void Post(Likes like){
if(ModelState.IsValid){
db.Likes.Add(like)
db.SaveChanges();
}
}
The below return is passed into the JSON.stringify() in the ajax call:
var UserName = "Dave";
//More stuff
var Blog = "????";
return {UserName:UserName, More Stuff, Blog:Blog}
So that last line is my problem I think, what do I pass in for "Blog"? I have tried using the ID of the Blog but it's still null in the controller. It seems the controller wants a full Blog model instead of just the ID, is there a way around this or am I doing something bad?
TLDR I guess is: What to pass to a field that's a public virtual Blog Blog{get;set;} in the model when sending JSON to the controller?
P.S. My code works when I don't include the "Blog" as part of the JSON.

if you are posting a like then this would probably do the thing
{
ID : 789 //ID of the Like
UserName : "Username",
Blog : {
ID : 789 //id of the blog
}
}
This way you will have the id of the blog and would be mapped correctly.
But i would advise you make a separate view model of the following structure
public LikeAjax
{
public string UserName{get; set;}
public int BlogId {get; set;}
}
then send json like below
{
UserName : "User Name",
BlogId : 789
}

Related

OData WebAPI 2.2 Post method Example

I am in creation of webapi odata service. I have a post method named "Validate" in my controller named "User" as below:
public class UserController : ODataController
{
[HttpPost]
public HttpResponseMessage Post(LoginEntityDto objLogin)
{
//mylogin
}
}
//Custom class
public class LoginEntityDto
{
public string username { get; set; }
public string password { get; set; }
}
I am inputting this post method with the below JSON Format
{
"username": "C201566",
"password" : "pwd"
}
I am using the content-type : application / json
but in my post method the input objLogin is always null
Please help me in resolving this issue.
OData/Webapi doesn't support post a complex type in this way, why not make it as an entity type by define the key and entityset.
[key]
username {get;set;}
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<LoginEntityDto>("LoginEntityDto");
or you can use action to post this complex type as parameter.
FYI: http://odata.github.io/WebApi/#04-07-action-parameter-support

Get Latest record of table via Entity Framework

I'm using code first feature of EntityFramework and I have created a model class with this field that have their own property (I don't mention them here!) :
public class Portrait
{
private Guid _id;
private string _aboutimage;
private string _aboutMe;
private string _mainMenu;
private string _headerImage;
private string _resume;
private string _showpiece;
private string _siteMenu;
private string _adminMenu;
}
and for each part of this class I have separate ViewModel, for example I have AboutViewModel to update About in admin part and navigate in about page in website :
public class AboutViewModel
{
public Guid Id { get; set; }
public string AboutText { get; set; }
public string Image { get; set; }
}
Now when I update the AboutViewModel, Portrait table in database will create a record that will have about text (other field will be null)
And for updating for other part of this table like Resume or others, it will generate another record with updated and inserted field (now in this record about text will be null!)
Now how can I get the about field to show it in UI as I have several records !? I don't want and also can not get these field by ID because I always want to have their latest updated to show in web site, what I have written is like this ,my about action to get the about text is like this :
public ViewResult About()
{
var about= _portraitRepository.GetContent();
return View(about);
}
and the GetContent() is like this :
public Portrait GetContent()
{
return _siteContext.Portraits.Find();
}
but dosn't work and I got this error:
The number of primary key values passed must match number of primary key values defined on the entity. Parameter name: keyValues
Am I in a wrong direction? How can I solve this problem please?
Another option is to get the Max value of the Id of Portrait table if it is an identity column.
The action will look like below.
public ActionResult About()
{
var about= _portraitRepository.GetLatest();
}
Repository will look like below.
public Portrait GetLatest()
{
var latestId = _siteContext.Portraits.Max(p => p.Id);
return _siteContext.Portraits.Find(latestId);
}
You should retrieve the ID when you perform the insert. Then save that value to Session or something for later use in your About Action
The call to the repository to persom the insert will look like below.
Session["LatestPortraitId"] = _portraitRepository.AddPortrait();
The method in the Portrait repository used to insert a new Portrait should look like below.
public int AddPortrait(portrait)
{
_siteContext.AddObject(portrait);
_siteContext.SaveChanges();
return portrait.Id;
}
The About action will look like below.
public ActionResult About()
{
var latestPortraitId = Int.Parse(Session["LatestPortraitId"]);
var about= _portraitRepository.GetContent(latestPortraitId);
}
Inside the repository it should be as shown below.
public Portrait GetContent(int id)
{
return _siteContext.Portraits.Find(id);
}
Order the search by descendent Id then use first property

MVC 3 Edit Function not working

I can't seem to get the edit function of my view to work..i have a page that lists, a page that shows specific detail and on that page, i should be able to edit the information of the form..PROBLEM: when i run the application it says:No parameterless constructor defined for this object. What am i doing wrong...?
In the Home Controller i have:
Edit Functions:
[HttpGet]
public ViewResult EditSchoolDetails(int id)
{
var institution = _educationRepository.GetInstititionById(id);
var model = (Mapper.Map<Institution, InstitutionModel>(institution));
return View(model);
}
post
[HttpPost]
public ActionResult EditSchoolDetails( InstitutionModel institutionModel, int id)
{
if (ModelState.IsValid) {
//_get from repository and add to instituion
var institution = _educationRepository.GetInstititionById(institutionModel.Id);
// Map from the view model back to the domain model
var model = Mapper.Map<Institution, InstitutionModel>(institution);
//UpdateModel(model);
SaveChanges();
return RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
}
return View(institutionModel);
}
InstitutionModel
public class InstitutionModel {
public InstitutionModel() {
NAABAccreditations = new List<AccreditationModel>();
}
public int Id { get; set; }
public string Name { get; set; }
public bool IsNAAB { get { return NAABAccreditations.Any(); } }
public string Website { get; set; }
public AddressModel Address { get; set; }
public IEnumerable<AccreditationModel> NAABAccreditations { get; set; }
}
Does the Institution class have a parameterless constructor? If not, that will be the problem. You are passing an InstitutionModel to the the edit view, so the post action should probably take an InstitutionModel too, then you can map back to the original Institution model:
public ActionResult EditSchoolDetails(int id, InstitutionModel institutionModel)
{
if (ModelState.IsValid)
{
//add to database and save changes
Institution institutionEntity = _educationRepository.GetInstititionById(institution.Id);
// Map from the view model back to the domain model
Mapper.Map<InstitutionModel, Institution>(institutionModel, institutionEntity);
SaveChanges();
return RedirectToAction("ViewSchoolDetails",);
}
return View(institutionModel);
}
Notice also how it returns the view model back to the view if the model state isn't valid, otherwise you will lose all your form values!
Here's a similar question too which might help: ASP.NET MVC: No parameterless constructor defined for this object
Is it possible you need to pass a parameter to ViewSchoolDetails? I notice in the return statement you commented out that you were passing it an id, but in the return statement you're using, you're not passing in anything.
EDIT
This (from your comment below):
parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult ViewSchoolDetails(Int32)
...tells me you need to pass a parameter to ViewSchoolDetails
EDIT 2
I saw your edit, and would say this: if the method you are calling is
public ActionResult ViewSchoolDetails(InstitutionModel institutionModel, int id)
Then you MUST pass it an object of type InstitutionModel and an int as parameters or you will get an exception. Meaning, you need
RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
Whenever i get this, i have forgotten to create a parameter-less constructor on my view-model. I always add one now just in case it's needed and i forget.
Does InstitutionModel have one?

asp.net MVC 3 - reading POST payload in paramterized controller method

I had
[HttpPost]
public ActionResult Foo()
{
// read HTTP payload
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
The payload is application/json; worked fine; then I changed to
public ActionResult Foo(string thing)
{
....
}
The intention being to post to MyController/Foo?thing=yo
Now I cant read the payload(the length is correct but the stream is empty). My guess is that the controller plumbing has eaten the payload looking for form post data that can be mapped to the method parameters. Is there some way that I can stop this behavior (surely MVC should not have eaten a payload whose type is marked as JSON , it should only look at form post data). My work around is to add 'thing' to the json but I dont really like that
Try resetting the input stream position before reading:
public ActionResult Foo(string thing)
{
Request.InputStream.Position = 0;
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
Now this being said, if you are sending an application/json payload why on the holy Earth are you bothering to read directly the request stream instead of simply defining and using a view model:
public class MyViewModel
{
public string Thing { get; set; }
public string Foo { get; set; }
public string Bar { get; set; }
...
}
and then:
public ActionResult Foo(MyViewModel model)
{
// use the model here
....
}
ASP.NET MVC 3 has a built-in JsonValueProviderFactory which allows you to automatically bind JSON requests to models. And if you are using an older version it is trivially easy to add such factory your self as Phil Haack illustrates in his blog post.

Create object with list of properties and pass it to Controller

Perhaps there is an easy solution for my problem but I simply cannot seem to find it. I have read lots of tutorials about Knockout so I get the basics but I ask this question because my entity-structure is a bit more complicated than a person with a name and a list of friends which may or may not be on Twitter (Video on Channel9: Helping you build dynamic JavaScript UIs with MVVM and ASP.NET). Here's my situation:
I have a class PersonnelClass with this basic structure:
[Serializable]
//The interface is for the implementation of 'Name' and 'Description'
public class PersonnelClass : IPersonnelClassOrPerson
{
public PersonnelClass() : this(Guid.NewGuid(), "", "") { }
public PersonnelClass(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
Id = id;
Name = name;
Description = description;
Properties = new PropertyCollection();
}
public Guid Id { get; private set; }
public String Name { get; set; }
public String Description { get; set; }
public PropertyCollection Properties { get; private set; }
}
The PropertyCollection class and associated AbstractProperty class look like this:
[Serializable]
public class PropertyCollection: List<AbstractProperty> { }
[Serializable]
public abstract class AbstractProperty: IEntity, IProperty
{
public AbstractProperty(String name, String description = null) : this(Guid.NewGuid(), name, description) { }
public AbstractProperty(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); }
Id = id;
Name = name;
Description = description;
}
public Guid Id { get; private set; }
public String Name { get; private set; }
public String Description { get; private set; }
}
In my Controller, I create an instance of a PersonnelClassViewModel that has this structure:
public class PersonnelClassViewModel
{
public PersonnelClass PersonnelClass { get; set; }
public List<AbstractProperty> Properties { get; set; }
}
I fill this viewmodel with a new PersonnelClass and two test-properties to pass to my View like this:
var properties = new List<AbstractProperty>
{
new TextProperty("prop1", "descr1"),
new TextProperty("prop2", "descr2")
//TextProperty is derived from AbstractProperty
};
var vm = new PersonnelClassViewModel { Properties = properties };
return View(vm);
I get everything in my View as I wanted. From the View I want to create a new PersonnelClass with a set of selected properties. I have the fields for Name and Description and to add the properties I have a ListBox with the properties that already exist (for demo-purpose they came from the controller now). Through a bit of Knockout JavaScript code I can select items from this list and populate an HTML select-control () with the selected properties to add to the PersonnelClass. This all works fine, until I want to build up an object to pass back to the Controller and create the PersonnelClass.
My question is: what Knockout JS code is needed to build up this object and pass it to the Controller by submitting the form and in my Controller how should I receive this object, meaning: what type of object should this be (PersonnelClass, PersonnelClassViewModel, ...) ?
If any more info/code is needed, please do ask. Thanks in advance!
Update after answer of 'B Z':
I followed a few more of Steven Sanderson's tutorials about this to be sure I understand this, especially the one you provided in your answer. Now I have following code in my View to start with:
var initialData = #Html.Raw(new JavaScriptSerializer().Serialize(Model));
var viewModel = {
personnelClassViewModel : ko.mapping.fromJS(initialData),
properties : personnelClassViewModel.Properties,
selectedProperties : ko.observableArray([]),
addedProperties : ko.observableArray([])
};
ko.applyBindings(viewModel);
The variable 'initialData' contains the values I expect it to have but then I get the following error:
Microsoft JScript runtime error: 'personnelClassViewModel' is undefined
I have no clue anymore. Can anyone help me fix this?
Steven Sanderson has an example of how to to work with variable length lists and knockoutjs
http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/
Having said that, I think your problem isn't so much on the knockout side and more on the how to databind the data correctly on the server side. In the link above, Steven uses a FromJson attribute to model bind which you may find useful...
HTH

Resources