Browse Source

Introduce AddAbpOptions to prevent options deadlocks

Related to #24247
pull/24260/head
maliming 2 months ago
parent
commit
1be22edac9
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs
  2. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  3. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  4. 22
      framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionOptionsExtensions.cs
  5. 34
      framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpUnnamedOptionsManager.cs
  6. 2
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs
  7. 2
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs
  8. 4
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs
  9. 2
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs
  10. 2
      modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs

2
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs

@ -13,7 +13,7 @@ public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule
{
context.Services.AddMvcCore().AddNewtonsoftJson();
context.Services.AddOptions<MvcNewtonsoftJsonOptions>()
context.Services.AddAbpOptions<MvcNewtonsoftJsonOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.SerializerSettings.ContractResolver =

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -165,7 +165,7 @@ public class AbpAspNetCoreMvcModule : AbpModule
context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
context.Services.TryAddEnumerable(ServiceDescriptor.Transient<IActionDescriptorProvider, AbpMvcActionDescriptorProvider>());
context.Services.AddOptions<MvcOptions>()
context.Services.AddAbpOptions<MvcOptions>()
.Configure<IServiceProvider>((mvcOptions, serviceProvider) =>
{
mvcOptions.AddAbp(context.Services);

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs

@ -13,7 +13,7 @@ public static class MvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddAbpJson(this IMvcCoreBuilder builder)
{
builder.Services.AddOptions<JsonOptions>()
builder.Services.AddAbpOptions<JsonOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;

22
framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionOptionsExtensions.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.Options;
namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionOptionsExtensions
{
/// <summary>
/// You should only use this method to register options if you need to continue using the ServiceProvider to get other options in your Options configuration method.
/// Otherwise, please use the default AddOptions method for better performance.
/// </summary>
/// <param name="services"></param>
/// <typeparam name="TOptions"></typeparam>
/// <returns></returns>
public static OptionsBuilder<TOptions> AddAbpOptions<TOptions>(this IServiceCollection services)
where TOptions : class
{
services.TryAddSingleton<IOptions<TOptions>, AbpUnnamedOptionsManager<TOptions>>();
return services.AddOptions<TOptions>();
}
}

34
framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpUnnamedOptionsManager.cs

@ -0,0 +1,34 @@
using Microsoft.Extensions.Options;
namespace Volo.Abp.Options;
/// <summary>
/// This Options manager is similar to Microsoft UnnamedOptionsManager but without the locking mechanism.
/// Prevent deadlocks when accessing options in multiple threads.
/// </summary>
/// <typeparam name="TOptions"></typeparam>
public class AbpUnnamedOptionsManager<TOptions> : IOptions<TOptions>
where TOptions : class
{
private readonly IOptionsFactory<TOptions> _factory;
private volatile TOptions? _value;
public AbpUnnamedOptionsManager(IOptionsFactory<TOptions> factory)
{
_factory = factory;
}
public TOptions Value
{
get
{
if (_value is TOptions value)
{
return value;
}
_value = _factory.Create(Microsoft.Extensions.Options.Options.DefaultName);
return _value;
}
}
}

2
framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs

@ -10,7 +10,7 @@ public class AbpJsonNewtonsoftModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpNewtonsoftJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpNewtonsoftJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerSettings.ContractResolver = new AbpCamelCasePropertyNamesContractResolver(

2
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs

@ -15,7 +15,7 @@ public class AbpJsonSystemTextJsonModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpSystemTextJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpSystemTextJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.

4
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs

@ -19,7 +19,7 @@ public class AbpJsonSystemTextJsonTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpSystemTextJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpSystemTextJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
if (options.JsonSerializerOptions.TypeInfoResolver != null)
@ -43,7 +43,7 @@ public class AbpJsonNewtonsoftTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpNewtonsoftJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpNewtonsoftJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerSettings.ContractResolver = new AbpCamelCasePropertyNamesContractResolver(

2
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs

@ -34,7 +34,7 @@ public class AbpMemoryDbTestModule : AbpModule
options.AddRepository<City, CityRepository>();
});
context.Services.AddOptions<Utf8JsonMemoryDbSerializerOptions>()
context.Services.AddAbpOptions<Utf8JsonMemoryDbSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerOptions.Converters.Add(new EntityJsonConverter<EntityWithIntPk, int>());

2
modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs

@ -47,7 +47,7 @@ public class AbpIdentityAspNetCoreModule : AbpModule
public override void PostConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<SecurityStampValidatorOptions>()
context.Services.AddAbpOptions<SecurityStampValidatorOptions>()
.Configure<IServiceProvider>((securityStampValidatorOptions, serviceProvider) =>
{
var abpRefreshingPrincipalOptions = serviceProvider.GetRequiredService<IOptions<AbpRefreshingPrincipalOptions>>().Value;

Loading…
Cancel
Save