在WEBAPI方法中处理通用对象的正确方法是什么?

时间:2017-10-21 21:17:22

标签: c# .net generics asp.net-web-api

情况如下:

我有这个web-api可以处理各种支付网关,我希望所有这些网关具有相同的端点。

所以,我想到的是得到一些像这样的json数据:

{
    "OperationId":"N0004",
    "Generic_Object_That_Will_Change_According_ToThe_GateWay":
    {
        "Sale_id":1000,
        "CodUser":"1000040",
        "Email":"teste@teste.com"
    }
}

或者,对于其他一些支付网关

{
    "OperationId":"N044444",

    "Generic_Object_That_Will_Change_According_ToThe_GateWay":
    {
        "Token":1000,
        "UserSettings":{
            id: "4563345",
            name: "Average Joe"
        }        
    }
}

我想要做的是在每个支付网关(paypal或其他一些)的特定对象中转换这个“Generic_Object_That_Will_Change_According_ToThe_GateWay”,因为每个支付网站完全不同,但我不希望这会影响到客户端将调用此API - 我希望它尽可能灵活,只需要传递Generic_Object_That_Will_Change_According_ToThe_GateWay中的任何数据,然后我将其转换为正确的对象,然后调用另一个端点(如aggragate)微服务设计)传递这个新创建的对象。

到目前为止,我的想法是使用像这样的通用属性创建一些类

 public class Payment<Gateway>
    {
        public int OperationId{ get; set; }
        public Gateway paymentGateWay{ get; set; }
    }

此属性paymentGateWay可根据可用的支付网关键入。

然后也许我可以在API方法中将这些数据作为Object获取,并进行必要的强制转换

[Route("api/payment")]
[HttpPost]
public string Compra(Object payment) {

但是,说实话,我不知道我是否采取了正确的方式。

我已经知道我在web-api端点中没有通用方法 - 所以考虑到这个json数据的一部分是灵活的/通用的,可能是在我的端点中获取这些数据的正确方法被投射到几个不同的对象。

总结一下,我想处理可以反序列化为几个不同的已知对象的json数据,但我不想在我的API中使用不同的方法来处理这些可能的数据场景。< /强>

3 个答案:

答案 0 :(得分:1)

如果你想在webapi中使用泛型方法,你必须使用JObject 类似于以下内容

 public void Post([FromBody] JObject testJObject)
        {
            //here you have to do some additional work in order to parse and get it working for generic entity 
        }

除此之外,您可以对任何收到的请求使用Schema验证器并使用工厂模式来创建正确的对象

这里有一个例子

var json =
                " {\"OperationId\":\"N0004\",\"Generic_Object_That_Will_Change_According_ToThe_GateWay\":{\"Sale_id\":1000,\"CodUser\":\"1000040\"}}";

            JsonSchema paypalschema = new JsonSchema();
            paypalschema.Type = JsonSchemaType.Object;
            paypalschema.Properties = new Dictionary<string, JsonSchema>
            {
                {"OperationId", new JsonSchema {Type = JsonSchemaType.String}},
                {
                    "Generic_Object_That_Will_Change_According_ToThe_GateWay",
                    new JsonSchema {Type = JsonSchemaType.Object,Properties = new Dictionary<string, JsonSchema>
                    {
                        {"Sale_id", new JsonSchema {Type = JsonSchemaType.Integer}},
                        {"CodUser", new JsonSchema {Type = JsonSchemaType.String}},
                                                }}                   
                }
            };

        JObject requestObject = JObject.Parse( json);
            bool valid = requestObject.IsValid(paypalschema);
            if (valid)
            {
                //create your GatewayObject here 
            }
            //else check another gateway object 

答案 1 :(得分:0)

考虑使用JObject或String作为输入(然后转换为JObject。)然后,您可以在转换之前执行某些类型或数据检查。 Here's an example shows how they use a pre-defined 'type' value provided,但取而代之的是,您可以在JObject中查找&#39;部分&#39;每个唯一提供商的有效负载,以确定使用哪种类型。

答案 2 :(得分:0)

您可以使用通用控制器来实现继承通用控制器的方法和实例控制器:

// I'll rename Gateway to TGateway according to the fact, that it is a generic Type parameter.
 public class Payment<TGateway>
    {
        public int OperationId{ get; set; }
        public TGateway paymentGateWay{ get; set; }
    }

GenericController:

// Don't add a RouteAttribute to this Controller.
public class GenericController<TGateway>: ApiController
{
    // The implementation of the method. No RouteAttribute.
   [HttpPost]
   public string Compra(Payment<TGateway> payment) {...}
}

InstanceController:

// No need to override the method. RouteAttribute.
[Route("api/payment/"+typeof(AGateway).Name)]
public class AGatewayController : GenericController<AGateway>
{}