Improve IHttpClient factories (#20)

Codestyle fixes
Setup CODEOWNERS
Setup dependabot
This commit is contained in:
2022-09-06 15:49:07 +02:00
committed by GitHub
parent 3c741ab969
commit e6a06915cd
99 changed files with 8108 additions and 7558 deletions
@@ -1,14 +1,13 @@
namespace System.Configuration
{
public sealed class DefaultOptionsManager : IOptionsManager
{
public T GetOptions<T>() where T : class
{
return default;
}
namespace System.Configuration;
public void UpdateOptions<T>(T value) where T : class
{
}
public sealed class DefaultOptionsManager : IOptionsManager
{
public T GetOptions<T>() where T : class
{
return default;
}
public void UpdateOptions<T>(T value) where T : class
{
}
}
@@ -1,9 +1,8 @@
using Microsoft.Extensions.Options;
namespace System.Configuration
namespace System.Configuration;
public interface ILiveOptions<T> : IOptions<T>
where T : class
{
public interface ILiveOptions<T> : IOptions<T>
where T : class
{
}
}
@@ -1,7 +1,6 @@
namespace System.Configuration
namespace System.Configuration;
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
where T : class
{
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
where T : class
{
}
}
@@ -1,10 +1,9 @@
namespace System.Configuration
namespace System.Configuration;
public interface IOptionsManager
{
public interface IOptionsManager
{
T GetOptions<T>()
where T : class;
void UpdateOptions<T>(T value)
where T : class;
}
T GetOptions<T>()
where T : class;
void UpdateOptions<T>(T value)
where T : class;
}
@@ -1,13 +1,12 @@
using Microsoft.Extensions.Options;
namespace System.Configuration
namespace System.Configuration;
public interface IUpdateableOptions<out T> : IOptions<T>
where T : class
{
public interface IUpdateableOptions<out T> : IOptions<T>
where T : class
{
/// <summary>
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
/// </summary>
void UpdateOption();
}
/// <summary>
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
/// </summary>
void UpdateOption();
}
@@ -1,27 +1,26 @@
using Slim.Resolvers;
namespace System.Configuration
namespace System.Configuration;
public sealed class LiveOptionsResolver : IDependencyResolver
{
public sealed class LiveOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return false;
}
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
@@ -1,26 +1,25 @@
using Slim.Resolvers;
namespace System.Configuration
namespace System.Configuration;
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
{
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
return Activator.CreateInstance(typedOptionsType, configurationManager);
}
}
@@ -1,31 +1,30 @@
using System.Extensions;
namespace System.Configuration
namespace System.Configuration;
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
where T : class
{
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
where T : class
private readonly IOptionsManager configurationManager;
private T value;
public T Value
{
private readonly IOptionsManager configurationManager;
private T value;
public T Value
get
{
get
{
this.value = this.configurationManager.GetOptions<T>();
return this.value;
}
}
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions<T>(this.value);
this.value = this.configurationManager.GetOptions<T>();
return this.value;
}
}
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions<T>(this.value);
}
}
@@ -1,33 +1,32 @@
using Microsoft.Extensions.Options;
using Slim.Resolvers;
namespace System.Configuration
namespace System.Configuration;
public sealed class OptionsResolver : IDependencyResolver
{
public sealed class OptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(OptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(OptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return false;
}
return Activator.CreateInstance(typedOptionsType, optionsValue);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return Activator.CreateInstance(typedOptionsType, optionsValue);
}
}
@@ -1,33 +1,32 @@
using Slim.Resolvers;
using System.Extensions.Configuration;
namespace System.Configuration
namespace System.Configuration;
public sealed class UpdateableOptionsResolver : IDependencyResolver
{
public sealed class UpdateableOptionsResolver : IDependencyResolver
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
{
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
private static readonly Type configurationType = typeof(IOptionsManager);
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return false;
}
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
var configurationManager = serviceProvider.GetService<IOptionsManager>();
var optionsValue = configurationType
.GetMethod(nameof(IOptionsManager.GetOptions))
.MakeGenericMethod(type.GetGenericArguments())
.Invoke(configurationManager, Array.Empty<object>());
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
}
}
@@ -1,23 +1,22 @@
using System.Configuration;
namespace System.Extensions.Configuration
namespace System.Extensions.Configuration;
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
{
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
private readonly IOptionsManager configurationManager;
public T Value { get; }
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
{
private readonly IOptionsManager configurationManager;
public T Value { get; }
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.Value = options;
}
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
{
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
this.Value = options;
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions(this.Value);
}
public void UpdateOption()
{
this.configurationManager.UpdateOptions(this.Value);
}
}
@@ -2,157 +2,188 @@
using Microsoft.Extensions.Options;
using Slim;
using System.Configuration;
using System.DependencyInjection.Http;
using System.Http;
using System.Logging;
using System.Net.Http;
namespace System.Extensions
namespace System.Extensions;
public static class ServiceManagerExtensions
{
public static class ServiceManagerExtensions
/// <summary>
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceProducer RegisterOptionsManager(this IServiceProducer serviceProducer)
{
/// <summary>
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager)
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="IOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceProducer RegisterOptionsManager<T>(this IServiceProducer serviceProducer)
where T : IOptionsManager
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterSingleton<IOptionsManager, T>();
serviceProducer.RegisterOptionsResolver();
return serviceProducer;
}
/// <summary>
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns><see cref="IServiceManager"/>.</returns>
public static IServiceProducer RegisterOptionsResolver(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterResolver(new OptionsResolver());
serviceProducer.RegisterResolver(new UpdateableOptionsResolver());
serviceProducer.RegisterResolver(new LiveOptionsResolver());
serviceProducer.RegisterResolver(new LiveUpdateableOptionsResolver());
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
serviceManager.RegisterOptionsResolver();
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
return serviceManager;
}
return serviceManager;
}
/// <summary>
/// Registers a <see cref="IOptionsManager"/>.
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
/// </summary>
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsManager<T>(this IServiceManager serviceManager)
where T : IOptionsManager
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : TILogsWriter
where TILogsWriter : class, ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.RegisterSingleton<IOptionsManager, T>();
serviceManager.RegisterOptionsResolver();
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
return factory;
});
return serviceManager;
}
return serviceManager;
}
/// <summary>
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
/// </summary>
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
/// <returns><see cref="IServiceManager"/>.</returns>
public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager)
/// <summary>
/// Register a <see cref="ILoggerFactory"/> with a <see cref="CVLoggerProvider"/>.
/// </summary>
/// <param name="serviceProducer"></param>
/// <returns></returns>
public static IServiceProducer RegisterCVLoggerFactory(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceProducer.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
serviceManager.ThrowIfNull(nameof(serviceManager));
LoggerFactory loggerFactory = new();
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return loggerFactory;
});
serviceManager.RegisterResolver(new OptionsResolver());
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
serviceManager.RegisterResolver(new LiveOptionsResolver());
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
return serviceProducer;
}
return serviceManager;
}
/// <summary>
/// Registers a <see cref="ILoggerFactory"/>.
/// </summary>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <param name="loggerFactory">Factory that produces a <see cref="ILoggerFactory"/>.</param>
/// <returns></returns>
public static IServiceProducer RegisterLoggerFactory(this IServiceProducer serviceProducer, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceProducer.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceProducer;
}
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
/// <summary>
/// Registers a <see cref="ILoggerFactory"/> with a <see cref="ILogsWriter"/> that writes to <see cref="Diagnostics.Debug"/>.
/// </summary>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <returns></returns>
public static IServiceProducer RegisterDebugLoggerFactory(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
return serviceManager;
}
serviceProducer.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceProducer;
}
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : TILogsWriter
where TILogsWriter : class, ILogsWriter
{
serviceManager.ThrowIfNull(nameof(serviceManager));
/// <summary>
/// Register a scoped <see cref="IHttpClient{TScope}"/> to be used by the DI engine.
/// </summary>
/// <typeparam name="T">Type of the scoped <see cref="IHttpClient{TScope}"/>.</typeparam>
/// <param name="serviceProducer"><see cref="IServiceProducer"/>.</param>
/// <returns><see cref="HttpClientBuilder{T}"/> to build the http client.</returns>
public static HttpClientBuilder<T> RegisterHttpClient<T>(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
return factory;
});
return new HttpClientBuilder<T>(serviceProducer);
}
return serviceManager;
}
[Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient<object>)}.")]
public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
/// <summary>
/// Register a <see cref="ILoggerFactory"/> with a <see cref="CVLoggerProvider"/>.
/// </summary>
/// <param name="serviceManager"></param>
/// <returns></returns>
public static IServiceManager RegisterCVLoggerFactory(this IServiceManager serviceManager)
{
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
LoggerFactory loggerFactory = new();
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return loggerFactory;
});
serviceProducer.RegisterResolver(new HttpClientResolver());
return serviceProducer;
}
[Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient<object>)}.")]
public static IServiceProducer RegisterHttpFactory(this IServiceProducer serviceProducer, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
return serviceManager;
}
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceManager;
}
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(new HttpClientResolver());
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
return serviceManager;
}
serviceProducer.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
return serviceProducer;
}
}
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("SystemExtensions.NetStandard.DependencyInjection.Tests")]
@@ -0,0 +1,85 @@
using Slim;
using System.Extensions;
using System.Net.Http;
using System.Net.Http.Headers;
namespace System.DependencyInjection.Http;
public sealed class HttpClientBuilder<T>
{
private readonly IServiceProducer serviceProducer;
private Uri baseAddress;
private HttpMessageHandler httpMessageHandler;
private bool disposeMessageHandler;
private Action<HttpRequestHeaders> defaultRequestHeadersSetup;
private long maxResponseBufferSize = 2147483647L; //2GB default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.maxresponsecontentbuffersize?view=net-6.0]
private TimeSpan timeout = TimeSpan.FromSeconds(100); //100 seconds default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-6.0]
internal HttpClientBuilder(IServiceProducer serviceProducer)
{
serviceProducer.ThrowIfNull(nameof(serviceProducer));
this.serviceProducer = serviceProducer;
}
public HttpClientBuilder<T> WithMessageHandler(HttpMessageHandler httpMessageHandler)
{
httpMessageHandler.ThrowIfNull(nameof(httpMessageHandler));
this.httpMessageHandler = httpMessageHandler;
return this;
}
public HttpClientBuilder<T> WithDisposeMessageHandler(bool disposeMessageHandler)
{
this.disposeMessageHandler = disposeMessageHandler;
return this;
}
public HttpClientBuilder<T> WithBaseAddress(Uri baseAddress)
{
baseAddress.ThrowIfNull(nameof(baseAddress));
this.baseAddress = baseAddress;
return this;
}
public HttpClientBuilder<T> WithDefaultRequestHeadersSetup(Action<HttpRequestHeaders> setup)
{
setup.ThrowIfNull(nameof(setup));
this.defaultRequestHeadersSetup = setup;
return this;
}
public HttpClientBuilder<T> WithMaxResponseBufferSize(long responseBufferSize)
{
this.maxResponseBufferSize = responseBufferSize;
return this;
}
public HttpClientBuilder<T> WithTimeout(TimeSpan timeout)
{
this.timeout = timeout;
return this;
}
public IServiceProducer Build()
{
this.serviceProducer.RegisterScoped<IHttpClient<T>>(_ =>
{
var client = this.httpMessageHandler is not null ?
new HttpClient<T>(this.httpMessageHandler, this.disposeMessageHandler) :
new HttpClient<T>();
client.BaseAddress = this.baseAddress;
this.defaultRequestHeadersSetup?.Invoke(client.DefaultRequestHeaders);
client.MaxResponseContentBufferSize = this.maxResponseBufferSize;
client.Timeout = this.timeout;
return client;
});
return this.serviceProducer;
}
}
@@ -2,46 +2,46 @@
using System.Linq;
using System.Net.Http;
namespace System.Http
namespace System.Http;
[Obsolete($"Please use {nameof(Extensions.ServiceManagerExtensions.RegisterHttpClient)} for each use case of {nameof(IHttpClient<object>)}")]
public sealed class HttpClientResolver : IDependencyResolver
{
public sealed class HttpClientResolver : IDependencyResolver
private static readonly Type clientType = typeof(HttpClient<>);
/// <summary>
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
/// </summary>
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
/// <summary>
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
/// </summary>
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
/// <returns></returns>
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
{
private static readonly Type clientType = typeof(HttpClient<>);
this.HttpMessageHandlerFactory = factory;
return this;
}
/// <summary>
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
/// </summary>
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
/// <summary>
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
/// </summary>
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
/// <returns></returns>
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
{
this.HttpMessageHandlerFactory = factory;
return this;
return true;
}
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
{
return true;
}
return false;
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
var httpClient = handler is null ?
Activator.CreateInstance(typedClientType) :
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
var httpClient = handler is null ?
Activator.CreateInstance(typedClientType) :
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
}
@@ -1,44 +1,43 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace System.Logging
namespace System.Logging;
public sealed class CVLogger : ILogger
{
public sealed class CVLogger : ILogger
private readonly string category;
private readonly ICVLoggerProvider cvLoggerProvider;
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
{
private readonly string category;
private readonly ICVLoggerProvider cvLoggerProvider;
this.category = category;
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider));
}
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
this.category = category;
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider));
}
Exception = exception,
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
Exception = exception,
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
this.cvLoggerProvider.LogEntry(log);
}
this.cvLoggerProvider.LogEntry(log);
}
}
@@ -2,38 +2,37 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
namespace System.Logging
namespace System.Logging;
public sealed class CVLoggerProvider : ICVLoggerProvider
{
public sealed class CVLoggerProvider : ICVLoggerProvider
private readonly ILogsWriter logsManager;
private readonly CorrelationVector correlationVector;
public CVLoggerProvider(ILogsWriter logsWriter)
{
private readonly ILogsWriter logsManager;
private readonly CorrelationVector correlationVector;
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
this.correlationVector = new CorrelationVector();
}
public CVLoggerProvider(ILogsWriter logsWriter)
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
this.correlationVector = new CorrelationVector();
log.CorrelationVector = this.correlationVector.Value.ToString();
this.correlationVector.Increment();
}
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
log.CorrelationVector = this.correlationVector.Value.ToString();
this.correlationVector.Increment();
}
this.logsManager.WriteLog(log);
}
this.logsManager.WriteLog(log);
}
public ILogger CreateLogger(string categoryName)
{
return new CVLogger(categoryName, this);
}
public ILogger CreateLogger(string categoryName)
{
return new CVLogger(categoryName, this);
}
public void Dispose()
{
throw new System.NotImplementedException();
}
public void Dispose()
{
throw new System.NotImplementedException();
}
}
@@ -1,12 +1,11 @@
using System.Diagnostics;
namespace System.Logging
namespace System.Logging;
public sealed class DebugLogsWriter : ILogsWriter
{
public sealed class DebugLogsWriter : ILogsWriter
public void WriteLog(Log log)
{
public void WriteLog(Log log)
{
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
}
@@ -1,9 +1,8 @@
using Microsoft.Extensions.Logging;
namespace System.Logging
namespace System.Logging;
public interface ICVLoggerProvider : ILoggerProvider
{
public interface ICVLoggerProvider : ILoggerProvider
{
void LogEntry(Log log);
}
void LogEntry(Log log);
}
@@ -1,7 +1,6 @@
namespace System.Logging
namespace System.Logging;
public interface ILogsWriter
{
public interface ILogsWriter
{
void WriteLog(Log log);
}
void WriteLog(Log log);
}
@@ -2,49 +2,48 @@
using Slim.Resolvers;
using System.Linq;
namespace System.Logging
namespace System.Logging;
public sealed class LoggerResolver : IDependencyResolver
{
public sealed class LoggerResolver : IDependencyResolver
public bool CanResolve(Type type)
{
public bool CanResolve(Type type)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
type == typeof(ILogger))
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
type == typeof(ILogger))
{
return true;
}
return false;
return true;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
{
return ResolveScopedLogger(serviceProvider, type);
}
else if (type == typeof(ILogger))
{
return ResolveLogger(serviceProvider);
}
else
{
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
}
}
return false;
}
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var categoryTypes = type.GetGenericArguments();
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
return ResolveScopedLogger(serviceProvider, type);
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider)
else if (type == typeof(ILogger))
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
return ResolveLogger(serviceProvider);
}
else
{
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
}
}
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var categoryTypes = type.GetGenericArguments();
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
}
}
@@ -1,15 +1,14 @@
using Microsoft.Extensions.Logging;
namespace System.Logging
namespace System.Logging;
public sealed record Log
{
public sealed record Log
{
public Exception Exception { get; set; }
public DateTime LogTime { get; set; }
public string Category { get; set; }
public string EventId { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
public Exception Exception { get; set; }
public DateTime LogTime { get; set; }
public string Category { get; set; }
public string EventId { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
@@ -0,0 +1,8 @@
using System.Net.Http;
namespace System.DependencyInjection.Models;
internal sealed class TypedHttpClientFactory<T>
{
public Func<Slim.IServiceProvider, HttpMessageHandler> Factory { get; set; }
}
@@ -6,7 +6,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<LangVersion>latest</LangVersion>
<Version>1.1.8</Version>
<Version>1.2</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the Slim Dependency Injection engine</Description>
@@ -22,7 +22,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Slim" Version="1.7.3" />
<PackageReference Include="Slim" Version="1.8.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
</ItemGroup>