Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: splat init checks for pre registrations #360

Merged
merged 16 commits into from
Jul 27, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ There are 2 parts to the locator design:
* **Locator.Current** The property to use to **retrieve** services. Locator.Current is a static variable that can be set on startup, to adapt Splat to other DI/IoC frameworks. We're currently working from v7 onward to make it easier to use your DI/IoC framework of choice. (see below)
* **Locator.CurrentMutable** The property to use to **register** services

**Note:** Currently these properties point to the same object and you can use CurrentMutable to also GetServices, but this is not the intention and the interfaces may be adjusted in future to lock this down (and make it more obvious what the use cases are).

To get a service:

```cs
Expand Down Expand Up @@ -132,6 +130,10 @@ Locator.CurrentMutable.RegisterLazySingleton(() => new LazyToaster(), typeof(ITo
### Dependency Resolver Packages
For each of the provided dependency resolver adapters, there is a specific package that allows the service locator to be implemented by another ioc container.

Please note: If you are adjusting behaviours of Splat by working with your custom container directly. Please read the relevant projects documentation on
REPLACING the registration. If the container supports appending\ multiple registrations you may get undesired behaviours, such as the wrong logger factory
being used.

| Container | NuGet | Read Me
|---------|-------|-------|
| [Splat.Autofac][SplatAutofacNuGet] | [![SplatAutofacBadge]][SplatAutofacNuGet] | [Setup Autofac][SplatAutofacReadme]
Expand Down
6 changes: 6 additions & 0 deletions src/Splat.Autofac/AutofacDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public virtual IEnumerable<object> GetServices(Type serviceType, string contract
}
}

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
return _componentContext.IsRegistered(serviceType);
}

/// <summary>
/// Register a function with the resolver which will generate a object
/// for the specified service type.
Expand Down
32 changes: 32 additions & 0 deletions src/Splat.DryIoc.Tests/DependencyResolverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,37 @@ public void DryIocDependencyResolver_Should_Throw_If_ServiceRegistionCallback_Ca

result.ShouldBeOfType<NotImplementedException>();
}

/// <summary>
/// Check to ensure the correct logger is returned.
/// </summary>
/// <remarks>
/// Introduced for Splat #331.
/// </remarks>
[Fact]
public void DryIocDependencyResolver_Should_ReturnRegisteredLogger()
{
var c = new Container();
c.UseDryIocDependencyResolver();
c.Register<ILogger, ConsoleLogger>(ifAlreadyRegistered: IfAlreadyRegistered.Replace);
var d = Splat.Locator.Current.GetService<ILogger>();
Assert.IsType<ConsoleLogger>(d);
}

/// <summary>
/// Test that a pre-init logger isn't overriden.
/// </summary>
/// <remarks>
/// Introduced for Splat #331.
/// </remarks>
[Fact]
public void DryIocDependencyResolver_PreInit_Should_ReturnRegisteredLogger()
{
var c = new Container();
c.Register<ILogger, ConsoleLogger>();
c.UseDryIocDependencyResolver();
var d = Splat.Locator.Current.GetService<ILogger>();
Assert.IsType<ConsoleLogger>(d);
}
}
}
11 changes: 9 additions & 2 deletions src/Splat.DryIoc/DryIocDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using DryIoc;

namespace Splat.DryIoc
Expand Down Expand Up @@ -39,16 +40,22 @@ public virtual IEnumerable<object> GetServices(Type serviceType, string contract
? _container.ResolveMany(serviceType)
: _container.ResolveMany(serviceType, serviceKey: contract);

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
return _container.GetServiceRegistrations().Any(x => x.ServiceType == serviceType);
}

/// <inheritdoc />
public virtual void Register(Func<object> factory, Type serviceType, string contract = null)
{
if (string.IsNullOrEmpty(contract))
{
_container.UseInstance(serviceType, factory(), IfAlreadyRegistered.AppendNewImplementation);
_container.UseInstance(serviceType, factory(), IfAlreadyRegistered.Replace);
glennawatson marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
_container.UseInstance(serviceType, factory(), IfAlreadyRegistered.AppendNewImplementation, serviceKey: contract);
_container.UseInstance(serviceType, factory(), IfAlreadyRegistered.Replace, serviceKey: contract);
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/Splat.Ninject/NinjectDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public virtual IEnumerable<object> GetServices(Type serviceType, string contract
? _kernel.GetAll(serviceType)
: _kernel.GetAll(serviceType, contract);

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
return _kernel.CanResolve(serviceType);
}

/// <inheritdoc />
public virtual void Register(Func<object> factory, Type serviceType, string contract = null) =>
_kernel.Bind(serviceType).ToMethod(_ => factory());
Expand Down
12 changes: 11 additions & 1 deletion src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using SimpleInjector;

namespace Splat.SimpleInjector
Expand All @@ -27,12 +28,21 @@ public SimpleInjectorDependencyResolver(Container container)
}

/// <inheritdoc />
public object GetService(Type serviceType, string contract = null) => _container.GetInstance(serviceType);
public object GetService(Type serviceType, string contract = null)
{
return _container.GetInstance(serviceType);
}

/// <inheritdoc />
public IEnumerable<object> GetServices(Type serviceType, string contract = null) =>
_container.GetAllInstances(serviceType);

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
return _container.GetCurrentRegistrations().Any(x => x.ServiceType == serviceType);
glennawatson marked this conversation as resolved.
Show resolved Hide resolved
}

/// <inheritdoc />
public void Register(Func<object> factory, Type serviceType, string contract = null) =>
_container.Register(serviceType, factory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ namespace Splat
protected virtual void Dispose(bool isDisposing) { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down Expand Up @@ -440,6 +441,7 @@ namespace Splat
}
public interface IMutableDependencyResolver
{
bool HasRegistration(System.Type serviceType);
void Register(System.Func<object> factory, System.Type serviceType, string contract = null);
System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback);
void UnregisterAll(System.Type serviceType, string contract = null);
Expand Down Expand Up @@ -689,6 +691,7 @@ namespace Splat
public Splat.ModernDependencyResolver Duplicate() { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ namespace Splat
protected virtual void Dispose(bool isDisposing) { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down Expand Up @@ -429,6 +430,7 @@ namespace Splat
}
public interface IMutableDependencyResolver
{
bool HasRegistration(System.Type serviceType);
void Register(System.Func<object> factory, System.Type serviceType, string contract = null);
System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback);
void UnregisterAll(System.Type serviceType, string contract = null);
Expand Down Expand Up @@ -678,6 +680,7 @@ namespace Splat
public Splat.ModernDependencyResolver Duplicate() { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ namespace Splat
protected virtual void Dispose(bool isDisposing) { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down Expand Up @@ -440,6 +441,7 @@ namespace Splat
}
public interface IMutableDependencyResolver
{
bool HasRegistration(System.Type serviceType);
void Register(System.Func<object> factory, System.Type serviceType, string contract = null);
System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback);
void UnregisterAll(System.Type serviceType, string contract = null);
Expand Down Expand Up @@ -689,6 +691,7 @@ namespace Splat
public Splat.ModernDependencyResolver Duplicate() { }
public object GetService(System.Type serviceType, string contract = null) { }
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType, string contract = null) { }
public bool HasRegistration(System.Type serviceType) { }
public void Register(System.Func<object> factory, System.Type serviceType, string contract = null) { }
public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string contract, System.Action<System.IDisposable> callback) { }
public void UnregisterAll(System.Type serviceType, string contract = null) { }
Expand Down
33 changes: 29 additions & 4 deletions src/Splat/ServiceLocation/DependencyResolverMixins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,38 @@ public static void UnregisterAll<T>(this IMutableDependencyResolver resolver, st
/// <param name="resolver">The resolver to register the needed service types against.</param>
public static void InitializeSplat(this IMutableDependencyResolver resolver)
{
resolver.Register(() => new DefaultLogManager(), typeof(ILogManager));
resolver.RegisterConstant(new DebugLogger(), typeof(ILogger));
RegisterDefaultLogManager(resolver);
RegisterLogger(resolver);
#if !NETSTANDARD
RegisterPlatformBitmapLoader(resolver);
#endif
}

private static void RegisterDefaultLogManager(IMutableDependencyResolver resolver)
{
if (!resolver.HasRegistration(typeof(ILogManager)))
{
resolver.Register(() => new DefaultLogManager(), typeof(ILogManager));
}
}

private static void RegisterLogger(IMutableDependencyResolver resolver)
glennawatson marked this conversation as resolved.
Show resolved Hide resolved
{
if (!resolver.HasRegistration(typeof(ILogger)))
{
resolver.RegisterConstant(new DebugLogger(), typeof(ILogger));
dpvreony marked this conversation as resolved.
Show resolved Hide resolved
}
}

#if !NETSTANDARD
private static void RegisterPlatformBitmapLoader(IMutableDependencyResolver resolver)
{
// not supported in netstandard2.0
resolver.RegisterLazySingleton(() => new PlatformBitmapLoader(), typeof(IBitmapLoader));
#endif
if (!resolver.HasRegistration(typeof(IBitmapLoader)))
{
resolver.RegisterLazySingleton(() => new PlatformBitmapLoader(), typeof(IBitmapLoader));
}
}
#endif
}
}
6 changes: 6 additions & 0 deletions src/Splat/ServiceLocation/FuncDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ public IEnumerable<object> GetServices(Type serviceType, string contract = null)
return _innerGetServices(serviceType, contract);
}

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
return _innerGetServices(serviceType, null) != null;
}

/// <inheritdoc />
public void Register(Func<object> factory, Type serviceType, string contract = null)
{
Expand Down
7 changes: 7 additions & 0 deletions src/Splat/ServiceLocation/IMutableDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ namespace Splat
/// </summary>
public interface IMutableDependencyResolver
{
/// <summary>
/// Check to see if a resolvers has a registration for a type.
/// </summary>
/// <param name="serviceType">The type to check for registration.</param>
/// <returns>Whether there is a registration for the type.</returns>
bool HasRegistration(Type serviceType);

/// <summary>
/// Register a function with the resolver which will generate a object
/// for the specified service type.
Expand Down
7 changes: 7 additions & 0 deletions src/Splat/ServiceLocation/ModernDependencyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ protected ModernDependencyResolver(Dictionary<Tuple<Type, string>, List<Func<obj
_callbackRegistry = new Dictionary<Tuple<Type, string>, List<Action<IDisposable>>>();
}

/// <inheritdoc />
public bool HasRegistration(Type serviceType)
{
var pair = Tuple.Create(serviceType, string.Empty);
return _registry.ContainsKey(pair);
}

/// <inheritdoc />
public void Register(Func<object> factory, Type serviceType, string contract = null)
{
Expand Down