Skip to content

Add supporting of unity resolver overrides. #5

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

Merged
merged 1 commit into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
65 changes: 65 additions & 0 deletions LazyProxy.Unity.Tests/UnityExtensionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using Unity.Exceptions;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Resolution;
using Xunit;
using DependencyAttribute = Unity.Attributes.DependencyAttribute;

[assembly: InternalsVisibleTo("LazyProxy.DynamicTypes")]

Expand Down Expand Up @@ -60,6 +62,11 @@ public Service2()
public string Method(string arg) => "service2->" + arg;
}

private class Service2Ex : IService2
{
public string Method(string arg) => "service2Ex->" + arg;
}

internal interface IInternalService
{
string Get();
Expand Down Expand Up @@ -126,6 +133,47 @@ public DerivedGenericService(string value)
}
}

public class Argument
{
public string StringValue { get; }

public Argument(string stringValue)
{
StringValue = stringValue;
}
}

enum SomeEnum
{
Value1,
Value2
}

public interface IServiceToTestOverrides
{
string Property { get; set; }
string Get(string arg);
}

private class ServiceToTestOverrides : IServiceToTestOverrides
{
private readonly SomeEnum _someEnum;
private readonly IService2 _service;
private readonly Argument _argument;

[Dependency]
public string Property { get; set; }

public string Get(string arg) => $"{_someEnum}_{_service.Method(arg)}_{Property}_{_argument.StringValue}";

public ServiceToTestOverrides(SomeEnum someEnum, IService2 service, Argument argument)
{
_someEnum = someEnum;
_service = service;
_argument = argument;
}
}

[Fact]
public void ServiceCtorMustBeExecutedAfterMethodIsCalledAndOnlyOnce()
{
Expand Down Expand Up @@ -487,5 +535,22 @@ public void GenericServicesMustBeResolvedByNameWithCorrectInjectionMembers()
Assert.Equal($"Argument1A_Argument2_Int32_{value1}", service1.Get(new Argument1A(), new Argument2(), 42).Value);
Assert.Equal($"Argument1A_Argument2_Int32_{value2}", service2.Get(new Argument1A(), new Argument2(), 42).Value);
}

[Fact]
public void OverridesMustBeAppliedByProxy()
{
var result = new UnityContainer()
.RegisterType<IService2, Service2>()
.RegisterLazy<IServiceToTestOverrides, ServiceToTestOverrides>()
.Resolve<IServiceToTestOverrides>(
new ParameterOverride("someEnum", SomeEnum.Value2),
new DependencyOverride(typeof(IService2), new Service2Ex()),
new PropertyOverride("Property", "propertyValue"),
new TypeBasedOverride(typeof(Argument), new ParameterOverride("stringValue", "stringValue"))
)
.Get("arg");

Assert.Equal("Value2_service2Ex->arg_propertyValue_stringValue", result);
}
}
}
5 changes: 2 additions & 3 deletions LazyProxy.Unity/UnityExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using Unity;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Registration;

Expand Down Expand Up @@ -154,8 +153,8 @@ public static IUnityContainer RegisterLazy(this IUnityContainer container,

return container
.RegisterType(typeFrom, typeTo, registrationName, getLifetimeManager(), injectionMembers)
.RegisterType(typeFrom, name, getLifetimeManager(), new InjectionFactory(
(c, t, n) => LazyProxyBuilder.CreateInstance(t, () => c.Resolve(t, registrationName))));
.RegisterType(typeFrom, name, getLifetimeManager(), new UnityInjectionFactory(
(c, t, n, o) => LazyProxyBuilder.CreateInstance(t, () => c.Resolve(t, registrationName, o))));
}
}
}
74 changes: 74 additions & 0 deletions LazyProxy.Unity/UnityInjectionFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity;
using Unity.Builder;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;

namespace LazyProxy.Unity
{
/// <summary>
/// A class that lets you specify a factory method the container will use to create the object.
/// </summary>
public class UnityInjectionFactory : InjectionMember, IInjectionFactory, IBuildPlanPolicy
{
private static readonly FieldInfo ResolverOverrides = typeof(BuilderContext)
.GetField("_resolverOverrides", BindingFlags.Instance | BindingFlags.NonPublic);

private readonly Func<IUnityContainer, Type, string, ResolverOverride[], object> _factoryFunc;

/// <summary>
/// Create a new instance of <see cref="UnityInjectionFactory"/> with the given factory function.
/// </summary>
/// <param name="factoryFunc">Factory function.</param>
public UnityInjectionFactory(Func<IUnityContainer, Type, string, ResolverOverride[], object> factoryFunc)
{
_factoryFunc = factoryFunc ?? throw new ArgumentNullException(nameof(factoryFunc));
}

/// <summary>
/// Add policies to the policies to configure the container
/// to call this constructor with the appropriate parameter values.
/// </summary>
/// <param name="serviceType">Type of interface being registered. If no interface, this will be null.
/// This parameter is ignored in this implementation.</param>
/// <param name="implementationType">Type of concrete type being registered.</param>
/// <param name="name">Name used to resolve the type object.</param>
/// <param name="policies">Policy list to add policies to.</param>
public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
{
policies.Set(serviceType, name, typeof(IBuildPlanPolicy), this);
}

/// <summary>
/// Creates an instance of this build plan's type, or fills in the existing type if passed in.
/// </summary>
/// <param name="context">Context used to build up the object.</param>
/// <exception cref="ArgumentNullException">Context is null.</exception>
public void BuildUp(IBuilderContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));

if (context.Existing != null)
return;

var resolverOverride = ResolverOverrides.GetValue(context);

var resolverOverrides = resolverOverride == null
? new ResolverOverride[] { }
: ((IEnumerable<ResolverOverride>)resolverOverride).ToArray();

var container = context.Container;
var type = context.BuildKey.Type;
var name = context.BuildKey.Name;

context.Existing = _factoryFunc(container, type, name, resolverOverrides);
context.SetPerBuildSingleton();
}
}
}