I have been experimenting with Web API 2 for the past couple of weeks and I'm trying to figure out the best way to handle a particular scenario during partial updates.
The API will allow the user to do partial updates via POST. By design, any properties that are not supplied in the request body are assumed to be unchanged and no changes will be made to those properties.
The challenge, however, is trying to determine when a user has explicitly set a property value to null. When the request body is pulled in via the controller, any absent properties are set as null automatically as the JSON request body is deserialized. As such, I lose my ability to determine if the property value is null explicitly (i.e. the user is trying to set the property value as null, in which case I want to update the property to null) or if the property value is null implicitly (i.e. the property value was set to null during deserilaization, in which case I want to ignore it).
I am looking for any ideas of how I might approach this situation.
I have played around with this a bit and I have come up with a way to work around this. Maybe there's another way to address the issue but this seems to be a reasonable approach:
In Web API, the request body can only be read once. Therefore, if you have the controller pull the object in for you, the object will be deserialized and you will lose access to the original request content and will not be able to determine if something was explicitly null or absent. This is demonstrated by something like this:
[Route("cars"), HttpPost]
public IHttpActionResult AddCar(Car car)
{
Car newCar = Car.Add(car);
return Created<Car>("/cars/" + newCar.car_id, newCar);
}
If you want to be able to examine exactly what was sent in, you don't have the controller pull in the object for you, instead, you pull the request body in manually, thus preserving your ability to see exactly what was sent in, like this:
[Route("cars"), HttpPost]
public IHttpActionResult AddCar()
{
HttpContent content = Request.Content;
string carJson = content.ReadAsStringAsync().Result;
// You now have the original JSON and can examine it before deserialization
}
It certainly adds a few more steps, but at least in my case where I needed to be able to see exactly what was POSTed, this provides a solution that seems to work.
Related
I have an ASP.NET CORE Web API app and placed a Model as:
public class SamplePayload
{
public string Attribute1 { get; set; }
public string Attribute2 { get; set; }
}
then my controller looks like:
[ApiController]
public class SampleController : ControllerBase
{
[HttpPost]
public async Task<string> Add(SamplePayload samplePayload)
{
if (!ModelState.IsValid)
{
//Throw Error
}
return "Hello";
}
}
However, the Action still accepts the payload if the Request Body had its payload like this (with additional attributes):
{
"Attribute1":"Value1",
"Attribute2":"Value2",
"EvilAttribute":"EvilValue"
}
As you see, EvilAttribute is not a valid attribute according to the Model, but still, the controller accepts it, and Model.IsValid also returns true despite the fact that I have [ApiController] assigned on top of the controller.
My question is how can I do validation to check that only attributes defined in the Model need to be passed in the Request body? Doesn't ASP.NET core offer simpler handling?
Note:
The reason for this requirement is, Under a Vulnerability assessment done by an independent assessor, highlighted that my Endpoint
accepts additional parameters in request body
The Assessment quoted as:
Test Category: Mass Assignment;
Test Conducted: Adding additional parameters to the requests
Findings: Additional parameters accepted with a request body
Recommendations:
If possible, avoid using functions that automatically bind a client's input into code variables or internal objects.
Whitelist only the properties that should be updated by the client.
If applicable, explicitly dene and enforce schemas for the input data payloads.
I see not much benefits from rejecting the requests that have more data in it.
If that is some sort of requirement, here is what you can try:
I think you may need to implement your own ModelBinder as per example described here:
https://learn.microsoft.com/en-US/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-5.0
The way default model binding works - is going from Model perspective and search for matching fields in the request and assigns values to related model properties.
Once the model that is required can be constructed and passes all of it's internal constraints - it is Valid.
Please check this article: Model Binding in ASP.NET Core
Model binding tries to find values for the following kinds of targets:
Parameters of the controller action method that a request is routed to.
Parameters of the Razor Pages handler method that a request is routed to.
Public properties of a controller or PageModel class, if specified by attributes.
For your scenario, if you set a break point in the Add method, you can see that the Model Binding will just find values based on the SamplePayload's properties.
So, I think there is no need to check whether the request body contains more data or not.
An [ApiController] or a parameter marked as [FromBody] will be serialised in MVC via an input formatter, rather than binding from a value provider.
Working backwards from the mvc source code. It looks like you can control MVC's serialisation settings if you are using System.Text.Json, though I don't see a way to reject extra values;
services.Configure<JsonOptions>(o =>
{
});
Or newtonsoft, which does seem to allow rejecting extra values;
services.Configure<MvcNewtonsoftJsonOptions>(o =>
{
o.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
});
(I haven't tested this myself though...)
I would still push back on this "security" assessment. If you don't have any extra fields available to bind, then rejecting requests doesn't improve security. Though it may help consumers to understand if they have mis-spelled an attribute name.
I'm following and implementing a side project from:
https://learn.microsoft.com/es-mx/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.0&tabs=visual-studio
But in the part where [HttpGet("{id}")] is invoked, it works only with the id field, but I want to retrieve a JSON stored in the DBmemory, with other field instead of id; in this case I want to manage data by field TAG.
How can I accomplish this?
I've try to change all the id parts to TAG, which is the field I'm looking for, but when I do this, the post method breaks up.
// GET: api/Maquinas/5
[HttpGet("{id}")]
public async Task<ActionResult<Maquina>> GetMaquina(string id)
{
// HERE. i need to find data with the field of "TAG" not "id"
var maquina = await _context.Maquinas.FindAsync(id);
if (maquina == null)
{
return NotFound();
}
return maquina;
}
Don't get stuck on the fact that is called id. You could make use of this endpoint and instead of passing the value of id to pass the value of tag, api/Maquinas/tagvalue.
Later on you should use this value in the call you make to retrieve the entity you are looking for.
_context.Maquinas.FirstOrDefaultAsync(maquina => maquina.Tag == id);
I have assumed here that the property on which you want to filter is called Tag and it's type is string. It is quite probable, at least the name of the property to not be this one. So you have to change the above code correspondingly.
This will fix your problem, but you should not consider this a best practice. The semantics of your API would be broken. The very reason, I shared the above, is to show you that the name of the parameter id is irrelevant with that you pass. There isn't any check that would halt you for passing there "anything". The reason I wrote that the semantics of your API would be broken is that since this is going to be a REST api, someone would expect an endpoint like the following one:
api/Maquinas/1
for getting the entity with id 1.
I'm currently working on a large project involving Sitecore CMS (7.2). For viewmodel validation we are using FluentValidations. Because of the combination of Sitecore and FluentValidations I seem to be running in some kind of technical deadlock. I sort-of found a solution myself, but I'm not sure whether this is the right approach or not. Here's the problem:
Situation
There is a Sitecore component which contains a HTML form. Via the modelbinder each value of this form is binded to it's corresponding field in the (complex) viewmodel. This is standard .NET MVC approach.
However, some values in the viewmodel are NOT part of the form. For instance, a date at which the mutation will be applied is calculated by the application. The user can only see this date-value as plain text, and thus can not edit it. It's still part of the viewmodel though. To make sure this value is being posted back to the model in code, one would normally use a hidden field. But if I use a hidden field, it means that users are able to spoof that date and because some validations depend on this value, they are able to spoof the entire validity of the form.
Moreover, in the same viewmodel I have a list of complex objects that I can't simply put in a hidden field (or I should serialize it to JSON, which I don't want).
The conclusion is that I need to store this data somewhere else. Somewhere the user can't spoof it, but I'm still able to validate user input with FluentValidations. I therefore decided to put the entire viewmodel in the users Session, and delete it directly after a succesful mutation.
Problem
By using session data I run into problems. Let's first see these steps:
(GET) Viewmodel is created. Calculated date is set and list of complex types is retrieved once from a (slow) webservice.
Entire viewmodel is stored as session data.
Form is shown to the user, who fills the form. Some data is only shown as readonly, like the date and list of complex types.
User submits form, FluentValidations kicks in to validate the data (POST).
That's where I run into problems. The validation done by FluentValidations kicks in before it reaches the POST controller method. That's exactly the way we want it, because that means validation errors are automatically added to the ModelState. However, because of security reasons I don't want to add this data as hidden fields to the cshtml file, which means they are empty at the time FluentValidations is going to validate the form.
This is creating problems because some of the form validations rely on the missing data. What I basically want is to merge the viewmodel that is stored in the session with the viewmodel that was posted to the controller method. But I have to do that before FluentValidations is going to do it's work.
My current solution
Gladly, I learned about FluentValidation's IValidatorInterceptor: an interface that can be used to 'do stuff' before or after the validations process kicks in. I used the BeforeMvcValidation method to do my merging process. The code is as follows:
public ValidationContext BeforeMvcValidation(ControllerContext controllerContext, ValidationContext validationContext)
{
if (controllerContext.HttpContext.Session == null)
return validationContext;
var sessionData = controllerContext.HttpContext.Session["some_identifier"];
if (sessionData == null)
return validationContext;
var mergedObjectToValidate = Utils.MergeViewModelData(sessionData, validationContext.InstanceToValidate);
// Unfortunately, we have to do this..
var privateSetterProperty = validationContext.GetType().GetProperty(ValidationContextInstancePropertyName);
if (privateSetterProperty == null)
return validationContext;
privateSetterProperty.SetValue(validationContext, mergedObjectToValidate);
return validationContext;
}
Basically this interceptor method allows me to do my merging-process before validation. So I thought I had the solution here, but as you can see I am using reflection to set a property. That is because the property InstanceToValidate in the ValidationContext object has a private setter. I simply can not set it without using reflection. Which is, obviously, a bit dirty.
It does work exactly as I want though! :) I do not need any hidden fields that can be spoofed (which is horrible for straight-trough-processing) and I can still use FluentValidations exactly as I always did before. Also, the MVC modelbinding-process is left untouched, which I prefer.
The actual question
So the above solution works exactly as you want so what are your questions?! Well, simple:
I'm using reflection to set a private property in a 3rd party library (FluentValidations). The obvious answer is: don't go that way. But in this case it works flawlessly. If the InstanceToValidate-property had a public setter, I wouldn't even be posting this question at all: I would feel like I nailed it. But unfortunately it is private, so are there any real reasons why I shouldn't do this, maybe someone being an expert in FluentValidations behaviour?
Let's say there is a genuine reason why I shouldn't go this way; is there another approach which has the same effect? Can I hook in even earlier, so before FluentValidations kicks in, perhaps some kind of 'hook' just after the MVC model-binding process but before validation kicks in?
Is this entire approach simply wrong and should I tackle it in a completely different way?
Thanks!
i have tried to surf the internet but i could not get anything related to what i want.
This is in relation to ASP.Net. But could be any other instance as well.
Following is my attribute
class SomeAttribute :Attribute
{
string someparam;
string SomeParam
{
get{ return someparam;}
set { someparam = val;}
//the value generated for someparam is dynamically generated with respect to some attribute present in the request header.
}
}
it's similar to the [Authorize] attribute that .net uses in its asp .net memberships to validate if the user has logged in and it redirects him back to log in page if validation fails.
I have an attribute associated with a method like below:
[SomeAttribute]
public void someFunction
{
//i want to retrieve here the value of someparam jus generated before entering this method.
}
Note that i don't pass any value or used any named properties in this attribute. It is simply going to check a condition for me whenever the method is called and return true or false and accordingly the function is either called or not.
In my case, After validating, it generates a value and that value has to be shared with the function to which it is associated 'somefunction'.
i know reflections can help me get the attributes associated with a function and the value of its properties.
But here i dont want to fetch the value from some other function. And i dont want to just fetch the attribute either.
As i mentioned earlier when the function is called the attribute will work upon that. What the attribute does is fetches some data from request header and does some processing and generates a value. Now this value has to be passed on to the function just after that.
Well, what you want to accomplish is certainly possible, but it would not be an optimal use of the run-time or the MVC model.
In this particular case, think of an attribute as an annotation. It's something you use to mark a function, controller, etc. so that its execution behaves differently at run-time. The attribute itself should not be doing the bulk of the work, rather just signalling to other pieces in your design to behave differently.
It seems like you want to check some header values, and calculate something based off of that. You can use extension methods off of a Request class to accomplish this.
Now, let's say that inside your Controller's function, you want to guarantee that the header values exist. You can have an attribute called RequireHeaderValues that implements IActionFilter. The attribute would check the header for the required values and if they don't exist, it routes the response to another location or somehow indicates error. This way, when inside your function, you call the extension method off the Request object, you are guaranteed that the values will exist. The MVC run-time will automatically call your filter attribute for you. For more info, see this.
I need to define a WCF API to enable user to update large object. While I can define few smaller methods and let the user update specific parts of the large object at a time. But for some reason I am not able to do that. The other way I tried is defined the data contract as collection of key-value (key is an enum and value is some string) and let the user add whatever he wants to update. This api very compact but it's not very intuitive and can be confusing for the user. Also since the value is of string type, so it's not very type safe.
So I now I have create one api, where the user can update the entire object.
for example:
public UpdateResult UpdateAPI(UpdateParam param){}
Now the UpdateParam class will several nullable fields.
Q: If there is a null value in one of the fields, how can differentiate at the server side,
the null value was specified by the user or it's default non-specified one? Is there something in the incoming soap message that can help differentiate?
Any help would be greatly appreciated.
Similar questions asked are
1. Data member default values, how to figure out whether something was really sent?
2.
no, as far as i know there is no way to tell the conditions apart if you only have a nullable field ...
however, you could provide an additional bool per property that could serve as a flag to indicate if the value was set by the user or is still on its default value
You can implement the setters of your properties to automatically set the corresponding bool when your properties are set