dot net core custom model binding for generic type parameters in mvc action methods

ⅰ亾dé卋堺 提交于 2020-01-05 05:51:53

问题


I am building a simple search, sort, page feature. I have attached the code below. Below are the usecases:

  1. My goal is to pass the "current filters" via each request to persist them particularly while sorting and paging.

  2. Instead of polluting my action method with many (if not too many) parameters, I am thinking to use a generic type parameter that holds the current filters.

  3. I need a custom model binder that can be able to achieve this.

Could someone please post an example implementation?

PS: I am also exploring alternatives as opposed to passing back and forth the complex objects. But i would need to take this route as a last resort and i could not find a good example of custom model binding generic type parameters. Any pointers to such examples can also help. Thanks!.

public async Task<IActionResult> Index(SearchSortPage<ProductSearchParamsVm> currentFilters, string sortField, int? page)
{
    var currentSort = currentFilters.Sort;
    // pass the current sort and sortField to determine the new sort & direction
    currentFilters.Sort = SortUtility.DetermineSortAndDirection(sortField, currentSort);
    currentFilters.Page = page ?? 1;

    ViewData["CurrentFilters"] = currentFilters;

    var bm = await ProductsProcessor.GetPaginatedAsync(currentFilters);

    var vm = AutoMapper.Map<PaginatedResult<ProductBm>, PaginatedResult<ProductVm>>(bm);

    return View(vm);
}

public class SearchSortPage<T> where T : class
{
    public T Search { get; set; }
    public Sort Sort { get; set; }
    public Nullable<int> Page { get; set; }
}

public class Sort
{
    public string Field { get; set; }
    public string Direction { get; set; }
}

public class ProductSearchParamsVm
{
    public string ProductTitle { get; set; }
    public string ProductCategory { get; set; }
    public Nullable<DateTime> DateSent { get; set; }
}

回答1:


First create the Model Binder which should be implementing the interface IModelBinder

SearchSortPageModelBinder.cs

public class SearchSortPageModelBinder<T> : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }   

        SearchSortPage<T> ssp = new SearchSortPage<T>();

        //TODO: Setup the SearchSortPage<T> model 

        bindingContext.Result = ModelBindingResult.Success(ssp);

        return TaskCache.CompletedTask;
    }
}

And then create the Model Binder Provider which should be implementing the interface IModelBinderProvider

SearchSortPageModelBinderProvider.cs

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

        if (context.Metadata.ModelType.GetTypeInfo().IsGenericType && 
            context.Metadata.ModelType.GetGenericTypeDefinition() == typeof(SearchSortPage<>))
        {
            Type[] types = context.Metadata.ModelType.GetGenericArguments();
            Type o = typeof(SearchSortPageModelBinder<>).MakeGenericType(types);

            return (IModelBinder)Activator.CreateInstance(o);
        }

        return null;
    }
}

And the last thing is register the Model Binder Provider, it should be done in your Startup.cs

public void ConfigureServices(IServiceCollection services)
{
        .
        .

        services.AddMvc(options=>
        {
            options.ModelBinderProviders.Insert(0, new SearchSortPageModelBinderProvider());
        });
        .
        .
}


来源:https://stackoverflow.com/questions/45239364/dot-net-core-custom-model-binding-for-generic-type-parameters-in-mvc-action-meth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!