Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the ContainsPrefix method of the Web API IValueProvider interface?

I've created some implementations of IValueProvider for my Web API project and I'm confused about the purpose of the ContainsPrefix method on the interface.

The ContainsPrefix method has this summary comment:

Determines whether the collection contains the specified prefix.

However the summary of the method is abstract and doesn't explain what prefix will be provided to the method or what function the method serves. Is prefix going to be the action parameter name? The action name? The controller name? The first three letters of either of these? Does this method exist to automatically figure out which action parameter the IValueProvider should provide a value for?

I never see the ContainsPrefix method get called by the Web API framework in my IValueProvider implementations although I do see references in Web API's CollectionModelBinder, MutableObjectModelBinder, SimpleModelBinderProvider, and CompositeValueProvider. For instance, the following implementation has caused me no issues in my testing:

MyValueProvider:

public class MyValueProvider : IValueProvider
{
    public bool ContainsPrefix(string prefix)
    {
        throw new NotYetImplementedException();
    }

    public ValueProviderResult GetValue(string key)
    {
        return new ValueProviderResult("hello", "hello", CultureInfo.InvariantCulture);
    }
}

TestController:

public class TestController : ApiController
{
    public string Get([ModelBinder]string input)
    {
        return input;
    }
}

GET requests to my TestController will return hello, so I know GetValue is being called from MyValueProvider, but no exception is thrown so I know that ContainsPrefix isn't called.

  1. When can I expect ContainsPrefix to be called by the Web API framework?
  2. What prefix will be provided to this method?
like image 508
Corey Smith Avatar asked Oct 10 '16 16:10

Corey Smith


2 Answers

It's strange that you were able to create value provider without knowing what this (quite important) method does. First what value providers do? In short they provide values for parameters you specify in your actions. For example:

public ActionResult Index(string test) {

}

Here we have action with parameter named "test". Where to get value for it? From value providers. There are several built-in providers, like query string or form data providers. Those providers are invoked one by one, until some of the providers will be able to provide a value. For example, if there is query string parameter "test" - query string value provider will notice that and return a value, so other providers will not be invoked. Next, if post data contains parameter "test" - it will be used, and so on.

So this parameter name ("test" in this case), is what ContainsPrefix is called with. Take for example query string value provider. If query string contains no "test" - ContainsPrefix for this provider will return "false" and next value provider will be invoked. If it returns true - GetValue should return value and no other providers will be invoked.

If you want to provide a value for parameter from say cookie, in your ContainsPrefix method you will check if there is a cookie with given name. Note that it will be called only if all default value providers will fail to provide a value.

So, TLDR: prefix represents parameter name to provide value for.

like image 87
Evk Avatar answered Nov 01 '22 10:11

Evk


Here is parts of Pride Parrot How to create a custom session value provider article

The ContainsPrefix method is called by the model binder to determine whether the value provider can resolve the data for a given prefix.

If you have SessionValueProvider

public class SessionValueProvider: IValueProvider
{
    public bool ContainsPrefix(string prefix)
    {
        return HttpContext.Current.Session[prefix] != null;
    }

    public ValueProviderResult GetValue(string key)
    {
        if(HttpContext.Current.Session[key] == null)
            return null;

        return new ValueProviderResult(HttpContext.Current.Session[key],
            HttpContext.Current.Session[key].ToString(), CultureInfo.CurrentCulture);
    }
}


public class UserModel
{
    public string AccountNo { get; set; }
    ...
}

public ViewResult SomeAction(UserModel userModel, ...)
{
    ...
}

At the time of model binding the DefaultModelBinder checks with the value providers could they return value for the parameter AccountNo by calling the ContainsPrefix method. If none of the value providers registered eariler could return the value our SessionValueProvider checks with session whether such a parameter is stored and if yes it return the value.

like image 39
mybirthname Avatar answered Nov 01 '22 09:11

mybirthname