【问题标题】:dotnet core webapi json-api compliant querystring routedotnet core webapi json-api 兼容查询字符串路由
【发布时间】:2017-03-26 11:58:11
【问题描述】:

我试图从请求的 URL 中获取“状态”和“全部”键、值,但不知道如何构建我的类对象。

我所指的 JSON API 规范可以在这里找到: http://jsonapi.org/recommendations/#filtering

// requested url
/api/endpoint?filter[status]=all


// my attempt at model binding
public class FilterParams
{
    public Dictionary<string, string> Filter { get; set; }
}

[HttpGet]
public string Get([FromUri] FilterParams filter)
{
    // never gets populated...
    var filterStatus = filter.Filter["status"];
}

【问题讨论】:

    标签: c# asp.net-web-api asp.net-web-api2 json-api .net-core


    【解决方案1】:

    如果您在 .Net Core 上构建 json:api 应用程序,我强烈建议您查看这个库:https://github.com/json-api-dotnet/JsonApiDotNetCore

    它为您处理所有繁重的工作,对于这个特定示例,(您需要获取过滤器值)解决方案如下所示:

    public FooController : JsonApiController<Foo> {
        private readonly IQueryAccessor _queryAccessor;
        public FooController(IQueryAccessor queryAccessor, /* ... */) 
        : base(/* ... */) {
           _queryAccessor = queryAccessor;
        }
    
        [HttpGet]
        public override async Task<IActionResult> GetAsync() {
            var status = _queryAccessor.GetRequired<string>("status");
            // ...
        }
    }
    

    【讨论】:

      【解决方案2】:
      1. 您可以为此使用IModelBinder

        • 定义模型绑定器:

          public class FilterParamsModelBinder : IModelBinder
          {
              public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
              {
                  if (bindingContext.ModelType != typeof(FilterParams)) return false;
          
                  Dictionary<string, string> result = new Dictionary<string, string>();
          
                  var parameters = actionContext.Request.RequestUri.Query.Substring(1);
          
                  if(parameters.Length == 0) return false;
          
                  var regex = new Regex(@"filter\[(?<key>[\w]+)\]=(?<value>[\w^,]+)");
          
                  parameters
                      .Split('&')
                      .ToList()
                      .ForEach(_ =>
                      {
                          var groups = regex.Match(_).Groups;
          
                          if(groups.Count == 0)
                              bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value.");
          
                          result.Add(groups["key"].Value, groups["value"].Value);
                      });
          
                  bindingContext.Model = new FilterParams { Filter = result};
          
                  return bindingContext.ModelState.IsValid;
              }
          }
          
        • 使用它:

          [HttpGet]
          public string Get([ModelBinderAttribute(typeof(FilterParamsModelBinder))] FilterParams filter)
          {
            //your code
          }
          
      2. 如果您可以定义类似“/api/endpoint?filter=status,all”的路由,则可以使用TypeConverter

        • 定义一个转换器:

          public class FilterConverter : TypeConverter
          {
              public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
              {
                  if (!(value is string)) return base.ConvertFrom(context, culture, value);
          
                  var keyValue = ((string)value).Split(',');
          
                  return new FilterParams 
                  {
                      Filter = new Dictionary<string, string> { [keyValue[0]] = keyValue[1] } 
                  };
              }
          
              public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
              {
                 return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
              }            
          }
          
        • 使用它:

          [TypeConverter(typeof(FilterConverter))]
          public class FilterParams
          {
              public Dictionary<string, string> Filter { get; set; }
          }
          
          [HttpGet]
          public string Get(FilterParams filter)
          {
              var filterStatus = filter.Filter["status"]; 
          }
          

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2020-04-26
      • 2021-09-07
      • 2015-04-12
      • 1970-01-01
      相关资源
      最近更新 更多