如何在Model Binder中使用泛型?

时间:2019-03-11 23:19:37

标签: asp.net-core asp.net-core-2.0

在ASP.NET Core上,我具有以下模型:

public class Model {
  public Filter<Int32> filter { get; set; }
}

以下是过滤器:

public class Filter<T> {
  public T Value { get; set; }
  public Filter(T value) {
    Value = value;
  }
} 

public static class Filter {
  public static Boolean TryParse<T>(String value, out Filter<T> filter) {
    // Try parse code
  }
}

我需要创建一个ModelBinder来绑定Filter类型的属性:

public class FilterModelBinder : IModelBinder {

  public Task BindModelAsync(ModelBindingContext bindingContext) {

    if (bindingContext == null)            
      throw new ArgumentNullException(nameof(bindingContext));

    String modelName = bindingContext.ModelName;

    ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

    if (valueProviderResult == ValueProviderResult.None)
      return Task.CompletedTask;

    bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

    String value = valueProviderResult.FirstValue;

    if (String.IsNullOrEmpty(value))
      return Task.CompletedTask;

    if (!Filter.TryParse(value, out Filter<T> filter)) {

      bindingContext.ModelState.TryAddModelError(modelName, "Value is not of type Filter");
      return Task.CompletedTask;

    } 

    bindingContext.Result = ModelBindingResult.Success(filter);
    return Task.CompletedTask;

  }

}

我的问题是如何将TryParse应用于通用过滤器:

Filter.TryParse(value, out Filter<T> filter)

如何在ModelBinder中使用泛型类型?

1 个答案:

答案 0 :(得分:0)

解决方案1 ​​

使用反射调用TryParse

public class FilterModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        //same binder code

        //get filter generic type
        Type filterType = bindingContext.ModelType.GenericTypeArguments.Single();

        if (!TryGetFilter(value, filterType, out object filter))
        {
            bindingContext.ModelState.TryAddModelError(modelName, "Value is not of type Filter");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(filter);
        return Task.CompletedTask;
    }

    private bool TryGetFilter(string value, Type filterType, out object filter)
    {
        var parameters = new object[] { value, null };

        bool result = (bool)typeof(Filter)
           .GetMethod(nameof(Filter.TryParse))
           .MakeGenericMethod(filterType)
           .Invoke(null, parameters);

        filter = parameters[1]; //out parameter is placed here

        return result;
    }
}

解决方案2

介绍接受过滤器类型的TryParse的非通用版本

public static class Filter
{
    public static bool TryParse<T>(string value, out Filter<T> filter)
    {
        bool result = TryParse(value, typeof(T), out object innerFilter);
        filter = (Filter<T>)innerFilter;

        return result;
    }

    public static bool TryParse(string value, Type type, out object filter)
    {
        //parse logic here

    }
}

并在模型活页夹中调用它

//same binder code

//get filter generic type
Type filterType = bindingContext.ModelType.GenericTypeArguments.Single();

if (!Filter.TryParse(value, filterType, out object filter))
{
    bindingContext.ModelState.TryAddModelError(modelName, "Value is not of type Filter");
    return Task.CompletedTask;
}

//same binder code