From ecc018e2edcc5bac9e1ae377f84f00e0a3b29842 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 31 Jul 2020 13:23:16 -0700 Subject: [PATCH 01/20] WebJobs prototype --- eng/Packages.Data.props | 2 + .../src/AzureClientFactoryBuilder.cs | 17 +- .../AzureClientServiceCollectionExtensions.cs | 11 + .../src/FallbackAzureClientFactory.cs | 98 +++++++ .../src/Internal/AzureClientBuilder.cs | 4 +- .../src/Internal/AzureClientFactory.cs | 9 +- .../src/Internal/AzureClientsGlobalOptions.cs | 2 + .../src/Internal/ClientFactory.cs | 69 +++++ .../src/Internal/ClientOptionsFactory.cs | 69 +---- ...ons}.cs => ClientRegistration{TClient}.cs} | 8 +- .../Internal/ConfigureClientCredentials.cs | 4 +- .../src/Internal/ConfigureClientOptions.cs | 4 +- .../tests/AzureClientFactoryTests.cs | 25 ++ .../.gitignore | 264 ++++++++++++++++++ .../Azure.Extensions.WebJobs.Sample.csproj | 18 ++ .../Function1.cs | 35 +++ .../Azure.Extensions.WebJobs.Sample/host.json | 11 + .../src/Azure.Extensions.WebJobs.csproj | 17 ++ .../src/AzureClientAttribute.cs | 18 ++ .../AzureClientsExtensionConfigProvider.cs | 67 +++++ .../AzureClientsWebJobsBuilderExtensions.cs | 32 +++ .../src/EventHubsWebJobsStartup.cs | 24 ++ sdk/extensions/Azure.Extensions.sln | 114 +++++++- 23 files changed, 829 insertions(+), 93 deletions(-) create mode 100644 sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs rename sdk/core/Microsoft.Extensions.Azure/src/Internal/{ClientRegistration{TClient,TOptions}.cs => ClientRegistration{TClient}.cs} (83%) create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index 14b829b72a73..013e7abf189c 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -139,7 +139,9 @@ + + diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs index 5a1e57e84764..4a42de497f29 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using System; +using System.Collections.Concurrent; namespace Microsoft.Extensions.Azure { @@ -25,6 +26,7 @@ internal AzureClientFactoryBuilder(IServiceCollection serviceCollection) _serviceCollection = serviceCollection; _serviceCollection.AddOptions(); _serviceCollection.TryAddSingleton(); + _serviceCollection.TryAddSingleton( typeof(IAzureClientFactory<>), typeof(FallbackAzureClientFactory<>)); } IAzureClientBuilder IAzureClientFactoryBuilder.RegisterClientFactory(Func clientFactory) @@ -91,7 +93,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 +130,18 @@ public AzureClientFactoryBuilder UseCredential(Func(options => options.CredentialFactory = tokenCredentialFactory); return this; } + + /// + /// + /// + /// + /// + public AzureClientFactoryBuilder SetConfigurationRoot(IConfiguration configuration) + { + _serviceCollection.Configure(options => options.ConfigurationRoot = configuration); + + 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..e35c9ab911c5 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 { @@ -20,5 +21,15 @@ public static void AddAzureClients(this IServiceCollection collection, Action + /// + /// + /// + /// + public static void AddAzureClients(this IServiceCollection collection, IConfiguration configuration) + { + new AzureClientFactoryBuilder(collection).SetConfigurationRoot(configuration); + } } } \ No newline at end of file diff --git a/sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs new file mode 100644 index 000000000000..64f2207f70c3 --- /dev/null +++ b/sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Azure.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Azure +{ + internal class FallbackAzureClientFactory: IAzureClientFactory + { + private readonly IOptionsMonitor _globalOptions; + private readonly IServiceProvider _serviceProvider; + private readonly Dictionary> _clientRegistrations; + private readonly Type _clientOptionType; + + public FallbackAzureClientFactory( + IOptionsMonitor globalOptions, + IServiceProvider serviceProvider) + { + _globalOptions = globalOptions; + _serviceProvider = serviceProvider; + _clientRegistrations = new Dictionary>(); + + foreach (var constructor in typeof(TClient).GetConstructors(BindingFlags.Public | BindingFlags.Instance)) + { + var lastParameter = constructor.GetParameters().LastOrDefault(); + if (lastParameter != null && typeof(ClientOptions).IsAssignableFrom(lastParameter.ParameterType)) + { + _clientOptionType = lastParameter.ParameterType; + break; + } + } + + if (_clientOptionType == null) + { + throw new InvalidOperationException("Unable to detect the client option type"); + } + } + + public TClient CreateClient(string name) + { + var globalOptions = _globalOptions.CurrentValue; + + FallbackClientRegistration registration; + lock (_clientRegistrations) + { + if (!_clientRegistrations.TryGetValue(name, out registration)) + { + var section = globalOptions.ConfigurationRoot?.GetSection(name); + if (!section.Exists()) + { + throw new InvalidOperationException($"Unable to find a configuration section with the name {name} to configure the client with or the configuration root wasn't set."); + } + + registration = new FallbackClientRegistration( + name, + (options, credential) => (TClient) ClientFactory.CreateClient(typeof(TClient), _clientOptionType, options, section, credential), + section); + + _clientRegistrations.Add(name, registration); + } + } + + + return registration.GetClient( + GetClientOptions(globalOptions, registration.Configuration), + ClientFactory.CreateCredential(registration.Configuration) ?? globalOptions.CredentialFactory(_serviceProvider)); + } + + private object GetClientOptions(AzureClientsGlobalOptions globalOptions, IConfiguration section) + { + var clientOptions = (ClientOptions) ClientFactory.CreateClientOptions(null, _clientOptionType); + foreach (var globalConfigureOptions in globalOptions.ConfigureOptionDelegates) + { + globalConfigureOptions(clientOptions, _serviceProvider); + } + + section.Bind(clientOptions); + + return clientOptions; + } + + private class FallbackClientRegistration: ClientRegistration + { + public IConfiguration Configuration { get; } + + public FallbackClientRegistration(string name, Func factory, IConfiguration configuration) : base(name, factory) + { + Configuration = configuration; + } + } + } +} \ 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..18da9309403b 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,7 @@ public AzureClientFactory( public TClient CreateClient(string name) { - if (!_clientRegistrations.TryGetValue(name, out ClientRegistration registration)) + 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..4df2a32a152f 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 IConfiguration ConfigurationRoot { 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..b54690d102ac 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs @@ -15,6 +15,8 @@ namespace Microsoft.Extensions.Azure { internal static class ClientFactory { + private const string ServiceVersionParameterTypeName = "ServiceVersion"; + public static object CreateClient(Type clientType, Type optionsType, object options, IConfiguration configuration, TokenCredential credential) { List arguments = new List(); @@ -120,6 +122,73 @@ internal static TokenCredential CreateCredential(IConfiguration configuration, T return null; } + + internal static object CreateClientOptions(object version, Type optionsType) + { + ConstructorInfo parameterlessConstructor = null; + int versionParameterIndex = 0; + object[] constructorArguments = null; + + foreach (var constructor in optionsType.GetConstructors()) + { + var parameters = constructor.GetParameters(); + if (parameters.Length == 0) + { + parameterlessConstructor = constructor; + continue; + } + + bool allParametersHaveDefaultValue = true; + for (int i = 0; i < parameters.Length; i++) + { + ParameterInfo parameter = parameters[i]; + if (parameter.HasDefaultValue) + { + if (IsServiceVersionParameter(parameter)) + { + versionParameterIndex = i; + } + } + else + { + allParametersHaveDefaultValue = false; + break; + } + } + + if (allParametersHaveDefaultValue) + { + constructorArguments = new object[parameters.Length]; + + for (int i = 0; i < parameters.Length; i++) + { + constructorArguments[i] = parameters[i].DefaultValue; + } + } + } + + if (version != null) + { + if (constructorArguments != null) + { + constructorArguments[versionParameterIndex] = version; + return Activator.CreateInstance(optionsType, constructorArguments); + } + + throw new InvalidOperationException("Unable to find constructor that takes service version"); + } + + if (parameterlessConstructor != null) + { + return Activator.CreateInstance(optionsType); + } + + return Activator.CreateInstance(optionsType, constructorArguments); + } + + private static bool IsServiceVersionParameter(ParameterInfo parameter) => + parameter.ParameterType.Name == ServiceVersionParameterTypeName; + private static bool IsCredentialParameter(ParameterInfo parameter) { return parameter.ParameterType == typeof(TokenCredential); diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientOptionsFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientOptionsFactory.cs index c2d3cbcac9f1..78d497a81012 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientOptionsFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientOptionsFactory.cs @@ -11,14 +11,12 @@ namespace Microsoft.Extensions.Azure // Slightly adjusted copy of https://github.com/aspnet/Extensions/blob/master/src/Options/Options/src/OptionsFactory.cs internal class ClientOptionsFactory where TOptions : class { - private const string ServiceVersionParameterTypeName = "ServiceVersion"; - private readonly IEnumerable> _setups; private readonly IEnumerable> _postConfigures; - private readonly IEnumerable> _clientRegistrations; + private readonly IEnumerable> _clientRegistrations; - public ClientOptionsFactory(IEnumerable> setups, IEnumerable> postConfigures, IEnumerable> clientRegistrations) + public ClientOptionsFactory(IEnumerable> setups, IEnumerable> postConfigures, IEnumerable> clientRegistrations) { _setups = setups; _postConfigures = postConfigures; @@ -37,70 +35,9 @@ private TOptions CreateOptions(string name) } } - ConstructorInfo parameterlessConstructor = null; - int versionParameterIndex = 0; - object[] constructorArguments = null; - - foreach (var constructor in typeof(TOptions).GetConstructors()) - { - var parameters = constructor.GetParameters(); - if (parameters.Length == 0) - { - parameterlessConstructor = constructor; - continue; - } - - bool allParametersHaveDefaultValue = true; - for (int i = 0; i < parameters.Length; i++) - { - ParameterInfo parameter = parameters[i]; - if (parameter.HasDefaultValue) - { - if (IsServiceVersionParameter(parameter)) - { - versionParameterIndex = i; - } - } - else - { - allParametersHaveDefaultValue = false; - break; - } - } - - if (allParametersHaveDefaultValue) - { - constructorArguments = new object[parameters.Length]; - - for (int i = 0; i < parameters.Length; i++) - { - constructorArguments[i] = parameters[i].DefaultValue; - } - } - } - - if (version != null) - { - if (constructorArguments != null) - { - constructorArguments[versionParameterIndex] = version; - return (TOptions)Activator.CreateInstance(typeof(TOptions), constructorArguments); - } - - throw new InvalidOperationException("Unable to find constructor that takes service version"); - } - - if (parameterlessConstructor != null) - { - return Activator.CreateInstance(); - } - - return (TOptions)Activator.CreateInstance(typeof(TOptions), constructorArguments); + return (TOptions)ClientFactory.CreateClientOptions(version, typeof(TOptions)); } - private static bool IsServiceVersionParameter(ParameterInfo parameter) => - parameter.ParameterType.Name == ServiceVersionParameterTypeName; - /// /// Returns a configured instance with the given . /// diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient,TOptions}.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient}.cs similarity index 83% rename from sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient,TOptions}.cs rename to sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient}.cs index 3c89888c75f8..d926aedeab09 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient,TOptions}.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientRegistration{TClient}.cs @@ -7,13 +7,13 @@ namespace Microsoft.Extensions.Azure { - internal class ClientRegistration + internal class ClientRegistration { public string Name { get; set; } public object Version { get; set; } public bool RequiresTokenCredential { get; set; } - private readonly Func _factory; + private readonly Func _factory; private readonly object _cacheLock = new object(); @@ -21,13 +21,13 @@ internal class ClientRegistration private ExceptionDispatchInfo _cachedException; - public ClientRegistration(string name, Func factory) + public ClientRegistration(string name, Func factory) { Name = name; _factory = factory; } - public TClient GetClient(TOptions options, TokenCredential tokenCredential) + public TClient GetClient(object options, TokenCredential tokenCredential) { _cachedException?.Throw(); diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientCredentials.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientCredentials.cs index 6e62aa15c08d..f3b9b4d2e587 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientCredentials.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientCredentials.cs @@ -9,11 +9,11 @@ namespace Microsoft.Extensions.Azure { internal class ConfigureClientCredentials : IConfigureNamedOptions> { - private readonly ClientRegistration _registration; + private readonly ClientRegistration _registration; private readonly Func _credentialFactory; public ConfigureClientCredentials( - ClientRegistration registration, + ClientRegistration registration, Func credentialFactory) { _registration = registration; diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientOptions.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientOptions.cs index 10708f684d95..5490d1f263e0 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientOptions.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ConfigureClientOptions.cs @@ -9,10 +9,10 @@ namespace Microsoft.Extensions.Azure internal class ConfigureClientOptions : IConfigureNamedOptions where TOptions : class { private readonly IServiceProvider _serviceProvider; - private readonly ClientRegistration _registration; + private readonly ClientRegistration _registration; private readonly Action _configureOptions; - public ConfigureClientOptions(IServiceProvider serviceProvider, ClientRegistration registration, Action configureOptions) + public ConfigureClientOptions(IServiceProvider serviceProvider, ClientRegistration registration, Action configureOptions) { _serviceProvider = serviceProvider; _registration = registration; diff --git a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs index e0e8cea60f63..8c6be9726abe 100644 --- a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs +++ b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs @@ -309,6 +309,31 @@ public void UsesCredentialFromConfiguration() Assert.AreEqual("ConfigurationTenantId", clientSecretCredential.TenantId); } + [Test] + public void CanCreateClientWithoutRegistration() + { + var configuration = GetConfiguration( + new KeyValuePair("TestClient:uri", "http://localhost/"), + new KeyValuePair("TestClient:clientId", "ConfigurationClientId"), + new KeyValuePair("TestClient:clientSecret", "ConfigurationClientSecret"), + new KeyValuePair("TestClient:tenantId", "ConfigurationTenantId")); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddAzureClients(configuration); + + ServiceProvider provider = serviceCollection.BuildServiceProvider(); + IAzureClientFactory factory = provider.GetService>(); + TestClientWithCredentials client = factory.CreateClient("TestClient"); + + Assert.IsInstanceOf(client.Credential); + var clientSecretCredential = (ClientSecretCredential)client.Credential; + + Assert.AreEqual("http://localhost/", client.Uri.ToString()); + Assert.AreEqual("ConfigurationClientId", clientSecretCredential.ClientId); + Assert.AreEqual("ConfigurationClientSecret", clientSecretCredential.ClientSecret); + Assert.AreEqual("ConfigurationTenantId", clientSecretCredential.TenantId); + } + [Test] public void SupportsSettingVersion() { diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore new file mode 100644 index 000000000000..ff5b00c506bd --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj new file mode 100644 index 000000000000..a6bad7eeafa6 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj @@ -0,0 +1,18 @@ + + + netcoreapp3.1 + v3 + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs new file mode 100644 index 000000000000..5a367434722e --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace Azure.Extensions.WebJobs.Sample +{ + public static class Function1 + { + [FunctionName("Function1")] + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, + ILogger log) + { + log.LogInformation("C# HTTP trigger function processed a request."); + + string name = req.Query["name"]; + + string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); + dynamic data = JsonConvert.DeserializeObject(requestBody); + name = name ?? data?.name; + + string responseMessage = string.IsNullOrEmpty(name) + ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." + : $"Hello, {name}. This HTTP triggered function executed successfully."; + + return new OkObjectResult(responseMessage); + } + } +} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json new file mode 100644 index 000000000000..bb3b8dadd7d6 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json @@ -0,0 +1,11 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingExcludedTypes": "Request", + "samplingSettings": { + "isEnabled": true + } + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj b/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj new file mode 100644 index 000000000000..b3bb34853085 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj @@ -0,0 +1,17 @@ + + + + $(RequiredTargetFrameworks) + + aspnetcore;dataprotection;azure;blob;key store + 1.0.0-preview.1 + true + $(NoWarn);AZC0001;CA1812 + + + + + + + + diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs new file mode 100644 index 000000000000..839518d37b64 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Azure.WebJobs; + +namespace Azure.Extensions.WebJobs +{ + /// + /// + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class AzureClientAttribute: Attribute, IConnectionProvider + { + /// + public string Connection { get; set; } + } +} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs new file mode 100644 index 000000000000..274c118d148f --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Extensions.WebJobs; +using Microsoft.Azure.WebJobs.Host.Bindings; +using Microsoft.Azure.WebJobs.Host.Config; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.Extensions.Hosting +{ + internal class AzureClientsExtensionConfigProvider : IExtensionConfigProvider + { + private readonly IServiceProvider _serviceProvider; + + public AzureClientsExtensionConfigProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void Initialize(ExtensionConfigContext context) + { + context.AddBindingRule() + .BindToValueProvider((attribute, type) => Task.FromResult(CreateValueBinder(type, attribute))); + } + + private IValueBinder CreateValueBinder(Type type, AzureClientAttribute attribute) + { + return (IValueBinder)Activator.CreateInstance(typeof(AzureClientValueProvider<>).MakeGenericType(type), _serviceProvider, attribute.Connection); + } + + private class AzureClientValueProvider : IValueBinder + { + private readonly IServiceProvider _serviceProvider; + private readonly string _connection; + + public AzureClientValueProvider(IServiceProvider serviceProvider, string connection) + { + _serviceProvider = serviceProvider; + _connection = connection; + } + + public Task GetValueAsync() + { + return Task.FromResult( + (object)_serviceProvider + .GetService>() + .CreateClient(_connection)); + } + + public string ToInvokeString() + { + throw new NotImplementedException(); + } + + public Type Type => typeof(TClient); + + public Task SetValueAsync(object value, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs new file mode 100644 index 000000000000..bd2bf7e2aed0 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Azure.WebJobs; + +namespace Microsoft.Extensions.Hosting +{ + /// + /// + /// + public static class AzureClientsWebJobsBuilderExtensions + { + /// + /// + /// + /// + /// + /// + public static IWebJobsBuilder AddAzureClients(this IWebJobsBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AddExtension(); + + return builder; + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs new file mode 100644 index 000000000000..b9027a63c553 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Hosting; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.Hosting; + +[assembly: WebJobsStartup(typeof(Azure.Extensions.WebJobs.EventHubsWebJobsStartup))] +namespace Azure.Extensions.WebJobs +{ + internal class EventHubsWebJobsStartup : Microsoft.Azure.WebJobs.Hosting.IWebJobsStartup2 + { + public void Configure(IWebJobsBuilder builder) + { + } + + public void Configure(WebJobsBuilderContext context, IWebJobsBuilder builder) + { + builder.Services.AddAzureClients(builder => builder.SetConfigurationRoot(context.Configuration)); + builder.AddAzureClients(); + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.sln b/sdk/extensions/Azure.Extensions.sln index 1f8b4d7724e5..45fe37466514 100644 --- a/sdk/extensions/Azure.Extensions.sln +++ b/sdk/extensions/Azure.Extensions.sln @@ -1,29 +1,44 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30327.8 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure.Extensions.AspNetCore.DataProtection.Blobs", "Azure.Extensions.AspNetCore.DataProtection.Blobs", "{12C39FF8-57E3-4A24-AE05-42A104EC9C69}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.DataProtection.Blobs", "Azure.Extensions.AspNetCore.DataProtection.Blobs\src\Azure.Extensions.AspNetCore.DataProtection.Blobs.csproj", "{70DAB56B-C642-480D-9F47-D490959A3431}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.DataProtection.Blobs", "Azure.Extensions.AspNetCore.DataProtection.Blobs\src\Azure.Extensions.AspNetCore.DataProtection.Blobs.csproj", "{70DAB56B-C642-480D-9F47-D490959A3431}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.DataProtection.Blobs.Tests", "Azure.Extensions.AspNetCore.DataProtection.Blobs\tests\Azure.Extensions.AspNetCore.DataProtection.Blobs.Tests.csproj", "{CE0F89E2-9894-43DE-A9F6-90C5D186DD84}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.DataProtection.Blobs.Tests", "Azure.Extensions.AspNetCore.DataProtection.Blobs\tests\Azure.Extensions.AspNetCore.DataProtection.Blobs.Tests.csproj", "{CE0F89E2-9894-43DE-A9F6-90C5D186DD84}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure.Extensions.AspNetCore.DataProtection.Keys", "Azure.Extensions.AspNetCore.DataProtection.Keys", "{B358FBE9-0833-484D-B988-588B75AE99CF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.DataProtection.Keys", "Azure.Extensions.AspNetCore.DataProtection.Keys\src\Azure.Extensions.AspNetCore.DataProtection.Keys.csproj", "{4324C3A5-67DA-4130-B506-69BDB282DB42}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.DataProtection.Keys", "Azure.Extensions.AspNetCore.DataProtection.Keys\src\Azure.Extensions.AspNetCore.DataProtection.Keys.csproj", "{4324C3A5-67DA-4130-B506-69BDB282DB42}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.DataProtection.Keys.Tests", "Azure.Extensions.AspNetCore.DataProtection.Keys\tests\Azure.Extensions.AspNetCore.DataProtection.Keys.Tests.csproj", "{0BE93DC0-97FC-48D6-BA9F-482BCF974D83}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.DataProtection.Keys.Tests", "Azure.Extensions.AspNetCore.DataProtection.Keys\tests\Azure.Extensions.AspNetCore.DataProtection.Keys.Tests.csproj", "{0BE93DC0-97FC-48D6-BA9F-482BCF974D83}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure.Extensions.AspNetCore.Configuration.Secrets", "Azure.Extensions.AspNetCore.Configuration.Secrets", "{A6B68F68-8FDF-4D1F-9277-BABEE6904DCA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.Configuration.Secrets", "Azure.Extensions.AspNetCore.Configuration.Secrets\src\Azure.Extensions.AspNetCore.Configuration.Secrets.csproj", "{8EFE342E-7C53-4489-B14B-EB813CE015B6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.Configuration.Secrets", "Azure.Extensions.AspNetCore.Configuration.Secrets\src\Azure.Extensions.AspNetCore.Configuration.Secrets.csproj", "{8EFE342E-7C53-4489-B14B-EB813CE015B6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.AspNetCore.Configuration.Secrets.Tests", "Azure.Extensions.AspNetCore.Configuration.Secrets\tests\Azure.Extensions.AspNetCore.Configuration.Secrets.Tests.csproj", "{5F56D5D1-670D-4C34-BB1A-E4D46F0CD05E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore.Configuration.Secrets.Tests", "Azure.Extensions.AspNetCore.Configuration.Secrets\tests\Azure.Extensions.AspNetCore.Configuration.Secrets.Tests.csproj", "{5F56D5D1-670D-4C34-BB1A-E4D46F0CD05E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Core.TestFramework", "..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.TestFramework", "..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.WebJobs", "Azure.Extensions.WebJobs\src\Azure.Extensions.WebJobs.csproj", "{6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure", "..\core\Microsoft.Extensions.Azure\src\Microsoft.Extensions.Azure.csproj", "{AF8C46F0-00DF-4E9C-B99C-82DD361115DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.Tests", "..\core\Microsoft.Extensions.Azure\tests\Microsoft.Extensions.Azure.Tests.csproj", "{439AD388-D698-4A82-B509-D79D511624F5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs.Host", "..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs.Host\WebJobs.Host.csproj", "{C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs", "..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs\WebJobs.csproj", "{424AD6CB-B5F8-492A-97A5-F988945713CF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.WebJobs.Sample", "Azure.Extensions.WebJobs\sample\Azure.Extensions.WebJobs.Sample\Azure.Extensions.WebJobs.Sample.csproj", "{570CBB6C-2808-4B04-AE69-29084BD3C518}" EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs.Shared\WebJobs.Shared.projitems*{c7f85171-4dbb-4e91-8ebb-5bca24d6be82}*SharedItemsImports = 5 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 @@ -32,9 +47,6 @@ Global Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {70DAB56B-C642-480D-9F47-D490959A3431}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70DAB56B-C642-480D-9F47-D490959A3431}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -120,6 +132,81 @@ Global {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x64.Build.0 = Release|Any CPU {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x86.ActiveCfg = Release|Any CPU {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x86.Build.0 = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x64.Build.0 = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x86.Build.0 = Debug|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|Any CPU.Build.0 = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x64.ActiveCfg = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x64.Build.0 = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x86.ActiveCfg = Release|Any CPU + {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x86.Build.0 = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|x64.ActiveCfg = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|x64.Build.0 = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|x86.ActiveCfg = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|x86.Build.0 = Debug|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|Any CPU.Build.0 = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|x64.ActiveCfg = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|x64.Build.0 = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|x86.ActiveCfg = Release|Any CPU + {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Release|x86.Build.0 = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|x64.ActiveCfg = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|x64.Build.0 = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|x86.ActiveCfg = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Debug|x86.Build.0 = Debug|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|Any CPU.Build.0 = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|x64.ActiveCfg = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|x64.Build.0 = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.ActiveCfg = Release|Any CPU + {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.Build.0 = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x64.ActiveCfg = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x64.Build.0 = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x86.ActiveCfg = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x86.Build.0 = Debug|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|Any CPU.Build.0 = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x64.ActiveCfg = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x64.Build.0 = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x86.ActiveCfg = Release|Any CPU + {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x86.Build.0 = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x64.ActiveCfg = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x64.Build.0 = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x86.ActiveCfg = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x86.Build.0 = Debug|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|Any CPU.Build.0 = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x64.ActiveCfg = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x64.Build.0 = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.ActiveCfg = Release|Any CPU + {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.Build.0 = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|Any CPU.Build.0 = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x64.ActiveCfg = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x64.Build.0 = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x86.ActiveCfg = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x86.Build.0 = Debug|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|Any CPU.ActiveCfg = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|Any CPU.Build.0 = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x64.ActiveCfg = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x64.Build.0 = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x86.ActiveCfg = Release|Any CPU + {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {70DAB56B-C642-480D-9F47-D490959A3431} = {12C39FF8-57E3-4A24-AE05-42A104EC9C69} @@ -129,4 +216,7 @@ Global {8EFE342E-7C53-4489-B14B-EB813CE015B6} = {A6B68F68-8FDF-4D1F-9277-BABEE6904DCA} {5F56D5D1-670D-4C34-BB1A-E4D46F0CD05E} = {A6B68F68-8FDF-4D1F-9277-BABEE6904DCA} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D0A9B115-40CC-478C-BDD7-76E2752E8BF2} + EndGlobalSection EndGlobal From 7785dfa7f7dddfd39742b5f6fa87fd431a7838c3 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 4 Aug 2020 13:10:05 -0700 Subject: [PATCH 02/20] Progress --- .../src/AzureClientFactoryBuilder.cs | 6 ++-- .../AzureClientServiceCollectionExtensions.cs | 10 ------ .../src/Internal/AzureClientsGlobalOptions.cs | 2 +- .../FallbackAzureClientFactory.cs | 7 ++-- .../tests/AzureClientFactoryTests.cs | 2 +- .../Azure.Extensions.WebJobs.Sample.csproj | 18 ---------- .../Function1.cs | 35 ------------------- .../Azure.Extensions.WebJobs.Sample/host.json | 11 ------ .../.gitignore | 0 .../Azure.Extensions.WebJobs.Samples.csproj | 22 ++++++++++++ .../samples/Function1.cs | 25 +++++++++++++ .../samples/host.json | 22 ++++++++++++ .../src/Azure.Extensions.WebJobs.csproj | 2 +- .../src/AzureClientAttribute.cs | 13 ++++++- .../src/AzureClientsWebJobsStartup.cs | 25 +++++++++++++ .../src/EventHubsWebJobsStartup.cs | 24 ------------- sdk/extensions/Azure.Extensions.sln | 26 +++++++------- 17 files changed, 130 insertions(+), 120 deletions(-) rename sdk/core/Microsoft.Extensions.Azure/src/{ => Internal}/FallbackAzureClientFactory.cs (93%) delete mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj delete mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs delete mode 100644 sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json rename sdk/extensions/Azure.Extensions.WebJobs/{sample/Azure.Extensions.WebJobs.Sample => samples}/.gitignore (100%) create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/samples/host.json create mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs delete mode 100644 sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs index 4a42de497f29..43e00dc58cff 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs @@ -134,11 +134,11 @@ public AzureClientFactoryBuilder UseCredential(Func /// /// - /// + /// /// - public AzureClientFactoryBuilder SetConfigurationRoot(IConfiguration configuration) + public AzureClientFactoryBuilder SetConfigurationRoot(Func configurationProvider) { - _serviceCollection.Configure(options => options.ConfigurationRoot = configuration); + _serviceCollection.Configure(options => options.ConfigurationRootResolver = configurationProvider); return this; } diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs index e35c9ab911c5..86ba38094cb5 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientServiceCollectionExtensions.cs @@ -21,15 +21,5 @@ public static void AddAzureClients(this IServiceCollection collection, Action - /// - /// - /// - /// - public static void AddAzureClients(this IServiceCollection collection, IConfiguration configuration) - { - new AzureClientFactoryBuilder(collection).SetConfigurationRoot(configuration); - } } } \ No newline at end of file diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs index 4df2a32a152f..03884bdc98eb 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientsGlobalOptions.cs @@ -14,6 +14,6 @@ internal class AzureClientsGlobalOptions { public Func CredentialFactory { get; set; } = _ => new DefaultAzureCredential(); public List> ConfigureOptionDelegates { get; } = new List>(); - public IConfiguration ConfigurationRoot { get; set; } + public Func ConfigurationRootResolver { get; set; } } } \ No newline at end of file diff --git a/sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs similarity index 93% rename from sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs rename to sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs index 64f2207f70c3..05721213e808 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/FallbackAzureClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs @@ -15,15 +15,18 @@ internal class FallbackAzureClientFactory: IAzureClientFactory { private readonly IOptionsMonitor _globalOptions; private readonly IServiceProvider _serviceProvider; + private readonly EventSourceLogForwarder _logForwarder; private readonly Dictionary> _clientRegistrations; private readonly Type _clientOptionType; public FallbackAzureClientFactory( IOptionsMonitor globalOptions, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + EventSourceLogForwarder logForwarder) { _globalOptions = globalOptions; _serviceProvider = serviceProvider; + _logForwarder = logForwarder; _clientRegistrations = new Dictionary>(); foreach (var constructor in typeof(TClient).GetConstructors(BindingFlags.Public | BindingFlags.Instance)) @@ -51,7 +54,7 @@ public TClient CreateClient(string name) { if (!_clientRegistrations.TryGetValue(name, out registration)) { - var section = globalOptions.ConfigurationRoot?.GetSection(name); + var section = globalOptions.ConfigurationRootResolver?.Invoke(_serviceProvider).GetSection(name); if (!section.Exists()) { throw new InvalidOperationException($"Unable to find a configuration section with the name {name} to configure the client with or the configuration root wasn't set."); diff --git a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs index 8c6be9726abe..f1dbfaa30b4b 100644 --- a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs +++ b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs @@ -319,7 +319,7 @@ public void CanCreateClientWithoutRegistration() new KeyValuePair("TestClient:tenantId", "ConfigurationTenantId")); var serviceCollection = new ServiceCollection(); - serviceCollection.AddAzureClients(configuration); + serviceCollection.AddAzureClients(builder => builder.SetConfigurationRoot(_ => configuration)); ServiceProvider provider = serviceCollection.BuildServiceProvider(); IAzureClientFactory factory = provider.GetService>(); diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj deleted file mode 100644 index a6bad7eeafa6..000000000000 --- a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Azure.Extensions.WebJobs.Sample.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - netcoreapp3.1 - v3 - - - - - - - PreserveNewest - - - PreserveNewest - Never - - - \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs deleted file mode 100644 index 5a367434722e..000000000000 --- a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/Function1.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; - -namespace Azure.Extensions.WebJobs.Sample -{ - public static class Function1 - { - [FunctionName("Function1")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, - ILogger log) - { - log.LogInformation("C# HTTP trigger function processed a request."); - - string name = req.Query["name"]; - - string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); - dynamic data = JsonConvert.DeserializeObject(requestBody); - name = name ?? data?.name; - - string responseMessage = string.IsNullOrEmpty(name) - ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." - : $"Hello, {name}. This HTTP triggered function executed successfully."; - - return new OkObjectResult(responseMessage); - } - } -} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json b/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json deleted file mode 100644 index bb3b8dadd7d6..000000000000 --- a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/host.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingExcludedTypes": "Request", - "samplingSettings": { - "isEnabled": true - } - } - } -} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore b/sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore similarity index 100% rename from sdk/extensions/Azure.Extensions.WebJobs/sample/Azure.Extensions.WebJobs.Sample/.gitignore rename to sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj b/sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj new file mode 100644 index 000000000000..3137728f3203 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj @@ -0,0 +1,22 @@ + + + netcoreapp3.1 + $(RequiredTargetFrameworks) + v3 + + + + + + + + + + + Always + + + Always + + + \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs new file mode 100644 index 000000000000..30f4742af107 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Azure.Storage.Blobs; +using System.Linq; + +namespace Azure.Extensions.WebJobs.Sample +{ + public static class Function1 + { + [FunctionName("Function1")] + public static IActionResult Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, + [AzureClient("MyClientWithCreds")] BlobServiceClient client, + ILogger log) + { + return new OkObjectResult(client.GetBlobContainers().ToArray()); + } + } +} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json b/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json new file mode 100644 index 000000000000..567fd594abb1 --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json @@ -0,0 +1,22 @@ +{ + "version": "2.0", + "logging": { + "logLevel": { + "Azure": "Information" + }, + "applicationInsights": { + "samplingExcludedTypes": "Request", + "samplingSettings": { + "isEnabled": true + } + } + }, + "azure": { + "MyClient": { + "connectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;" + }, + "MyClientWithCreds": { + "serviceUri": "https://pakrym0test0storag2e.blob.core.windows.net/" + } + } +} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj b/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj index b3bb34853085..6834ae8543c8 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj @@ -10,7 +10,7 @@ - + diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs index 839518d37b64..b9e79f67c962 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs @@ -3,6 +3,7 @@ using System; using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Description; namespace Azure.Extensions.WebJobs { @@ -10,9 +11,19 @@ namespace Azure.Extensions.WebJobs /// /// [AttributeUsage(AttributeTargets.Parameter)] + [Binding] public class AzureClientAttribute: Attribute, IConnectionProvider { + /// + /// + /// + /// + public AzureClientAttribute(string connection) + { + Connection = connection; + } + /// public string Connection { get; set; } } -} \ No newline at end of file +} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs new file mode 100644 index 000000000000..75390c611dfd --- /dev/null +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Hosting; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +[assembly: WebJobsStartup(typeof(Azure.Extensions.WebJobs.AzureClientsWebJobsStartup))] +namespace Azure.Extensions.WebJobs +{ + internal class AzureClientsWebJobsStartup : Microsoft.Azure.WebJobs.Hosting.IWebJobsStartup + { + public void Configure(IWebJobsBuilder builder) + { + builder.Services.AddAzureClients(builder => + builder.SetConfigurationRoot(provider => provider.GetRequiredService() + .GetWebJobsRootConfiguration() + .GetSection("azure"))); + builder.AddAzureClients(); + } + } +} diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs deleted file mode 100644 index b9027a63c553..000000000000 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/EventHubsWebJobsStartup.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Hosting; -using Microsoft.Extensions.Azure; -using Microsoft.Extensions.Hosting; - -[assembly: WebJobsStartup(typeof(Azure.Extensions.WebJobs.EventHubsWebJobsStartup))] -namespace Azure.Extensions.WebJobs -{ - internal class EventHubsWebJobsStartup : Microsoft.Azure.WebJobs.Hosting.IWebJobsStartup2 - { - public void Configure(IWebJobsBuilder builder) - { - } - - public void Configure(WebJobsBuilderContext context, IWebJobsBuilder builder) - { - builder.Services.AddAzureClients(builder => builder.SetConfigurationRoot(context.Configuration)); - builder.AddAzureClients(); - } - } -} \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.sln b/sdk/extensions/Azure.Extensions.sln index 45fe37466514..834735cc21dc 100644 --- a/sdk/extensions/Azure.Extensions.sln +++ b/sdk/extensions/Azure.Extensions.sln @@ -33,7 +33,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs.Host", "..\..\..\az EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs", "..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs\WebJobs.csproj", "{424AD6CB-B5F8-492A-97A5-F988945713CF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Extensions.WebJobs.Sample", "Azure.Extensions.WebJobs\sample\Azure.Extensions.WebJobs.Sample\Azure.Extensions.WebJobs.Sample.csproj", "{570CBB6C-2808-4B04-AE69-29084BD3C518}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.WebJobs.Samples", "Azure.Extensions.WebJobs\samples\Azure.Extensions.WebJobs.Samples.csproj", "{F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -192,18 +192,18 @@ Global {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x64.Build.0 = Release|Any CPU {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.ActiveCfg = Release|Any CPU {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.Build.0 = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|Any CPU.Build.0 = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x64.ActiveCfg = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x64.Build.0 = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x86.ActiveCfg = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Debug|x86.Build.0 = Debug|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|Any CPU.ActiveCfg = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|Any CPU.Build.0 = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x64.ActiveCfg = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x64.Build.0 = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x86.ActiveCfg = Release|Any CPU - {570CBB6C-2808-4B04-AE69-29084BD3C518}.Release|x86.Build.0 = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x64.Build.0 = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x86.ActiveCfg = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x86.Build.0 = Debug|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|Any CPU.Build.0 = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x64.ActiveCfg = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x64.Build.0 = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x86.ActiveCfg = Release|Any CPU + {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 24fbd4f99ffd163062653a95b2efc98fed9a09dc Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 24 Aug 2020 14:27:45 -0700 Subject: [PATCH 03/20] Progress --- .../src/IAzureClientFactory.cs | 2 +- .../src/Internal/ClientFactory.cs | 11 ++++++++ .../tests/AzureClientFactoryTests.cs | 16 +++++++++++ .../samples/Function1.cs | 2 +- .../src/AzureClientsWebJobsStartup.cs | 3 +- sdk/extensions/Azure.Extensions.sln | 28 ------------------- 6 files changed, 30 insertions(+), 32 deletions(-) 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/ClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs index b54690d102ac..6c9987a27994 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs @@ -16,10 +16,21 @@ 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 arguments = new List(); + if (configuration is IConfigurationSection section && section.Value != null) + { + var connectionString = section.Value; + configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new[] + { + new KeyValuePair(ConnectionStringParameterName, connectionString) + }) + .Build(); + } foreach (var constructor in clientType.GetConstructors().OrderByDescending(c => c.GetParameters().Length)) { if (!IsApplicableConstructor(constructor, optionsType)) diff --git a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs index f1dbfaa30b4b..cb4cdb2f3150 100644 --- a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs +++ b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs @@ -334,6 +334,22 @@ public void CanCreateClientWithoutRegistration() Assert.AreEqual("ConfigurationTenantId", clientSecretCredential.TenantId); } + [Test] + public void CanCreateClientWithoutRegistrationUsingConnectionString() + { + var configuration = GetConfiguration( + new KeyValuePair("TestClient", "http://localhost/")); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddAzureClients(builder => builder.SetConfigurationRoot(_ => configuration)); + + ServiceProvider provider = serviceCollection.BuildServiceProvider(); + IAzureClientFactory factory = provider.GetService>(); + TestClient client = factory.CreateClient("TestClient"); + + Assert.AreEqual("http://localhost/", client.ConnectionString); + } + [Test] public void SupportsSettingVersion() { diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs index 30f4742af107..90e9278aa69d 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs @@ -16,7 +16,7 @@ public static class Function1 [FunctionName("Function1")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, - [AzureClient("MyClientWithCreds")] BlobServiceClient client, + [AzureClient("AzureWebJobsStorage")] BlobServiceClient client, ILogger log) { return new OkObjectResult(client.GetBlobContainers().ToArray()); diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs index 75390c611dfd..aba4614dd6f7 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs @@ -17,8 +17,7 @@ public void Configure(IWebJobsBuilder builder) { builder.Services.AddAzureClients(builder => builder.SetConfigurationRoot(provider => provider.GetRequiredService() - .GetWebJobsRootConfiguration() - .GetSection("azure"))); + .GetWebJobsRootConfiguration())); builder.AddAzureClients(); } } diff --git a/sdk/extensions/Azure.Extensions.sln b/sdk/extensions/Azure.Extensions.sln index 834735cc21dc..6e4417de8a46 100644 --- a/sdk/extensions/Azure.Extensions.sln +++ b/sdk/extensions/Azure.Extensions.sln @@ -29,10 +29,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.Tests", "..\core\Microsoft.Extensions.Azure\tests\Microsoft.Extensions.Azure.Tests.csproj", "{439AD388-D698-4A82-B509-D79D511624F5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs.Host", "..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs.Host\WebJobs.Host.csproj", "{C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs", "..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs\WebJobs.csproj", "{424AD6CB-B5F8-492A-97A5-F988945713CF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.WebJobs.Samples", "Azure.Extensions.WebJobs\samples\Azure.Extensions.WebJobs.Samples.csproj", "{F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}" EndProject Global @@ -168,30 +164,6 @@ Global {439AD388-D698-4A82-B509-D79D511624F5}.Release|x64.Build.0 = Release|Any CPU {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.ActiveCfg = Release|Any CPU {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.Build.0 = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x64.ActiveCfg = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x64.Build.0 = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x86.ActiveCfg = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Debug|x86.Build.0 = Debug|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|Any CPU.Build.0 = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x64.ActiveCfg = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x64.Build.0 = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x86.ActiveCfg = Release|Any CPU - {C7F85171-4DBB-4E91-8EBB-5BCA24D6BE82}.Release|x86.Build.0 = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x64.ActiveCfg = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x64.Build.0 = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x86.ActiveCfg = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Debug|x86.Build.0 = Debug|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|Any CPU.Build.0 = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x64.ActiveCfg = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x64.Build.0 = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.ActiveCfg = Release|Any CPU - {424AD6CB-B5F8-492A-97A5-F988945713CF}.Release|x86.Build.0 = Release|Any CPU {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.Build.0 = Debug|Any CPU {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x64.ActiveCfg = Debug|Any CPU From eb44e85dd8ff258c3f513e3156d0912a3ffd01f5 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 25 Aug 2020 08:09:34 -0700 Subject: [PATCH 04/20] small progres --- .../src/Azure.Core.TestFramework.csproj | 4 + .../samples/.gitignore | 264 ------------------ .../samples/Function1.cs | 4 +- .../samples/host.json | 9 +- .../AzureClientsWebJobsBuilderExtensions.cs | 2 +- 5 files changed, 7 insertions(+), 276 deletions(-) delete mode 100644 sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore diff --git a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj index 1fe7225fc26a..db094d29ce93 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj +++ b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj @@ -8,6 +8,7 @@ + @@ -17,4 +18,7 @@ + + + diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore b/sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore deleted file mode 100644 index ff5b00c506bd..000000000000 --- a/sdk/extensions/Azure.Extensions.WebJobs/samples/.gitignore +++ /dev/null @@ -1,264 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# Azure Functions localsettings file -local.settings.json - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -project.fragment.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc \ No newline at end of file diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs index 90e9278aa69d..c9394871bebd 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs @@ -5,7 +5,6 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; using Azure.Storage.Blobs; using System.Linq; @@ -16,8 +15,7 @@ public static class Function1 [FunctionName("Function1")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, - [AzureClient("AzureWebJobsStorage")] BlobServiceClient client, - ILogger log) + [AzureClient("AzureWebJobsStorage")] BlobServiceClient client) { return new OkObjectResult(client.GetBlobContainers().ToArray()); } diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json b/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json index 567fd594abb1..2f2277b1b75f 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json +++ b/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json @@ -11,12 +11,5 @@ } } }, - "azure": { - "MyClient": { - "connectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;" - }, - "MyClientWithCreds": { - "serviceUri": "https://pakrym0test0storag2e.blob.core.windows.net/" - } - } + "AzureWebJobsStorage": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;" } diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs index bd2bf7e2aed0..42ed84f2d98f 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs +++ b/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs @@ -29,4 +29,4 @@ public static IWebJobsBuilder AddAzureClients(this IWebJobsBuilder builder) return builder; } } -} \ No newline at end of file +} From 3c78d7fa5c5817b86a822e328aadd8620def905f Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 26 Aug 2020 10:31:55 -0700 Subject: [PATCH 05/20] Start tests --- eng/Packages.Data.props | 2 +- .../src/Azure.Core.TestFramework.csproj | 4 - sdk/extensions/Azure.Extensions.sln | 71 ++-- .../Directory.Build.props | 7 + .../samples/Function1.cs | 0 ...t.Extensions.Azure.WebJobs.Samples.csproj} | 2 +- .../samples/host.json | 0 .../src/AzureClientAttribute.cs | 0 .../AzureClientsExtensionConfigProvider.cs | 2 +- .../AzureClientsWebJobsBuilderExtensions.cs | 5 + .../src/AzureClientsWebJobsStartup.cs | 6 - ...Microsoft.Extensions.Azure.WebJobs.csproj} | 0 .../tests/AzureClientAttributeTests.cs | 50 +++ ...soft.Extensions.Azure.WebJobs.Tests.csproj | 23 ++ .../tests/WebJobsTestEnvironment.cs | 16 + .../tests/shared/FakeActivator.cs | 32 ++ .../tests/shared/FakeNameResolver.cs | 36 ++ .../tests/shared/FakeTypeLocator.cs | 23 ++ .../tests/shared/JobHost.cs | 84 +++++ .../tests/shared/LogMessage.cs | 41 +++ .../shared/TestExceptionHandlerFactory.cs | 38 ++ .../tests/shared/TestHelpers.cs | 324 ++++++++++++++++++ .../tests/shared/TestLogger.cs | 84 +++++ .../tests/shared/TestLoggerProvider.cs | 52 +++ 24 files changed, 859 insertions(+), 43 deletions(-) create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/samples/Function1.cs (100%) rename sdk/extensions/{Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj => Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj} (89%) rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/samples/host.json (100%) rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/src/AzureClientAttribute.cs (100%) rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/src/AzureClientsExtensionConfigProvider.cs (96%) rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/src/AzureClientsWebJobsBuilderExtensions.cs (72%) rename sdk/extensions/{Azure.Extensions.WebJobs => Microsoft.Extensions.Azure.WebJobs}/src/AzureClientsWebJobsStartup.cs (62%) rename sdk/extensions/{Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj => Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj} (100%) create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index 013e7abf189c..de4b7a773637 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -53,6 +53,7 @@ + @@ -139,7 +140,6 @@ - diff --git a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj index db094d29ce93..1fe7225fc26a 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj +++ b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj @@ -8,7 +8,6 @@ - @@ -18,7 +17,4 @@ - - - diff --git a/sdk/extensions/Azure.Extensions.sln b/sdk/extensions/Azure.Extensions.sln index 6e4417de8a46..73e29627257e 100644 --- a/sdk/extensions/Azure.Extensions.sln +++ b/sdk/extensions/Azure.Extensions.sln @@ -23,18 +23,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.AspNetCore EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.TestFramework", "..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.WebJobs", "Azure.Extensions.WebJobs\src\Azure.Extensions.WebJobs.csproj", "{6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure", "..\core\Microsoft.Extensions.Azure\src\Microsoft.Extensions.Azure.csproj", "{AF8C46F0-00DF-4E9C-B99C-82DD361115DE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.Tests", "..\core\Microsoft.Extensions.Azure\tests\Microsoft.Extensions.Azure.Tests.csproj", "{439AD388-D698-4A82-B509-D79D511624F5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Extensions.WebJobs.Samples", "Azure.Extensions.WebJobs\samples\Azure.Extensions.WebJobs.Samples.csproj", "{F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs", "Microsoft.Extensions.Azure.WebJobs\src\Microsoft.Extensions.Azure.WebJobs.csproj", "{8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs.Tests", "Microsoft.Extensions.Azure.WebJobs\tests\Microsoft.Extensions.Azure.WebJobs.Tests.csproj", "{BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs.Samples", "Microsoft.Extensions.Azure.WebJobs\samples\Microsoft.Extensions.Azure.WebJobs.Samples.csproj", "{45CF248B-6CBA-4BF2-8E8D-44092A525709}" EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\..\azure-webjobs-sdk\src\Microsoft.Azure.WebJobs.Shared\WebJobs.Shared.projitems*{c7f85171-4dbb-4e91-8ebb-5bca24d6be82}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 @@ -128,18 +127,6 @@ Global {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x64.Build.0 = Release|Any CPU {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x86.ActiveCfg = Release|Any CPU {A1DF6702-2C7C-4A1E-B324-B574BF2BACCD}.Release|x86.Build.0 = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x64.ActiveCfg = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x64.Build.0 = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x86.ActiveCfg = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Debug|x86.Build.0 = Debug|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|Any CPU.Build.0 = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x64.ActiveCfg = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x64.Build.0 = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x86.ActiveCfg = Release|Any CPU - {6C5E9EF4-8B15-4721-873B-2AEE56D70EDF}.Release|x86.Build.0 = Release|Any CPU {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {AF8C46F0-00DF-4E9C-B99C-82DD361115DE}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -164,18 +151,42 @@ Global {439AD388-D698-4A82-B509-D79D511624F5}.Release|x64.Build.0 = Release|Any CPU {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.ActiveCfg = Release|Any CPU {439AD388-D698-4A82-B509-D79D511624F5}.Release|x86.Build.0 = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x64.ActiveCfg = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x64.Build.0 = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x86.ActiveCfg = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Debug|x86.Build.0 = Debug|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|Any CPU.Build.0 = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x64.ActiveCfg = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x64.Build.0 = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x86.ActiveCfg = Release|Any CPU - {F05E7AC4-C794-4425-89F4-FBE71F9BF1CA}.Release|x86.Build.0 = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|x64.ActiveCfg = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|x64.Build.0 = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|x86.ActiveCfg = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Debug|x86.Build.0 = Debug|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|Any CPU.Build.0 = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|x64.ActiveCfg = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|x64.Build.0 = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|x86.ActiveCfg = Release|Any CPU + {8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}.Release|x86.Build.0 = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|x64.Build.0 = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|x86.ActiveCfg = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Debug|x86.Build.0 = Debug|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|Any CPU.Build.0 = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|x64.ActiveCfg = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|x64.Build.0 = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|x86.ActiveCfg = Release|Any CPU + {BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}.Release|x86.Build.0 = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|x64.ActiveCfg = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|x64.Build.0 = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|x86.ActiveCfg = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Debug|x86.Build.0 = Debug|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|Any CPU.Build.0 = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|x64.ActiveCfg = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|x64.Build.0 = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|x86.ActiveCfg = Release|Any CPU + {45CF248B-6CBA-4BF2-8E8D-44092A525709}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props new file mode 100644 index 000000000000..805ca8beaf23 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props @@ -0,0 +1,7 @@ + + + true + + + + diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs similarity index 100% rename from sdk/extensions/Azure.Extensions.WebJobs/samples/Function1.cs rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj similarity index 89% rename from sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj index 3137728f3203..8125217de291 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/samples/Azure.Extensions.WebJobs.Samples.csproj +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj @@ -8,7 +8,7 @@ - + diff --git a/sdk/extensions/Azure.Extensions.WebJobs/samples/host.json b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json similarity index 100% rename from sdk/extensions/Azure.Extensions.WebJobs/samples/host.json rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs similarity index 100% rename from sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientAttribute.cs rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs similarity index 96% rename from sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs index 274c118d148f..3092596c90a2 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsExtensionConfigProvider.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs @@ -47,7 +47,7 @@ public Task GetValueAsync() { return Task.FromResult( (object)_serviceProvider - .GetService>() + .GetRequiredService>() .CreateClient(_connection)); } diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs similarity index 72% rename from sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs index 42ed84f2d98f..e7953c2e095b 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs @@ -3,6 +3,9 @@ using System; using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.Extensions.Hosting { @@ -24,6 +27,8 @@ public static IWebJobsBuilder AddAzureClients(this IWebJobsBuilder builder) throw new ArgumentNullException(nameof(builder)); } + builder.Services.AddAzureClients(builder => + builder.SetConfigurationRoot(provider => provider.GetRequiredService().GetWebJobsRootConfiguration())); builder.AddExtension(); return builder; diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsStartup.cs similarity index 62% rename from sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsStartup.cs index aba4614dd6f7..ef8b9e7ca908 100644 --- a/sdk/extensions/Azure.Extensions.WebJobs/src/AzureClientsWebJobsStartup.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsStartup.cs @@ -3,9 +3,6 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Hosting; -using Microsoft.Extensions.Azure; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; [assembly: WebJobsStartup(typeof(Azure.Extensions.WebJobs.AzureClientsWebJobsStartup))] @@ -15,9 +12,6 @@ internal class AzureClientsWebJobsStartup : Microsoft.Azure.WebJobs.Hosting.IWeb { public void Configure(IWebJobsBuilder builder) { - builder.Services.AddAzureClients(builder => - builder.SetConfigurationRoot(provider => provider.GetRequiredService() - .GetWebJobsRootConfiguration())); builder.AddAzureClients(); } } diff --git a/sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj similarity index 100% rename from sdk/extensions/Azure.Extensions.WebJobs/src/Azure.Extensions.WebJobs.csproj rename to sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs new file mode 100644 index 000000000000..49cf02747070 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using NUnit.Framework; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.Extensions.WebJobs; +using Azure.Security.KeyVault.Keys; +using Microsoft.Azure.WebJobs.Host.TestCommon; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +namespace Microsoft.Extensions.Azure.WebJobs.Tests +{ + public class AzureClientAttributeTests : RecordedTestBase + { + public AzureClientAttributeTests(bool isAsync) : base(isAsync) + { + } + + [Test] + public async Task A() + { + var host = new HostBuilder() + .ConfigureServices(services => services.AddAzureClients(builder => builder.ConfigureDefaults(options => Recording.InstrumentClientOptions(options)))) + .ConfigureAppConfiguration(config => + { + config.AddInMemoryCollection(new Dictionary + { + { "Connection:vaultUri", TestEnvironment.KeyVaultUrl } + }); + }) + .ConfigureDefaultTestHost(builder => + { + builder.AddAzureClients(); + }).Build(); + + var jobHost = host.GetJobHost(); + await jobHost.CallAsync(nameof(FunctionWithAzureClient.Run)); + } + + public class FunctionWithAzureClient + { + public void Run([AzureClient("Connection")] KeyClient serviceClient) + { + } + } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj new file mode 100644 index 000000000000..917cc04ef139 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj @@ -0,0 +1,23 @@ + + + + $(RequiredTargetFrameworks) + true + + + + + + + + + + + + + + + + + + diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs new file mode 100644 index 000000000000..406970449d38 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.TestFramework; + +namespace Microsoft.Extensions.Azure.WebJobs.Tests +{ + public class WebJobsTestEnvironment : TestEnvironment + { + public WebJobsTestEnvironment() : base("extensions") + { + } + + public string KeyVaultUrl => GetRecordedVariable("AZURE_KEYVAULT_URL"); + } +} \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs new file mode 100644 index 000000000000..80b7caeebf93 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + + public class FakeActivator : IJobActivator + { + public Dictionary _instances = new Dictionary(); + + public FakeActivator(params object[] objs) + { + foreach (var obj in objs) + { + Add(obj); + } + } + + public void Add(object o) + { + _instances[o.GetType()] = o; + } + + public T CreateInstance() + { + return (T)_instances[typeof(T)]; + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs new file mode 100644 index 000000000000..31982e9f498f --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class FakeNameResolver : INameResolver + { + public IDictionary _dict = new Dictionary(); + + public string Resolve(string name) + { + // some name resolvers can't handle null values + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + string value; + if (_dict.TryGetValue(name, out value)) + { + return value; + } + + return null; + } + + // Fluid method for adding entries. + public FakeNameResolver Add(string key, string value) + { + _dict[key] = value; + return this; + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs new file mode 100644 index 000000000000..608aae592a6e --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class FakeTypeLocator : ITypeLocator + { + private readonly Type[] _types; + + public FakeTypeLocator(params Type[] types) + { + _types = types; + } + + public IReadOnlyList GetTypes() + { + return _types; + } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs new file mode 100644 index 000000000000..313f1c596b6e --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Azure.WebJobs.Host.Executors; +using Microsoft.Azure.WebJobs.Host.Indexers; +using Microsoft.Extensions.Options; +using NUnit; +using NUnit.Framework; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class JobHost : JobHost + { + private readonly IJobActivator _jobActivator; + + public JobHost( + IOptions options, + IJobHostContextFactory contextFactory, + IJobActivator jobActivator) + : base(options, contextFactory) + { + _jobActivator = jobActivator; + } + + public async Task CallAsync(string methodName, object arguments = null) + { + await base.CallAsync(methodName, arguments); + } + + public async Task CallAsync(string methodName, IDictionary arguments) + { + await base.CallAsync(typeof(TProgram).GetMethod(methodName), arguments); + } + + // Start listeners and run until the Task source is set. + public async Task RunTriggerAsync(TaskCompletionSource taskSource= null) + { + // Program was registered with the job activator, so we can get it + TProgram prog = _jobActivator.CreateInstance(); + if (taskSource == null) + { + var progResult = prog as IProgramWithResult; + taskSource = new TaskCompletionSource(); + progResult.TaskSource = taskSource; + } + + TResult result = default(TResult); + // Act + using (this) + { + await this.StartAsync(); + // Assert + result = await TestHelpers.AwaitWithTimeout(taskSource); + } + return result; + } + + // Helper for quickly testing indexing errors + public async Task AssertIndexingError(string methodName, string expectedErrorMessage) + { + try + { + // Indexing is lazy, so must actually try a call first. + await this.CallAsync(methodName); + } + catch (FunctionIndexingException e) + { + string functionName = typeof(TProgram).Name + "." + methodName; + Assert.AreEqual("Error indexing method '" + functionName + "'", e.Message); + Assert.True(e.InnerException.Message.Contains(expectedErrorMessage)); + return; + } + Assert.True(false, "Invoker should have failed"); + } + } + + // $$$ Meanth to simplify some tests - is this worth it? + public interface IProgramWithResult + { + TaskCompletionSource TaskSource { get; set; } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs new file mode 100644 index 000000000000..8471e9540e17 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class LogMessage + { + public LogLevel Level { get; set; } + + public EventId EventId { get; set; } + + public IEnumerable> State { get; set; } + + public Exception Exception { get; set; } + + public string FormattedMessage { get; set; } + + public string Category { get; set; } + + public DateTime Timestamp { get; set; } + + public override string ToString() => $"[{Timestamp.ToString("HH:mm:ss.fff")}] [{Category}] {FormattedMessage} {Exception}"; + + /// + /// Returns the value for the key in State. Will throw an exception if there is not + /// exactly one instance of this key in the dictionary. + /// + /// The type to cast the value to. + /// The key to look up. + /// The value. + public T GetStateValue(string key) + { + return (T)State.Single(p => p.Key == key).Value; + } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs new file mode 100644 index 000000000000..70df9a5a258f --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.ExceptionServices; +using System.Threading.Tasks; +using Microsoft.Azure.WebJobs.Host.Timers; +using Microsoft.Extensions.Hosting; +using NUnit.Framework; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class TestExceptionHandlerFactory : IWebJobsExceptionHandlerFactory + { + private TestExceptionHandler _handler = new TestExceptionHandler(); + + public IWebJobsExceptionHandler Create(IHost jobHost) => _handler; + + public class TestExceptionHandler : IWebJobsExceptionHandler + { + public void Initialize(JobHost host) + { + } + + public Task OnTimeoutExceptionAsync(ExceptionDispatchInfo exceptionInfo, TimeSpan timeoutGracePeriod) + { + Assert.True(false, $"Timeout exception in test exception handler: {exceptionInfo.SourceException}"); + return Task.CompletedTask; + } + + public Task OnUnhandledExceptionAsync(ExceptionDispatchInfo exceptionInfo) + { + Assert.True(false, $"Error in test exception handler: {exceptionInfo.SourceException}"); + return Task.CompletedTask; + } + } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs new file mode 100644 index 000000000000..6ff7740b33cf --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs @@ -0,0 +1,324 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Azure.WebJobs.Host.Config; +using Microsoft.Azure.WebJobs.Host.Indexers; +using Microsoft.Azure.WebJobs.Host.Timers; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NUnit.Framework; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public static class TestHelpers + { + public static IServiceCollection AddSingletonIfNotNull(this IServiceCollection services, T instance) where T : class + { + if (instance != null) + { + services.AddSingleton(instance); + } + + return services; + } + + /// + /// Helper that builds a test host to configure the options type specified. + /// + /// The options type to configure. + /// Delegate used to configure the target extension. + /// Set of test configuration values to apply. + /// + public static TOptions GetConfiguredOptions(Action configure, Dictionary configValues) where TOptions : class, new() + { + IHost host = new HostBuilder() + .ConfigureDefaultTestHost(b => + { + configure(b); + }) + .ConfigureAppConfiguration(cb => + { + cb.AddInMemoryCollection(configValues); + }) + .Build(); + + TOptions options = host.Services.GetRequiredService>().Value; + return options; + } + + // Test error if not reached within a timeout + public static Task AwaitWithTimeout(this TaskCompletionSource taskSource) + { + return taskSource.Task; + } + + // Test error if not reached within a timeout + public static TResult AwaitWithTimeout(this Task taskSource) + { + Await(() => taskSource.IsCompleted).Wait(); + return taskSource.Result; + } + + public static async Task Await(Func> condition, int timeout = 60 * 1000, int pollingInterval = 50, bool throwWhenDebugging = false, Func userMessageCallback = null) + { + DateTime start = DateTime.Now; + while (!await condition()) + { + await Task.Delay(pollingInterval); + + bool shouldThrow = !Debugger.IsAttached || (Debugger.IsAttached && throwWhenDebugging); + if (shouldThrow && (DateTime.Now - start).TotalMilliseconds > timeout) + { + string error = "Condition not reached within timeout."; + if (userMessageCallback != null) + { + error += " " + userMessageCallback(); + } + throw new ApplicationException(error); + } + } + } + + public static async Task Await(Func condition, int timeout = 60 * 1000, int pollingInterval = 50, bool throwWhenDebugging = false, Func userMessageCallback = null) + { + await Await(() => Task.FromResult(condition()), timeout, pollingInterval, throwWhenDebugging, userMessageCallback); + } + + public static void WaitOne(WaitHandle handle, int timeout = 60 * 1000) + { + bool ok = handle.WaitOne(timeout); + if (!ok) + { + // timeout. Event not signaled in time. + throw new ApplicationException("Condition not reached within timeout."); + } + } + + public static void SetField(object target, string fieldName, object value) + { + FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); + if (field == null) + { + field = target.GetType().GetField($"<{fieldName}>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); + } + field.SetValue(target, value); + } + + public static T New() + { + var constructor = typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null); + return (T)constructor.Invoke(null); + } + + + + // Test that we get an indexing error (FunctionIndexingException) + // functionName - the function name that has the indexing error. + // expectedErrorMessage - inner exception's message with details. + // Invoking func() should cause an indexing error. + public static void AssertIndexingError(Action func, string functionName, string expectedErrorMessage) + { + try + { + func(); // expected indexing error + } + catch (FunctionIndexingException e) + { + Assert.AreEqual("Error indexing method '" + functionName + "'", e.Message); + StringAssert.StartsWith(expectedErrorMessage, e.InnerException.Message); + return; + } + Assert.True(false, "Invoker should have failed"); + } + public static IHostBuilder ConfigureDefaultTestHost(this IHostBuilder builder, params Type[] types) + { + return builder.ConfigureDefaultTestHost(b => { }, types); + } + + public static IHostBuilder ConfigureDefaultTestHost(this IHostBuilder builder, Action configureWebJobs, params Type[] types) + { + return builder.ConfigureWebJobs(configureWebJobs) + .ConfigureServices(services => + { + services.AddSingleton(new FakeTypeLocator(types)); + + // Register this to fail a test if a background exception is thrown + services.AddSingleton(); + }) + .ConfigureTestLogger(); + } + + public static IHostBuilder ConfigureDefaultTestHost(this IHostBuilder builder, + TProgram instance, Action configureWebJobs) + { + return builder.ConfigureDefaultTestHost(configureWebJobs, typeof(TProgram)) + .ConfigureServices(services => + { + services.AddSingleton>(); + + services.AddSingleton(new FakeActivator(instance)); + }); + } + + public static IHostBuilder ConfigureDefaultTestHost(this IHostBuilder builder) + { + return builder.ConfigureDefaultTestHost(o => { }, typeof(TProgram)) + .ConfigureServices(services => + { + services.AddSingleton>(); + }); + } + + public static IHostBuilder ConfigureDefaultTestHost(this IHostBuilder builder, Action configureWebJobs, + INameResolver nameResolver = null, IJobActivator activator = null) + { + return builder.ConfigureDefaultTestHost(configureWebJobs, typeof(TProgram)) + .ConfigureServices(services => + { + services.AddSingleton>(); + + if (nameResolver != null) + { + services.AddSingleton(nameResolver); + } + + if (activator != null) + { + services.AddSingleton(activator); + } + }); + } + + public static IHostBuilder ConfigureTestLogger(this IHostBuilder builder) + { + return builder.ConfigureLogging(logging => + { + logging.AddProvider(new TestLoggerProvider()); + }); + } + + + public static IHostBuilder ConfigureTypeLocator(this IHostBuilder builder, params Type[] types) + { + return builder.ConfigureServices(services => + { + services.AddSingleton(new FakeTypeLocator(types)); + }); + } + + public static TestLoggerProvider GetTestLoggerProvider(this IHost host) + { + return host.Services.GetServices().OfType().Single(); + } + + public static TExtension GetExtension(this IHost host) + { + return host.Services.GetServices().OfType().SingleOrDefault(); + } + + public static JobHost GetJobHost(this IHost host) + { + return host.Services.GetService() as JobHost; + } + + public static JobHost GetJobHost(this IHost host) + { + return host.Services.GetService() as JobHost; + } + + public static async Task CallAsync(this JobHost host, string methodName, object arguments) + { + await host.CallAsync(typeof(T).GetMethod(methodName), arguments); + } + + public static async Task CallAsync(this JobHost host, string methodName) + { + await host.CallAsync(typeof(T).GetMethod(methodName)); + } + + public static TOptions GetOptions(this IHost host) where TOptions : class, new() + { + return host.Services.GetService>().Value; + } + +#pragma warning disable CS0618 // Type or member is obsolete + public static IJobHostMetadataProvider CreateMetadataProvider(this IHost host) + { + return host.Services.GetService(); +#pragma warning restore CS0618 // Type or member is obsolete + } + + public static List GetAssemblyReferences(Assembly assembly) + { + var assemblyRefs = assembly.GetReferencedAssemblies(); + var names = (from assemblyRef in assemblyRefs + orderby assemblyRef.Name.ToLowerInvariant() + select assemblyRef.Name).ToList(); + return names; + } + + public static void AssertPublicTypes(IEnumerable expected, Assembly assembly) + { + var publicTypes = (assembly.GetExportedTypes() + .Select(type => type.Name) + .OrderBy(n => n)); + + AssertPublicTypes(expected.ToArray(), publicTypes.ToArray()); + } + + public static void AssertPublicTypes(string[] expected, string[] actual) + { + var newlyIntroducedPublicTypes = actual.Except(expected).ToArray(); + + if (newlyIntroducedPublicTypes.Length > 0) + { + string message = string.Format("Found {0} unexpected public type{1}: \r\n{2}", + newlyIntroducedPublicTypes.Length, + newlyIntroducedPublicTypes.Length == 1 ? "" : "s", + string.Join("\r\n", newlyIntroducedPublicTypes)); + Assert.True(false, message); + } + + var missingPublicTypes = expected.Except(actual).ToArray(); + + if (missingPublicTypes.Length > 0) + { + string message = string.Format("missing {0} public type{1}: \r\n{2}", + missingPublicTypes.Length, + missingPublicTypes.Length == 1 ? "" : "s", + string.Join("\r\n", missingPublicTypes)); + Assert.True(false, message); + } + } + + public static IDictionary CreateInMemoryCollection() + { + return new Dictionary(); + } + + public static IDictionary AddSetting(this IDictionary dict, string name, string value) + { + dict.Add(name, value); + return dict; + } + + public static IConfiguration BuildConfiguration(this IDictionary dict) + { + return new ConfigurationBuilder().AddInMemoryCollection(dict).Build(); + } + public class TestProgram + { + } + } + +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs new file mode 100644 index 000000000000..1639d92eae19 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class TestLogger : ILogger + { + private readonly Action _logAction; + private IList _logMessages = new List(); + + // protect against changes to logMessages while enumerating + private object _syncLock = new object(); + + public TestLogger(string category, Action logAction = null) + { + Category = category; + _logAction = logAction; + } + + public string Category { get; private set; } + + public IDisposable BeginScope(TState state) + { + return null; + } + + public bool IsEnabled(LogLevel logLevel) + { + return true; + } + + public IList GetLogMessages() + { + lock (_syncLock) + { + return _logMessages.ToList(); + } + } + + public void ClearLogMessages() + { + lock (_syncLock) + { + _logMessages.Clear(); + } + } + + public virtual void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + var logMessage = new LogMessage + { + Level = logLevel, + EventId = eventId, + State = state as IEnumerable>, + Exception = exception, + FormattedMessage = formatter(state, exception), + Category = Category, + Timestamp = DateTime.UtcNow + }; + + lock (_syncLock) + { + _logMessages.Add(logMessage); + } + + _logAction?.Invoke(logMessage); + } + + public override string ToString() + { + return Category; + } + } +} \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs new file mode 100644 index 000000000000..bfb6d5152b1a --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Azure.WebJobs.Host.TestCommon +{ + public class TestLoggerProvider : ILoggerProvider + { + private readonly LoggerFilterOptions _filter; + private readonly Action _logAction; + private Dictionary _loggerCache { get; } = new Dictionary(); + + public TestLoggerProvider(Action logAction = null) + { + _filter = new LoggerFilterOptions(); + _logAction = logAction; + } + + public IList CreatedLoggers => _loggerCache.Values.ToList(); + + public ILogger CreateLogger(string categoryName) + { + if (!_loggerCache.TryGetValue(categoryName, out TestLogger logger)) + { + logger = new TestLogger(categoryName, _logAction); + _loggerCache.Add(categoryName, logger); + } + + return logger; + } + + public IEnumerable GetAllLogMessages() => CreatedLoggers.SelectMany(l => l.GetLogMessages()).OrderBy(p => p.Timestamp); + + public string GetLogString() => string.Join(Environment.NewLine, GetAllLogMessages()); + + public void ClearAllLogMessages() + { + foreach (TestLogger logger in CreatedLoggers) + { + logger.ClearLogMessages(); + } + } + + public void Dispose() + { + } + } +} From bfe5ec5ef5a0ceb6aadc121f9022827ac7773513 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 26 Aug 2020 12:24:08 -0700 Subject: [PATCH 06/20] Recorded test --- .../src/RecordedTestAttribute.cs | 4 +- .../src/TestRecording.cs | 2 +- .../tests/AzureClientAttributeTests.cs | 15 +-- ...soft.Extensions.Azure.WebJobs.Tests.csproj | 2 +- .../CanInjectKeyVaultClient.json | 93 +++++++++++++++++++ .../CanInjectKeyVaultClientAsync.json | 54 +++++++++++ 6 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs index b9594be5d426..8293c3e3cb98 100644 --- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs +++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs @@ -51,7 +51,7 @@ public override TestResult Execute(TestExecutionContext context) context.CurrentResult = innerCommand.Execute(context); // If the recording succeeded, set a warning result. - if (!IsTestFailedWithRecordingMismatch(context)) + 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."); } @@ -71,7 +71,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/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs index 49cf02747070..3adb9d9b3190 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Azure.Core.TestFramework; using Azure.Extensions.WebJobs; -using Azure.Security.KeyVault.Keys; +using Azure.Security.KeyVault.Secrets; using Microsoft.Azure.WebJobs.Host.TestCommon; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; @@ -19,16 +19,18 @@ public AzureClientAttributeTests(bool isAsync) : base(isAsync) { } - [Test] - public async Task A() + [RecordedTest] + public async Task CanInjectKeyVaultClient() { var host = new HostBuilder() - .ConfigureServices(services => services.AddAzureClients(builder => builder.ConfigureDefaults(options => Recording.InstrumentClientOptions(options)))) + .ConfigureServices(services => services.AddAzureClients(builder => builder + .ConfigureDefaults(options => Recording.InstrumentClientOptions(options)) + .UseCredential(TestEnvironment.Credential))) .ConfigureAppConfiguration(config => { config.AddInMemoryCollection(new Dictionary { - { "Connection:vaultUri", TestEnvironment.KeyVaultUrl } + { "AzureWebJobs:Connection:vaultUri", TestEnvironment.KeyVaultUrl } }); }) .ConfigureDefaultTestHost(builder => @@ -42,8 +44,9 @@ public async Task A() public class FunctionWithAzureClient { - public void Run([AzureClient("Connection")] KeyClient serviceClient) + public async Task Run([AzureClient("Connection")] SecretClient keyClient) { + await keyClient.SetSecretAsync("TestSecret", "Secret value"); } } } diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj index 917cc04ef139..522e407f39d5 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json new file mode 100644 index 000000000000..1c0b4076cf5d --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json @@ -0,0 +1,93 @@ +{ + "Entries": [ + { + "RequestUri": "https://pakrymext.vault.azure.net/secrets/TestSecret?api-version=7.0", + "RequestMethod": "PUT", + "RequestHeaders": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-Security.KeyVault.Secrets/4.0.1", + "(.NET Core 4.6.29130.01; Microsoft Windows 10.0.19041 )" + ], + "x-ms-client-request-id": "2a212bde8ee6a733d305c4a33777c0b9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 401, + "ResponseHeaders": { + "Cache-Control": "no-cache", + "Content-Length": "87", + "Content-Type": "application/json; charset=utf-8", + "Date": "Wed, 26 Aug 2020 19:22:40 GMT", + "Expires": "-1", + "Pragma": "no-cache", + "Strict-Transport-Security": "max-age=31536000;includeSubDomains", + "WWW-Authenticate": "Bearer authorization=\u0022https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\u0022, resource=\u0022https://vault.azure.net\u0022", + "X-AspNet-Version": "4.0.30319", + "X-Content-Type-Options": "nosniff", + "x-ms-keyvault-network-info": "conn_type=Ipv4;addr=167.220.2.219;act_addr_fam=InterNetwork;", + "x-ms-keyvault-region": "westus2", + "x-ms-keyvault-service-version": "1.1.44.0", + "x-ms-request-id": "5d13ca79-fd6b-4c23-a496-e2fdd3c85bc8", + "X-Powered-By": "ASP.NET" + }, + "ResponseBody": { + "error": { + "code": "Unauthorized", + "message": "Request is missing a Bearer or PoP token." + } + } + }, + { + "RequestUri": "https://pakrymext.vault.azure.net/secrets/TestSecret?api-version=7.0", + "RequestMethod": "PUT", + "RequestHeaders": { + "Accept": "application/json", + "Authorization": "Sanitized", + "Content-Length": "24", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-Security.KeyVault.Secrets/4.0.1", + "(.NET Core 4.6.29130.01; Microsoft Windows 10.0.19041 )" + ], + "x-ms-client-request-id": "2a212bde8ee6a733d305c4a33777c0b9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "value": "Secret value" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Cache-Control": "no-cache", + "Content-Length": "229", + "Content-Type": "application/json; charset=utf-8", + "Date": "Wed, 26 Aug 2020 19:22:42 GMT", + "Expires": "-1", + "Pragma": "no-cache", + "Strict-Transport-Security": "max-age=31536000;includeSubDomains", + "X-AspNet-Version": "4.0.30319", + "X-Content-Type-Options": "nosniff", + "x-ms-keyvault-network-info": "conn_type=Ipv4;addr=167.220.2.219;act_addr_fam=InterNetwork;", + "x-ms-keyvault-region": "westus2", + "x-ms-keyvault-service-version": "1.1.44.0", + "x-ms-request-id": "8f079617-6d14-4a4a-b53f-494698718ebf", + "X-Powered-By": "ASP.NET" + }, + "ResponseBody": { + "value": "Secret value", + "id": "https://pakrymext.vault.azure.net/secrets/TestSecret/532a5c91516443a5ae7eb9407f993879", + "attributes": { + "enabled": true, + "created": 1598469762, + "updated": 1598469762, + "recoveryLevel": "Recoverable\u002BPurgeable" + } + } + } + ], + "Variables": { + "AZURE_KEYVAULT_URL": "https://pakrymext.vault.azure.net", + "RandomSeed": "548087225" + } +} \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json new file mode 100644 index 000000000000..a0f32df85b9e --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json @@ -0,0 +1,54 @@ +{ + "Entries": [ + { + "RequestUri": "https://pakrymext.vault.azure.net/secrets/TestSecret?api-version=7.0", + "RequestMethod": "PUT", + "RequestHeaders": { + "Accept": "application/json", + "Authorization": "Sanitized", + "Content-Length": "24", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-Security.KeyVault.Secrets/4.0.1", + "(.NET Core 4.6.29130.01; Microsoft Windows 10.0.19041 )" + ], + "x-ms-client-request-id": "49b692b5ecad1611e064d51bbe308eff", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "value": "Secret value" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Cache-Control": "no-cache", + "Content-Length": "229", + "Content-Type": "application/json; charset=utf-8", + "Date": "Wed, 26 Aug 2020 19:22:42 GMT", + "Expires": "-1", + "Pragma": "no-cache", + "Strict-Transport-Security": "max-age=31536000;includeSubDomains", + "X-AspNet-Version": "4.0.30319", + "X-Content-Type-Options": "nosniff", + "x-ms-keyvault-network-info": "conn_type=Ipv4;addr=167.220.2.219;act_addr_fam=InterNetwork;", + "x-ms-keyvault-region": "westus2", + "x-ms-keyvault-service-version": "1.1.44.0", + "x-ms-request-id": "235c697d-46cf-4a36-90ae-144e849b3238", + "X-Powered-By": "ASP.NET" + }, + "ResponseBody": { + "value": "Secret value", + "id": "https://pakrymext.vault.azure.net/secrets/TestSecret/4cc02b5d5a31462c804ec5ccf94f782b", + "attributes": { + "enabled": true, + "created": 1598469763, + "updated": 1598469763, + "recoveryLevel": "Recoverable\u002BPurgeable" + } + } + } + ], + "Variables": { + "AZURE_KEYVAULT_URL": "https://pakrymext.vault.azure.net", + "RandomSeed": "2137402530" + } +} \ No newline at end of file From d063b9457538551e2cfc9def2e3f0fe0da2cc138 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 26 Aug 2020 12:53:11 -0700 Subject: [PATCH 07/20] Updates --- ...Microsoft.Extensions.Azure.netstandard2.0.cs | 1 + .../src/AzureClientFactoryBuilder.cs | 8 ++++---- ...t.Extensions.Azure.WebJobs.netstandard2.0.cs | 17 +++++++++++++++++ .../src/AzureClientsWebJobsBuilderExtensions.cs | 7 ++++--- 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs 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 43e00dc58cff..c658aa405de7 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs @@ -132,11 +132,11 @@ public AzureClientFactoryBuilder UseCredential(Func - /// + /// Sets the configuration instance that is used to resolve clients that were not explicitly registered. /// - /// - /// - public AzureClientFactoryBuilder SetConfigurationRoot(Func configurationProvider) + /// 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); diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs new file mode 100644 index 000000000000..67510f7b7242 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs @@ -0,0 +1,17 @@ +namespace Azure.Extensions.WebJobs +{ + [Microsoft.Azure.WebJobs.Description.BindingAttribute] + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter)] + public partial class AzureClientAttribute : System.Attribute, Microsoft.Azure.WebJobs.IConnectionProvider + { + public AzureClientAttribute(string connection) { } + public string Connection { get { throw null; } set { } } + } +} +namespace Microsoft.Extensions.Hosting +{ + public static partial class AzureClientsWebJobsBuilderExtensions + { + public static Microsoft.Azure.WebJobs.IWebJobsBuilder AddAzureClients(this Microsoft.Azure.WebJobs.IWebJobsBuilder builder) { throw null; } + } +} diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs index e7953c2e095b..b1f116005007 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using Azure.Extensions.WebJobs; using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Azure; using Microsoft.Extensions.Configuration; @@ -10,12 +11,12 @@ namespace Microsoft.Extensions.Hosting { /// - /// + /// The extensions for Azure SDK client support. /// public static class AzureClientsWebJobsBuilderExtensions { /// - /// + /// Adds support for and in WebJobs. /// /// /// @@ -28,7 +29,7 @@ public static IWebJobsBuilder AddAzureClients(this IWebJobsBuilder builder) } builder.Services.AddAzureClients(builder => - builder.SetConfigurationRoot(provider => provider.GetRequiredService().GetWebJobsRootConfiguration())); + builder.UseConfiguration(provider => provider.GetRequiredService().GetWebJobsRootConfiguration())); builder.AddExtension(); return builder; From 7970d21ff8c3c2d9af0eb22ee912eef66fff240e Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 26 Aug 2020 13:37:35 -0700 Subject: [PATCH 08/20] More logging --- .../Azure.Core.TestFramework/src/RecordedTestAttribute.cs | 5 +++++ .../src/AzureClientFactoryBuilder.cs | 3 +-- .../Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs index 8293c3e3cb98..04c4ebb113f5 100644 --- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs +++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs @@ -45,6 +45,7 @@ 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); @@ -55,6 +56,10 @@ public override TestResult Execute(TestExecutionContext context) { 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."); } + else + { + context.CurrentResult.SetResult(context.CurrentResult.ResultState, context.CurrentResult.Message + Environment.NewLine + "Original error: " + originalResult.Message, context.CurrentResult.Message); + } // revert RecordTestMode to Playback SetRecordMode(context.TestObject as RecordedTestBase, RecordedTestMode.Playback); diff --git a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs index c658aa405de7..6b9332a07570 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/AzureClientFactoryBuilder.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using System; -using System.Collections.Concurrent; namespace Microsoft.Extensions.Azure { @@ -26,7 +25,7 @@ internal AzureClientFactoryBuilder(IServiceCollection serviceCollection) _serviceCollection = serviceCollection; _serviceCollection.AddOptions(); _serviceCollection.TryAddSingleton(); - _serviceCollection.TryAddSingleton( typeof(IAzureClientFactory<>), typeof(FallbackAzureClientFactory<>)); + _serviceCollection.TryAddSingleton(typeof(IAzureClientFactory<>), typeof(FallbackAzureClientFactory<>)); } IAzureClientBuilder IAzureClientFactoryBuilder.RegisterClientFactory(Func clientFactory) diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs index 6c9987a27994..c250191c3f92 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/ClientFactory.cs @@ -21,6 +21,7 @@ internal static class ClientFactory public static object CreateClient(Type clientType, Type optionsType, object options, IConfiguration configuration, TokenCredential credential) { List arguments = new List(); + // Handle single values as connection strings if (configuration is IConfigurationSection section && section.Value != null) { var connectionString = section.Value; From 3028d1c41b088491ba5b69d6b31381327ee77397 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 26 Aug 2020 14:22:24 -0700 Subject: [PATCH 09/20] Fixes --- .../src/RecordedTestAttribute.cs | 9 ++++++--- .../tests/AzureClientFactoryTests.cs | 4 ++-- .../tests/AzureClientAttributeTests.cs | 8 ++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs index 04c4ebb113f5..f95a8fa3ad28 100644 --- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs +++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestAttribute.cs @@ -51,14 +51,17 @@ public override TestResult Execute(TestExecutionContext context) SetRecordMode(context.TestObject as RecordedTestBase, RecordedTestMode.Record); context.CurrentResult = innerCommand.Execute(context); - // If the recording succeeded, set a warning result. + // 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, context.CurrentResult.Message + Environment.NewLine + "Original error: " + originalResult.Message, context.CurrentResult.Message); + 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 diff --git a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs index cb4cdb2f3150..d781617af450 100644 --- a/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs +++ b/sdk/core/Microsoft.Extensions.Azure/tests/AzureClientFactoryTests.cs @@ -319,7 +319,7 @@ public void CanCreateClientWithoutRegistration() new KeyValuePair("TestClient:tenantId", "ConfigurationTenantId")); var serviceCollection = new ServiceCollection(); - serviceCollection.AddAzureClients(builder => builder.SetConfigurationRoot(_ => configuration)); + serviceCollection.AddAzureClients(builder => builder.UseConfiguration(_ => configuration)); ServiceProvider provider = serviceCollection.BuildServiceProvider(); IAzureClientFactory factory = provider.GetService>(); @@ -341,7 +341,7 @@ public void CanCreateClientWithoutRegistrationUsingConnectionString() new KeyValuePair("TestClient", "http://localhost/")); var serviceCollection = new ServiceCollection(); - serviceCollection.AddAzureClients(builder => builder.SetConfigurationRoot(_ => configuration)); + serviceCollection.AddAzureClients(builder => builder.UseConfiguration(_ => configuration)); ServiceProvider provider = serviceCollection.BuildServiceProvider(); IAzureClientFactory factory = provider.GetService>(); diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs index 3adb9d9b3190..26574aa46145 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs @@ -17,6 +17,14 @@ public class AzureClientAttributeTests : RecordedTestBase Date: Thu, 27 Aug 2020 10:19:04 -0700 Subject: [PATCH 10/20] Readme and changelog --- .../CHANGELOG.md | 5 ++ .../README.md | 69 +++++++++++++++++++ .../samples/Function1.cs | 2 + 3 files changed, 76 insertions(+) create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md create mode 100644 sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md new file mode 100644 index 000000000000..6d5d556c3456 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History + +## 1.0.0-preview.1 (Unreleased) + +- Initial release of the package. \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md new file mode 100644 index 000000000000..bb662a6f3230 --- /dev/null +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md @@ -0,0 +1,69 @@ +# Azure client library integration for WebJobs/Azure.Functions + +Microsoft.Extensions.Azure.Core provides shared primitives to integrate Azure clients with ASP.NET Core [dependency injection][dependency_injection] and [configuration][configuration] systems. + +[Source code][source_root] | [Package (NuGet)][package] + +## Getting started + +### Install the package + +Install the ASP.NET Core integration library using [NuGet][nuget]: + +```powershell +dotnet add package Microsoft.Extensions.Azure +``` + +### Reference the client from a function + +Annotate a function parameter with an `AzureClient` attribute passing a connection name as a parameter. + +```C# Snippet:AzureClientInFunction +public static class Function1 +{ + [FunctionName("Function1")] + public static IActionResult Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, + [AzureClient("AzureWebJobsStorage")] BlobServiceClient client) + { + return new OkObjectResult(client.GetBlobContainers().ToArray()); + } +} +``` + +The connection name should correspond to a configuration section with a connection string or a set of connection parameters that correspond to a client constructor. + +For example to construct a BlobClient using a connection string use the following configuration: + +```json +{ + "StorageConnection": "UseDevelopmentStorage=true" +} +``` + +To construct a client using a `blobUri`: + +```json +{ + "StorageConnection": { + "blobUri": "https://{storage_account}.blob.core.windows.net/" + } +} +``` + +You can do the same via [Azure.Function settings in the portal][azure_function_settings] by setting `StorageConnection` or `StorageConnection__blobUri` application settings (*NOTE* configuration format uses [ASP.NET Core environment variable provider][aspnet_core_env_vars] syntax). + +## Contributing +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. + + + +[source_root]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/core/Microsoft.Extensions.Azure.WebJobs/ +[nuget]: https://www.nuget.org/ +[package]: https://www.nuget.org/packages/Microsoft.Extensions.Azure/ +[azure_function_settings]: https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings +[aspnet_core_env_vars]: https://docs.microsoft.com/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#environment-variables \ No newline at end of file diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs index c9394871bebd..d9a3838ced29 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs @@ -10,6 +10,7 @@ namespace Azure.Extensions.WebJobs.Sample { + #region Snippet:AzureClientInFunction public static class Function1 { [FunctionName("Function1")] @@ -20,4 +21,5 @@ public static IActionResult Run( return new OkObjectResult(client.GetBlobContainers().ToArray()); } } + #endregion } From e3ab3054b3ac0ef9f07ba502018452acb89695a3 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 12:35:08 -0700 Subject: [PATCH 11/20] Fix docs --- eng/.docsettings.yml | 1 + sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index 95544f50c84d..fa23cd35903b 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/core/Microsoft.Extensions.Azure/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/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md index bb662a6f3230..63c2b803ecdb 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md @@ -62,7 +62,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con -[source_root]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/core/Microsoft.Extensions.Azure.WebJobs/ +[source_root]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/ [nuget]: https://www.nuget.org/ [package]: https://www.nuget.org/packages/Microsoft.Extensions.Azure/ [azure_function_settings]: https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings From d263448bc7a1ed91315540f3a31385b5dbed82b8 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 12:36:44 -0700 Subject: [PATCH 12/20] CI --- sdk/extensions/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/extensions/ci.yml b/sdk/extensions/ci.yml index 49f0f27639bc..ea97139448b9 100644 --- a/sdk/extensions/ci.yml +++ b/sdk/extensions/ci.yml @@ -33,3 +33,5 @@ extends: safeName: AzureExtensionsAspNetCoreDataProtectionKeys - name: Azure.Extensions.AspNetCore.Configuration.Secrets safeName: AzureExtensionsAspNetCoreConfigurationSecrets + - name: Microsoft.Extensions.Azure.WebJobs + safeName: MicrosoftExtensionsAzureWebJobs From 83f8fd9cd6cb60c2c42b703a49584d33dea02c2e Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 13:29:39 -0700 Subject: [PATCH 13/20] Try again --- eng/.docsettings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index fa23cd35903b..a73edc72af69 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -143,7 +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/core/Microsoft.Extensions.Azure/README.md','azure-sdk-tools/issues/404'] + - ['sdk/extensions/Microsoft.Extensions.Azure.WebJobs/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'] From 7c52b903eba7e599b1bfc9f8bba2e14177cd29a4 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 15:32:28 -0700 Subject: [PATCH 14/20] Feedback --- .../src/Internal/AzureClientFactory.cs | 1 + .../src/Internal/EventSourceLogForwarder.cs | 8 ++++++-- .../src/Internal/FallbackAzureClientFactory.cs | 2 ++ .../Microsoft.Extensions.Azure/tests/LogForwarderTests.cs | 2 ++ .../Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs | 2 +- .../src/AzureClientAttribute.cs | 2 +- .../src/AzureClientsExtensionConfigProvider.cs | 7 ++----- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs index 18da9309403b..485364813f31 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/AzureClientFactory.cs @@ -40,6 +40,7 @@ public AzureClientFactory( public TClient CreateClient(string name) { + _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/EventSourceLogForwarder.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/EventSourceLogForwarder.cs index e969cbabb934..fbb2ec0796e8 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/EventSourceLogForwarder.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/EventSourceLogForwarder.cs @@ -20,12 +20,16 @@ internal class EventSourceLogForwarder: IDisposable private readonly Func _formatMessage = FormatMessage; - private readonly AzureEventSourceListener _listener; + private AzureEventSourceListener _listener; public EventSourceLogForwarder(ILoggerFactory loggerFactory = null) { _loggerFactory = loggerFactory; - _listener = new AzureEventSourceListener((e, s) => LogEvent(e), EventLevel.Verbose); + } + + public void Start() + { + _listener ??= new AzureEventSourceListener((e, s) => LogEvent(e), EventLevel.Verbose); } private void LogEvent(EventWrittenEventArgs eventData) diff --git a/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs b/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs index 05721213e808..ca5915c0c116 100644 --- a/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs +++ b/sdk/core/Microsoft.Extensions.Azure/src/Internal/FallbackAzureClientFactory.cs @@ -47,6 +47,8 @@ public FallbackAzureClientFactory( public TClient CreateClient(string name) { + _logForwarder.Start(); + var globalOptions = _globalOptions.CurrentValue; FallbackClientRegistration registration; diff --git a/sdk/core/Microsoft.Extensions.Azure/tests/LogForwarderTests.cs b/sdk/core/Microsoft.Extensions.Azure/tests/LogForwarderTests.cs index 5824a5e4bfe2..534d270a35bb 100644 --- a/sdk/core/Microsoft.Extensions.Azure/tests/LogForwarderTests.cs +++ b/sdk/core/Microsoft.Extensions.Azure/tests/LogForwarderTests.cs @@ -23,6 +23,7 @@ public void MapsLevelsCorrectly(EventLevel eventLevel, LogLevel logLevel) var loggerFactory = new MockLoggerFactory(); using (var forwarder = new EventSourceLogForwarder(loggerFactory)) { + forwarder.Start(); typeof(TestSource).GetMethod(eventLevel.ToString(), BindingFlags.Instance | BindingFlags.Public).Invoke(TestSource.Log, Array.Empty()); } @@ -35,6 +36,7 @@ public void MapsLevelsCorrectly(EventLevel eventLevel, LogLevel logLevel) public void WorksWithNullLoggerFactory() { using var forwarder = new EventSourceLogForwarder( null); + forwarder.Start(); TestSource.Log.Informational(); } diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs index 67510f7b7242..2ec632d09abd 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs @@ -1,4 +1,4 @@ -namespace Azure.Extensions.WebJobs +namespace Microsoft.Azure.WebJobs { [Microsoft.Azure.WebJobs.Description.BindingAttribute] [System.AttributeUsageAttribute(System.AttributeTargets.Parameter)] diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs index b9e79f67c962..3b0244702e56 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs @@ -5,7 +5,7 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Description; -namespace Azure.Extensions.WebJobs +namespace Microsoft.Azure.WebJobs { /// /// diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs index 3092596c90a2..eaeaf409a018 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs @@ -4,7 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using Azure.Extensions.WebJobs; +using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Host.Bindings; using Microsoft.Azure.WebJobs.Host.Config; using Microsoft.Extensions.Azure; @@ -51,10 +51,7 @@ public Task GetValueAsync() .CreateClient(_connection)); } - public string ToInvokeString() - { - throw new NotImplementedException(); - } + public string ToInvokeString() => $"{typeof(TClient).Name} Connection: {_connection}"; public Type Type => typeof(TClient); From 9ed93c46a9d37b2df7e2447eb8162406e35a10d1 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 15:43:39 -0700 Subject: [PATCH 15/20] Builds --- .../tests/AzureClientAttributeTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs index 26574aa46145..613e64746022 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs @@ -7,6 +7,7 @@ using Azure.Core.TestFramework; using Azure.Extensions.WebJobs; using Azure.Security.KeyVault.Secrets; +using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Host.TestCommon; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; From 59eab961484f7aeccafa4634305b5db55c8eae09 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Aug 2020 15:54:01 -0700 Subject: [PATCH 16/20] Connection name in sample --- sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md | 2 +- .../Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs | 2 +- .../Microsoft.Extensions.Azure.WebJobs/samples/host.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md index 63c2b803ecdb..6308a57624dc 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md @@ -24,7 +24,7 @@ public static class Function1 [FunctionName("Function1")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, - [AzureClient("AzureWebJobsStorage")] BlobServiceClient client) + [AzureClient("StorageConnection")] BlobServiceClient client) { return new OkObjectResult(client.GetBlobContainers().ToArray()); } diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs index d9a3838ced29..43948721d370 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs @@ -16,7 +16,7 @@ public static class Function1 [FunctionName("Function1")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, - [AzureClient("AzureWebJobsStorage")] BlobServiceClient client) + [AzureClient("StorageConnection")] BlobServiceClient client) { return new OkObjectResult(client.GetBlobContainers().ToArray()); } diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json index 2f2277b1b75f..ec3f8ddb7c84 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json +++ b/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json @@ -11,5 +11,5 @@ } } }, - "AzureWebJobsStorage": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;" + "StorageConnection": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;" } From 3e904b7576cfa46f7d0d18fe68f5456d32eaf5c9 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 16:03:18 -0700 Subject: [PATCH 17/20] Microsoft.Azure.WebJobs.Extensions.Clients --- eng/.docsettings.yml | 2 +- sdk/extensions/Azure.Extensions.sln | 6 +++--- .../CHANGELOG.md | 0 .../Directory.Build.props | 0 .../README.md | 2 +- ...soft.Azure.WebJobs.Extensions.Clients.netstandard2.0.cs} | 0 .../samples/Function1.cs | 0 ...crosoft.Azure.WebJobs.Extensions.Clients.Samples.csproj} | 0 .../samples/host.json | 0 .../src/AzureClientAttribute.cs | 0 .../src/AzureClientsExtensionConfigProvider.cs | 0 .../src/AzureClientsWebJobsBuilderExtensions.cs | 0 .../src/AzureClientsWebJobsStartup.cs | 0 .../src/Microsoft.Azure.WebJobs.Extensions.Clients.csproj} | 2 +- .../tests/AzureClientAttributeTests.cs | 0 ...Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj} | 0 .../AzureClientAttributeTests/CanInjectKeyVaultClient.json | 0 .../CanInjectKeyVaultClientAsync.json | 0 .../tests/WebJobsTestEnvironment.cs | 0 .../tests/shared/FakeActivator.cs | 0 .../tests/shared/FakeNameResolver.cs | 0 .../tests/shared/FakeTypeLocator.cs | 0 .../tests/shared/JobHost.cs | 0 .../tests/shared/LogMessage.cs | 0 .../tests/shared/TestExceptionHandlerFactory.cs | 0 .../tests/shared/TestHelpers.cs | 0 .../tests/shared/TestLogger.cs | 0 .../tests/shared/TestLoggerProvider.cs | 0 sdk/extensions/ci.yml | 4 ++-- 29 files changed, 8 insertions(+), 8 deletions(-) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/CHANGELOG.md (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/Directory.Build.props (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/README.md (97%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs => Microsoft.Azure.WebJobs.Extensions.Clients/api/Microsoft.Azure.WebJobs.Extensions.Clients.netstandard2.0.cs} (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/samples/Function1.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj => Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj} (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/samples/host.json (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/src/AzureClientAttribute.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/src/AzureClientsExtensionConfigProvider.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/src/AzureClientsWebJobsBuilderExtensions.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/src/AzureClientsWebJobsStartup.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj => Microsoft.Azure.WebJobs.Extensions.Clients/src/Microsoft.Azure.WebJobs.Extensions.Clients.csproj} (93%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/AzureClientAttributeTests.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj => Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj} (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/WebJobsTestEnvironment.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/FakeActivator.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/FakeNameResolver.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/FakeTypeLocator.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/JobHost.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/LogMessage.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/TestExceptionHandlerFactory.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/TestHelpers.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/TestLogger.cs (100%) rename sdk/extensions/{Microsoft.Extensions.Azure.WebJobs => Microsoft.Azure.WebJobs.Extensions.Clients}/tests/shared/TestLoggerProvider.cs (100%) diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index a73edc72af69..8ea85037bbda 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -143,7 +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.Extensions.Azure.WebJobs/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/sdk/extensions/Azure.Extensions.sln b/sdk/extensions/Azure.Extensions.sln index 73e29627257e..c83cf36d675b 100644 --- a/sdk/extensions/Azure.Extensions.sln +++ b/sdk/extensions/Azure.Extensions.sln @@ -27,11 +27,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.Tests", "..\core\Microsoft.Extensions.Azure\tests\Microsoft.Extensions.Azure.Tests.csproj", "{439AD388-D698-4A82-B509-D79D511624F5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs", "Microsoft.Extensions.Azure.WebJobs\src\Microsoft.Extensions.Azure.WebJobs.csproj", "{8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.WebJobs.Extensions.Clients", "Microsoft.Azure.WebJobs.Extensions.Clients\src\Microsoft.Azure.WebJobs.Extensions.Clients.csproj", "{8AF0DAC5-3F8A-49A7-AA9E-A05D589DD279}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs.Tests", "Microsoft.Extensions.Azure.WebJobs\tests\Microsoft.Extensions.Azure.WebJobs.Tests.csproj", "{BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.WebJobs.Extensions.Clients.Tests", "Microsoft.Azure.WebJobs.Extensions.Clients\tests\Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj", "{BFCD7A9E-27A9-448F-B98A-4C1A8808CFFB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Azure.WebJobs.Samples", "Microsoft.Extensions.Azure.WebJobs\samples\Microsoft.Extensions.Azure.WebJobs.Samples.csproj", "{45CF248B-6CBA-4BF2-8E8D-44092A525709}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.WebJobs.Extensions.Clients.Samples", "Microsoft.Azure.WebJobs.Extensions.Clients\samples\Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj", "{45CF248B-6CBA-4BF2-8E8D-44092A525709}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/CHANGELOG.md rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/Directory.Build.props similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/Directory.Build.props rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/Directory.Build.props diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md similarity index 97% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md index 6308a57624dc..106c8b14ce81 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/README.md +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md @@ -11,7 +11,7 @@ Microsoft.Extensions.Azure.Core provides shared primitives to integrate Azure cl Install the ASP.NET Core integration library using [NuGet][nuget]: ```powershell -dotnet add package Microsoft.Extensions.Azure +dotnet add package Microsoft.Azure.WebJobs.Extensions.Clients --version 1.0.0-beta.1 ``` ### Reference the client from a function diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/api/Microsoft.Azure.WebJobs.Extensions.Clients.netstandard2.0.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/api/Microsoft.Extensions.Azure.WebJobs.netstandard2.0.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/api/Microsoft.Azure.WebJobs.Extensions.Clients.netstandard2.0.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Function1.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Function1.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Function1.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/Microsoft.Extensions.Azure.WebJobs.Samples.csproj rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/host.json similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/samples/host.json rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/host.json diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientAttribute.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientAttribute.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientAttribute.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsExtensionConfigProvider.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsExtensionConfigProvider.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsExtensionConfigProvider.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsWebJobsBuilderExtensions.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsBuilderExtensions.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsWebJobsBuilderExtensions.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsStartup.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsWebJobsStartup.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/AzureClientsWebJobsStartup.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/AzureClientsWebJobsStartup.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/Microsoft.Azure.WebJobs.Extensions.Clients.csproj similarity index 93% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/Microsoft.Azure.WebJobs.Extensions.Clients.csproj index 6834ae8543c8..31f0c59d7dad 100644 --- a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/src/Microsoft.Extensions.Azure.WebJobs.csproj +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/src/Microsoft.Azure.WebJobs.Extensions.Clients.csproj @@ -4,7 +4,7 @@ $(RequiredTargetFrameworks) aspnetcore;dataprotection;azure;blob;key store - 1.0.0-preview.1 + 1.0.0-beta.1 true $(NoWarn);AZC0001;CA1812 diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/AzureClientAttributeTests.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/Microsoft.Extensions.Azure.WebJobs.Tests.csproj rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClient.json diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/SessionRecords/AzureClientAttributeTests/CanInjectKeyVaultClientAsync.json diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/WebJobsTestEnvironment.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/WebJobsTestEnvironment.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/WebJobsTestEnvironment.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeActivator.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeActivator.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeActivator.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeNameResolver.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeNameResolver.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeNameResolver.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeTypeLocator.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/FakeTypeLocator.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/FakeTypeLocator.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/JobHost.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/JobHost.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/JobHost.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/LogMessage.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/LogMessage.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/LogMessage.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestExceptionHandlerFactory.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestExceptionHandlerFactory.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestExceptionHandlerFactory.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestHelpers.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestHelpers.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestHelpers.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestLogger.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLogger.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestLogger.cs diff --git a/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestLoggerProvider.cs similarity index 100% rename from sdk/extensions/Microsoft.Extensions.Azure.WebJobs/tests/shared/TestLoggerProvider.cs rename to sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/shared/TestLoggerProvider.cs diff --git a/sdk/extensions/ci.yml b/sdk/extensions/ci.yml index ea97139448b9..eda38fcc605c 100644 --- a/sdk/extensions/ci.yml +++ b/sdk/extensions/ci.yml @@ -33,5 +33,5 @@ extends: safeName: AzureExtensionsAspNetCoreDataProtectionKeys - name: Azure.Extensions.AspNetCore.Configuration.Secrets safeName: AzureExtensionsAspNetCoreConfigurationSecrets - - name: Microsoft.Extensions.Azure.WebJobs - safeName: MicrosoftExtensionsAzureWebJobs + - name: Microsoft.Azure.WebJobs.Extensions.Clients + safeName: MicrosoftAzureWebJobsExtensionsClients From 551df0f712718254708bc8846a47af4553ed1543 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 16:12:39 -0700 Subject: [PATCH 18/20] Fix build --- ...oft.Azure.WebJobs.Extensions.Clients.Samples.csproj | 2 +- .../tests/AzureClientAttributeTests.cs | 10 +++++----- ...osoft.Azure.WebJobs.Extensions.Clients.Tests.csproj | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj index 8125217de291..91348a8ae58e 100644 --- a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/samples/Microsoft.Azure.WebJobs.Extensions.Clients.Samples.csproj @@ -8,7 +8,7 @@ - + diff --git a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs index 613e64746022..a6f307791bbf 100644 --- a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/AzureClientAttributeTests.cs @@ -2,17 +2,17 @@ // Licensed under the MIT License. using System.Collections.Generic; -using NUnit.Framework; using System.Threading.Tasks; +using Azure.Core; using Azure.Core.TestFramework; -using Azure.Extensions.WebJobs; using Azure.Security.KeyVault.Secrets; -using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Host.TestCommon; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.Azure.WebJobs.Tests; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Microsoft.Extensions.Azure.WebJobs.Tests +namespace Microsoft.Azure.WebJobs.Extensions.Clients.Tests { public class AzureClientAttributeTests : RecordedTestBase { @@ -33,7 +33,7 @@ public async Task CanInjectKeyVaultClient() { var host = new HostBuilder() .ConfigureServices(services => services.AddAzureClients(builder => builder - .ConfigureDefaults(options => Recording.InstrumentClientOptions(options)) + .ConfigureDefaults(options => Recording.InstrumentClientOptions(options)) .UseCredential(TestEnvironment.Credential))) .ConfigureAppConfiguration(config => { diff --git a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj index 522e407f39d5..406a7bf62d70 100644 --- a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/tests/Microsoft.Azure.WebJobs.Extensions.Clients.Tests.csproj @@ -17,7 +17,7 @@ - + From 707c1070c6bb01061bab1d0750dbecf190ef1c3d Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 16:26:37 -0700 Subject: [PATCH 19/20] changelog --- .../Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md index 6d5d556c3456..4624755472c0 100644 --- a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/CHANGELOG.md @@ -1,5 +1,5 @@ # Release History -## 1.0.0-preview.1 (Unreleased) +## 1.0.0-beta.1 (Unreleased) - Initial release of the package. \ No newline at end of file From c8e1cf3f8623d22251b8c78d3315f80e080e44c3 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 16:44:00 -0700 Subject: [PATCH 20/20] Link --- .../Microsoft.Azure.WebJobs.Extensions.Clients/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md index 106c8b14ce81..8cd65b959357 100644 --- a/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md +++ b/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md @@ -62,7 +62,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con -[source_root]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/extensions/Microsoft.Extensions.Azure.WebJobs/ +[source_root]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/ [nuget]: https://www.nuget.org/ [package]: https://www.nuget.org/packages/Microsoft.Extensions.Azure/ [azure_function_settings]: https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings