Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kahbazi/4cad9602fe9381f2b598c4c570a95e5f to your computer and use it in GitHub Desktop.
Save Kahbazi/4cad9602fe9381f2b598c4c570a95e5f to your computer and use it in GitHub Desktop.
Integrating SimpleInjector and Microsoft DI in ASP.Net Owin/Katana
public class Startup
{
public void Configuration(IAppBuilder app)
{
IServiceCollection serviceCollection = new ServiceCollection()
.AddLogging()
.AddAutoMapper()
.AddOptions();
IServiceProvider serviceProvider = serviceCollection.EnableSimpleInjectorCrossWiring(container);
container.Register<ScopeAccessor>(Lifestyle.Scoped);
container.CrossWire<ILoggerFactory>(serviceProvider);
container.CrossWire<IMapper>(serviceProvider);
app.Use(async (context, next) =>
{
using (AsyncScopedLifestyle.BeginScope(container))
using (container.GetInstance<ScopeAccessor>().ServiceScope)
{
await next();
}
});
}
}
public class ScopeAccessor
{
public ScopeAccessor(IServiceProvider serviceProvider)
{
IServiceScopeFactory serviceScopeFactory = serviceProvider.GetService<IServiceScopeFactory>();
ServiceScope = serviceScopeFactory.CreateScope();
}
public IServiceScope ServiceScope { get; }
}
public static class SimpleInjectorExtensions
{
private static readonly object CrossWireContextKey = new object();
public static void CrossWire<TServiceType>(this Container container, IServiceProvider serviceProvider)
{
container.CrossWire(typeof(TServiceType), serviceProvider);
}
public static void CrossWire(this Container container, Type serviceType, IServiceProvider serviceProvider)
{
Registration registration = CreateCrossWireRegistration(container, serviceType, serviceProvider);
container.AddRegistration(serviceType, registration);
}
public static IServiceProvider EnableSimpleInjectorCrossWiring(this IServiceCollection services, Container container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (container.GetItem(CrossWireContextKey) == null)
{
container.SetItem(CrossWireContextKey, services);
}
IServiceProvider serviceProvider = services.BuildServiceProvider();
container.RegisterSingleton(serviceProvider);
return serviceProvider;
}
private static Registration CreateCrossWireRegistration(Container container, Type serviceType, IServiceProvider serviceProvider)
{
IServiceCollection services = GetServiceCollection(container);
Lifestyle lifestyle = DetermineLifestyle(serviceType, services);
Registration registration;
if (lifestyle == Lifestyle.Singleton)
{
registration = lifestyle.CreateRegistration(
serviceType,
() => serviceProvider.GetRequiredService(serviceType),
container);
}
else
{
registration = lifestyle.CreateRegistration(
serviceType,
() => container.GetInstance<ScopeAccessor>().ServiceScope.ServiceProvider.GetRequiredService(serviceType),
container);
}
if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
{
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
justification: "This is a cross-wired service. ASP.NET Core will ensure it gets disposed.");
}
return registration;
}
private static Lifestyle DetermineLifestyle(Type serviceType, IServiceCollection services)
{
var descriptor = FindDescriptor(serviceType, services);
// In case the service type is an IEnumerable, a registration can't be found, but collections are
// in Core always registered as Transient, so it's safe to fall back to the transient lifestyle.
return ToLifestyle(descriptor?.Lifetime ?? ServiceLifetime.Transient);
}
private static ServiceDescriptor FindDescriptor(Type serviceType, IServiceCollection services)
{
var descriptor = services.LastOrDefault(d => d.ServiceType == serviceType);
if (descriptor == null && serviceType.GetTypeInfo().IsGenericType)
{
var serviceTypeDefinition = serviceType.GetTypeInfo().GetGenericTypeDefinition();
// In case the type is an IEnumerable<T>, no registration can be found and null is returned.
return services.LastOrDefault(d => d.ServiceType == serviceTypeDefinition);
}
else
{
return descriptor;
}
}
private static IServiceCollection GetServiceCollection(Container container)
{
var context = (IServiceCollection)container.GetItem(CrossWireContextKey);
if (context == null)
{
throw new InvalidOperationException(
"Cross-wiring has to be enabled first. Please make sure the " +
$"{nameof(EnableSimpleInjectorCrossWiring)} extension method is called first by " +
"adding it to the ConfigureServices method as follows: " + Environment.NewLine +
$"services.{nameof(EnableSimpleInjectorCrossWiring)}(container);" + Environment.NewLine +
"See: https://simpleinjector.org/aspnetcore");
}
return context;
}
private static Lifestyle ToLifestyle(ServiceLifetime lifetime)
{
switch (lifetime)
{
case ServiceLifetime.Singleton: return Lifestyle.Singleton;
case ServiceLifetime.Scoped: return Lifestyle.Scoped;
default: return Lifestyle.Transient;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment