繁体   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