从包含冒号 (:) 的查询参数名称中读取值
Reading a value from a Query parameter name containing a colon (:)
我收到在 .NET 应用程序中创建新 REST API 的请求,但我不知道如何实现其中一个参数。
我得到了一个Swagger定义,参数定义如下:
如果它只是 eventCreatedDateTime=2021-04-01T14:12:56+01:00
没问题,但它正在获取冒号和等号之间的部分,我不知道如何获取。
基本上,我可以获得 eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00
作为查询字符串参数,我必须阅读 gte
部分并且还能够验证它是否是允许的后缀之一。后缀不是强制性的,因此 eventCreatedDateTime=2021-04-01T14:12:56+01:00
也应该有效。
为了澄清,这是一个查询字符串参数,所以是 URL 的一部分。
例如https://example.com/api/mycontroller?param1=value¶m2=value&eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00¶m4=value
知道如何在 .NET 中执行此操作吗?
为此,我将使用自定义类型,例如:
public class EventCreatedDateTime
{
public string Operator { get; set; }
public string Value { get; set; }
}
接下来我将创建一个自定义模型活页夹:
public class EventCreatedDateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if(context.Metadata.ModelType == typeof(EventCreatedDateTime))
{
return new EventCreatedDateTimeModelBinder();
}
return null;
}
}
public class EventCreatedDateTimeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
foreach(var kvp in bindingContext.HttpContext.Request.Query)
{
if (kvp.Key.StartsWith("eventCreatedDateTime:"))
{
bindingContext.Result = ModelBindingResult.Success(
new EventCreatedDateTime {
Operator = kvp.Key.Substring("eventCreatedDateTime:".Length),
Value = kvp.Value.First()
});
}
}
return Task.CompletedTask;
}
}
我在启动中添加:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
options.ModelBinderProviders.Insert(0, new EventCreatedDateTimeModelBinderProvider())
);
...
}
}
那么动作就是:
[HttpGet]
public IActionResult Get(
string param1,
string param2,
EventCreatedDateTime eventCreatedDateTime)
{...}
请参阅 vernou 对 .NET Core 方法的回应。
我的环境仍然是框架,所以这是解决方案。
我的自定义类型有点不同,有一个 DateTime 和一个枚举器 属性,这当然也可以在 Core 中使用:
public enum Operator
{
Equals,
GreaterThenEquals,
GreaterThen,
LesserThenEquals,
LesserThen
}
public class DateTimeFilter
{
public DateTime? Date { get; set; }
public Operator Operator { get; set; }
}
框架中的自定义模型绑定器有点不同:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ModelBinding.Binders;
namespace CustomModelBinders
{
public class DateTimeFilterModelBinderProvider : ModelBinderProvider
{
private CollectionModelBinderProvider originalProvider = null;
public DateTimeFilterModelBinderProvider(CollectionModelBinderProvider originalProvider)
{
this.originalProvider = originalProvider;
}
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
IModelBinder originalBinder = originalProvider.GetBinder(configuration, modelType);
if (originalBinder != null && modelType == typeof(DateTimeFilter))
{
return new DateTimeFilterModelBinder();
}
return null;
}
}
public class DateTimeFilterModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(DateTimeFilter))
{
return false;
}
//Get's the correct key/value from the querystring based on your receiving paramter name.
//note: you can't use [FromUri(Name = "customName")] with the custom binder so the have to match (partially)
var query = actionContext.Request.Properties["MS_QueryNameValuePairs"] as ICollection<KeyValuePair<string, string>>;
KeyValuePair<string, string> kvp = query.First(q => q.Key.Contains(bindingContext.ModelName));
if (kvp.Key.Contains(":"))
{
bindingContext.Model =
new DateTimeFilter
{
Operator = ConvertOperator(kvp.Key.Substring(kvp.Key.IndexOf(":")+1)),
Date = ConvertDate(kvp.Value)
};
}
else
{
bindingContext.Model =
new DateTimeFilter
{
Operator = Operator.Equals,
Date = ConvertDate(kvp.Value)
};
}
return true;
}
private DateTime? ConvertDate(string str)
{
DateTime result;
DateTimeOffset resultOffset;
if (DateTime.TryParse(str, out result))
return result;
//Apparently the + gets converted into a space, so we need to revert that to have a valid offset
else if (DateTimeOffset.TryParse(str.Replace(' ', '+'), out resultOffset))
return resultOffset.ToLocalTime().DateTime;
else
return null;
}
private Operator ConvertOperator(string str)
{
switch (str.ToLowerInvariant())
{
case "gte": return Operator.GreaterThenEquals;
case "gt": return Operator.GreaterThen;
case "lte": return Operator.LesserThenEquals;
case "lt": return Operator.LesserThen;
case "eq": return Operator.Equals;
default: throw new ArgumentException("Invalid operator");
}
}
}
}
转换方法非常适合在核心应用程序中使用
Framework 中没有启动,参数必须通过属性耦合到绑定器:
[HttpGet]
public IHttpActionResult Get(string param1 = null, string param2 = null, [ModelBinder(typeof(DateTimeFilterModelBinder))] DateTimeFilter eventCreatedDateTime = null, string param3 = null)
{
//Do Logic
}
以上对于 eventCreatedDateTime=2021-04-01T14:12:56+01:00 按预期工作
例如 eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00
我收到在 .NET 应用程序中创建新 REST API 的请求,但我不知道如何实现其中一个参数。
我得到了一个Swagger定义,参数定义如下:
如果它只是 eventCreatedDateTime=2021-04-01T14:12:56+01:00
没问题,但它正在获取冒号和等号之间的部分,我不知道如何获取。
基本上,我可以获得 eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00
作为查询字符串参数,我必须阅读 gte
部分并且还能够验证它是否是允许的后缀之一。后缀不是强制性的,因此 eventCreatedDateTime=2021-04-01T14:12:56+01:00
也应该有效。
为了澄清,这是一个查询字符串参数,所以是 URL 的一部分。
例如https://example.com/api/mycontroller?param1=value¶m2=value&eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00¶m4=value
知道如何在 .NET 中执行此操作吗?
为此,我将使用自定义类型,例如:
public class EventCreatedDateTime
{
public string Operator { get; set; }
public string Value { get; set; }
}
接下来我将创建一个自定义模型活页夹:
public class EventCreatedDateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if(context.Metadata.ModelType == typeof(EventCreatedDateTime))
{
return new EventCreatedDateTimeModelBinder();
}
return null;
}
}
public class EventCreatedDateTimeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
foreach(var kvp in bindingContext.HttpContext.Request.Query)
{
if (kvp.Key.StartsWith("eventCreatedDateTime:"))
{
bindingContext.Result = ModelBindingResult.Success(
new EventCreatedDateTime {
Operator = kvp.Key.Substring("eventCreatedDateTime:".Length),
Value = kvp.Value.First()
});
}
}
return Task.CompletedTask;
}
}
我在启动中添加:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
options.ModelBinderProviders.Insert(0, new EventCreatedDateTimeModelBinderProvider())
);
...
}
}
那么动作就是:
[HttpGet]
public IActionResult Get(
string param1,
string param2,
EventCreatedDateTime eventCreatedDateTime)
{...}
请参阅 vernou 对 .NET Core 方法的回应。 我的环境仍然是框架,所以这是解决方案。
我的自定义类型有点不同,有一个 DateTime 和一个枚举器 属性,这当然也可以在 Core 中使用:
public enum Operator
{
Equals,
GreaterThenEquals,
GreaterThen,
LesserThenEquals,
LesserThen
}
public class DateTimeFilter
{
public DateTime? Date { get; set; }
public Operator Operator { get; set; }
}
框架中的自定义模型绑定器有点不同:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ModelBinding.Binders;
namespace CustomModelBinders
{
public class DateTimeFilterModelBinderProvider : ModelBinderProvider
{
private CollectionModelBinderProvider originalProvider = null;
public DateTimeFilterModelBinderProvider(CollectionModelBinderProvider originalProvider)
{
this.originalProvider = originalProvider;
}
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
IModelBinder originalBinder = originalProvider.GetBinder(configuration, modelType);
if (originalBinder != null && modelType == typeof(DateTimeFilter))
{
return new DateTimeFilterModelBinder();
}
return null;
}
}
public class DateTimeFilterModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(DateTimeFilter))
{
return false;
}
//Get's the correct key/value from the querystring based on your receiving paramter name.
//note: you can't use [FromUri(Name = "customName")] with the custom binder so the have to match (partially)
var query = actionContext.Request.Properties["MS_QueryNameValuePairs"] as ICollection<KeyValuePair<string, string>>;
KeyValuePair<string, string> kvp = query.First(q => q.Key.Contains(bindingContext.ModelName));
if (kvp.Key.Contains(":"))
{
bindingContext.Model =
new DateTimeFilter
{
Operator = ConvertOperator(kvp.Key.Substring(kvp.Key.IndexOf(":")+1)),
Date = ConvertDate(kvp.Value)
};
}
else
{
bindingContext.Model =
new DateTimeFilter
{
Operator = Operator.Equals,
Date = ConvertDate(kvp.Value)
};
}
return true;
}
private DateTime? ConvertDate(string str)
{
DateTime result;
DateTimeOffset resultOffset;
if (DateTime.TryParse(str, out result))
return result;
//Apparently the + gets converted into a space, so we need to revert that to have a valid offset
else if (DateTimeOffset.TryParse(str.Replace(' ', '+'), out resultOffset))
return resultOffset.ToLocalTime().DateTime;
else
return null;
}
private Operator ConvertOperator(string str)
{
switch (str.ToLowerInvariant())
{
case "gte": return Operator.GreaterThenEquals;
case "gt": return Operator.GreaterThen;
case "lte": return Operator.LesserThenEquals;
case "lt": return Operator.LesserThen;
case "eq": return Operator.Equals;
default: throw new ArgumentException("Invalid operator");
}
}
}
}
转换方法非常适合在核心应用程序中使用
Framework 中没有启动,参数必须通过属性耦合到绑定器:
[HttpGet]
public IHttpActionResult Get(string param1 = null, string param2 = null, [ModelBinder(typeof(DateTimeFilterModelBinder))] DateTimeFilter eventCreatedDateTime = null, string param3 = null)
{
//Do Logic
}
以上对于 eventCreatedDateTime=2021-04-01T14:12:56+01:00 按预期工作
例如 eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00