在Web API中未发布数据时,请避免使用null模型

时间:2015-02-10 11:02:23

标签: c# asp.net-web-api

这个问题类似于我想要实现的目标:

Avoiding null model in ASP.Net Web API when no posted properties match the model

但是没有回答。

我有一个采用GET模型的路线:

    [HttpGet, Route("accounts")]
    public AccountListResult Post(AccountListRequest loginRequest)
    {
        return accountService.GetAccounts(loginRequest);
    }

使用动作过滤器中的其他数据填充模型。

在这种情况下,所有需要知道的是UserId,动作过滤器根据cookie / header将模型添加到模型中,并传入请求。

我想在WebAPI中使用所有默认模型绑定,但我想避免使用null对象。

我不相信模型绑定可以解决我的问题。

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

这更接近我想要做的事情,除了它的每种类型,这是乏味的。

2 个答案:

答案 0 :(得分:4)

编辑:由于问题是针对Web API,我也在下面发布Web API解决方案。

您可以在动作过滤器中执行以下操作。仅当您的模型包含默认构造函数时,以下代码才有效。

Web API实施:

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实施:

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);
}

答案 1 :(得分:3)

@ Sarathy的解决方案有效,但不会对其创建的对象触发模型验证。这可能导致将空模型传递给某个操作但ModelState.IsValid仍然计算为true的情况。

出于我自己的目的,有必要在创建空模型对象时触发模型的重新验证:

    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);
    }