【问题标题】:Service Stack POST-Request Body-Format / Transformation服务堆栈 POST 请求正文格式/转换
【发布时间】:2014-06-04 06:45:10
【问题描述】:

iam 使用带有 Route 注释的 RequestClass 来调用 Json-Client POST 方法。 现在,虽然参数的结构是这样的

public class GetTicketRequest: IReturn<JsonObject>
{
    public string CartId {
        get;
        set;
    }
    public string PriceId {
        get;
        set;
    }
}

BackendAPI 需要将它们嵌套在 json 请求中的“数据”中,所以更像

{
   "data":[
   {"cartid":123,
   "priceId":11}]
}

有没有办法在调用之前从请求对象转换为body

JsonServiceClient _restClient = new JsonServiceClient(baseUrl);
JsonObject oneResponse = _restClient.Post(options);

【问题讨论】:

标签: json rest post servicestack


【解决方案1】:

此解决方案适用于需要打包和转换许多 DTO 的情况,并且高度可重用,无需更改现有 DTO。

您可以通过重写处理准备发送请求的方法来转换JsonServiceClient 的请求。这意味着实现您自己的扩展 JsonServiceClient如下所示

如果您想对所有动词执行此操作,则覆盖它的 Send&lt;TResponse&gt; 方法(否则,如果它仅适用于 POST,则取消注释掉注释掉的代码,并删除 Send 方法) .

public class MyJsonServiceClient : JsonServiceClient
{
    public Dictionary<Type, Func<object, object>> DtoConverters = new Dictionary<Type, Func<object, object>>();

    public MyJsonServiceClient() {}
    public MyJsonServiceClient(string baseUri) : base(baseUri) {}
    public MyJsonServiceClient(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri) {}

    public override TResponse Send<TResponse>(object request)
    {
        return base.Send<TResponse>(ConvertRequest(request));
    }

    public override TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request)
    {
        return base.Send<TResponse>(httpMethod, relativeOrAbsoluteUrl, ConvertRequest(request));
    }

    /*
    public override TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object requestDto)
    {
        return base.Post(relativeOrAbsoluteUrl, ConvertRequest(requestDto));
    }
    */

    object ConvertRequest(object request)
    {
        Type dtoType = request.GetType();
        return (DtoConverters.ContainsKey(dtoType)) ? DtoConverters[dtoType](request) : request;
    }
}

用法:

所以给定这个 DTO:

[Route("/test", "POST")]
public class TicketRequest : IReturnVoid
{
    public string CartId { get; set; }
    public string PriceId { get; set; }
}

您只需添加转换器:

var client = new MyJsonServiceClient("http://localhost:9000");

// Simple converter for TicketRequest
client.DtoConverters.Add(typeof(TicketRequest), dto => {
    var d = (TicketRequest)dto;
    return new { 
        data = new { 
            CartId = d.CartId.ToInt(), 
            PriceId = d.PriceId.ToInt() 
        } 
    };
});

client.Post(new TicketRequest { CartId = "123", PriceId = "456" });

【讨论】:

  • 一个非常有帮助的答案,非常感谢。尽管我的回答是直截了当的方法,并且您可以逐个解决,但在 90% 的情况下,您的方法会更加优雅和有用 - 在我的特定情况下,您的方法要优越得多。谢谢!
  • @emx 很高兴它很有用 :) 祝你的项目好运。
【解决方案2】:

我使用类型化数据属性解决了这个问题

public class GetTicketRequest: IReturn<JsonObject>
{
    public class TicketCreateData
    {            
        public int priceId {
            get;
            set;
        }
    }

    public string CartId {
      get;
      set;
    }
    public string PriceId {
      get;
      set;
    }

    public List<TicketCreateData> data {
        get {
            var list = new List<TicketCreateData>();
            list.Add(new TicketCreateData {
                priceId = this.PriceId.ToInt()
            });
            return list;
        }
        set {
            data = value;
        }
    }
}

对此的注释:

  • 如果需要,使用 DataContract/DataMember(Name="") 重命名字段或只进行部分序列化
  • 从不将结构用于数据类,例如在本例中,它们根本不可序列化
  • 在我的特定案例中,数据甚至需要是一个数组,这就是我使用列表的原因

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-10
    • 2016-01-29
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多