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"
]
}
}
在 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"
]
}
}