2015-10-19 4 views
0

В Web Api 2, метод на контроллере может иметь несколько параметров, предоставленных из URI, например. строка, преобразованная в int, и автоматическое сообщение об ошибке в сети, если строка не может быть преобразована в int.Web Api 2: выборочная проверка параметров (typeconverter)

Я хотел бы сделать то же самое с настраиваемым типом. Я создал класс, который содержит только объект DateTime, и я хочу сделать пользовательское преобразование строкового аргумента веб-URI этому объекту DateTime. Для этого я применил TypeConverter. Оно работает. Моя проблема заключается в том, что если я дам ему плохую строку даты, я не получаю никакой веб-ошибки, и мой метод получает нулевой указатель. Это моя модель с 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 вызвала исключение, это будет отражено на веб-апи и сообщение об ошибке в сети будет отправлено обратно вызывающему абоненту. Если я дам «2», как StatusCode, я получаю веб ошибку вроде этого:

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

Как вызвать то же самое сообщение об ошибке с моей TypeConverter? Возможно, typeconverter не может помочь, но каким образом я должен посмотреть?

ответ

2

Что вы делаете правильно, и это по дизайну. Подумайте, что вы ожидаете от недопустимого Guid в параметре messageid. То же самое происходит и там. Либо маршрут не совпадает, либо вы получаете неверный запрос. Чтобы иметь больший контроль над проверкой состояния модели & сообщение об ошибке, вы должны наследовать от IModelBinder и создать свой собственный DkDateTimeModelBinder.

Проверить этот пост: 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 Bad Request

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

На самом деле, если я дать плохой указатель на URI, я получаю сообщение об ошибке в сети, как и с плохим целым числом. Я хочу, чтобы мой пользовательский объект вызывал ту же ошибку. Если ModelBinder - это способ сделать это, я рассмотрю это. – galmok

+0

Я реализовал пример ModelBinder, предоставленный вашей ссылкой, и сначала это не сработало. Но когда я заменил последнее «return false» с throw FormatException, я получил веб-ошибку. Благодарю. :) – galmok

+0

рад быть в состоянии помочь – cleftheris

Смежные вопросы