With the default route and this controller:
using System.ComponentModel.DataAnnotations;
using System.Web.Http;
namespace ActionSelectionTest.Controllers
{
[FromUri]
public class Test
{
[Required]
public int ID { get; set; }
}
public class ValuesController : ApiController
{
public string Get(Test test)
{
return test.ID.ToString();
}
}
}
And a GET request to api/values/1 you get this error:
{"Message":"An error has occurred.","ExceptionMessage":"Property 'ID' on type 'ActionSelectionTest.Controllers.Test' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Validation.Validators.ErrorModelValidator.Validate(ModelMetadata metadata, Object container)\r\n at System.Web.Http.Validation.ModelValidationNode.ValidateThis(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.Validation.ModelValidationNode.Validate(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.Validation.ModelValidationNode.ValidateChildren(HttpActionContext actionContext)\r\n at System.Web.Http.Validation.ModelValidationNode.Validate(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.ModelBinding.Binders.CompositeModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)\r\n at System.Web.Http.ModelBinding.ModelBinderParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder)\r\n at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()\r\n at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"}
Expected result:
We shouldn’t need to require data contract attributes for FromUri types. We should only require the data contract attributes when our formatters that require them are in use.
Workaround:
Remove the validation logic in your config:
config.Services.RemoveAll(
typeof(System.Web.Http.Validation.ModelValidatorProvider),
v => v is InvalidModelValidatorProvider);
Comments: If the user wants to have their value types to be required, they can make the value type nullable and mark it with Required attribute. And DataAnnodationValidators will pick that up. Also, it is extremely overkill to double check the required attribute at the formatter level and stick the error message inside the ModelState for no reason: http://stackoverflow.com/questions/12458532/suppress-requiredattribute-validation-for-the-jsonmediatypeformatter-in-asp-net Maybe I am missing something here but in general, it seems totally unnecessary.
using System.ComponentModel.DataAnnotations;
using System.Web.Http;
namespace ActionSelectionTest.Controllers
{
[FromUri]
public class Test
{
[Required]
public int ID { get; set; }
}
public class ValuesController : ApiController
{
public string Get(Test test)
{
return test.ID.ToString();
}
}
}
And a GET request to api/values/1 you get this error:
{"Message":"An error has occurred.","ExceptionMessage":"Property 'ID' on type 'ActionSelectionTest.Controllers.Test' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Validation.Validators.ErrorModelValidator.Validate(ModelMetadata metadata, Object container)\r\n at System.Web.Http.Validation.ModelValidationNode.ValidateThis(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.Validation.ModelValidationNode.Validate(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.Validation.ModelValidationNode.ValidateChildren(HttpActionContext actionContext)\r\n at System.Web.Http.Validation.ModelValidationNode.Validate(HttpActionContext actionContext, ModelValidationNode parentNode)\r\n at System.Web.Http.ModelBinding.Binders.CompositeModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)\r\n at System.Web.Http.ModelBinding.ModelBinderParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder)\r\n at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()\r\n at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"}
Expected result:
We shouldn’t need to require data contract attributes for FromUri types. We should only require the data contract attributes when our formatters that require them are in use.
Workaround:
Remove the validation logic in your config:
config.Services.RemoveAll(
typeof(System.Web.Http.Validation.ModelValidatorProvider),
v => v is InvalidModelValidatorProvider);
Comments: If the user wants to have their value types to be required, they can make the value type nullable and mark it with Required attribute. And DataAnnodationValidators will pick that up. Also, it is extremely overkill to double check the required attribute at the formatter level and stick the error message inside the ModelState for no reason: http://stackoverflow.com/questions/12458532/suppress-requiredattribute-validation-for-the-jsonmediatypeformatter-in-asp-net Maybe I am missing something here but in general, it seems totally unnecessary.