-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #414 from YudApps/feature/serialization_unitresult
Add UnitResult support to CSharpFunctionalExtensions.Json.Serialization
- Loading branch information
Showing
7 changed files
with
258 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 5 additions & 1 deletion
6
CSharpFunctionalExtensions/Result/Json/Serialization/DtoMessages.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
namespace CSharpFunctionalExtensions.Json.Serialization | ||
using System.Net; | ||
|
||
namespace CSharpFunctionalExtensions.Json.Serialization | ||
{ | ||
internal static class DtoMessages | ||
{ | ||
public static readonly string HttpResponseMessageIsNull = "HttpResponseMessage is null"; | ||
|
||
public static readonly string ContentJsonNotResult = "The response content in not a Result"; | ||
|
||
public static string NotSuccsessStatusCodeFormat(HttpStatusCode statusCode, string content) => $"HttpStatus code is {statusCode}, Content {content}"; | ||
} | ||
} |
46 changes: 40 additions & 6 deletions
46
CSharpFunctionalExtensions/Result/Json/Serialization/HttpResponseMessageJsonExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,69 @@ | ||
#nullable enable | ||
using System.Net.Http; | ||
using System.Net.Http.Json; | ||
using System.Text.Json; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace CSharpFunctionalExtensions.Json.Serialization | ||
{ | ||
public static class HttpResponseMessageJsonExtensions | ||
{ | ||
public static Task<Result> ReadResultAsync(this HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken)) | ||
public static async Task<Result> ReadResultAsync(this HttpResponseMessage response, bool ensureSuccessStatusCode = true, CancellationToken cancellationToken = default(CancellationToken)) | ||
{ | ||
if (response is null) | ||
{ | ||
return Task.FromResult(Result.Failure(DtoMessages.HttpResponseMessageIsNull)); | ||
return Result.Failure(DtoMessages.HttpResponseMessageIsNull); | ||
} | ||
|
||
return | ||
if (ensureSuccessStatusCode && !response.IsSuccessStatusCode) | ||
{ | ||
return Result.Failure(DtoMessages.NotSuccsessStatusCodeFormat(response.StatusCode, await response.Content.ReadAsStringAsync())); | ||
} | ||
|
||
return await | ||
Result.Try(() => response.Content.ReadFromJsonAsync<Result>(CSharpFunctionalExtensionsJsonSerializerOptions.Options, cancellationToken), ex => DtoMessages.ContentJsonNotResult) | ||
.Bind(result => result); | ||
} | ||
|
||
public static Task<Result<T>> ReadResultAsync<T>(this HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken)) | ||
public static async Task<Result<T>> ReadResultAsync<T>(this HttpResponseMessage response, bool ensureSuccessStatusCode = true, CancellationToken cancellationToken = default(CancellationToken)) | ||
{ | ||
if (response is null) | ||
{ | ||
return Task.FromResult(Result.Failure<T>(DtoMessages.HttpResponseMessageIsNull)); | ||
return Result.Failure<T>(DtoMessages.HttpResponseMessageIsNull); | ||
} | ||
|
||
if (ensureSuccessStatusCode && !response.IsSuccessStatusCode) | ||
{ | ||
return Result.Failure<T>(DtoMessages.NotSuccsessStatusCodeFormat(response.StatusCode, await response.Content.ReadAsStringAsync())); | ||
} | ||
|
||
return | ||
return await | ||
Result.Try(() => response.Content.ReadFromJsonAsync<Result<T>>(CSharpFunctionalExtensionsJsonSerializerOptions.Options, cancellationToken), ex => DtoMessages.ContentJsonNotResult) | ||
.Bind(result => result); | ||
} | ||
|
||
public static async Task<UnitResult<E>> ReadUnitResultAsync<E>(this HttpResponseMessage? response, bool ensureSuccessStatusCode = true, CancellationToken cancellationToken = default(CancellationToken)) | ||
where E : new() | ||
{ | ||
if (response is null) | ||
{ | ||
return UnitResult.Failure<E>(new()); | ||
} | ||
|
||
if (ensureSuccessStatusCode && !response.IsSuccessStatusCode) | ||
{ | ||
return UnitResult.Failure<E>(new()); | ||
} | ||
|
||
try | ||
{ | ||
return await response.Content.ReadFromJsonAsync<UnitResult<E>>(CSharpFunctionalExtensionsJsonSerializerOptions.Options, cancellationToken); | ||
} | ||
catch (JsonException) | ||
{ | ||
return UnitResult.Failure<E>(new()); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
CSharpFunctionalExtensions/Result/Json/Serialization/UnitResultDto.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace CSharpFunctionalExtensions.Json.Serialization | ||
{ | ||
/// <summary> | ||
/// Alternative entry-point for <see cref="UnitResultDto{E}" /> to avoid ambiguous calls | ||
/// </summary> | ||
internal static partial class UnitResultDto | ||
{ | ||
/// <summary> | ||
/// Creates a failure result with the given error. | ||
/// </summary> | ||
public static UnitResultDto<E> Failure<E>(E error) | ||
{ | ||
return new UnitResultDto<E>(error); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a success <see cref="UnitResultDto{E}" />. | ||
/// </summary> | ||
public static UnitResultDto<E> Success<E>() | ||
{ | ||
return new UnitResultDto<E>(); | ||
} | ||
} | ||
|
||
internal record UnitResultDto<E>([property:Required] E? Error = default) | ||
{ | ||
[JsonIgnore] | ||
public bool IsSuccess => Error is null; | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
CSharpFunctionalExtensions/Result/Json/Serialization/UnitResultJsonConverterFactoryOfT.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#nullable enable | ||
using System; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace CSharpFunctionalExtensions.Json.Serialization | ||
{ | ||
internal class UnitResultJsonConverterFactory : JsonConverterFactory | ||
{ | ||
public override bool CanConvert(Type typeToConvert) | ||
{ | ||
if (!typeToConvert.IsGenericType) return false; | ||
|
||
return typeToConvert.GetGenericTypeDefinition() == typeof(UnitResult<>); | ||
} | ||
|
||
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
Type wrappedType = typeToConvert.GetGenericArguments()[0]; | ||
|
||
var genericResultType = typeof(UnitResultJsonConverterOfT<>).MakeGenericType(wrappedType); | ||
JsonConverter? converter = Activator.CreateInstance(genericResultType) as JsonConverter; | ||
|
||
return converter!; | ||
} | ||
} | ||
|
||
internal class UnitResultJsonConverterOfT<E> : JsonConverter<UnitResult<E>> | ||
{ | ||
public override UnitResult<E> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
try | ||
{ | ||
return ToUnitResult(JsonSerializer.Deserialize<UnitResultDto<E>>(ref reader, options)); | ||
} | ||
catch (JsonException) | ||
{ | ||
return UnitResult.Failure<E>(default!); | ||
} | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, UnitResult<E> value, JsonSerializerOptions options) | ||
=> JsonSerializer.Serialize(writer, ToUnitResultDto(value), options); | ||
|
||
private static UnitResult<E> ToUnitResult(UnitResultDto<E>? resultDto) | ||
{ | ||
if (resultDto is not null) | ||
{ | ||
if (resultDto.IsSuccess) | ||
{ | ||
return UnitResult.Success<E>(); | ||
} | ||
|
||
if (resultDto.Error is not null) | ||
{ | ||
return UnitResult.Failure<E>(resultDto.Error); | ||
} | ||
} | ||
|
||
return UnitResult.Failure<E>(default!); | ||
} | ||
|
||
private static UnitResultDto<E> ToUnitResultDto(UnitResult<E> unitResult) | ||
=> unitResult.IsSuccess | ||
? UnitResultDto.Success<E>() | ||
: UnitResultDto.Failure(unitResult.Error); | ||
} | ||
} |