This question is similar to what I want to achieve:
Avoiding null model in ASP.Net Web API when no posted properties match the model
But it's gone un-answered.
I have a route which takes a model that is a GET:
[HttpGet, Route("accounts")]
public AccountListResult Post(AccountListRequest loginRequest)
{
return accountService.GetAccounts(loginRequest);
}
The model is populated with additional data from an action filter.
In this case all that needs to be known is the UserId, which the action filter add's to the model based on cookie/header into passed in with the request.
I want to use all the default model binding in WebAPI but I want to avoid null objects.
I don't believe model binding solves my problem.
How do I replace the behaviour of Web API model binding so that instead of Null I receive a new instance when no parameters are passed in
This is closer to what I want to do except its per type which is tedious.
EDIT: Since the question is for Web API, I am posting the Web API solution also below.
You can do this as below in an Action Filter. The below code works only if your model contains default constructor.
Web API Implementation:
public override void OnActionExecuting(HttpActionContext actionContext)
{
var parameters = actionContext.ActionDescriptor.GetParameters();
foreach (var parameter in parameters)
{
object value = null;
if (actionContext.ActionArguments.ContainsKey(parameter.ParameterName))
value = actionContext.ActionArguments[parameter.ParameterName];
if (value != null)
continue;
value = CreateInstance(parameter.ParameterType);
actionContext.ActionArguments[parameter.ParameterName] = value;
}
base.OnActionExecuting(actionContext);
}
protected virtual object CreateInstance(Type type)
{
// Check for existence of default constructor using reflection if needed
// and if performance is not a constraint.
// The below line will fail if the model does not contain a default constructor.
return Activator.CreateInstance(type);
}
MVC Implementation:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var parameters = filterContext.ActionDescriptor.GetParameters();
foreach (var parameter in parameters)
{
if (filterContext.ActionParameters.ContainsKey(parameter.ParameterName))
{
object value = filterContext.ActionParameters[parameter.ParameterName];
if (value == null)
{
// The below line will fail if the model does not contain a default constructor.
value = Activator.CreateInstance(parameter.ParameterType);
filterContext.ActionParameters[parameter.ParameterName] = value;
}
}
}
base.OnActionExecuting(filterContext);
}
@Sarathy's solution works, but doesn't trigger model validation on objects it creates. This can cause situations where an empty model was passed in to an action but ModelState.IsValid
still evaluates true.
For my own purposes, it was necessary to trigger re-validation of the model in the event that an empty model object was created:
public override void OnActionExecuting(HttpActionContext actionContext)
{
var parameters = actionContext.ActionDescriptor.GetParameters();
foreach (var parameter in parameters)
{
object value = null;
if (actionContext.ActionArguments.ContainsKey(parameter.ParameterName))
value = actionContext.ActionArguments[parameter.ParameterName];
if (value != null)
continue;
value = Activator.CreateInstance(parameter.ParameterType);
actionContext.ActionArguments[parameter.ParameterName] = value;
var bodyModelValidator = actionContext.ControllerContext.Configuration.Services.GetBodyModelValidator();
var metadataProvider = actionContext.ControllerContext.Configuration.Services.GetModelMetadataProvider();
bodyModelValidator.Validate(value, value.GetType(), metadataProvider, actionContext, string.Empty);
}
base.OnActionExecuting(actionContext);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With