I am working on exploring some json validation patterns and ran into something unexpected in Json.Net Schema (v3.0.3).
In short if I generate my schema from a .net type, then feed in a data string that includes one of the properties twice, I would expect the validator to throw an exception. However it accepts the multiple values in a last in wins manner. Is there a way to get it to reject the data that has multiple values?
Example, this is my type:
class TestObject {
[Required]
public int? Id { get; set; }
public string Name { get; set; }
public bool? Flag { get; set; }
}
Then this is the code of the test I put together using that type (note that the data contains the name property twice):
var jsonString="{'Id': 111, 'Name': 'SomeValue', 'Flag': true, 'Name':'IgnoredValue'}";
var reader=new JSchemaValidatingReader(new JsonTextReader(new StringReader(jsonString))) {
Schema=new JSchemaGenerator() { DefaultRequired=Required.Default }.Generate(typeof(TestObject))
};
// Act
try {
var result=JsonSerializer.Create().Deserialize<TestObject>(reader);
Assert.Fail("Exception expected.");
}
Note: This use pattern passes all of the other test cases we are concerned with.
JSON Schema doesn't have any validation to detect duplicate properties in a JSON object.
The JSON spec doesn't make any mention of duplicate properties so they are valid but not recommended.
Related
This question is similar to Return "raw" json in ASP.NET Core 2.0 Web Api but slightly more complicated.
I have a mixed content, some class like:
public class ResponseModel
{
public Guid Id { get; set; }
public DateTime TimesStamp { get; set; }
// this is actually JSON serialized data,
// which the function just passes through and doesn't need to understand
public string Data { get; set; }
}
Currently, a response would contain the Id and TimeStamp serialized correctly and Data would just be a string which would need to be deserialized one more time.
I'd instead want Data to be just pointing to the "Raw" json string, which I set it to, without further escaping it.
We don't make use of content negotiation, we only support JSON request and response, so this would be fine.
I know that I could deserialize the json string into a dynamic object and that would work, but why should the string be deserialized just to be serialized again?
So what I would want is something like
public class ResponseModel
{
public Guid Id { get; set; }
public DateTime TimesStamp { get; set; }
public object Data { get; set; }
}
but without the need to spend unnecessary time to deserialize and again serialize the content of the json string.
Not possible. If it's a string, you know it's JSON, but the serializer has no way of knowing that. However, even if it could somehow determine that it's a JSON string, it would still need to internally deserialize it so it could work it into the rest of the object, before serializing the whole thing - effectively no different than doing it yourself.
I'm learning asp.net mvc and wonder when we need to use BindAttribute.
The first case (using Bind):
Model:
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
}
Controller:
public IActionResult Create([Bind(nameof(Book.Name), nameof(Book.Author))] Book model)
{
return Ok();
}
The book Id would be generated on server side. So, client side has nothing to do with it, every actions try to change/make the id is prevented.
The second case (not using Bind):
Model:
public class BookViewModel
{
public string Name { get; set; }
public string Author { get; set; }
}
Controller:
public IActionResult Create(BookViewModel model)
{
return Ok();
}
Because the second model doesn't contain Id property, we don't need to prevent from creating or changing.
I prefer the second. It's easy to manage model.
Is there a case we must use Bind attribute?
We use bind when we want that some properties of complex property are ignored when received on server. It could be for safety or other reasons.
When this action is executed the MVC model binder will use the request parameters to populate the user parameter's properties, as you may already know. However, the Bind attribute tells the model binder to only populate properties with names specified.
So in this case only the Username, FullName and Email properties will be populated. All others will be ignored.
See here for more details: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/
If you have situation when you only have to ignore one parametar from binding you could use Exclude property:
[Exclude]
public Entity Name {get; set;}
Bind is used to increase security and unauthorized data to be posted on server . In your model class , suppose you have content property also. if the content property is not needed in the future. Then it would be difficult for you to remove all the occurrences of that property. Here you can use bind property like this
[Bind(exclude="content")]
or you can bind only selected properties to be posted on server by including the properties like this
public ActionResult create([Bind(Include = "Name,Author")] Modelclass modelclass)
{
//Do something here
}
You can learn more about it here
Second approach is more suitable instead writing all the properties and bind them but there are some situations where you must bind user like you have a roles property or IsAdmin property in your model then you might not want that user somehow posts the IsAdmin or roles properties to the server . That's where you can use Bind attribute
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.
I have a Request DTO set up for performing a PUT against a service that results in an update.
I require both route parameters AND a json payload to be sent as the PUT (this payload is the ApprovalRoleData object below, and represents the new state of the object I want to have reflected on the server):
[Route("/qms/{QAID}/reviewers/{RoleType}", "PUT")]
public class UpdateReviewer
{
public string QAID { get; set; }
public string RoleType { get; set; }
public ApprovalRoleData UpdatedRoleData { get; set; }
}
Within my service, I have a Put() call that accepts this DTO: The issue is that the ApprovalRoleData object is not being deserialized (but the QAID and RoleType are):
public object Put(UpdateReviewer request)
{
string QAID = request.QAID; //can see value
string RT = request.RoleType; //can see value
ApprovalRoleData ard = request.UpdatedRoleData; //null
}
Is there a way like in WebAPI to specify that I want model binding to work with both route parameters AND a body?
Side Note:
Also, getting the underlying stream so I can just parse myself with base.RequestContext.Get<IHttpRequest>().InputStream didn't work since there was no remaining stream to read (i'm assuming the part of ServiceStack that does the model binding probably consumed the stream by the time I got to it?)
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.