Update the default serializer to use System.Text.Json
This commit is contained in:
Родитель
75b3a6b1e3
Коммит
765ef2cac5
|
@ -18,6 +18,7 @@
|
|||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)buildtask.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<Product>Refit HTTP Client Factory Extensions</Product>
|
||||
<Description>Refit HTTP Client Factory Extensions</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<DebugType>embedded</DebugType>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -15,7 +17,7 @@ namespace Refit
|
|||
/// <summary>
|
||||
/// The <see cref="Lazy{T}"/> instance providing the JSON serialization settings to use
|
||||
/// </summary>
|
||||
private readonly Lazy<JsonSerializerSettings> jsonSerializerSettings;
|
||||
readonly Lazy<JsonSerializerSettings> jsonSerializerSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="NewtonsoftJsonContentSerializer"/> instance
|
||||
|
@ -52,5 +54,15 @@ namespace Refit
|
|||
|
||||
return serializer.Deserialize<T>(jsonTextReader);
|
||||
}
|
||||
|
||||
public string GetFieldNameForProperty(PropertyInfo propertyInfo)
|
||||
{
|
||||
if (propertyInfo is null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo));
|
||||
|
||||
return propertyInfo.GetCustomAttributes<JsonPropertyAttribute>(true)
|
||||
.Select(a => a.PropertyName)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Product>Refit Serializer for Newtonsoft.Json ($(TargetFramework))</Product>
|
||||
<Description>Refit Serializers for Newtonsoft.Json</Description>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net461</TargetFrameworks>
|
||||
<GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
|
||||
<RootNamespace>Refit</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies"
|
||||
Version="1.0.0"
|
||||
PrivateAssets="All" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Refit\Refit.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
@ -328,10 +329,12 @@ namespace Refit.Tests
|
|||
public string Foo { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "b")]
|
||||
[JsonPropertyName("b")]
|
||||
public string Bar { get; set; }
|
||||
|
||||
[AliasAs("a")]
|
||||
[JsonProperty(PropertyName = "z")]
|
||||
[JsonPropertyName("z")]
|
||||
public string Baz { get; set; }
|
||||
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace Refit.Tests
|
|||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.WithHeaders("X-Refit", "99")
|
||||
.WithQueryString("param", "foo")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get', 'args': {'param': 'foo'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"foo\"}}");
|
||||
|
||||
var fixture = RestService.For<IUseOverloadedGenericMethods<HttpBinGet, string, int>>("https://httpbin.org/", settings);
|
||||
|
||||
|
@ -173,7 +173,7 @@ namespace Refit.Tests
|
|||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.WithHeaders("X-Refit", "foo")
|
||||
.WithQueryString("param", "99")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get', 'args': {'param': '99'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"99\"}}");
|
||||
|
||||
var fixture = RestService.For<IUseOverloadedGenericMethods<HttpBinGet, string, int>>("https://httpbin.org/", settings);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />
|
||||
<ProjectReference Include="..\InterfaceStubGenerator.App\InterfaceStubGenerator.App.csproj" />
|
||||
<ProjectReference Include="..\Refit.HttpClientFactory\Refit.HttpClientFactory.csproj" />
|
||||
<ProjectReference Include="..\Refit\Refit.csproj" />
|
||||
<ProjectReference Include="..\Refit.Newtonsoft.Json\Refit.Newtonsoft.Json.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461' ">
|
||||
|
|
|
@ -1857,6 +1857,7 @@ namespace Refit.Tests
|
|||
using global::Refit.Buffers;
|
||||
using global::Xunit;
|
||||
using JsonSerializer = global::Newtonsoft.Json.JsonSerializer;
|
||||
using global::System.Text.Json.Serialization;
|
||||
|
||||
/// <inheritdoc />
|
||||
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
|
|
|
@ -1857,6 +1857,7 @@ namespace Refit.Tests
|
|||
using global::Refit.Buffers;
|
||||
using global::Xunit;
|
||||
using JsonSerializer = global::Newtonsoft.Json.JsonSerializer;
|
||||
using global::System.Text.Json.Serialization;
|
||||
|
||||
/// <inheritdoc />
|
||||
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
|
|
|
@ -1857,6 +1857,7 @@ namespace Refit.Tests
|
|||
using global::Refit.Buffers;
|
||||
using global::Xunit;
|
||||
using JsonSerializer = global::Newtonsoft.Json.JsonSerializer;
|
||||
using global::System.Text.Json.Serialization;
|
||||
|
||||
/// <inheritdoc />
|
||||
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
|
|
|
@ -1857,6 +1857,7 @@ namespace Refit.Tests
|
|||
using global::Refit.Buffers;
|
||||
using global::Xunit;
|
||||
using JsonSerializer = global::Newtonsoft.Json.JsonSerializer;
|
||||
using global::System.Text.Json.Serialization;
|
||||
|
||||
/// <inheritdoc />
|
||||
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
|
|
|
@ -14,6 +14,7 @@ using Refit.Buffers;
|
|||
// for the code gen
|
||||
using Xunit;
|
||||
using JsonSerializer = Newtonsoft.Json.JsonSerializer;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Refit.Tests
|
||||
{
|
||||
|
@ -23,6 +24,7 @@ namespace Refit.Tests
|
|||
public string ShortNameForAlias { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")]
|
||||
[JsonPropertyName("FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")]
|
||||
public string ShortNameForJsonProperty { get; set; }
|
||||
}
|
||||
|
||||
|
@ -52,7 +54,7 @@ namespace Refit.Tests
|
|||
public async Task JsonPropertyCanBeUsedToAliasFieldNamesInResponses()
|
||||
{
|
||||
mockHandler.Expect(HttpMethod.Get, "http://api/aliasTest")
|
||||
.Respond("application/json", "{FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS: 'Hello', FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY: 'World'}");
|
||||
.Respond("application/json", "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}");
|
||||
|
||||
var result = await fixture.GetTestObject();
|
||||
|
||||
|
@ -68,7 +70,7 @@ namespace Refit.Tests
|
|||
{
|
||||
|
||||
mockHandler.Expect(HttpMethod.Get, "http://api/aliasTest")
|
||||
.Respond("application/json", "{FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS: 'Hello', FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY: 'World'}");
|
||||
.Respond("application/json", "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}");
|
||||
|
||||
var result = await fixture.GetTestObject();
|
||||
|
||||
|
|
|
@ -1151,7 +1151,7 @@ namespace Refit.Tests
|
|||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Get, "https://registry.npmjs.org/congruence")
|
||||
.Respond("application/json", "{ '_id':'congruence', '_rev':'rev' , 'name':'name'}");
|
||||
.Respond("application/json", "{ \"_id\":\"congruence\", \"_rev\":\"rev\" , \"name\":\"name\"}");
|
||||
|
||||
|
||||
|
||||
|
@ -1373,37 +1373,6 @@ namespace Refit.Tests
|
|||
mockHttp.VerifyNoOutstandingExpectation();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ErrorsFromApiReturnErrorContentNonAsync()
|
||||
{
|
||||
var mockHttp = new MockHttpMessageHandler();
|
||||
|
||||
var settings = new RefitSettings
|
||||
{
|
||||
HttpMessageHandlerFactory = () => mockHttp,
|
||||
ContentSerializer = new NewtonsoftJsonContentSerializer(new JsonSerializerSettings() { ContractResolver = new SnakeCasePropertyNamesContractResolver() })
|
||||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Post, "https://api.github.com/users")
|
||||
.Respond(HttpStatusCode.BadRequest, "application/json", "{ 'errors': [ 'error1', 'message' ]}");
|
||||
|
||||
|
||||
var fixture = RestService.For<IGitHubApi>("https://api.github.com", settings);
|
||||
|
||||
|
||||
var result = await Assert.ThrowsAsync<ApiException>(async () => await fixture.CreateUser(new User { Name = "foo" }));
|
||||
|
||||
|
||||
#pragma warning disable CS0618 // Ensure that this code continues to be tested until it is removed
|
||||
var errors = result.GetContentAs<ErrorResponse>();
|
||||
#pragma warning restore CS0618
|
||||
|
||||
Assert.Contains("error1", errors.Errors);
|
||||
Assert.Contains("message", errors.Errors);
|
||||
|
||||
mockHttp.VerifyNoOutstandingExpectation();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonRefitInterfacesThrowMeaningfulExceptions()
|
||||
{
|
||||
|
@ -1444,7 +1413,7 @@ namespace Refit.Tests
|
|||
mockHttp.Expect(HttpMethod.Get, "http://httpbin.org/get")
|
||||
.WithHeaders("X-Refit", "99")
|
||||
.WithQueryString("param", "foo")
|
||||
.Respond("application/json", "{'url': 'http://httpbin.org/get?param=foo', 'args': {'param': 'foo'}, 'headers':{'X-Refit':'99'}}");
|
||||
.Respond("application/json", "{\"url\": \"http://httpbin.org/get?param=foo\", \"args\": {\"param\": \"foo\"}, \"headers\":{\"X-Refit\":\"99\"}}");
|
||||
|
||||
|
||||
|
||||
|
@ -1494,7 +1463,7 @@ namespace Refit.Tests
|
|||
|
||||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.WithHeaders("X-Refit", "99")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get?FirstName=John&LastName=Rambo', 'args': {'FirstName': 'John', 'lName': 'Rambo'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get?FirstName=John&LastName=Rambo\", \"args\": {\"FirstName\": \"John\", \"lName\": \"Rambo\"}}");
|
||||
|
||||
var myParams = new MySimpleQueryParams
|
||||
{
|
||||
|
@ -1521,7 +1490,7 @@ namespace Refit.Tests
|
|||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a', 'args': { 'Addr_Street': 'HomeStreet 99', 'Addr_Zip': '9999', 'FirstName': 'John', 'LastName': 'Rambo', 'MetaData_Age': '99', 'MetaData_Birthday': '10/31/1981 4:32:59 PM', 'MetaData_Initials': 'JR', 'Other': ['12345','10/31/2017 4:32:59 PM','60282dd2-f79a-4400-be01-bcb0e86e7bc6'], 'hardcoded': 'true'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}");
|
||||
|
||||
var myParams = new MyComplexQueryParams
|
||||
{
|
||||
|
@ -1560,7 +1529,7 @@ namespace Refit.Tests
|
|||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Post, "https://httpbin.org/post")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/post?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a', 'args': { 'Addr_Street': 'HomeStreet 99', 'Addr_Zip': '9999', 'FirstName': 'John', 'LastName': 'Rambo', 'MetaData_Age': '99', 'MetaData_Birthday': '10/31/1981 4:32:59 PM', 'MetaData_Initials': 'JR', 'Other': ['12345','10/31/2017 4:32:59 PM','60282dd2-f79a-4400-be01-bcb0e86e7bc6'], 'hardcoded': 'true'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/post?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}");
|
||||
|
||||
var myParams = new MyComplexQueryParams
|
||||
{
|
||||
|
@ -1682,7 +1651,7 @@ namespace Refit.Tests
|
|||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Address_Zip=9999&Address_Street=HomeStreet 99', 'args': {'Address_Street': 'HomeStreet 99','Address_Zip': '9999','FirstName': 'John','LastName': 'Rambo','hardcoded': 'true'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Address_Zip=9999&Address_Street=HomeStreet 99\", \"args\": {\"Address_Street\": \"HomeStreet 99\",\"Address_Zip\": \"9999\",\"FirstName\": \"John\",\"LastName\": \"Rambo\",\"hardcoded\": \"true\"}}");
|
||||
|
||||
var myParams = new Dictionary<string, object>
|
||||
{
|
||||
|
@ -1715,7 +1684,7 @@ namespace Refit.Tests
|
|||
};
|
||||
|
||||
mockHttp.Expect(HttpMethod.Get, "https://httpbin.org/get")
|
||||
.Respond("application/json", "{'url': 'https://httpbin.org/get?search.FirstName=John&search.LastName=Rambo&search.Addr.Zip=9999&search.Addr.Street=HomeStreet 99', 'args': {'search.Addr.Street': 'HomeStreet 99','search.Addr.Zip': '9999','search.FirstName': 'John','search.LastName': 'Rambo'}}");
|
||||
.Respond("application/json", "{\"url\": \"https://httpbin.org/get?search.FirstName=John&search.LastName=Rambo&search.Addr.Zip=9999&search.Addr.Street=HomeStreet 99\", \"args\": {\"search.Addr.Street\": \"HomeStreet 99\",\"search.Addr.Zip\": \"9999\",\"search.FirstName\": \"John\",\"search.LastName\": \"Rambo\"}}");
|
||||
|
||||
var myParams = new MyComplexQueryParams
|
||||
{
|
||||
|
|
|
@ -91,12 +91,12 @@ namespace Refit.Tests
|
|||
var settings = new RefitSettings();
|
||||
|
||||
Assert.NotNull(settings.ContentSerializer);
|
||||
Assert.IsType<NewtonsoftJsonContentSerializer>(settings.ContentSerializer);
|
||||
Assert.IsType<SystemTextJsonContentSerializer>(settings.ContentSerializer);
|
||||
|
||||
settings = new RefitSettings(new SystemTextJsonContentSerializer());
|
||||
settings = new RefitSettings(new NewtonsoftJsonContentSerializer());
|
||||
|
||||
Assert.NotNull(settings.ContentSerializer);
|
||||
Assert.IsType<SystemTextJsonContentSerializer>(settings.ContentSerializer);
|
||||
Assert.IsType<NewtonsoftJsonContentSerializer>(settings.ContentSerializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
18
Refit.sln
18
Refit.sln
|
@ -30,6 +30,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InterfaceStubGenerator.Buil
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Refit.HttpClientFactory", "Refit.HttpClientFactory\Refit.HttpClientFactory.csproj", "{01AE14AC-88D1-49C4-A612-2F9B2DEB5DEA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Refit.Newtonsoft.Json", "Refit.Newtonsoft.Json\Refit.Newtonsoft.Json.csproj", "{2210E606-1C91-4EA0-8876-3B2F501F2669}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -138,6 +140,22 @@ Global
|
|||
{01AE14AC-88D1-49C4-A612-2F9B2DEB5DEA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{01AE14AC-88D1-49C4-A612-2F9B2DEB5DEA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{01AE14AC-88D1-49C4-A612-2F9B2DEB5DEA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2210E606-1C91-4EA0-8876-3B2F501F2669}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -21,12 +21,12 @@ namespace Refit
|
|||
public bool HasContent => !string.IsNullOrWhiteSpace(Content);
|
||||
public RefitSettings RefitSettings { get; set; }
|
||||
|
||||
protected ApiException(HttpRequestMessage message, HttpMethod httpMethod, HttpStatusCode statusCode, string reasonPhrase, HttpResponseHeaders headers, RefitSettings refitSettings = null) :
|
||||
this(CreateMessage(statusCode, reasonPhrase), message, httpMethod, statusCode, reasonPhrase, headers, refitSettings)
|
||||
protected ApiException(HttpRequestMessage message, HttpMethod httpMethod, string content, HttpStatusCode statusCode, string reasonPhrase, HttpResponseHeaders headers, RefitSettings refitSettings = null) :
|
||||
this(CreateMessage(statusCode, reasonPhrase), message, httpMethod, content, statusCode, reasonPhrase, headers, refitSettings)
|
||||
{
|
||||
}
|
||||
|
||||
protected ApiException(string exceptionMessage, HttpRequestMessage message, HttpMethod httpMethod, HttpStatusCode statusCode, string reasonPhrase, HttpResponseHeaders headers, RefitSettings refitSettings = null) :
|
||||
protected ApiException(string exceptionMessage, HttpRequestMessage message, HttpMethod httpMethod, string content, HttpStatusCode statusCode, string reasonPhrase, HttpResponseHeaders headers, RefitSettings refitSettings = null) :
|
||||
base(exceptionMessage)
|
||||
{
|
||||
RequestMessage = message;
|
||||
|
@ -35,11 +35,9 @@ namespace Refit
|
|||
ReasonPhrase = reasonPhrase;
|
||||
Headers = headers;
|
||||
RefitSettings = refitSettings;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
[Obsolete("Use GetContentAsAsync<T>() instead", false)]
|
||||
public T GetContentAs<T>() => GetContentAsAsync<T>().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
|
||||
public async Task<T> GetContentAsAsync<T>() => HasContent ?
|
||||
await RefitSettings.ContentSerializer.DeserializeAsync<T>(new StringContent(Content)).ConfigureAwait(false) :
|
||||
default;
|
||||
|
@ -56,7 +54,7 @@ namespace Refit
|
|||
public static async Task<ApiException> Create(string exceptionMessage, HttpRequestMessage message, HttpMethod httpMethod, HttpResponseMessage response, RefitSettings refitSettings = null)
|
||||
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
|
||||
{
|
||||
var exception = new ApiException(exceptionMessage, message, httpMethod, response.StatusCode, response.ReasonPhrase, response.Headers, refitSettings);
|
||||
var exception = new ApiException(exceptionMessage, message, httpMethod, null, response.StatusCode, response.ReasonPhrase, response.Headers, refitSettings);
|
||||
|
||||
if (response.Content == null)
|
||||
{
|
||||
|
@ -71,8 +69,7 @@ namespace Refit
|
|||
|
||||
if (response.Content.Headers?.ContentType?.MediaType?.Equals("application/problem+json") ?? false)
|
||||
{
|
||||
exception = await ValidationApiException.Create(exception).ConfigureAwait(false);
|
||||
exception.Content = content;
|
||||
exception = ValidationApiException.Create(exception);
|
||||
}
|
||||
|
||||
response.Content.Dispose();
|
||||
|
|
|
@ -5,8 +5,6 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Refit
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -22,8 +20,14 @@ namespace Refit
|
|||
|
||||
readonly IList<KeyValuePair<string, string>> formEntries = new List<KeyValuePair<string, string>>();
|
||||
|
||||
readonly IContentSerializer contentSerializer;
|
||||
|
||||
public FormValueMultimap(object source, RefitSettings settings)
|
||||
{
|
||||
if (settings is null)
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
contentSerializer = settings.ContentSerializer;
|
||||
|
||||
if (source == null) return;
|
||||
|
||||
if (source is IDictionary dictionary)
|
||||
|
@ -120,12 +124,7 @@ namespace Refit
|
|||
var name = propertyInfo.GetCustomAttributes<AliasAsAttribute>(true)
|
||||
.Select(a => a.Name)
|
||||
.FirstOrDefault()
|
||||
?? propertyInfo.GetCustomAttributes<JsonPropertyAttribute>(true)
|
||||
.Select(a => a.PropertyName)
|
||||
.FirstOrDefault()
|
||||
?? propertyInfo.GetCustomAttributes<JsonPropertyNameAttribute>(true)
|
||||
.Select(a => a.Name)
|
||||
.FirstOrDefault()
|
||||
?? contentSerializer.GetFieldNameForProperty(propertyInfo)
|
||||
?? propertyInfo.Name;
|
||||
|
||||
var qattrib = propertyInfo.GetCustomAttributes<QueryAttribute>(true)
|
||||
|
|
|
@ -1,49 +1,28 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Refit
|
||||
{
|
||||
[Obsolete("Use NewtonsoftJsonContentSerializer instead", false)]
|
||||
[Obsolete("Use NewtonsoftJsonContentSerializer in the Refit.Newtonsoft.Json package instead", true)]
|
||||
public class JsonContentSerializer : IContentSerializer
|
||||
{
|
||||
readonly Lazy<JsonSerializerSettings> jsonSerializerSettings;
|
||||
|
||||
public JsonContentSerializer() : this(null) { }
|
||||
|
||||
public JsonContentSerializer(JsonSerializerSettings jsonSerializerSettings)
|
||||
{
|
||||
this.jsonSerializerSettings = new Lazy<JsonSerializerSettings>(() =>
|
||||
{
|
||||
if (jsonSerializerSettings == null)
|
||||
{
|
||||
if (JsonConvert.DefaultSettings == null)
|
||||
{
|
||||
return new JsonSerializerSettings();
|
||||
}
|
||||
return JsonConvert.DefaultSettings();
|
||||
}
|
||||
return jsonSerializerSettings;
|
||||
});
|
||||
}
|
||||
|
||||
public Task<HttpContent> SerializeAsync<T>(T item)
|
||||
{
|
||||
var content = new StringContent(JsonConvert.SerializeObject(item, jsonSerializerSettings.Value), Encoding.UTF8, "application/json");
|
||||
return Task.FromResult((HttpContent)content);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<T> DeserializeAsync<T>(HttpContent content)
|
||||
public Task<T> DeserializeAsync<T>(HttpContent content)
|
||||
{
|
||||
var serializer = JsonSerializer.Create(jsonSerializerSettings.Value);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
using var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
using var reader = new StreamReader(stream);
|
||||
using var jsonTextReader = new JsonTextReader(reader);
|
||||
return serializer.Deserialize<T>(jsonTextReader);
|
||||
public string GetFieldNameForProperty(PropertyInfo propertyInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Refit
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ namespace Refit
|
|||
/// Collection of ProblemDetails extensions
|
||||
/// </summary>
|
||||
[JsonExtensionData]
|
||||
public IDictionary<string, object> Extensions { get; } = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
public IDictionary<string, object> Extensions { get; set; } = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// A URI reference that identifies the problem type.
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
<Product>Refit ($(TargetFramework))</Product>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net461</TargetFrameworks>
|
||||
<GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -7,20 +7,17 @@ using System.Reflection;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Refit
|
||||
{
|
||||
public class RefitSettings
|
||||
{
|
||||
JsonSerializerSettings jsonSerializerSettings;
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="RefitSettings"/> instance with the default parameters
|
||||
/// </summary>
|
||||
public RefitSettings()
|
||||
{
|
||||
ContentSerializer = new NewtonsoftJsonContentSerializer();
|
||||
ContentSerializer = new SystemTextJsonContentSerializer();
|
||||
UrlParameterFormatter = new DefaultUrlParameterFormatter();
|
||||
FormUrlEncodedParameterFormatter = new DefaultFormUrlEncodedParameterFormatter();
|
||||
ExceptionFactory = new DefaultApiExceptionFactory(this).CreateAsync;
|
||||
|
@ -64,17 +61,6 @@ namespace Refit
|
|||
/// </summary>
|
||||
public Func<HttpResponseMessage, Task<Exception>> ExceptionFactory { get; set; }
|
||||
|
||||
[Obsolete("Set RefitSettings.ContentSerializer = new NewtonsoftJsonContentSerializer(JsonSerializerSettings) instead.", false)]
|
||||
public JsonSerializerSettings JsonSerializerSettings
|
||||
{
|
||||
get => jsonSerializerSettings;
|
||||
set
|
||||
{
|
||||
jsonSerializerSettings = value;
|
||||
ContentSerializer = new JsonContentSerializer(value);
|
||||
}
|
||||
}
|
||||
|
||||
public IContentSerializer ContentSerializer { get; set; }
|
||||
public IUrlParameterFormatter UrlParameterFormatter { get; set; }
|
||||
public IFormUrlEncodedParameterFormatter FormUrlEncodedParameterFormatter { get; set; }
|
||||
|
@ -87,6 +73,13 @@ namespace Refit
|
|||
Task<HttpContent> SerializeAsync<T>(T item);
|
||||
|
||||
Task<T> DeserializeAsync<T>(HttpContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates what the field name should be for the given property. This may be affected by custom attributes the serializer understands
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo"></param>
|
||||
/// <returns></returns>
|
||||
string GetFieldNameForProperty(PropertyInfo propertyInfo);
|
||||
}
|
||||
|
||||
public interface IUrlParameterFormatter
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Refit.Buffers;
|
||||
|
||||
|
@ -19,12 +23,21 @@ namespace Refit
|
|||
/// <summary>
|
||||
/// The JSON serialization options to use
|
||||
/// </summary>
|
||||
private readonly JsonSerializerOptions jsonSerializerOptions;
|
||||
readonly JsonSerializerOptions jsonSerializerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SystemTextJsonContentSerializer"/> instance
|
||||
/// </summary>
|
||||
public SystemTextJsonContentSerializer() : this(new JsonSerializerOptions()) { }
|
||||
public SystemTextJsonContentSerializer() : this(new JsonSerializerOptions())
|
||||
{
|
||||
|
||||
// Set some defaults
|
||||
// Default to case insensitive property name matching as that's likely the behavior most users expect
|
||||
jsonSerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
jsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
|
||||
jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SystemTextJsonContentSerializer"/> instance with the specified parameters
|
||||
|
@ -105,12 +118,76 @@ namespace Refit
|
|||
/// <returns>A <typeparamref name="T"/> item deserialized from the UTF8 bytes within <paramref name="buffer"/></returns>
|
||||
[Pure]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static T Deserialize<T>(byte[] buffer, int length, JsonSerializerOptions jsonSerializerOptions)
|
||||
static T Deserialize<T>(byte[] buffer, int length, JsonSerializerOptions jsonSerializerOptions)
|
||||
{
|
||||
var span = new ReadOnlySpan<byte>(buffer, 0, length);
|
||||
var utf8JsonReader = new Utf8JsonReader(span);
|
||||
|
||||
return JsonSerializer.Deserialize<T>(ref utf8JsonReader, jsonSerializerOptions);
|
||||
}
|
||||
|
||||
public string GetFieldNameForProperty(PropertyInfo propertyInfo)
|
||||
{
|
||||
if (propertyInfo is null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo));
|
||||
|
||||
return propertyInfo.GetCustomAttributes<JsonPropertyNameAttribute>(true)
|
||||
.Select(a => a.Name)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// From https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#deserialize-inferred-types-to-object-properties
|
||||
public class ObjectToInferredTypesConverter
|
||||
: JsonConverter<object>
|
||||
{
|
||||
public override object Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.True)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.False)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.Number)
|
||||
{
|
||||
if (reader.TryGetInt64(out long l))
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
return reader.GetDouble();
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
if (reader.TryGetDateTime(out DateTime datetime))
|
||||
{
|
||||
return datetime;
|
||||
}
|
||||
|
||||
return reader.GetString();
|
||||
}
|
||||
|
||||
// Use JsonElement as fallback.
|
||||
// Newtonsoft uses JArray or JObject.
|
||||
using JsonDocument document = JsonDocument.ParseValue(ref reader);
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
object objectToWrite,
|
||||
JsonSerializerOptions options) =>
|
||||
throw new InvalidOperationException("Should not get here.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Refit
|
||||
|
@ -9,24 +10,35 @@ namespace Refit
|
|||
[Serializable]
|
||||
public class ValidationApiException : ApiException
|
||||
{
|
||||
static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions();
|
||||
|
||||
static ValidationApiException()
|
||||
{
|
||||
SerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
SerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
|
||||
}
|
||||
|
||||
ValidationApiException(ApiException apiException) :
|
||||
base(apiException.RequestMessage, apiException.HttpMethod, apiException.StatusCode, apiException.ReasonPhrase, apiException.Headers, apiException.RefitSettings)
|
||||
base(apiException.RequestMessage, apiException.HttpMethod, apiException.Content, apiException.StatusCode, apiException.ReasonPhrase, apiException.Headers, apiException.RefitSettings)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
|
||||
/// <summary>
|
||||
/// Creates a new instance of a ValidationException from an existing ApiException.
|
||||
/// </summary>
|
||||
/// <param name="exception">An instance of an ApiException to use to build a ValidationException.</param>
|
||||
/// <returns>ValidationApiException</returns>
|
||||
public static async Task<ValidationApiException> Create(ApiException exception)
|
||||
#pragma warning restore VSTHRD200
|
||||
public static ValidationApiException Create(ApiException exception)
|
||||
{
|
||||
if (exception is null)
|
||||
throw new ArgumentNullException(nameof(exception));
|
||||
if (string.IsNullOrWhiteSpace(exception.Content))
|
||||
throw new ArgumentException("Content must be an 'application/problem+json' compliant json string.");
|
||||
|
||||
return new ValidationApiException(exception)
|
||||
{
|
||||
Content = await exception.GetContentAsAsync<ProblemDetails>().ConfigureAwait(false)
|
||||
Content = JsonSerializer.Deserialize<ProblemDetails>(exception.Content, SerializerOptions)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
@ -50,6 +52,20 @@ namespace Refit
|
|||
using var reader = XmlReader.Create(input, settings.XmlReaderWriterSettings.ReaderSettings);
|
||||
return (T)xmlSerializer.Deserialize(reader);
|
||||
}
|
||||
|
||||
public string GetFieldNameForProperty(PropertyInfo propertyInfo)
|
||||
{
|
||||
if (propertyInfo is null)
|
||||
throw new ArgumentNullException(nameof(propertyInfo));
|
||||
|
||||
return propertyInfo.GetCustomAttributes<XmlElementAttribute>(true)
|
||||
.Select(a => a.ElementName)
|
||||
.FirstOrDefault()
|
||||
??
|
||||
propertyInfo.GetCustomAttributes<XmlAttributeAttribute>(true)
|
||||
.Select(a => a.AttributeName)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public class XmlReaderWriterSettings
|
||||
|
|
Загрузка…
Ссылка в новой задаче