I'm trying to build a model to receive data from a HTTPPOST.
The model is received and populated fine - except for IList<harsta> harequest
It shows as having a count of 1, but having null values against the fields:
My model is:
public class HAR
{
public int api_version { get; set; }
public IList<harsta> harequest { get; set; }
public class harsta
{
public int ta_id { get; set; }
public string partner_id { get; set; }
public string partner_url { get; set; }
}
...
...
}
The Post data for harrequest is (should have 2 entries):
[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},
{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
A screenshot from PostMan shows the form encoded data that is sent to the controller:
Example Request (this is the example provided on the 3rd party website)
POST
http://partner-site.com/api_implementation/ha
BODY
api_version=4
&harequest=[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
&start_date=2013-07-01
...
&query_key=6167a22d1f87d2028bf60a8e5e27afa7_191_13602996000
I'm sure it's not mapping to my model, because of the way I've setup my model here:
public IList<harsta> harequest { get; set; }
public class harsta
{
public int ta_id { get; set; }
public string partner_id { get; set; }
public string partner_url { get; set; }
}
Have I setup the model incorrectly, to receive the JSON data from the harequest field in the POST?
First of all, I'm not exactly comfortable with the embedding of the Harsta class in the Har class. Not good practice separate them.
Secondly, I think your problem actually stems from the fact the property names in the JSON object(s) you are returning are enclosed in quotes. Get rid of the quotes for only the property names.
That is don't do this:
[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},
{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
Do this instead:
[{ta_id:97497,partner_id:"229547",partner_url:"http://partner.com/deeplink/to/229547"},
{ta_id:97832,partner_id:"id34234",partner_url:"http://partner.com/deeplink/to/id34234"}].
Related
I am migrating /re-developing a web app from JavaScript to the ASP.NET MVC Framework using C#/ JS (with Handlebars.NET) for my Bachelor thesis.
So far I have created a Web.API and the actual app with a form.
In the app I enter details to create a new Employee, which is then Posted to the API, which receives that Json-Object as a "Business Object" BOEmployee.
Said BOEmployee looks like this (simplified):
public class BOEmployee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
I want to map this object to two other objects, representing tables of the underlying database, to then save them to the database. The two target tables are auto generated with Entity Framework.
Here are the table objects:
1. Employee:
public partial class Employee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
}
2. Employee_Details:
public partial class Employee_Detail
{
public int ID_Employee_Detail { get; set; }
public int ID_Employee { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
Now I could map them manually by assigning every attribute but clearly that is a horribly unsustainable idea. So I was looking for a way to automate that mapping process automatically using Json.Net like this:
[HttpPost]
public BOEmployee SaveEmployee([FromBody] string employee)
{
using (var context = new myDBEntities())
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Employee_Detail dbEmployeeDetails = serializer.Deserialize<Employee_Detail>(BOEmployee);
Employee dbEmployee = serializer.Deserialize<Employee>(BOemployee);
}
}
Now what happens when I run that code is, that the serializer-function complains that the input values cannot be null, which to my understanding is because the target Objects (e.g. Employee) do not have all attributes that are given in the serialized Json-Object.
The Error Message is this:
Value cannot be null.\r\nParameter name: input",
"ExceptionType":"System.ArgumentNullException"
Now my question would be, how can I map my object to the different Database tables? Or am I completely on the wrong path now?
Fundamental changes to the program structure cannot be made any more due to available time (and I am basically a complete beginner in programming).
I recommend AutoMapper than what you are using there.
I've often found myself fixing validations for the modelstate manually, due to the inconsistency of some fields that are required in a view model during post and get.
Supposing I've got this View Model:
public class RestaurantMenuName_ViewModel
{
public Int64 RestaurantMenuNameId { get; set; }
public Int64 OwnerId{ get; set; }
public string MenuNameCategory { get; set; }
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
During a GET request the controller/Action requires the validation of just the fields, RestaurantMenuNameId and OwnerId. When calling the Action RestaurantMenuName, the query string values are RestaurantMenuNameId and OwnerId. Modelstate validation will be done on:
RestaurantMenuNameId
OwnerId
During a POST request the controller/Action will require the modelstate validation of the fields:
RestaurantMenuNameId
OwnerId
MenuNameCategory
CategoryDescription
This is the inconsistency issue I'm talking about, a solution could be using a ViewModel for Get requests and one for Post, but this could be real a time waster and error prone. Using ViewBag is out of discussion.
Question:
Is there a way to tell MVC that we want some fields [required] for GET and other for POST?
The following is a Pseudo-code of what I'm talking about:
public class RestaurantMenuName_ViewModel
{
[Required: in GET, POST] //<--Pseudo code
public Int64 RestaurantMenuNameId { get; set; }
[Required: in GET, POST] //<--Pseudo code
public Int64 OwnerId { get; set; }
[Required: in POST] //<--Pseudo code
public string MenuNameCategory { get; set; }
[Required: in POST] //<--Pseudo code
public string CategoryDescription { get; set; }
public bool IsFormSaved { get; set; }
}
It's not a very good practice (and confusing in your case) to pass complex objects when you need only few properties. It will be better to pass only the required ids as primitives.
If the case is special and you really need the complex objects, it will be better to create two different view models for every request and decorate the required properties accordingly.
However, you can create your own require validation attribute which will validate properties dependening on the current request.
public class MyRequiredAttribute : ValidationAttribute
{
private string httpVerb;
public MyRequiredAttribute(string httpVerb)
{
this.httpVerb = httpVerb;
}
public override bool IsValid(object value)
{
if(HttpContext.Current.Request.HttpMethod == this.httpVerb)
{
return value != null;
}
return true;
}
}
// Usage
public class MyViewModel
{
[MyRequired("GET")]
public string A { get; set; }
[MyRequired("POST")]
public string B { get; set; }
}
Note: you can use an enumeration to avoid some difficulties (ex. upper case, lower case, misspelling etc.) and also you can override the FormatErrorMessage method to change the default error message and format it properly.
I'm trying to make a GET request to my SS service but the parameters have empty values when I send them as URL segments. According to https://github.com/ServiceStack/ServiceStack/wiki/Routing I can call the service in two ways:
/resource/p1/p2/p3
or
/resource?p1=v1&p2=v2&p3=v3
The first method never works (the parameters have default values depending on their types) and the second one always works. I wan't to call the service using the first method.
Here's my code
//Request DTO
[Route("/test/{Param1}/{Param2}/{Param3}")]
public class Test
{
public string Param1 { get; set; }
public int Param2 { get; set; }
public string Param3 { get; set; }
}
//Response DTO
public class TestResponse : IHasResponseStatus
{
public ResponseStatus ResponseStatus { get; set; }
public string Inputs { get; set; }
}
What am I doing wrong?
Just to close the question: esker posted a link where mythz confirms that what we're experiencing is actually an IIS/ASP.NET bug.
#Html.ActionLink("Reply", "BlogReplyCommentAdd", "Blog",
new { blogPostId = blogPostId, replyblogPostmodel = Model,
captchaValid = Model.AddNewComment.DisplayCaptcha },null)
My Controller :
public ActionResult BlogReplyCommentAdd(int blogPostId, BlogPostModel model, bool captchaValid)
{}
In my Controller i am passing whole model.But values of properties are null till reach to Action
BlogPostModel:
[Validator(typeof(BlogPostValidator))]
public partial class BlogPostModel : BaseNopEntityModel
{
public BlogPostModel()
{
Tags = new List<string>();
Comments = new List<BlogCommentModel>();
AddNewComment = new AddBlogCommentModel();
}
public string SeName { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public bool AllowComments { get; set; }
public int NumberOfComments { get; set; }
public DateTime CreatedOn { get; set; }
public IList<string> Tags { get; set; }
public IList<BlogCommentModel> Comments { get; set; }
public AddBlogCommentModel AddNewComment { get; set; }
}
Any how i need whole model.
Thanks in advance
You're not going about this correct way at all. The only time whole model data gets passed in the query string like this is when an HTML form is submitted via a GET operation; and even then that's not ideal except in cases where HTTP caching isn't a problem.
In this case, you're already passing the ID of the blog post in the query string to the controller method - so in your controller method you go and retrieve the blog post model and then pass it to the view.
Edit Upon adding this answer - #levelnis' comment then showed up - what (s)he's/they've said is exactly the same thing.
Update
And think about it - if you make it so that's how your site works - then anybody could 'publish' content on your blog's site by seeding the query string with all sorts of horrible stuff, not to mention making your site a playground for SEO spammers and such.
I defined a model like this
public class Planilla
{
[Key]
public int IDPlanilla { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "Dirección de Negocio")]
public int IDDireccionDeNegocio { get; set; }
[Required (ErrorMessage = "*")]
public string Nombre { get; set; }
[Display(Name = "Descripción")]
public string Descripcion { get; set; }
public bool Activo { get; set; }
[ScriptIgnore]
public virtual DireccionDeNegocio DireccionDeNegocio { get; set; }
}
And I have a method in my controller that returns the first element of this model
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(query);
}
My problem is when I invoke this method from client side throws an error that say's
circular reference is detected trying to serialize
System.Data.Entity.DynamicProxies.Planilla_7F7D4D6D9AD7AEDCC59865F32D5D02B4023989FC7178D7698895D2CA59F26FEE
Debugging my code I realized that the object returned by the execution
of the methodFirstit's a
{System.Data.Entity.DynamicProxies.Planilla_7F7D4D6D9AD7AEDCC59865F32D5D02B4023989FC7178D7698895D2CA59F26FEE}
instead a Model of my namespace like
Example.Models.DireccionDeNegocio`.
Why am I doing wrong?? Because I tried with other models and work's well
Use view models, that's the only advice I can give you. Never pass domain models to your views. It's as simple as that. And if you respect this simple rule and fundamental rule in ASP.NET MVC applications you will never have problems. So for example if you need only the id and the description in your view:
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(new
{
Id = query.IDPlanilla,
Description = query.Description
});
}
Notice that in this case the anonymous object serves as view model. But if you really wanted to do things properly you would write your view model:
public class PlanillaViewModel
{
public int Id { get; set; }
public string Description { get; set; }
}
and then:
[HttpPost]
public ActionResult GetElements(string IDCampana)
{
Planilla query = db.Planillas.First();
return Json(new PlanillaViewModel
{
Id = query.IDPlanilla,
Description = query.Description
});
}
By the way Ayende wrote a nice series of blog posts about this.
System.Data.Entity.DynamicProxies.* is the Entity Framework proxy namespace. Your DbContext creates your entities as such to support lazy loading and change tracking. This isn't your problem. The problem likely lies in a circular association.