如何为自定义类型创建 asp.net 控制器自动绑定属性?
How can I make an asp.net controller auto bind properties for a custom type?
我在 dotnet 控制器上有一个这样的方法
[HttpGet()]
public async Task<IActionResult> GetCar(
[FromQuery] GetCarFilter filters
)
使用如下所示的 GetCarFilter class
public class GetCarFilter
{
public GetCarFilter()
{
}
public string? SearchTerm { get; set; }
public int NumberOfWheels { get; set; }
public bool HasHeadLights { get; set; }
public ObjectId ModelId { get; set; }
}
使用这样的查询字符串
http://somedomain.com/cars?NumberOfWheels=4&HasHeadlights=true?ModelId=623c79ac554f9d15425f93c2
Dotnet 将自动从查询字符串中提取值,并通过非 ObjectId(来自 MongoDB C# 驱动程序)将它们转换为某些属性的整数和布尔值
我试过创建自定义类型转换器并将其添加到 属性 中,就像这样
[TypeConverter(typeof(MyObjectIdConverter))]
public ObjectId ModelId { get; set; }
但它从不调用我的代码。 dotnet 可以通过某种方式获取 NumberOfWheels 和 HasHeadLights 的查询字符串值,并将它们转换为 int 和 bool,但不会对我的 ModelId 执行相同的操作。有什么方法可以告诉 dotnet 这是一个 ObjectId 并且这是从字符串转换它的方式吗?
试试这个
.....
public string modelId { get; set; }
public ObjectId ModelId { get { return new ObjectId(modelId ); } }
发现 asp.net 核心正在使用模型绑定器,您可以 build your own。
只需创建一个 class 工具 IModelBinder
public class ObjectIdModelBinder : IModelBinder
{
public ObjectIdModelBinder()
{
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!ObjectId.TryParse(value, out var id))
{
// Not a valid object id
bindingContext.ModelState.TryAddModelError(
modelName, $"{modelName} must be a valid Mongo Object Id string.");
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(id);
return Task.CompletedTask;
}
}
然后用MVC/WebAPI
注册
services.AddControllers(config =>
{
config.ModelBinderProviders.Insert(0, new ObjectIdModelBinderProvider());
});
一定要插入而不是添加,因为默认情况下 asp.net 会在列表末尾放置一个 catchall 活页夹。 如果您添加,您的活页夹将放在后面这个包罗万象,永远不会被调用。
执行此操作后,任何标有 FromBody、FromQueryString、FromRoute、FromHeader、FromForm 的控制器参数都将自动转换。它甚至可以让您在转换失败时提供验证错误!
我在 dotnet 控制器上有一个这样的方法
[HttpGet()]
public async Task<IActionResult> GetCar(
[FromQuery] GetCarFilter filters
)
使用如下所示的 GetCarFilter class
public class GetCarFilter
{
public GetCarFilter()
{
}
public string? SearchTerm { get; set; }
public int NumberOfWheels { get; set; }
public bool HasHeadLights { get; set; }
public ObjectId ModelId { get; set; }
}
使用这样的查询字符串
http://somedomain.com/cars?NumberOfWheels=4&HasHeadlights=true?ModelId=623c79ac554f9d15425f93c2
Dotnet 将自动从查询字符串中提取值,并通过非 ObjectId(来自 MongoDB C# 驱动程序)将它们转换为某些属性的整数和布尔值
我试过创建自定义类型转换器并将其添加到 属性 中,就像这样
[TypeConverter(typeof(MyObjectIdConverter))]
public ObjectId ModelId { get; set; }
但它从不调用我的代码。 dotnet 可以通过某种方式获取 NumberOfWheels 和 HasHeadLights 的查询字符串值,并将它们转换为 int 和 bool,但不会对我的 ModelId 执行相同的操作。有什么方法可以告诉 dotnet 这是一个 ObjectId 并且这是从字符串转换它的方式吗?
试试这个
.....
public string modelId { get; set; }
public ObjectId ModelId { get { return new ObjectId(modelId ); } }
发现 asp.net 核心正在使用模型绑定器,您可以 build your own。
只需创建一个 class 工具 IModelBinder
public class ObjectIdModelBinder : IModelBinder
{
public ObjectIdModelBinder()
{
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!ObjectId.TryParse(value, out var id))
{
// Not a valid object id
bindingContext.ModelState.TryAddModelError(
modelName, $"{modelName} must be a valid Mongo Object Id string.");
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(id);
return Task.CompletedTask;
}
}
然后用MVC/WebAPI
注册services.AddControllers(config =>
{
config.ModelBinderProviders.Insert(0, new ObjectIdModelBinderProvider());
});
一定要插入而不是添加,因为默认情况下 asp.net 会在列表末尾放置一个 catchall 活页夹。 如果您添加,您的活页夹将放在后面这个包罗万象,永远不会被调用。
执行此操作后,任何标有 FromBody、FromQueryString、FromRoute、FromHeader、FromForm 的控制器参数都将自动转换。它甚至可以让您在转换失败时提供验证错误!