[英]ASP.NET Core Web API controller with generic params
I have an ASP.NET Core Web API communicating with a flutter mobile app.我有一个与颤振移动应用程序通信的 ASP.NET Core Web API。
The feature I am adding is a notification service.我要添加的功能是通知服务。 The issue is I have more than one notification type.
问题是我有不止一种通知类型。
Here is the code:这是代码:
public class NotificationSuper
{
public string Title { get; set; }
public string Body { get; set; }
public string Token { get; set; }
public string Type { get; set; }
}
public class UnitNotification :NotificationSuper
{
public String Renter_Key { get; set; }
public String Owner_Key { get; set; }
public String Building_Key { get; set; }
public String Unit_Key { get; set; }
}
public class MaintenanceNotification : UnitNotification
{
public DateTime RequestData { get; set; }
}
and so on.等等。
I wrote a controller for the notification using a super generic type in its params我在其参数中使用超泛型类型为通知编写了一个控制器
[HttpPost]
public async Task<IActionResult> Post([FromBody] NotificationSuper notification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
bool success = await Notify.Send(notification);
if (success)
{
return Ok();
}
return StatusCode(500);
}
The problem is when I retrieve the JSON data from the flutter app, I only get the properties of the NotificationSuper
class which are:问题是当我从颤振应用程序中检索 JSON 数据时,我只得到
NotificationSuper
类的属性,它们是:
public String Renter_Key { get; set; }
public String Owner_Key { get; set; }
public String Building_Key { get; set; }
I want to have a flexible way to get every property if I passed UnitNotification
or MaintenanceNotification
.如果我通过了
UnitNotification
或MaintenanceNotification
,我希望有一种灵活的方式来获取每个属性。 Should I have multiple controllers, one for each type of notification?我应该有多个控制器,每种类型的通知一个吗?
Thanks in advance提前致谢
You can combine your UnitNotification
and MaintenanceNotification
您可以结合您的
UnitNotification
和MaintenanceNotification
It should look like this它应该看起来像这样
public class CombinedNotification
{
public UnitNotification unitNotification { get; set; }
public MaintenanceNotification maintenanceNotification{ get; set; }
}
Then your controller code should look like this:然后您的控制器代码应如下所示:
[HttpPost]
public async Task<IActionResult> Post([FromBody] CombinedNotification notification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
bool success;
if (notification.UnitNotification != null)
{
bool success = await Notify.Send(notification.UnitNotification);
}
if (notification.MaintenanceNotification != null)
{
bool success = await Notify.Send(notification.MaintenanceNotification);
}
if (success)
{
return Ok();
}
return StatusCode(500);
}
The important thing is your post data now must be changed from: unitNotification
to {"unitNotification": {}}
重要的是您的帖子数据现在必须从:
unitNotification
更改为{"unitNotification": {}}
Here is a more flexible method, I use Polymorphic model binding
, You can refer to this simple demo:这里有一个比较灵活的方法,我用的是
Polymorphic model binding
,可以参考这个简单的demo:
Model模型
public abstract class Device
{
public string Kind { get; set; }
public string Name { get; set; }
}
public class Laptop : Device
{
public string CPUIndex { get; set; }
public string Price { get; set; }
}
public class SmartPhone : Device
{
public string ScreenSize { get; set; }
}
Model Binding Code模型绑定代码
public class DeviceModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(Device))
{
return null;
}
var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelKindName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(Device.Kind));
var modelTypeValue = bindingContext.ValueProvider.GetValue(modelKindName).FirstValue;
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (modelTypeValue == "Laptop")
{
(modelMetadata, modelBinder) = binders[typeof(Laptop)];
}
else if (modelTypeValue == "SmartPhone")
{
(modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
modelMetadata,
bindingInfo: null,
bindingContext.ModelName);
await modelBinder.BindModelAsync(newBindingContext);
bindingContext.Result = newBindingContext.Result;
if (newBindingContext.Result.IsModelSet)
{
// Setting the ValidationState ensures properties on derived types are correctly
bindingContext.ValidationState[newBindingContext.Result.Model] = new ValidationStateEntry
{
Metadata = modelMetadata,
};
}
}
}
Demo:演示:
Notice: This demo needs data from form , If you need data from request body , You need to change some code in DeviceModelBinder
And parent class needs a property to specify the class name of the subclass.注意:这个demo需要来自form的数据,如果需要来自request body的数据,需要修改
DeviceModelBinder
中的一些代码,并且父类需要一个属性来指定子类的类名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.