user4592495
user4592495

Reputation:

ASP.NET Core Custom Parameter Binding

I have a situation in which I would like to do custom parameter binding for an api controller in ASP.NET core.In WebAPI 2.0 it was possible to perform custom binding to primitive types by implementing various interfaces such as IValueProvider and providing a ValueProviderFactory. This does not seem the case with ASP.NET core in as far as what I understand from the documentation I found here.

I did notice this SO post which lead me to this article which overrides the behavior for the MutableObjectModelBinder. It would appear I could do something along those lines such as:

    [HttpGet]
    [Route("api/{domain}/[controller]")]
    public IEnumerable<string> Get([ModelBinder(BinderType = typeof(MyCustomBinder))]string orderby)
    {
        //Do stuff here
    }

This doesn't necessarily seem right to me since I am just dealing with a primitive type however I cannot seem to find any documentation for another way of doing this.

Upvotes: 4

Views: 4268

Answers (2)

TylerH
TylerH

Reputation: 21095

Migrating OP's solution from the question to an answer, with meta commentary trimmed:

I just decided to go with a helper class to parse the parameter due to having to meet deadlines.

Upvotes: 0

Sunil Buddala
Sunil Buddala

Reputation: 1231

Create a binder provider class for your custom type

public class MyCustomBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(MyCustom))
        {
            return new BinderTypeModelBinder(typeof(MyCustomBinder));
        }

        return null;
    }
}

and register it in the services

 services.AddMvc(c =>
 {
      c.ModelBinderProviders.Insert(0, new MyCustomBinderProvider());
 });

And the custom binder can go like

public class MyCustomBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(MyCustom))
        {
            return TaskCache.CompletedTask;
        }

        var parameters = new Dictionary<string, string>();
        foreach (var parameter in bindingContext.ModelType.GetProperties())
        {
            var valueProviderResult = bindingContext.ValueProvider.GetValue(parameter.Name);
            if (valueProviderResult.FirstValue != null)
            {
                parameters.Add(parameter.Name, valueProviderResult.FirstValue);
            }
        }

        var result = Activator.CreateInstance(bindingContext.ModelType);

        //write your custom code to map the result with the parameters

        bindingContext.Result = ModelBindingResult.Success(result);

        return TaskCache.CompletedTask;
    }
}

Your custom type class

[ModelBinder(BinderType = typeof(MyCustomBinder))]
public class MyCustom
{
    public int Page { get; set; }
    public int Rows { get; set; }
}

and your controller can take the custom class as query string parameter

[HttpGet("data")]
public DataTransferObject GetData(MyCustom query)
{
}

Upvotes: 4

Related Questions