diff --git a/src/Microsoft.OData.Core/ODataServiceCollectionExtensions.cs b/src/Microsoft.OData.Core/ODataServiceCollectionExtensions.cs
index 7637411ef3..66cd9c3199 100644
--- a/src/Microsoft.OData.Core/ODataServiceCollectionExtensions.cs
+++ b/src/Microsoft.OData.Core/ODataServiceCollectionExtensions.cs
@@ -55,15 +55,15 @@ public static IServiceCollection AddDefaultODataServices(this IServiceCollection
// Finally, register configurable settings.
var readerSettings = new ODataMessageReaderSettings(odataVersion);
configureReaderAction?.Invoke(readerSettings);
- services.AddScoped(sp => readerSettings);
+ services.AddScoped(sp => readerSettings.Clone());
var writerSettings = new ODataMessageWriterSettings(odataVersion);
configureWriterAction?.Invoke(writerSettings);
- services.AddScoped(sp => writerSettings);
+ services.AddScoped(sp => writerSettings.Clone());
var parserSettings = new ODataUriParserSettings();
configureUriParserAction?.Invoke(parserSettings);
- services.AddScoped(sp => parserSettings);
+ services.AddScoped(sp => parserSettings.Clone());
return services;
}
diff --git a/src/Microsoft.OData.Core/UriParser/ODataUriParserSettings.cs b/src/Microsoft.OData.Core/UriParser/ODataUriParserSettings.cs
index f41fbaacff..a19d663fe6 100644
--- a/src/Microsoft.OData.Core/UriParser/ODataUriParserSettings.cs
+++ b/src/Microsoft.OData.Core/UriParser/ODataUriParserSettings.cs
@@ -89,6 +89,20 @@ public ODataUriParserSettings()
this.EnableParsingKeyAsSegment = true;
}
+ internal ODataUriParserSettings Clone()
+ {
+ return new()
+ {
+ FilterLimit = this.FilterLimit,
+ OrderByLimit = this.OrderByLimit,
+ PathLimit = this.PathLimit,
+ SearchLimit = this.SearchLimit,
+ MaximumExpansionDepth = this.MaximumExpansionDepth,
+ MaximumExpansionCount = this.MaximumExpansionCount,
+ EnableParsingKeyAsSegment = this.EnableParsingKeyAsSegment
+ };
+ }
+
///
/// Gets or sets the maximum depth of the tree that results from parsing $expand.
///
diff --git a/test/FunctionalTests/Microsoft.OData.Core.Tests/ODataServiceCollectionExtensionTests.cs b/test/FunctionalTests/Microsoft.OData.Core.Tests/ODataServiceCollectionExtensionTests.cs
index 5450f5e7f1..8a1b05d6b1 100644
--- a/test/FunctionalTests/Microsoft.OData.Core.Tests/ODataServiceCollectionExtensionTests.cs
+++ b/test/FunctionalTests/Microsoft.OData.Core.Tests/ODataServiceCollectionExtensionTests.cs
@@ -4,11 +4,11 @@
//
//---------------------------------------------------------------------
-using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OData.Edm;
using Microsoft.OData.Json;
using Microsoft.OData.UriParser;
+using System;
using Xunit;
namespace Microsoft.OData.Tests
@@ -136,6 +136,29 @@ public void AddDefaultODataServices_ReaderSettings_CanConfigure()
Assert.True(readerSettings.EnableCharactersCheck);
}
+ [Fact]
+ public void AddDefaultODataServices_ReaderSettings_InstancesAreScoped()
+ {
+ var services = new ServiceCollection();
+ services.AddDefaultODataServices();
+ var provider = services.BuildServiceProvider();
+ using var scope1 = provider.CreateScope();
+ var settings = scope1.ServiceProvider.GetRequiredService();
+ settings.EnableCharactersCheck = true;
+
+ var settingsFromSameScope = scope1.ServiceProvider.GetRequiredService();
+
+ using var scope2 = provider.CreateScope();
+ var settingsFromOtherScope = scope2.ServiceProvider.GetRequiredService();
+
+ // Instances from the same scope should be the same
+ Assert.True(object.ReferenceEquals(settings, settingsFromSameScope));
+ Assert.True(settingsFromSameScope.EnableCharactersCheck);
+ // Instances from different scopes should be different
+ Assert.False(object.ReferenceEquals(settings, settingsFromOtherScope));
+ Assert.False(settingsFromOtherScope.EnableCharactersCheck);
+ }
+
///
/// Tests whether the can be configured using the .
///
@@ -160,6 +183,29 @@ public void AddDefaultODataServices_WriterSettings_CanConfigure()
Assert.True(writerSettings.EnableCharactersCheck);
}
+ [Fact]
+ public void AddDefaultODataServices_WriterSettings_InstancesAreScoped()
+ {
+ var services = new ServiceCollection();
+ services.AddDefaultODataServices();
+ var provider = services.BuildServiceProvider();
+ using var scope1 = provider.CreateScope();
+ var settings = scope1.ServiceProvider.GetRequiredService();
+ settings.EnableCharactersCheck = true;
+
+ var settingsFromSameScope = scope1.ServiceProvider.GetRequiredService();
+
+ using var scope2 = provider.CreateScope();
+ var settingsFromOtherScope = scope2.ServiceProvider.GetRequiredService();
+
+ // Instances from the same scope should be the same
+ Assert.True(object.ReferenceEquals(settings, settingsFromSameScope));
+ Assert.True(settingsFromSameScope.EnableCharactersCheck);
+ // Instances from different scopes should be different
+ Assert.False(object.ReferenceEquals(settings, settingsFromOtherScope));
+ Assert.False(settingsFromOtherScope.EnableCharactersCheck);
+ }
+
///
/// Tests whether the can be configured using the .
///
@@ -184,6 +230,29 @@ public void AddDefaultODataServices_ODataUriParserSettings_CanConfigure()
Assert.Equal(1, parserSettings.MaximumExpansionCount);
}
+ [Fact]
+ public void AddDefaultODataServices_ODataUriParserSettings_InstancesAreScoped()
+ {
+ var services = new ServiceCollection();
+ services.AddDefaultODataServices();
+ var provider = services.BuildServiceProvider();
+ using var scope1 = provider.CreateScope();
+ var settings = scope1.ServiceProvider.GetRequiredService();
+ settings.EnableParsingKeyAsSegment = false;
+
+ var settingsFromSameScope = scope1.ServiceProvider.GetRequiredService();
+
+ using var scope2 = provider.CreateScope();
+ var settingsFromOtherScope = scope2.ServiceProvider.GetRequiredService();
+
+ // Instances from the same scope should be the same
+ Assert.True(object.ReferenceEquals(settings, settingsFromSameScope));
+ Assert.False(settingsFromSameScope.EnableParsingKeyAsSegment);
+ // Instances from different scopes should be different
+ Assert.False(object.ReferenceEquals(settings, settingsFromOtherScope));
+ Assert.True(settingsFromOtherScope.EnableParsingKeyAsSegment);
+ }
+
///
/// Tests whether the correct exception is thrown when no is provided.
///