![](/img/trans.png)
[英]Not able to scaffold a controller in ASP.NET 6 Core Web API
[英]ASP.NET Core Web API controller with generic params
我有一個與顫振移動應用程序通信的 ASP.NET Core Web API。
我要添加的功能是通知服務。 問題是我有不止一種通知類型。
這是代碼:
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; }
}
等等。
我在其參數中使用超泛型類型為通知編寫了一個控制器
[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);
}
問題是當我從顫振應用程序中檢索 JSON 數據時,我只得到NotificationSuper
類的屬性,它們是:
public String Renter_Key { get; set; }
public String Owner_Key { get; set; }
public String Building_Key { get; set; }
如果我通過了UnitNotification
或MaintenanceNotification
,我希望有一種靈活的方式來獲取每個屬性。 我應該有多個控制器,每種類型的通知一個嗎?
提前致謝
您可以結合您的UnitNotification
和MaintenanceNotification
它應該看起來像這樣
public class CombinedNotification
{
public UnitNotification unitNotification { get; set; }
public MaintenanceNotification maintenanceNotification{ get; set; }
}
然后您的控制器代碼應如下所示:
[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);
}
重要的是您的帖子數據現在必須從: unitNotification
更改為{"unitNotification": {}}
這里有一個比較靈活的方法,我用的是Polymorphic model binding
,可以參考這個簡單的demo:
模型
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; }
}
模型綁定代碼
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需要來自form的數據,如果需要來自request body的數據,需要修改DeviceModelBinder
中的一些代碼,並且父類需要一個屬性來指定子類的類名。
請參閱文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.