簡體   English   中英

具有通用參數的 ASP.NET 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; }

如果我通過了UnitNotificationMaintenanceNotification ,我希望有一種靈活的方式來獲取每個屬性。 我應該有多個控制器,每種類型的通知一個嗎?

提前致謝

您可以結合您的UnitNotificationMaintenanceNotification

它應該看起來像這樣

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM