【问题标题】:How to properly post-process Refit return values?如何正确后处理 Refit 返回值?
【发布时间】:2019-01-14 14:03:14
【问题描述】:

我正在使用 Refit 编写一些 API,这很有效,但我在找出一种好的(如“干净”、“正确”)方法来对返回的数据执行一些任意处理时遇到了一些麻烦.

例如,考虑以下代码:

public interface ISomeService
{
    [Get("/someurl/{thing}.json")]
    Task<Data> GetThingAsync([AliasAs("thing")] string thing);
}

现在,我见过的许多 REST API 都有将实际数据(如“有用”数据)深入到 JSON 响应中的不幸习惯。比如说,实际的 JSON 有这样的结构:

{
    "a" = {
        "b" = {
            "data" = {
...
}

现在,我通常只映射所有必要的模型,这将允许 Refit 正确反序列化响应。这虽然使 API 使用起来有点笨拙,因为每次我使用它时,我都必须执行以下操作:

var response = await SomeService.GetThingAsync("foo");
var data = response.A.B.Data;

我的意思是,这两个外部模型实际上只是容器,不需要向用户公开。或者,假设Data 属性是具有另一个属性IEnumerable 的模型,我可能只想直接将其返回给用户。

我不知道如何做到这一点,而不必为每个服务编写无用的包装类,其中每个服务显然还必须重复接口等中的所有 XML cmets,从而导致更多无用的代码四处飘荡.

我只想有一些简单的、可选的 Func&lt;T, TResult&gt; 等效项,它会在给定的 Refit API 的结果上调用,并在将返回的数据呈现给用户之前对其进行一些修改。

【问题讨论】:

    标签: c# .net .net-core .net-standard refit


    【解决方案1】:

    我发现这个问题的一个足够干净的解决方案是使用扩展方法来扩展 Refit 服务。例如,假设我有一个这样的 JSON 映射:

    public class Response
    {
        [JsonProperty("container")]
        public DataContainer Container { get; set; }
    }
    
    public class DataContainer
    {
        [JsonProperty("data")]
        public Data Data { get; set; }
    }
    
    public class Data
    {
        [JsonProperty("ids")]
        public IList<string> Ids { get; set; }
    }
    

    然后我有一个这样的改装 API:

    public interface ISomeService
    {
        [Get("/someurl/{thing}.json")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("use extension " + nameof(ISomeService) + "." + nameof(SomeServiceExtensions.GetThingAsync))]
        Task<Response> _GetThingAsync(string thing);
    }
    

    我可以像这样定义一个扩展方法,并使用这个来代替 Refit 服务公开的 API:

    #pragma warning disable 612, 618
    
    public static class SomeServiceExtensions
    {
        public static Task<Data> GetThingAsync(this ISomeService service, string thing)
        {
            var response = await service._GetThingAsync(thing);
            return response.Container.Data.Ids;
        }
    }
    

    这样,每当我调用GetThingAsync API 时,我实际上是在使用可以为我处理所有额外反序列化的扩展方法。

    【讨论】:

      【解决方案2】:

      总结

      您可以将自定义的JsonConverters 传递给 Refit 以修改它如何序列化或反序列化各种类型。

      详情

      RefitSettings 类提供自定义选项,包括 JSON 序列化程序设置。

      请注意,RefitSettings 类在过去几个版本中发生了一些变化。您应该查阅适用于您的 Refit 版本的文档。

      来自改装最新的examples

      var myConverters = new List<JsonConverter>();
      myConverters += new myCustomADotBConverter();
      
      var myApi = RestService.For<IMyApi>("https://api.example.com",
          new RefitSettings {
              ContentSerializer = new JsonContentSerializer( 
                  new JsonSerializerSettings {
                      ContractResolver = new CamelCasePropertyNamesContractResolver(),
                      Converters = myConverters
              }
          )});
      

      这是来自JSON.Net docs 的自定义 JsonConverter 的基本示例。

      public class VersionConverter : JsonConverter<Version>
      {
          public override void WriteJson(JsonWriter writer, Version value, JsonSerializer serializer)
          {
              writer.WriteValue(value.ToString());
          }
      
          public override Version ReadJson(JsonReader reader, Type objectType, Version existingValue, bool hasExistingValue, JsonSerializer serializer)
          {
              string s = (string)reader.Value;
      
              return new Version(s);
          }
      }
      
      public class NuGetPackage
      {
          public string PackageId { get; set; }
          public Version Version { get; set; }
      }
      

      该示例 JsonConverter 旨在序列化或反序列化 JSON 有效负载的“版本”字段,如下所示:

      {
        "PackageId": "Newtonsoft.Json",
        "Version": "10.0.4"
      }
      

      您必须为要反序列化的嵌套数据结构编写自己的自定义 JsonConverter。

      【讨论】:

      • 您好,感谢您的回复,但这实际上并不能回答我的问题。正如我在示例中所展示的,我不需要自定义默认反序列化的工作方式,而是对反序列化数据执行额外的处理,而不是直接将其返回给调用者。或者,对可变的返回类型执行自定义反序列化(例如,具有不同类型对象的 JSON 数组)。这两种情况都不能使用自定义反序列化器轻松处理。
      • 感谢您提供反馈并发布您找到的解决方案!我赞成你的回答,希望它会出现在我的前面。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-26
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多