2

Context: ASP.NET Web API v2

Given an URL similar to this one:

http://localhost/something?id=cbc66d32-ece8-400f-a574-e36b911e1369

When the web method defines an "id" querystring parameter like this:

[FromUri] Guid? id = null

Then the web method gets called, whether the Guid is an invalid thing such as "asdf" or is completely ommited, the id variable gets filled with null.


We need to throw a HTTP 400 to the client on an invalid Guid, but do some valid generic processing on a null one. Those are very different outcomes. We thus need to differentiate them but get the same input on the method call.

Is there an efficient way to configure ASP.NET Web API so that it issues a HTTP 400 on invalid Guids all over the board? We use nullable Guids quite often and are expecting this kind of behaviour every time.

RooSoft
  • 1,481
  • 2
  • 17
  • 32
  • What about taking the `id parameter` as a string instead of a `Guid?`, and if it's empty it is your null case. And if it's not then try to parse, and can validate if it was a valid Guid or not. – Hypnobrew Apr 05 '16 at 20:46
  • It would indeed work, but we'd have to write that code on each method call using a nullable guid as a querystring. Furthermore, we have an automatic documentation tool that wouldn't know that this parameter should be a Guid, specifically. – RooSoft Apr 05 '16 at 20:49
  • Can you overload the id property and treat 'asdf' as a string while still capturing guids correctly? http://stackoverflow.com/questions/14353466/overload-web-api-action-method-based-on-parameter-type – Derek Tomes Apr 05 '16 at 20:50
  • You could use a string like @Merryweather suggested and put the logic in an action filter, you'll only have to add the action filter above each action you want to check – Aliz Apr 05 '16 at 20:51
  • How about a custom `model binder`, where you do this kind of logic? You only have to write once. – Hypnobrew Apr 05 '16 at 21:02
  • I would create a custom ModelBinder so that you have access to raw string values. Very clear documentation can be found http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api. – dario Apr 05 '16 at 21:07
  • Being that you're using webapi, you could look into using middleware to handle the authentication. – willaien Apr 05 '16 at 21:39
  • The action filter solution could be promising... – RooSoft Apr 06 '16 at 13:24

1 Answers1

1

You can use a custom Model Binder

public IHttpActionResult Get([ModelBinder(typeof(GuidParserModelBinder))] Guid? id = null)
{
    return Json(id);
}

public class GuidParserModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, 
        ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof (Guid?))
            return false;

        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var rawValue = value.RawValue.ToString();

        if (string.IsNullOrWhiteSpace(rawValue))
            return false;

        Guid guid;
        if (Guid.TryParse(rawValue, out guid))
        {
            bindingContext.Model = guid;
            return true;
        }

        // throw exception or logic here
        return false;
    }
}
David L
  • 32,885
  • 8
  • 62
  • 93
  • Could be a good start. The querystring key in the ModelBinder shouldn't be hardcoded though as some Guids could be associated to other ones. – RooSoft Apr 06 '16 at 13:23
  • @RooSoft You didn't mention a need for that type of flexibility in your question nor would it matter. You can use the bindingContext.ModelName, as I've updated in my answer. – David L Apr 06 '16 at 14:25