diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml
index 95544f50c84d..8ea85037bbda 100644
--- a/eng/.docsettings.yml
+++ b/eng/.docsettings.yml
@@ -143,6 +143,7 @@ known_content_issues:
- ['sdk/extensions/Azure.Extensions.AspNetCore.DataProtection.Blobs/README.md','azure-sdk-tools/issues/404']
- ['sdk/extensions/Azure.Extensions.AspNetCore.DataProtection.Keys/README.md','azure-sdk-tools/issues/404']
- ['sdk/extensions/Azure.Extensions.AspNetCore.Configuration.Secrets/README.md', 'azure-sdk-tools/issues/404']
+ - ['sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md','azure-sdk-tools/issues/404']
- ['sdk/search/README.md','azure-sdk-tools/issues/42']
- ['sdk/formrecognizer/Azure.AI.FormRecognizer/README.md','#5499']
- ['sdk/formrecognizer/Azure.AI.FormRecognizer/README.md','#11492']
diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props
index 609c9db97965..94da88b094cb 100644
--- a/eng/Packages.Data.props
+++ b/eng/Packages.Data.props
@@ -55,6 +55,7 @@
+
@@ -142,6 +143,7 @@
+
diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs
index b9594be5d426..f95a8fa3ad28 100644
--- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs
+++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs
@@ -45,15 +45,23 @@ public override TestResult Execute(TestExecutionContext context)
// Check the result
if (IsTestFailedWithRecordingMismatch(context))
{
+ var originalResult = context.CurrentResult;
context.CurrentResult = context.CurrentTest.MakeTestResult();
// Run the test again after setting the RecordedTestMode to Record
SetRecordMode(context.TestObject as RecordedTestBase, RecordedTestMode.Record);
context.CurrentResult = innerCommand.Execute(context);
- // If the recording succeeded, set a warning result.
- if (!IsTestFailedWithRecordingMismatch(context))
+ // If the recording succeeded, set an error result.
+ if (context.CurrentResult.ResultState.Status == TestStatus.Passed)
{
- context.CurrentResult.SetResult(ResultState.Error, "Test failed playback, but was successfully re-recorded (it should pass if re-run). Please copy updated recording to SessionFiles.");
+ context.CurrentResult.SetResult(ResultState.Error, "Test failed playback, but was successfully re-recorded (it should pass if re-run). Please copy updated recordings to SessionFiles using `dotnet msbuild /t:UpdateSessionRecords`.");
+ }
+ else
+ {
+ context.CurrentResult.SetResult(context.CurrentResult.ResultState,
+ "Error while trying to re-record: " + Environment.NewLine +
+ context.CurrentResult.Message + Environment.NewLine +
+ "Original error: " + originalResult.Message, context.CurrentResult.Message);
}
// revert RecordTestMode to Playback
@@ -71,7 +79,7 @@ private static bool IsTestFailedWithRecordingMismatch(TestExecutionContext conte
_ => true
};
- return failed && context.CurrentResult.Message.StartsWith(typeof(TestRecordingMismatchException).FullName);
+ return failed && context.CurrentResult.Message.Contains(typeof(TestRecordingMismatchException).FullName);
}
}
diff --git a/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs b/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs
index 0319b867da1f..6826c615f268 100644
--- a/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs
+++ b/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs
@@ -49,7 +49,7 @@ public TestRecording(RecordedTestMode mode, string sessionFile, RecordedTestSani
{
_session = Load();
}
- catch (FileNotFoundException ex)
+ catch (Exception ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException)
{
throw new TestRecordingMismatchException(ex.Message, ex);
}
diff --git a/sdk/core/Microsoft.Extensions.Azure/api/Microsoft.Extensions.Azure.netstandard2.0.cs b/sdk/core/Microsoft.Extensions.Azure/api/Microsoft.Extensions.Azure.netstandard2.0.cs
index a9be4f097bab..98c45d017157 100644
--- a/sdk/core/Microsoft.Extensions.Azure/api/Microsoft.Extensions.Azure.netstandard2.0.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/api/Microsoft.Extensions.Azure.netstandard2.0.cs
@@ -19,6 +19,7 @@ internal AzureClientFactoryBuilder() { }
public Microsoft.Extensions.Azure.AzureClientFactoryBuilder ConfigureDefaults(Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }
public Microsoft.Extensions.Azure.AzureClientFactoryBuilder ConfigureDefaults(System.Action configureOptions) { throw null; }
public Microsoft.Extensions.Azure.AzureClientFactoryBuilder ConfigureDefaults(System.Action configureOptions) { throw null; }
+ public Microsoft.Extensions.Azure.AzureClientFactoryBuilder UseConfiguration(System.Func configurationProvider) { throw null; }
public Microsoft.Extensions.Azure.AzureClientFactoryBuilder UseCredential(Azure.Core.TokenCredential tokenCredential) { throw null; }
public Microsoft.Extensions.Azure.AzureClientFactoryBuilder UseCredential(System.Func tokenCredentialFactory) { throw null; }
}
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs
index 5a1e57e84764..6b9332a07570 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs
@@ -25,6 +25,7 @@ internal AzureClientFactoryBuilder(IServiceCollection serviceCollection)
_serviceCollection = serviceCollection;
_serviceCollection.AddOptions();
_serviceCollection.TryAddSingleton();
+ _serviceCollection.TryAddSingleton(typeof(IAzureClientFactory<>), typeof(FallbackAzureClientFactory<>));
}
IAzureClientBuilder IAzureClientFactoryBuilder.RegisterClientFactory(Func clientFactory)
@@ -91,7 +92,7 @@ public AzureClientFactoryBuilder ConfigureDefaults(IConfiguration configuration)
IAzureClientBuilder IAzureClientFactoryBuilderWithCredential.RegisterClientFactory(Func clientFactory, bool requiresCredential)
{
- var clientRegistration = new ClientRegistration(DefaultClientName, clientFactory);
+ var clientRegistration = new ClientRegistration(DefaultClientName, (options, credential) => clientFactory((TOptions)options, credential));
clientRegistration.RequiresTokenCredential = requiresCredential;
_serviceCollection.AddSingleton(clientRegistration);
@@ -128,5 +129,18 @@ public AzureClientFactoryBuilder UseCredential(Func(options => options.CredentialFactory = tokenCredentialFactory);
return this;
}
+
+ ///
+ /// Sets the configuration instance that is used to resolve clients that were not explicitly registered.
+ ///
+ /// The delegate that returns a configuration instance that's used to resolve client configuration from.
+ /// This instance.
+ public AzureClientFactoryBuilder UseConfiguration(Func configurationProvider)
+ {
+ _serviceCollection.Configure(options => options.ConfigurationRootResolver = configurationProvider);
+
+ return this;
+ }
+
}
}
\ No newline at end of file
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs
index 00aeca7fd093..86ba38094cb5 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs
@@ -3,6 +3,7 @@
using Microsoft.Extensions.DependencyInjection;
using System;
+using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.Azure
{
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/IAzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/IAzureClientFactory.cs
index 5b3a9089382c..a469ab4b354d 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/IAzureClientFactory.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/IAzureClientFactory.cs
@@ -16,4 +16,4 @@ public interface IAzureClientFactory
/// An instance of .
TClient CreateClient(string name);
}
-}
\ No newline at end of file
+}
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientBuilder.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientBuilder.cs
index e4cc0a2e41fe..8405de050110 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientBuilder.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientBuilder.cs
@@ -8,10 +8,10 @@ namespace Microsoft.Extensions.Azure
{
internal sealed class AzureClientBuilder: IAzureClientBuilder where TOptions : class
{
- public ClientRegistration Registration { get; }
+ public ClientRegistration Registration { get; }
public IServiceCollection ServiceCollection { get; }
- internal AzureClientBuilder(ClientRegistration clientRegistration, IServiceCollection serviceCollection)
+ internal AzureClientBuilder(ClientRegistration clientRegistration, IServiceCollection serviceCollection)
{
Registration = clientRegistration;
ServiceCollection = serviceCollection;
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs
index 95f388540d32..485364813f31 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Extensions.Azure
{
internal class AzureClientFactory: IAzureClientFactory
{
- private readonly Dictionary> _clientRegistrations;
+ private readonly Dictionary> _clientRegistrations;
private readonly IServiceProvider _serviceProvider;
@@ -22,10 +22,11 @@ internal class AzureClientFactory: IAzureClientFactory> clientsOptions,
- IEnumerable> clientRegistrations, IOptionsMonitor monitor,
+ IEnumerable> clientRegistrations,
+ IOptionsMonitor monitor,
EventSourceLogForwarder logForwarder)
{
- _clientRegistrations = new Dictionary>();
+ _clientRegistrations = new Dictionary>();
foreach (var registration in clientRegistrations)
{
_clientRegistrations[registration.Name] = registration;
@@ -39,7 +40,8 @@ public AzureClientFactory(
public TClient CreateClient(string name)
{
- if (!_clientRegistrations.TryGetValue(name, out ClientRegistration registration))
+ _logForwarder.Start();
+ if (!_clientRegistrations.TryGetValue(name, out ClientRegistration registration))
{
throw new InvalidOperationException($"Unable to find client registration with type '{typeof(TClient).Name}' and name '{name}'.");
}
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs
index 65ce601caa34..03884bdc98eb 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs
@@ -6,6 +6,7 @@
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Identity;
+using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.Azure
{
@@ -13,5 +14,6 @@ internal class AzureClientsGlobalOptions
{
public Func CredentialFactory { get; set; } = _ => new DefaultAzureCredential();
public List> ConfigureOptionDelegates { get; } = new List>();
+ public Func ConfigurationRootResolver { get; set; }
}
}
\ No newline at end of file
diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs
index ea33aab420f7..c250191c3f92 100644
--- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs
+++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs
@@ -15,9 +15,23 @@ namespace Microsoft.Extensions.Azure
{
internal static class ClientFactory
{
+ private const string ServiceVersionParameterTypeName = "ServiceVersion";
+ private const string ConnectionStringParameterName = "connectionString";
+
public static object CreateClient(Type clientType, Type optionsType, object options, IConfiguration configuration, TokenCredential credential)
{
List