I created a custom model binder in my .NET Core 3.1 API to validate all JSON parameters (by the help of this post How to validate json request body as valid json in asp.net core).Due to security concern I am checking all the incoming request parameter with the actual model properties(entity model) to avoid parameter tempering(adding additional properties while sending the API request). This is working fine for normal json request but if I have a nested json(nested entity model)then it is validating only main properties(inside properties are not validating)
Example:
for non nested entity models the code is working fine, but if it is a nested models like bellow
public class dep
{
public int depId { get; set; }
public string depName { get; set; }
}
public class EmpModel
{
public dep DepDetails { get; set; }
public string empName { get; set; }
}
The code will validate only the main properties like DepDetails, empName but it wont check the inside properties of DepDetails
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); }
var modelName = bindingContext.BinderModelName ?? "XJson";
var modelType = bindingContext.ModelType;
// create a JsonTextReader
var req = bindingContext.HttpContext.Request;
var raw = req.Body;
if (raw == null)
{
bindingContext.ModelState.AddModelError(modelName, "invalid request body stream");
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
JsonTextReader reader = new JsonTextReader(new StreamReader(raw));
try
{
var jsonT = (JObject)JToken.Load(reader, this._loadSettings);
JObject reqeJson = JObject.Parse(jsonT.ToString());
var RequestParameters = reqeJson.Properties().ToList();
var actualParam = bindingContext.ModelMetadata.Properties.ToList();
//checking for additional parameters in input
//Here I am checking if any additional property is appended with the data and for the
//above model in both actualParam and RequestParameters I will get only 2 instead of 3
bool flag = true;
foreach (var obj in RequestParameters)
{
if(!actualParam.Any(item => item.Name.ToUpper() == obj.Name.ToUpper())){
flag = false;
break;
}
JObject tmp = JObject.Parse(obj.ToString());
};
if (!flag)
{
bindingContext.ModelState.AddModelError(modelName, "Additional Data is present in Request");
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
var o = jsonT.ToObject(modelType);
bindingContext.Result = ModelBindingResult.Success(o);
}
catch (Exception e)
{
bindingContext.ModelState.AddModelError(modelName, e.ToString());
bindingContext.Result = ModelBindingResult.Failed();
}
return Task.CompletedTask;
}
The Real problem is the content of RequestParameters and actualParam is {DepDetails,empName} but I should get as {depId,depName,empName}
If this method is not correct then please help me with some alternatives.