模型绑定器提供商应该被视为服务定位器吗?

时间:2015-03-24 11:38:42

标签: c# asp.net design-patterns asp.net-web-api model-binding

我想为可查询的web api提供一些自定义模型绑定,即以下接口:

  • IQueryOptions`1
  • ISortingOptions`2实施IQueryOptions`1
  • IPagingOptions`2实施ISortingOptions`2

根据控制器操作中指定的参数,我想提供正确的模型绑定器。

public void Test([ModelBinding] IPagingOptions<MyEntity, int> pagingOptions)
   // -> PagingOptionsModelBinder

我的问题是:每个模型绑定器是否应该有一个模型绑定器提供程序,或者模型绑定器是否应该作为服务定位器工作,并为每个要绑定的类型提供模型绑定器?

e.g ..

public QueryOptionsModelBinderProvider : ModelBinderProvider {

   public override IModelBinder GetBinder(HttpConf...
      if(modelType.IsOfGeneric((typeof(ISortingOptions<,>))
         return new SortingOptionsModelBinder();
      if(modelType.IsOfGeneric((typeof(IPagingOptions<,>))
         return new PagingOptionsModelBinder();
   ...

...或

public SortingOptionsModelBinderProvider

public PagingOptionsModelBinderProvider

// etc.

我问这个是因为一方面,服务定位是一个(可怕的,恕我直言)反模式,因为对于每个要绑定的新类型,我需要改变模型绑定器提供者,但另一方面,如果它不是'在这里完成,找到合适的提供者的责任只是委托给ASP.NET WebApi,我需要每次都注册一个新的提供者。

1 个答案:

答案 0 :(得分:2)

我曾经看过一个聪明的方式(不记得在哪里,当我找到它时我会赞同它)是创建一个通用的模型绑定器:

public class EntityModelBinder<TEntity> 
    : IModelBinder
    where TEntity : Entity
{
    private readonly IRepository<TEntity> _repository;

    public EntityModelBinder(IRepository<TEntity> repository)
    {
        _repository = repository;
    }

    public object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        ValueProviderResult value = bindingContext
            .ValueProvider.GetValue(bindingContext.ModelName);

        var id = Guid.Parse(value.AttemptedValue);

        var entity = _repository.GetById(id);

        return entity;
    }
}

然后在提供者中使用反射:

public class EntityModelBinderProvider
    : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        if (!typeof(Entity).IsAssignableFrom(modelType))
            return null;

        Type modelBinderType = typeof(EntityModelBinder<>)
            .MakeGenericType(modelType);

        var modelBinder = ObjectFactory.GetInstance(modelBinderType);

        return (IModelBinder) modelBinder;
    }
}

之后,您只需注册一个永不改变的提供商。