Cache JsonSerializerOptions

According to https://github.com/dotnet/runtime/issues/65396, using a new JsonSerializerOptions every time JsonSerializer is invoked is a suboptimal pattern.

Fix this by caching JsonSerializerOptions instances.
This commit is contained in:
Eric Erhardt 2023-06-13 11:31:11 -05:00
parent 3169a93344
commit fd76f390ef
10 changed files with 34 additions and 52 deletions

View File

@ -23,9 +23,6 @@ public class OrderApiClient : IOrderApiClient
var ordersDraftResponse = await response.Content.ReadAsStringAsync(); var ordersDraftResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
} }
} }

View File

@ -23,9 +23,6 @@ public class OrderApiClient : IOrderApiClient
var ordersDraftResponse = await response.Content.ReadAsStringAsync(); var ordersDraftResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
} }
} }

View File

@ -5,6 +5,9 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
{ {
const string BROKER_NAME = "eshop_event_bus"; const string BROKER_NAME = "eshop_event_bus";
private static readonly JsonSerializerOptions s_indentedOptions = new() { WriteIndented = true };
private static readonly JsonSerializerOptions s_caseInsensitiveOptions = new() { PropertyNameCaseInsensitive = true };
private readonly IRabbitMQPersistentConnection _persistentConnection; private readonly IRabbitMQPersistentConnection _persistentConnection;
private readonly ILogger<EventBusRabbitMQ> _logger; private readonly ILogger<EventBusRabbitMQ> _logger;
private readonly IEventBusSubscriptionsManager _subsManager; private readonly IEventBusSubscriptionsManager _subsManager;
@ -69,10 +72,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
var body = JsonSerializer.SerializeToUtf8Bytes(@event, @event.GetType(), new JsonSerializerOptions var body = JsonSerializer.SerializeToUtf8Bytes(@event, @event.GetType(), s_indentedOptions);
{
WriteIndented = true
});
policy.Execute(() => policy.Execute(() =>
{ {
@ -256,7 +256,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
var handler = scope.ServiceProvider.GetService(subscription.HandlerType); var handler = scope.ServiceProvider.GetService(subscription.HandlerType);
if (handler == null) continue; if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName); var eventType = _subsManager.GetEventTypeByName(eventName);
var integrationEvent = JsonSerializer.Deserialize(message, eventType, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); var integrationEvent = JsonSerializer.Deserialize(message, eventType, s_caseInsensitiveOptions);
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
await Task.Yield(); await Task.Yield();

View File

@ -2,16 +2,16 @@
public class IntegrationEventLogEntry public class IntegrationEventLogEntry
{ {
private static readonly JsonSerializerOptions s_indentedOptions = new() { WriteIndented = true };
private static readonly JsonSerializerOptions s_caseInsensitiveOptions = new() { PropertyNameCaseInsensitive = true };
private IntegrationEventLogEntry() { } private IntegrationEventLogEntry() { }
public IntegrationEventLogEntry(IntegrationEvent @event, Guid transactionId) public IntegrationEventLogEntry(IntegrationEvent @event, Guid transactionId)
{ {
EventId = @event.Id; EventId = @event.Id;
CreationTime = @event.CreationDate; CreationTime = @event.CreationDate;
EventTypeName = @event.GetType().FullName; EventTypeName = @event.GetType().FullName;
Content = JsonSerializer.Serialize(@event, @event.GetType(), new JsonSerializerOptions Content = JsonSerializer.Serialize(@event, @event.GetType(), s_indentedOptions);
{
WriteIndented = true
});
State = EventStateEnum.NotPublished; State = EventStateEnum.NotPublished;
TimesSent = 0; TimesSent = 0;
TransactionId = transactionId.ToString(); TransactionId = transactionId.ToString();
@ -30,7 +30,7 @@ public class IntegrationEventLogEntry
public IntegrationEventLogEntry DeserializeJsonContent(Type type) public IntegrationEventLogEntry DeserializeJsonContent(Type type)
{ {
IntegrationEvent = JsonSerializer.Deserialize(Content, type, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }) as IntegrationEvent; IntegrationEvent = JsonSerializer.Deserialize(Content, type, s_caseInsensitiveOptions) as IntegrationEvent;
return this; return this;
} }
} }

View File

@ -35,15 +35,12 @@ public class RedisBasketRepository : IBasketRepository
return null; return null;
} }
return JsonSerializer.Deserialize<CustomerBasket>(data, new JsonSerializerOptions return JsonSerializer.Deserialize<CustomerBasket>(data, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
} }
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket) public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket)
{ {
var created = await _database.StringSetAsync(basket.BuyerId, JsonSerializer.Serialize(basket)); var created = await _database.StringSetAsync(basket.BuyerId, JsonSerializer.Serialize(basket, JsonHelper.CaseInsensitiveOptions));
if (!created) if (!created)
{ {
@ -51,7 +48,7 @@ public class RedisBasketRepository : IBasketRepository
return null; return null;
} }
_logger.LogInformation("Basket item persisted succesfully."); _logger.LogInformation("Basket item persisted successfully.");
return await GetBasketAsync(basket.BuyerId); return await GetBasketAsync(basket.BuyerId);
} }

View File

@ -0,0 +1,12 @@
using System.Text.Json;
namespace Services.Common
{
public static class JsonHelper
{
public static readonly JsonSerializerOptions CaseInsensitiveOptions = new()
{
PropertyNameCaseInsensitive = true
};
}
}

View File

@ -29,10 +29,7 @@ public class BasketService : IBasketService
var responseString = await response.Content.ReadAsStringAsync(); var responseString = await response.Content.ReadAsStringAsync();
return string.IsNullOrEmpty(responseString) ? return string.IsNullOrEmpty(responseString) ?
new Basket() { BuyerId = user.Id } : new Basket() { BuyerId = user.Id } :
JsonSerializer.Deserialize<Basket>(responseString, new JsonSerializerOptions JsonSerializer.Deserialize<Basket>(responseString, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
} }
public async Task<Basket> UpdateBasket(Basket basket) public async Task<Basket> UpdateBasket(Basket basket)
@ -82,10 +79,7 @@ public class BasketService : IBasketService
var jsonResponse = await response.Content.ReadAsStringAsync(); var jsonResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<Basket>(jsonResponse, new JsonSerializerOptions return JsonSerializer.Deserialize<Basket>(jsonResponse, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
} }
public async Task<Order> GetOrderDraft(string basketId) public async Task<Order> GetOrderDraft(string basketId)
@ -94,10 +88,7 @@ public class BasketService : IBasketService
var responseString = await _apiClient.GetStringAsync(uri); var responseString = await _apiClient.GetStringAsync(uri);
var response = JsonSerializer.Deserialize<Order>(responseString, new JsonSerializerOptions var response = JsonSerializer.Deserialize<Order>(responseString, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
return response; return response;
} }

View File

@ -23,10 +23,7 @@ public class CatalogService : ICatalogService
var responseString = await _httpClient.GetStringAsync(uri); var responseString = await _httpClient.GetStringAsync(uri);
var catalog = JsonSerializer.Deserialize<Catalog>(responseString, new JsonSerializerOptions var catalog = JsonSerializer.Deserialize<Catalog>(responseString, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
return catalog; return catalog;
} }

View File

@ -23,10 +23,7 @@ public class OrderingService : IOrderingService
var responseString = await _httpClient.GetStringAsync(uri); var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonSerializer.Deserialize<Order>(responseString, new JsonSerializerOptions var response = JsonSerializer.Deserialize<Order>(responseString, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
return response; return response;
} }
@ -37,10 +34,7 @@ public class OrderingService : IOrderingService
var responseString = await _httpClient.GetStringAsync(uri); var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonSerializer.Deserialize<List<Order>>(responseString, new JsonSerializerOptions var response = JsonSerializer.Deserialize<List<Order>>(responseString, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
return response; return response;
} }

View File

@ -14,10 +14,7 @@ public class WebhooksClient : IWebhooksClient
var client = _httpClientFactory.CreateClient("GrantClient"); var client = _httpClientFactory.CreateClient("GrantClient");
var response = await client.GetAsync(_options.WebhooksUrl + "/api/v1/webhooks"); var response = await client.GetAsync(_options.WebhooksUrl + "/api/v1/webhooks");
var json = await response.Content.ReadAsStringAsync(); var json = await response.Content.ReadAsStringAsync();
var subscriptions = JsonSerializer.Deserialize<IEnumerable<WebhookResponse>>(json, new JsonSerializerOptions var subscriptions = JsonSerializer.Deserialize<IEnumerable<WebhookResponse>>(json, JsonHelper.CaseInsensitiveOptions);
{
PropertyNameCaseInsensitive = true
});
return subscriptions; return subscriptions;
} }
} }