Skip to content
Permalink
Browse files

Merge branch 'feature-718' of https://github.com/simpleinjector/Simpl…

…eInjector into v4.7.x
  • Loading branch information
dotnetjunkie committed Sep 1, 2019
2 parents 3af0e57 + bc87c83 commit f6526dce0472e029f6692a422be0de9caf4c721f
@@ -0,0 +1,18 @@
// Copyright (c) Simple Injector Contributors. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license information.

namespace SimpleInjector.Integration.ServiceCollection
{
using Microsoft.Extensions.Logging;

// This class wouldn't strictly be required, but since Microsoft could decide to add an extra ctor
// to the Microsoft.Extensions.Logging.Logger<T> class, this sub type prevents this integration
// package to break when this happens.
internal sealed class Logger<T> : Microsoft.Extensions.Logging.Logger<T>
{
// This constructor needs to be public for Simple Injector to create this type.
public Logger(ILoggerFactory factory) : base(factory)
{
}
}
}
@@ -0,0 +1,28 @@
// Copyright (c) Simple Injector Contributors. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license information.

namespace SimpleInjector.Integration.ServiceCollection
{
using System;
using Microsoft.Extensions.Logging;

internal sealed class RootLogger : ILogger
{
private readonly ILogger logger;

// This constructor needs to be public for Simple Injector to create this type.
public RootLogger(ILoggerFactory factory) => this.logger = factory.CreateLogger(string.Empty);

public IDisposable BeginScope<TState>(TState state) => this.logger.BeginScope(state);

public bool IsEnabled(LogLevel logLevel) => this.logger.IsEnabled(logLevel);

public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter) =>
this.logger.Log(logLevel, eventId, state, exception, formatter);
}
}
@@ -30,6 +30,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
</ItemGroup>

@@ -7,6 +7,7 @@ namespace SimpleInjector
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SimpleInjector.Diagnostics;
using SimpleInjector.Integration.ServiceCollection;
@@ -151,13 +152,64 @@ public static SimpleInjectorUseOptions UseLogging(this SimpleInjectorUseOptions
typeof(ILogger),
c => c.Consumer is null
? typeof(RootLogger)
: typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
: typeof(Integration.ServiceCollection.Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);

return options;
}

/// <summary>
/// Allows components that are built by Simple Injector to depend on the (non-generic)
/// <see cref="IStringLocalizer">Microsoft.Extensions.Localization.IStringLocalizer</see> abstraction. Components are
/// injected with an contextual implementation. Using this method, application components can simply
/// depend on <b>IStringLocalizer</b> instead of its generic counter part, <b>IStringLocalizer&lt;T&gt;</b>, which
/// simplifies development.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>The supplied <paramref name="options"/>.</returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="options"/> is a null reference.</exception>
/// <exception cref="InvalidOperationException">Thrown when no <see cref="IStringLocalizerFactory"/> entry
/// can be found in the framework's list of services defined by <see cref="IServiceCollection"/>.
/// </exception>
/// <exception cref="ActivationException">Thrown when an <see cref="IStringLocalizer"/> is directly resolved from the
/// container. Instead use <see cref="IStringLocalizer"/> within a constructor dependency.</exception>
public static SimpleInjectorUseOptions UseLocalization(this SimpleInjectorUseOptions options)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}

var localizerFactory = options.ApplicationServices.GetService<IStringLocalizerFactory>();

if (localizerFactory is null)
{
throw new InvalidOperationException(
$"The IServiceCollection is missing an entry for {typeof(IStringLocalizerFactory).FullName}. " +
"This is most likely caused by a missing call to .AddLocalization(). Make sure that the " +
"AddLocalization() extension method is called on the IServiceCollection. This method is " +
"part of the LocalizationServiceCollectionExtensions class of the Microsoft.Extensions" +
".Localization assembly.");
}

// Register localizer factory explicitly. This allows the IStringLocalizer<T> conditional registration to work
// even when auto cross wiring is disabled.
options.Container.RegisterInstance(localizerFactory);

options.Container.RegisterConditional(
typeof(IStringLocalizer),
c => c.Consumer is null
? throw new ActivationException("IStringLocalizer is being resolved directly from the container, " +
"but this is not supported as string localizers need to be related to a consuming type. " +
"Instead, make IStringLocalizer a constructor dependency of the type it is used in.")
: typeof(Integration.ServiceCollection.StringLocalizer<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);

return options;
}
/// <summary>
/// Cross wires an ASP.NET Core or third-party service to the container, to allow the service to be
/// injected into components that are built by Simple Injector.
@@ -372,36 +424,5 @@ private static void TrySetDefaultScopedLifestyle(Container container)
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
}
}

private sealed class RootLogger : ILogger
{
private readonly ILogger logger;

// This constructor needs to be public for Simple Injector to create this type.
public RootLogger(ILoggerFactory factory) => this.logger = factory.CreateLogger(string.Empty);

public IDisposable BeginScope<TState>(TState state) => this.logger.BeginScope(state);

public bool IsEnabled(LogLevel logLevel) => this.logger.IsEnabled(logLevel);

public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter) =>
this.logger.Log(logLevel, eventId, state, exception, formatter);
}

// This class wouldn't strictly be required, but since Microsoft could decide to add an extra ctor
// to the Microsoft.Extensions.Logging.Logger<T> class, this sub type prevents this integration
// package to break when this happens.
private sealed class Logger<T> : Microsoft.Extensions.Logging.Logger<T>
{
// This constructor needs to be public for Simple Injector to create this type.
public Logger(ILoggerFactory factory) : base(factory)
{
}
}
}
}
@@ -0,0 +1,17 @@
// Copyright (c) Simple Injector Contributors. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license information.

namespace SimpleInjector.Integration.ServiceCollection
{
using Microsoft.Extensions.Localization;

// This class wouldn't strictly be required, but since Microsoft could decide to add an extra ctor
// to the Microsoft.Extensions.Localization.StringLocalizer<T> class, this sub type prevents this integration
// package to break when this happens.
internal sealed class StringLocalizer<T> : Microsoft.Extensions.Localization.StringLocalizer<T>
{
public StringLocalizer(IStringLocalizerFactory factory) : base(factory)
{
}
}
}

0 comments on commit f6526dc

Please sign in to comment.
You can’t perform that action at this time.