Web Api 2:自定义参数验证(typeconverter)

Web Api 2: Custom parameter validation (typeconverter)

在 Web Api2 中,控制器上的方法可以有许多从 URI 提供的参数,例如如果字符串无法转换为 int,则将字符串转换为 int 并自动返回 Web 错误消息。

我想对自定义类型执行相同的操作。我创建了一个仅包含 DateTime 对象的 class,我想将 Web URI 字符串参数自定义转换为该 DateTime 对象。为此,我实现了一个 TypeConverter。有用。我的问题是,如果我给它一个错误的日期字符串,我就不会收到网络错误,而且我的方法会得到一个空指针。这是我的带有类型转换器的模型:

[TypeConverter(typeof(DkDateTimeConverter))]
public class DkDateTime
{
    private static readonly ILog log4 = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public DateTime dkDateTime;

    public static bool TryParse(string s, out DkDateTime result)
    {
        log4.Debug("TryParse");
        result = null;

        var culture = new CultureInfo("da");
        try
        {
            result = new DkDateTime()
            {
                dkDateTime = DateTime.ParseExact(s, "dd-MM-yyyy HH:mm:ss", culture)
            };
            return true;
        }
        catch
        {
            return false;
        }
    }
}

class DkDateTimeConverter : TypeConverter
{
    private static readonly ILog log4 = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        log4.Debug("CanConvertFrom");
        if (sourceType == typeof(string))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        log4.Debug("ConvertFrom");
        if (value is string)
        {
            DkDateTime dkDateTime;
            if (DkDateTime.TryParse((string)value, out dkDateTime))
            {
                return dkDateTime;
            }
            else
            {
                log4.Debug("Exception");
                throw new NotSupportedException();
            }
        }
        return base.ConvertFrom(context, culture, value);
    }
}

我的控制器将此方法作为入口点:

public IHttpActionResult Get(Guid messageid, int statuscode, DkDateTime sentdate, DkDateTime donedate)

我的印象是,如果 ConvertFrom 导致异常,这将由 web api 反映出来,并且 web 错误消息将被发送回调用者。如果我给“2a”作为状态码,我确实会收到这样的网络错误:

<Error>
<Message>The request is invalid.</Message>
</Error>

如何使用我的类型转换器触发相同的错误消息?也许类型转换器帮不上忙,但我应该看哪条路呢?

您所做的是正确的,并且是设计使然。想一想您对 messageid 参数中无效的 Guid 的期望。同样的事情也发生在那里。路由不匹配或您收到无效请求。为了更好地控制模型状态验证和错误消息,您应该继承 IModelBinder 并构建您的自定义 DkDateTimeModelBinder.

检查此 post:Parameter Binding in ASP.NET Web API

更新示例

public class DkDateTime
{
    public DateTime dkDateTime;

    public static bool TryParse(string s, out DkDateTime result) {
        result = null;
        var dateTime = default(DateTime);
        if (DateTime.TryParseExact(s, "dd-MM-yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime)) {
            result = new DkDateTime { dkDateTime = dateTime };
            return true;
        }
        return false;
    }
}

 public class DkDateTimeModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) {
        if (bindingContext.ModelType != typeof(DkDateTime)) {
            return false;
        }

        ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (val == null) {
            return false;
        }

        string key = val.RawValue as string;
        if (key == null) {
            bindingContext.ModelState.AddModelError(
                bindingContext.ModelName, "Wrong value type");
            return false;
        }

        DkDateTime result;
        if (DkDateTime.TryParse(key, out result)) {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(
            bindingContext.ModelName, "Cannot convert value to DkDateTime");
        return false;
    }
}

然后在控制器中:

public class ExampleController : ApiController
{
    [Route("test")]
    public async Task<IHttpActionResult> GetDk([ModelBinder(typeof(DkDateTimeModelBinder))]DkDateTime sendDate) {
        if (!ModelState.IsValid) {
            return BadRequest(ModelState);
        }
        return Ok(sendDate);
    }
}

现在,当我使用 url http://localhost:4814/example/test?senddate=dsfasdafsd 进行测试时,我得到了低于预期的响应

状态 400 错误请求

{
    "Message": "The request is invalid.",
    "ModelState": {
        "sendDate": [
            "Cannot convert value to DkDateTime"
        ]
    }
}