C# “的自定义数据类型”;HttpGet“;Asp.NETWebAPI项目中的路由
我尝试在HttpGet路由中添加一个“customdata type”变量 我有以下代码:C# “的自定义数据类型”;HttpGet“;Asp.NETWebAPI项目中的路由,c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,我尝试在HttpGet路由中添加一个“customdata type”变量 我有以下代码: [HttpGet("{idObject}")] public ResponseSchema Get(ObjectId idObject) { if (idObject == null) { throw new BodyParseException(); } var user = _usersLogic.GetById(idObject); if (use
[HttpGet("{idObject}")]
public ResponseSchema Get(ObjectId idObject)
{
if (idObject == null) {
throw new BodyParseException();
}
var user = _usersLogic.GetById(idObject);
if (user == null) {
_response.Success = false;
_response.ErrorCode = "UserDoesNotExist";
}
else {
_response.Objects.Add(user);
}
return _response;
}
ObjectId是在using MongoDB.Bson中定义的数据类型
对于Json序列化和反序列化,我们已经有了在两侧自动转换的代码。但在Url本身中也可以这样做
我们现在正在使用此Mvc版本:
"Microsoft.AspNet.Mvc": "6.0.0-beta8"
因此,URL如下所示:
GET Users/55b795827572761a08d735ac
将其从“字符串”解析为“ObjectId”的代码是:
问题是要把那个锥虫密码放在哪里。因为我需要告诉ASP.NET它应该如何将idObject从字符串解析为ObjectId。因为URL基本上是一个字符串
对于Post或Put JSON负载,我已经找到了一个解决方案。我知道这是不一样的。但了解该场景或找到该场景的解决方案可能会有所帮助:
public class EntityBaseDocument
{
[JsonConverter(typeof(ObjectIdConverter))]
public ObjectId Id { get; set; }
}
// Since we have this value converter. We can use ObjectId everywhere
public class ObjectIdConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
return new ObjectId(token.ToObject<string>());
}
public override bool CanConvert(Type objectType)
{
return typeof(ObjectId).IsAssignableFrom(objectType);
}
}
公共类EntityBaseDocument
{
[JsonConverter(类型(ObjectdConverter))]
公共对象Id{get;set;}
}
//因为我们有这个值转换器。我们可以在任何地方使用ObjectId
公共类ObjectdConverter:JsonConverter
{
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
serializer.Serialize(writer,value.ToString());
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
JToken令牌=JToken.Load(读卡器);
返回新的ObjectId(token.ToObject());
}
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(ObjectId).IsAssignableFrom(objectType);
}
}
这将从Uri对象绑定它:
public ResponseSchema Get([FromUri]ObjectId idObject)
所以:?param1=something¶m2=something其他
这将从主体(例如JSon对象)绑定它
或者您也可以自己滚动:
public ResponseSchema Get([ModelBinder(typeof(MyObjectBinder))]ObjectId idObject)
模型活页夹的示例如下:
public class GeoPointModelBinder : IModelBinder
{
// List of known locations.
private static ConcurrentDictionary<string, GeoPoint> _locations
= new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);
static GeoPointModelBinder()
{
_locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
_locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
_locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
}
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(GeoPoint))
{
return false;
}
ValueProviderResult val = bindingContext.ValueProvider.GetValue(
bindingContext.ModelName);
if (val == null)
{
return false;
}
string key = val.RawValue as string;
if (key == null)
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Wrong value type");
return false;
}
GeoPoint result;
if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
{
bindingContext.Model = result;
return true;
}
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Cannot convert value to Location");
return false;
}
}
公共类GeoPointModelBinder:IModelBinder
{
//已知地点的清单。
私有静态ConcurrentDictionary\u位置
=新的ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
静态地质点模型绑定器()
{
_地点[“redmond”]=新的地质点(){纬度=47.67856,经度=-122.131};
_地点[“巴黎”]=新地理点(){纬度=48.856930,经度=2.3412};
_地点[“东京”]=新地理点(){纬度=35.683208,经度=139.80894};
}
public bool BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext)
{
if(bindingContext.ModelType!=typeof(地质点))
{
返回false;
}
ValueProviderResult val=bindingContext.ValueProvider.GetValue(
bindingContext.ModelName);
if(val==null)
{
返回false;
}
字符串键=val.RawValue作为字符串;
if(key==null)
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,“错误的值类型”);
返回false;
}
地质点成果;
if(_locations.TryGetValue(键,输出结果)| | GeoPoint.TryParse(键,输出结果))
{
bindingContext.Model=result;
返回true;
}
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,“无法将值转换为位置”);
返回false;
}
}
我相信NikoliaDante的答案在您有/api/users?id={{idHere}这样的路由的情况下有效。然而,如果您希望有更多的RESTful路由,下面的解决方案将为您提供解决方案。我刚刚在一个WebAPI2应用程序中对此进行了测试,效果很好。这将处理这样的用例:您可能有一个路由,比如/api/users/{{userId}}/something/{{somethingId}}
//Http Parameter Binding Magic
public class ObjectIdParameterBinding : HttpParameterBinding
{
public ObjectIdParameterBinding(HttpParameterDescriptor p) : base(p){ }
public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var value = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName].ToString();
SetValue(actionContext, ObjectId.Parse(value));
var tsc = new TaskCompletionSource<object>();
tsc.SetResult(null);
return tsc.Task;
}
}
//Binding Attribute
public class ObjectIdRouteBinderAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new ObjectIdParameterBinding(parameter);
}
}
//Controller Example
[Route("api/users/{id}")]
public async Task<User> Get([ObjectIdRouteBinder] ObjectId id)
{
//Yay!
}
//Http参数绑定魔法
公共类ObjectdParameterBinding:HttpParameterBinding
{
公共ObjectdParameterBinding(HttpParameterDescriptor p):基(p){}
公共覆盖任务ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider、HttpActionContext actionContext、System.Threading.CancellationToken CancellationToken)
{
var value=actionContext.ControllerContext.RoutedData.Values[Descriptor.ParameterName].ToString();
SetValue(actionContext,ObjectId.Parse(value));
var tsc=new TaskCompletionSource();
tsc.SetResult(空);
返回tsc任务;
}
}
//绑定属性
公共类ObjectDuloteBinderAttribute:ParameterBindingAttribute
{
公共重写HttpParameterBinding GetBinding(HttpParameterDescriptor参数)
{
返回新的ObjectdParameterBinding(参数);
}
}
//控制器示例
[路由(“api/users/{id}”)]
公共异步任务Get([ObjectDuloteBinder]ObjectId)
{
//耶!
}
FromUri对于我的场景来说是不够的。我需要告诉ASP.NET如何将URL GET/Users/55b795827572761a08d735ac中给定的参数转换为ObjectId。这就是我需要BindModel的原因吗?@Matthias用于更复杂的映射,这些映射无法通过FromUri
或FromBody
推断。绑定器是保证事情按需要进行的方式。因此,“绑定器”可以用于我的URL,就像JSON转换器用于我的JSON负载一样。我将尝试实现BindModel。我还没有机会检查它,但我现在接受并投票。
public class GeoPointModelBinder : IModelBinder
{
// List of known locations.
private static ConcurrentDictionary<string, GeoPoint> _locations
= new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);
static GeoPointModelBinder()
{
_locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
_locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
_locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
}
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(GeoPoint))
{
return false;
}
ValueProviderResult val = bindingContext.ValueProvider.GetValue(
bindingContext.ModelName);
if (val == null)
{
return false;
}
string key = val.RawValue as string;
if (key == null)
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Wrong value type");
return false;
}
GeoPoint result;
if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
{
bindingContext.Model = result;
return true;
}
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Cannot convert value to Location");
return false;
}
}
//Http Parameter Binding Magic
public class ObjectIdParameterBinding : HttpParameterBinding
{
public ObjectIdParameterBinding(HttpParameterDescriptor p) : base(p){ }
public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var value = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName].ToString();
SetValue(actionContext, ObjectId.Parse(value));
var tsc = new TaskCompletionSource<object>();
tsc.SetResult(null);
return tsc.Task;
}
}
//Binding Attribute
public class ObjectIdRouteBinderAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new ObjectIdParameterBinding(parameter);
}
}
//Controller Example
[Route("api/users/{id}")]
public async Task<User> Get([ObjectIdRouteBinder] ObjectId id)
{
//Yay!
}