按后置值类型划分的C#WebAPI路由

按后置值类型划分的C#WebAPI路由,c#,post,asp.net-web-api,C#,Post,Asp.net Web Api,我请求创建一个Web API,该API能够接受POST请求,并根据参数中接收的数据类型(DataAvailableNotification与ExpiredNotification)采取不同的操作 我创建了一个ApicController并公开了两种方法: [HttpPost] public void DataAvailable(DataAvailableNotification dataAvailable, [FromUri] string book, [From

我请求创建一个Web API,该API能够接受POST请求,并根据参数中接收的数据类型(DataAvailableNotification与ExpiredNotification)采取不同的操作

我创建了一个ApicController并公开了两种方法:

    [HttpPost]
    public void DataAvailable(DataAvailableNotification dataAvailable,
        [FromUri] string book, [FromUri] string riskType)
    {

    }

    [HttpPost]
    public void DataAvailable(ExpiredNotification dataAvailable,
        [FromUri] string book, [FromUri] string riskType)
    {

    }

public class DataAvailableNotification
{
    [JsonProperty(PropertyName = "$type")]
    public string RdfType { get { return "App.RRSRC.Feeds.DataAvailable"; } }

    public string SnapshotRevisionId { get; set; }

    public string[] URLs { get; set; }

    public string ConsumerId { get; set; }

    public Guid ChannelId { get; set; }
}

public class ExpiredNotification
{
    [JsonProperty(PropertyName = "$type")]
    public string RdfType { get { return "Service.Feeds.Expired"; } }

    public string ConsumerId { get; set; }

    public Guid ChannelId { get; set; }
}
然而,他们根本没有接到电话

如果我注释掉其中一个,通知将到达控制器,但我无法正确处理通知类型(假设两个通知将映射到同一个方法)

有没有办法配置Web API来查看发布值的类型并调用最佳匹配控制器方法


PS:我不能有两个不同的URL来处理不同的通知。因此,请不要建议这样做。

根据类型使用一个操作和过滤器。 我通过使用反射和做如下事情来解决同样的问题

[HttpPost]
public void DataAvailable([FromBody]IDictionary DataAvailable,
[FromUri]字符串簿[FromUri]字符串类型){
if(dataAvailable!=null&&dataAvailable.ContainsKey($type){
var type=dataavailable[“$type”];
if(type==“App.RRSRC.Feeds.DataAvailable”){
DataAvailableNotification obj=createInstanceOf(dataAvailable);
可用数据(对象、账簿、风险类型);
}else if(type==“Service.Feeds.Expired”){
ExpiredNotification obj=createInstanceOf(数据可用);
可用数据(对象、账簿、风险类型);
}
}
}
私有无效数据可用(DataAvailableNotificationDataAvailable、string book、string riskType){
}
private void DataAvailable(ExpiredNotification DataAvailable、string book、string riskType){
}
私有T createInstanceOf(IDictionary数据),其中T:class,new(){
var结果=新的T();
var类型=类型(T);
//地图属性
foreach(数据中的var kvp){
var propertyName=kvp.Key;
var rawValue=kvp.值;
var property=type.GetProperty(propertyName);
if(property!=null&&property.CanWrite){
SetValue(结果、原始值);
}
}
返回结果;
}

我采用的解决方案与@Nikosi和@jpgrassi建议的类似

在控制器中,我创建了一个通知点:

    [HttpPost]
    public void Notify(BaseNotification notification, 
        [FromUri] string book, [FromUri] string riskType)
    {
        DataAvailableNotification dataAvailableNotification;
        ExpiredNotification expiredNotification;

        if ((dataAvailableNotification = notification as DataAvailableNotification) != null)
        {
            HandleDataAvailableNotification(dataAvailableNotification);
        }
        else if ((expiredNotification = notification as ExpiredNotification) != null)
        {
            HandleExpiredNotification(expiredNotification);
        }
    }

    private void HandleDataAvailableNotification(DataAvailableNotification dataAvailableNotification)
    {
    }

    private void HandleExpiredNotification(ExpiredNotification expiredNotification)
    {
    }
BaseNotification是所有通知的基类:

public abstract class BaseNotification
{
    [JsonProperty(PropertyName = "$type")]
    public abstract string RdfType { get; }

    public string ConsumerId { get; set; }

    public Guid ChannelId { get; set; }
}
创建了JsonConverter:

public class RdfNotificationJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var resultJson = JObject.Load(reader);
        var rdfType = resultJson["$type"].ToObject<string>();

        BaseNotification result;

        switch (rdfType)
        {
            case "App.RRSRC.Feeds.DataAvailable":
            {
                result = new DataAvailableNotification
                {
                    SnapshotRevisionId = resultJson["SnapshotRevisionId"].ToObject<string>(),
                    URLs = resultJson["URLs"].ToObject<string[]>()
                };
                break;
            }
            case "Service.Feeds.Expired":
            {
                result = new ExpiredNotification();
                break;
            }
            default:
            {
                throw new NotSupportedException();
            }
        }

        result.ChannelId = resultJson["ChannelId"].ToObject<Guid>();
        result.ConsumerId = resultJson["ConsumerId"].ToObject<string>();

        return result;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(BaseNotification);
    }
}
我更喜欢这个解决方案,因为我在控制器中有实际的类型,转换器处理难看的反序列化部分(也更容易测试)


PS:我会将文字字符串移动到其他地方,这样我就不会在解决方案中两次指定它们。

DataAvailableNotification和
ExpiredNotification
之间有什么区别?如果你想两者都有相同的url,你希望路由引擎如何知道要调用哪一个操作?进一步到@Darinditrov的com芒特:你要做的不是路由的工作原理。你需要重新思考你的方法,例如,有一个更复杂的对象可以处理这两种类型。嗨@DarinDimitrov。我已经用DataAvailableNotification和ExpiredNotification的类定义更新了帖子。嗨@AdrianWragg。是的。这可能是一种方法。但我很抱歉希望我可以在控制器中公开两种不同的方法。这将是一个更干净的实现。我还希望WebAPI为我提供一种处理这种情况的方法:)。为什么不创建一个POST操作(如果遵循REST,这是“正确”的方法),并基于值,你调用不同的方法来处理你的数据?做你想做的事,在我看来是很大的开销。不要把事情复杂化!
    public static void Configure(HttpSelfHostConfiguration config)
    {
        Throw.IfNull(config, "config");

        config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new RdfNotificationJsonConverter());
     }