I have a DataContract which my Web API action method accepts as an action parameter.
public HttpResponseMessage PostMyObject(MyObjectRequestDc objRequest){ ... }
[DataContract]
public class MyObjectRequestDc
{
public MyObjectRequestDc()
{
References = new List<Uri>();
}
[DataMember]
public List<Uri> References { get; set; }
}
One of the properties of the contract is a list of URI objects ('References').
If the client ever submits a request which contains a string that does not resolve to a correct URI, an exception is thrown deep within the framework code (because it can't instantiate the URI class from the given string):
Example Json Input:
{ "References": [ "This is not a valid uri." ] }
Exception Details / Stack Trace
Error details: System.InvalidOperationException: This operation is not supported for a relative URI.
at System.Uri.get_AbsolutePath()
at GetAbsolutePathFromUri(Object )
at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.<>c__DisplayClass3.<GetMetadataForPropertiesImpl>b__0()
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(IEnumerable model, ValidationContext validationContext)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
at System.Web.Http.ModelBinding.FormatterParameterBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(Object model)
at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass49.<ToAsyncVoidTask>b__48()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
The requirement is that the user be returned a Response with code 400 (BadRequest) and a message along the lines of "The referenced URI 'xxx' is not valid".
At the moment, the exception is caught by the GlobalExceptionFilter and a unhelpful 500 is returned.
Ideally, I'd like this scenario to be captured as a Model State error or some other mechanism which will allow me to control the response.
Options I've considered:
- Create a custom HttpParameterBinding class and handle the exception in there?
- Change the References property to be a list of String objects and then handle the instantiation of the URI class within the action method of the Controller
- Catch the exception in the GlobalExceptionFilter explictly and tailor the response from here (this has a rank code smell though...)