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: Microsoft dependency injection implementation #370

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a792f42
Initial attempt to add Msft DI to Splat
weitzhandler Jul 21, 2019
9059238
Re-implemented resolver and added test project
weitzhandler Jul 22, 2019
0ecec16
Remove unnecessary code
weitzhandler Jul 22, 2019
3e84792
Fixed a little oopsie (a little more than a little one)
weitzhandler Jul 22, 2019
6ac3f4a
Merge remote-tracking branch 'upstream/master'
weitzhandler Aug 1, 2019
e0f273f
Added new HasRegistration property
weitzhandler Aug 1, 2019
e0b7c5c
Added MS DI tests and work on scopes
weitzhandler Aug 1, 2019
f5c2900
Cleaned test csproj file based on dpvrenoy's comment
weitzhandler Aug 1, 2019
501a020
Changed build.cake
weitzhandler Aug 1, 2019
3e1e84d
Various fixes based on review from Glenn
weitzhandler Aug 1, 2019
a8d5623
Another typo
weitzhandler Aug 1, 2019
78691cb
Fixed mistake in build.cake
weitzhandler Aug 1, 2019
c0993d3
Rewritten MSDI resolver, with contract support, removed scopes, and a…
weitzhandler Aug 1, 2019
cd826fa
Enabled null 'serviceType' in MSDI + test
weitzhandler Aug 1, 2019
c7f5d5b
ConcurrentDictionary: composition instead of inheritance and atomic f…
weitzhandler Aug 3, 2019
5c73294
Updated ConcurrentDic calls to be atomic
weitzhandler Aug 5, 2019
499ccd1
Merge branch 'master' into microsoft-dependency-injection
glennawatson Aug 5, 2019
401a580
Merge branch 'master' into microsoft-dependency-injection
glennawatson Aug 5, 2019
3e49a98
Merge branch 'master' into microsoft-dependency-injection
glennawatson Aug 5, 2019
7e5312b
Allow null contract collections
weitzhandler Aug 5, 2019
ab515b0
Merge branch 'microsoft-dependency-injection' of https://github.com/w…
weitzhandler Aug 5, 2019
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
8 changes: 5 additions & 3 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ var packageWhitelist = new[]
MakeAbsolute(File("./src/Splat/Splat.csproj")),
MakeAbsolute(File("./src/Splat.Autofac/Splat.Autofac.csproj")),
MakeAbsolute(File("./src/Splat.DryIoc/Splat.DryIoc.csproj")),
MakeAbsolute(File("./src/Splat.Ninject/Splat.Ninject.csproj")),
MakeAbsolute(File("./src/Splat.SimpleInjector/Splat.SimpleInjector.csproj")),
MakeAbsolute(File("./src/Splat.Log4Net/Splat.Log4Net.csproj")),
MakeAbsolute(File("./src/Splat.Microsoft.Extensions.DependencyInjection/Splat.Microsoft.Extensions.DependencyInjection.csproj")),
weitzhandler marked this conversation as resolved.
Show resolved Hide resolved
MakeAbsolute(File("./src/Splat.Microsoft.Extensions.Logging/Splat.Microsoft.Extensions.Logging.csproj")),
MakeAbsolute(File("./src/Splat.Ninject/Splat.Ninject.csproj")),
weitzhandler marked this conversation as resolved.
Show resolved Hide resolved
MakeAbsolute(File("./src/Splat.NLog/Splat.NLog.csproj")),
MakeAbsolute(File("./src/Splat.Serilog/Splat.Serilog.csproj")),
MakeAbsolute(File("./src/Splat.Microsoft.Extensions.Logging/Splat.Microsoft.Extensions.Logging.csproj")),
MakeAbsolute(File("./src/Splat.SimpleInjector/Splat.SimpleInjector.csproj")),
};

var packageTestWhitelist = new[]
{
MakeAbsolute(File("./src/Splat.Tests/Splat.Tests.csproj")),
MakeAbsolute(File("./src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj")),
MakeAbsolute(File("./src/Splat.DryIoc.Tests/Splat.DryIoc.Tests.csproj")),
MakeAbsolute(File("./src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj")),
MakeAbsolute(File("./src/Splat.Ninject.Tests/Splat.Ninject.Tests.csproj")),
MakeAbsolute(File("./src/Splat.SimpleInjector.Tests/Splat.SimpleInjector.Tests.csproj")),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Shouldly;
using Splat.Common.Test;
using Xunit;
using Microsoft.Extensions.DependencyInjection;
using Splat.Microsoft.Extensions.DependencyInjection;

namespace Splat.Microsoft.Extensions.DependencyInjection.Tests
{
/// <summary>
/// Tests to show the <see cref="MicrosoftDependencyResolver"/> works correctly.
/// </summary>
public class DependencyResolverTests
{
/// <summary>
/// Should resolve views.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Resolve_Views()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;
services.AddTransient<IViewFor<ViewModelOne>, ViewOne>();
services.AddTransient<IViewFor<ViewModelTwo>, ViewTwo>();

wrapper.BuildAndUse();

var viewOne = Locator.Current.GetService(typeof(IViewFor<ViewModelOne>));
var viewTwo = Locator.Current.GetService(typeof(IViewFor<ViewModelTwo>));

viewOne.ShouldNotBeNull();
viewOne.ShouldBeOfType<ViewOne>();
viewTwo.ShouldNotBeNull();
viewTwo.ShouldBeOfType<ViewTwo>();
}

/// <summary>
/// Should resolve views.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Resolve_Named_View()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;
services.AddTransient<IViewFor<ViewModelTwo>, ViewTwo>();

wrapper.BuildAndUse();

var viewTwo = Locator.Current.GetService(typeof(IViewFor<ViewModelTwo>));

viewTwo.ShouldNotBeNull();
viewTwo.ShouldBeOfType<ViewTwo>();
}

/// <summary>
/// Should resolve view models.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Resolve_View_Models()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;
services.AddTransient<ViewModelOne>();
services.AddTransient<ViewModelTwo>();

wrapper.BuildAndUse();

var vmOne = Locator.Current.GetService<ViewModelOne>();
var vmTwo = Locator.Current.GetService<ViewModelTwo>();

vmOne.ShouldNotBeNull();
vmTwo.ShouldNotBeNull();
}

/// <summary>
/// Should resolve screen.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Resolve_Screen()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;
services.AddSingleton<IScreen>(new MockScreen());

wrapper.BuildAndUse();

var screen = Locator.Current.GetService<IScreen>();

screen.ShouldNotBeNull();
screen.ShouldBeOfType<MockScreen>();
}

/// <summary>
/// Should throw an exception if service registration call back called.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Throw_If_UnregisterCurrent_Called()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;
wrapper.BuildAndUse();

var result = Record.Exception(() =>
Locator.CurrentMutable.UnregisterCurrent(typeof(IScreen)));

result.ShouldBeOfType<NotImplementedException>();
}

/// <summary>
/// Should unregister all.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_UnregisterAll()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;

services.AddSingleton<IScreen>(new MockScreen());

Locator.CurrentMutable.HasRegistration(typeof(IScreen))
.ShouldBeTrue();

Locator.CurrentMutable.UnregisterAll(typeof(IScreen));

var result = Record.Exception(() => Locator.Current.GetService<IScreen>());

result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldStartWith("No service for type ");
}

/// <summary>
/// Test that scopes can be registered and unregistered.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Enable_Scoped_Services()
{
var wrapper = new ServicesWrapper();
var services = wrapper.ServiceCollection;

services.AddScoped<ViewOne>();

wrapper.BuildAndUse();

var view1 = Locator.Current.GetService<ViewOne>("foo");
var view2 = Locator.Current.GetService<ViewOne>("foo");
var view3 = Locator.Current.GetService<ViewOne>("bar");

Assert.True(ReferenceEquals(view1, view2));
Assert.False(ReferenceEquals(view1, view3));

Locator.CurrentMutable.UnregisterAll(null, "foo");
view2 = Locator.Current.GetService<ViewOne>("foo");
Assert.False(ReferenceEquals(view1, view2));
}

/// <summary>
/// Should throw an exception if service registration call back called.
/// </summary>
[Fact]
public void MicrosoftDependencyResolver_Should_Throw_If_ServiceRegistionCallback_Called()
{
var wrapper = new ServicesWrapper();
wrapper.BuildAndUse();

var result = Record.Exception(() =>
Locator.CurrentMutable.ServiceRegistrationCallback(typeof(IScreen), disposable => { }));

result.ShouldBeOfType<NotImplementedException>();
}

/// <summary>
/// Should throw an exception if trying to register services when the container is registered as immutable.
/// </summary>
public void MicrosoftDependencyResolver_Should_Throw_If_Attempt_Registration_After_Build()
{
var wrapper = new ServicesWrapper();

wrapper.BuildAndUse();

var result = Record.Exception(() => Locator.CurrentMutable.Register(() => new ViewOne()));

result.ShouldBeOfType<InvalidOperationException>();
}

private class ServicesWrapper
weitzhandler marked this conversation as resolved.
Show resolved Hide resolved
{
private IServiceProvider _serviceProvider;

public ServicesWrapper()
{
ServiceCollection.UseMicrosoftDependencyResolver();
}

public IServiceCollection ServiceCollection { get; } = new ServiceCollection();

public IServiceProvider ServiceProvider
{
get
{
if (_serviceProvider == null)
{
_serviceProvider = ServiceCollection.BuildServiceProvider();
}

return _serviceProvider;
}
}

public void BuildAndUse() => ServiceProvider.UseMicrosoftDependencyResolver();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<NoWarn>$(NoWarn);1591;CA1707;SA1633</NoWarn>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Splat.Common.Test\Splat.Common.Test.csproj" />
<ProjectReference Include="..\Splat.Microsoft.Extensions.DependencyInjection\Splat.Microsoft.Extensions.DependencyInjection.csproj" />
</ItemGroup>

</Project>
Loading