Web API 项目中“HttpGet”路由 Asp.Net 自定义数据类型
本文关键字:Asp 路由 Net 定义数据类型 HttpGet API 项目 Web | 更新日期: 2023-09-27 18:31:44
我尝试在我的HttpGet Route中添加一个"自定义数据类型"的变量。
我有这个代码:
[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 是使用 MongoDB.Bson 定义的数据类型。
对于 Json 序列化和反序列化,我们已经有了在两端自动转换的代码。但是这可以在 URL 本身中类似地完成吗?
我们现在正在使用这个 Mvc 版本:
"Microsoft.AspNet.Mvc": "6.0.0-beta8"
所以网址看起来像这样:
GET Users/55b795827572761a08d735ac
将其从"字符串"解析为"ObjectId"的代码是:
ObjectId.TryParse(idString, out idObject);
问题是将TryParse代码放在哪里。因为我需要告诉 ASP.NET 它应该如何将idObject从String解析为ObjectId。由于URL基本上是一个字符串。
对于发布或放置 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);
}
}
从 Uri 对象绑定它:
public ResponseSchema Get([FromUri]ObjectId idObject)
所以:?param1=something¶m2=sometingelse
这将从主体(例如 JSon 对象)绑定它
public ResponseSchema Get([FromBody]ObjectId idObject)
或者你可以自己滚动:
public ResponseSchema Get([ModelBinder(typeof(MyObjectBinder))]ObjectId idObject)
模型绑定程序 asp.net 的示例如下:
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;
}
}
我相信NikoliaDante的答案如果你有像/api/users?id={{idHere}}这样的路线,就会起作用。但是,如果您希望拥有更多的 RESTful 路线,下面的解决方案将为您解决问题。我刚刚在 Web API 2 应用程序中对此进行了测试,它运行良好。这将处理您可能有路由的用例,例如/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!
}
ASP.NET Web API 提供了几种方法来执行此操作。看看Web API 文档中的参数绑定。
总结:
-
FromUriAttribute
- 用于简单的 DTO 类 -
TypeConverter
- 帮助 Web API 将类视为简单类型 -
HttpParameterBinding
- 允许创建行为属性 -
ValueProvider
- 适用于更复杂的情况 -
IActionValueBinder
- 编写自己的参数绑定过程