按后置值类型划分的C#WebAPI路由
我请求创建一个Web API,该API能够接受POST请求,并根据参数中接收的数据类型(DataAvailableNotification与ExpiredNotification)采取不同的操作 我创建了一个ApicController并公开了两种方法:按后置值类型划分的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
[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());
}