2

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:

  1. Create a custom HttpParameterBinding class and handle the exception in there?
  2. 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
  3. Catch the exception in the GlobalExceptionFilter explictly and tailor the response from here (this has a rank code smell though...)

2 Answers 2

3

This is a bug in Web API. It currently will always fail when any public property on the type throws.

It's already been fixed in our current bits: https://aspnetwebstack.codeplex.com/workitem/611 and the fix should be available in our next release.

If you disable validation like this as a workaround:

config.Services.Clear(typeof(ModelValidatorProvider));

you might get a better behavior with an invalid model state.

Sign up to request clarification or add additional context in comments.

3 Comments

wouldn't clearing the ModelValidatorProvider disable ALL model validation? If so, that is not an acceptable workaround as the application relies on model validation in many other places.
what do you mean by "you might get a better behaviour with an invalid model state" ???
You can also just use strings instead of URIs in your model. That should be a valid workaround.
1

Given that there appears to be no answer to the problem, the work around I am going to employ is my second option:

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

And then handle any exceptions that occur during the instantiation of the URI myself...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.