├── assets ├── nf-logo.png └── readme.txt ├── .editorconfig ├── nanoFramework.DependencyInjection ├── key.snk ├── packages.config ├── Microsoft │ └── Extensions │ │ └── DependencyInjection │ │ ├── IServiceScope.cs │ │ ├── IServiceProviderIsService.cs │ │ ├── ServiceLifetime.cs │ │ ├── ServiceProviderOptions.cs │ │ ├── TypeExtensions.cs │ │ ├── ServiceScope.cs │ │ ├── ServiceCollectionContainerBuilderExtensions.cs │ │ ├── ServiceProvider.cs │ │ ├── IServiceCollection.cs │ │ ├── ServiceCollection.cs │ │ ├── ServiceProviderEngineScope.cs │ │ ├── ServiceProviderServiceExtensions.cs │ │ ├── ActivatorUtilities.cs │ │ ├── ServiceCollectionServiceExtensions.cs │ │ ├── ServiceDescriptor.cs │ │ └── ServiceProviderEngine.cs ├── packages.lock.json ├── Properties │ └── AssemblyInfo.cs ├── System │ ├── IServiceProvider.cs │ ├── Activator.cs │ └── AggregateException.cs └── nanoFramework.DependencyInjection.nfproj ├── NuGet.Config ├── tests ├── packages.config ├── Fakes │ ├── IService1.cs │ ├── IService3.cs │ ├── IFakeObject.cs │ ├── IFakeService.cs │ ├── IRootService.cs │ ├── Service1.cs │ ├── Service3.cs │ ├── FakeObject.cs │ ├── IFactoryService.cs │ ├── IStructFakeService.cs │ ├── IFakeMultipleService.cs │ ├── INonexistentService.cs │ ├── IService2.cs │ ├── FakeOneMultipleService.cs │ ├── FakeTwoMultipleService.cs │ ├── PocoClass.cs │ ├── AnotherClass.cs │ ├── ClassWithThrowingCtor.cs │ ├── ClassWithThrowingEmptyCtor.cs │ ├── StructFakeService.cs │ ├── Service2.cs │ ├── CreationCountFakeService.cs │ ├── AnotherClassAcceptingData.cs │ ├── FakeService .cs │ ├── InstanceCountServices │ │ ├── TransientInstanceCountService.cs │ │ └── SingletonInstanceCountService.cs │ ├── ClassWithAmbiguousCtors.cs │ ├── ClassWithNestedReferencesToProvider.cs │ ├── RootService.cs │ ├── ClassWithMultipleCtors.cs │ └── ClassWithPrimitiveBinding.cs ├── nano.runsettings ├── packages.lock.json ├── Properties │ └── AssemblyInfo.cs ├── ServiceProviderTests.cs ├── AggregateExceptionTests.cs ├── ActivatorTests.cs ├── ServiceProviderExtensionsTests.cs ├── nanoFramework.DependencyInjection.UnitTests.nfproj ├── ServiceCollectionDescriptorExtensionsTests.cs ├── ActivatorUtilitiesTests.cs └── ServiceCollectionTests.cs ├── .github ├── workflows │ ├── generate-changelog.yml │ ├── pr-checks.yml │ ├── keep-repo-active.yml │ └── update-dependencies.yml └── .changelog-config.json ├── version.json ├── LICENSE.md ├── nanoFramework.DependencyInjection.nuspec ├── nanoFramework.DependencyInjection.sln ├── .gitattributes ├── azure-pipelines.yml ├── CHANGELOG.md ├── .gitignore └── README.md /assets/nf-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanoframework/nanoFramework.DependencyInjection/HEAD/assets/nf-logo.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # Default severity for all analyzer diagnostics 4 | dotnet_analyzer_diagnostic.severity = silent 5 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanoframework/nanoFramework.DependencyInjection/HEAD/nanoFramework.DependencyInjection/key.snk -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/Fakes/IService1.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal interface IService1 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IService3.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal interface IService3 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IFakeObject.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface IFakeObject 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IFakeService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface IFakeService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IRootService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal interface IRootService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/Service1.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal class Service1 : IService1 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/Service3.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal class Service3 : IService3 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/FakeObject.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class FakeObject : IFakeObject 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IFactoryService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface IFactoryService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IStructFakeService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface IStructFakeService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/Fakes/IFakeMultipleService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface IFakeMultipleService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/INonexistentService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public interface INonexistentService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/IService2.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | internal interface IService2 9 | { 10 | IService3 Service3 { get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Fakes/FakeOneMultipleService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class FakeOneMultipleService : IFakeMultipleService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/FakeTwoMultipleService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class FakeTwoMultipleService : IFakeMultipleService 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Fakes/PocoClass.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class PocoClass 9 | { 10 | public PocoClass() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/generate-changelog.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation and Contributors 2 | # See LICENSE file in the project root for full license information. 3 | 4 | name: Generate Changelog 5 | run-name: Generate changelog 6 | 7 | on: 8 | push: 9 | tags: 10 | - '*' 11 | 12 | jobs: 13 | compose_changelog: 14 | name: nanoFramework 15 | uses: nanoframework/nf-tools/.github/workflows/generate-changelog.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /tests/Fakes/AnotherClass.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class AnotherClass 9 | { 10 | public AnotherClass(IFakeService fakeService) 11 | { 12 | FakeService = fakeService; 13 | } 14 | 15 | public IFakeService FakeService { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Fakes/ClassWithThrowingCtor.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | public class ClassWithThrowingCtor 11 | { 12 | public ClassWithThrowingCtor(FakeService service) 13 | { 14 | throw new Exception(nameof(ClassWithThrowingCtor)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Fakes/ClassWithThrowingEmptyCtor.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | public class ClassWithThrowingEmptyCtor 11 | { 12 | public ClassWithThrowingEmptyCtor() 13 | { 14 | throw new Exception(nameof(ClassWithThrowingEmptyCtor)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Fakes/StructFakeService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public struct StructFakeService : IStructFakeService 9 | { 10 | private readonly IFakeObject _fakeObject; 11 | 12 | public StructFakeService(IFakeObject fakeobject) 13 | { 14 | _fakeObject = fakeobject; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/pr-checks.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation and Contributors 2 | # See LICENSE file in the project root for full license information. 3 | 4 | name: PR Checks 5 | 6 | on: 7 | pull_request: 8 | 9 | jobs: 10 | check_package_lock: 11 | name: nanoFramework 12 | uses: nanoframework/nf-tools/.github/workflows/check-package-lock.yml@main 13 | check_nuget_latest: 14 | name: nanoFramework 15 | uses: nanoframework/nf-tools/.github/workflows/check-packages-updated.yml@main 16 | secrets: inherit 17 | with: 18 | solution: 'nanoFramework.DependencyInjection.sln' 19 | -------------------------------------------------------------------------------- /tests/Fakes/Service2.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | internal class Service2 : IService2 11 | { 12 | public IService3 Service3 { get; private set; } 13 | 14 | public Service2(IService3 service3) 15 | { 16 | if (service3 == null) 17 | { 18 | throw new ArgumentNullException("service3"); 19 | } 20 | 21 | Service3 = service3; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/keep-repo-active.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation and Contributors 2 | # See LICENSE file in the project root for full license information. 3 | 4 | # This workflow will periodically make an empty commit to keep the repository active thus preventing the workflows from being disabled. 5 | 6 | name: Keep repository active 7 | 8 | on: 9 | schedule: 10 | # every 2 weeks at 00:00 UTC 11 | - cron: '0 0 */2 * *' 12 | repository_dispatch: 13 | types: keep-repo-active 14 | 15 | jobs: 16 | update-dependencies: 17 | name: nanoFramework 18 | uses: nanoframework/nf-tools/.github/workflows/keep-repo-active.yml@main 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.1", 4 | "assemblyVersion": { 5 | "precision": "build" 6 | }, 7 | "semVer1NumericIdentifierPadding": 3, 8 | "nuGetPackageVersion": { 9 | "semVer": 2.0 10 | }, 11 | "publicReleaseRefSpec": [ 12 | "^refs/heads/main$", 13 | "^refs/heads/v\\d+(?:\\.\\d+)?$" 14 | ], 15 | "cloudBuild": { 16 | "setAllVariables": true 17 | }, 18 | "release": { 19 | "branchName": "release-v{version}", 20 | "versionIncrement": "build", 21 | "firstUnstableTag": "preview" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Fakes/CreationCountFakeService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class CreationCountFakeService 9 | { 10 | public static readonly object InstanceLock = new object(); 11 | 12 | public CreationCountFakeService(IFakeService dependency) 13 | { 14 | InstanceCount++; 15 | InstanceId = InstanceCount; 16 | } 17 | 18 | public static int InstanceCount { get; set; } 19 | 20 | public int InstanceId { get; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/nano.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1 6 | .\TestResults 7 | 120000 8 | net48 9 | x64 10 | 11 | 12 | None 13 | False 14 | 15 | -------------------------------------------------------------------------------- /tests/Fakes/AnotherClassAcceptingData.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class AnotherClassAcceptingData 9 | { 10 | public AnotherClassAcceptingData(IFakeService fakeService, string one, string two) 11 | { 12 | FakeService = fakeService; 13 | One = one; 14 | Two = two; 15 | } 16 | 17 | public IFakeService FakeService { get; } 18 | 19 | public string One { get; } 20 | 21 | public string Two { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/packages.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": { 4 | ".NETnanoFramework,Version=v1.0": { 5 | "nanoFramework.CoreLibrary": { 6 | "type": "Direct", 7 | "requested": "[1.17.11, 1.17.11]", 8 | "resolved": "1.17.11", 9 | "contentHash": "HezzAc0o2XrSGf85xSeD/6xsO6ohF9hX6/iMQ1IZS6Zw6umr4WfAN2Jv0BrPxkaYwzEegJxxZujkHoUIAqtOMw==" 10 | }, 11 | "nanoFramework.TestFramework": { 12 | "type": "Direct", 13 | "requested": "[3.0.77, 3.0.77]", 14 | "resolved": "3.0.77", 15 | "contentHash": "Py5W1oN84KMBmOOHCzdz6pyi3bZTnQu9BoqIx0KGqkhG3V8kGoem/t+BuCM0pMIWAyl2iMP1n2S9624YXmBJZw==" 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/IServiceScope.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Defines scope for . 12 | /// 13 | public interface IServiceScope : IDisposable 14 | { 15 | /// 16 | /// The used to resolve dependencies from the scope. 17 | /// 18 | IServiceProvider ServiceProvider { get; } 19 | } 20 | } -------------------------------------------------------------------------------- /tests/Fakes/FakeService .cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | public class FakeService : IFakeService, IDisposable 11 | { 12 | public PocoClass Value { get; set; } 13 | 14 | public bool Disposed { get; private set; } 15 | 16 | public void Dispose() 17 | { 18 | if (Disposed) 19 | { 20 | throw new ObjectDisposedException(nameof(FakeService)); 21 | } 22 | 23 | Disposed = true; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/packages.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": { 4 | ".NETnanoFramework,Version=v1.0": { 5 | "nanoFramework.CoreLibrary": { 6 | "type": "Direct", 7 | "requested": "[1.17.11, 1.17.11]", 8 | "resolved": "1.17.11", 9 | "contentHash": "HezzAc0o2XrSGf85xSeD/6xsO6ohF9hX6/iMQ1IZS6Zw6umr4WfAN2Jv0BrPxkaYwzEegJxxZujkHoUIAqtOMw==" 10 | }, 11 | "Nerdbank.GitVersioning": { 12 | "type": "Direct", 13 | "requested": "[3.9.50, 3.9.50]", 14 | "resolved": "3.9.50", 15 | "contentHash": "HtOgGF6jZ+WYbXnCUCYPT8Y2d6mIJo9ozjK/FINTRsXdm4Zgv9GehUMa7EFoGQkqrMcDJNOIDwCmENnvXg4UbA==" 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /.github/workflows/update-dependencies.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation and Contributors 2 | # See LICENSE file in the project root for full license information. 3 | 4 | # This workflow will periodically check .NET nanoFramework dependencies and updates them in the repository it's running. 5 | 6 | name: Daily update dependencies 7 | 8 | on: 9 | schedule: 10 | # At 00:00 UTC. 11 | - cron: '00 00 * * Tue,Thu' 12 | repository_dispatch: 13 | types: update-dependencies 14 | 15 | jobs: 16 | update-dependencies: 17 | name: nanoFramework 18 | uses: nanoframework/nf-tools/.github/workflows/update-dependencies.yml@main 19 | secrets: inherit 20 | with: 21 | solutionsToCheck: 'nanoFramework.DependencyInjection.sln' 22 | -------------------------------------------------------------------------------- /tests/Fakes/InstanceCountServices/TransientInstanceCountService.cs: -------------------------------------------------------------------------------- 1 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes.InstanceCountServices 2 | { 3 | internal interface ITransientInstanceCountService 4 | { 5 | int Id { get; } 6 | } 7 | 8 | internal class TransientInstanceCountService : ITransientInstanceCountService 9 | { 10 | private readonly object _syncLock = new(); 11 | 12 | public TransientInstanceCountService() 13 | { 14 | lock (_syncLock) 15 | { 16 | InstanceCount += 1; 17 | Id = InstanceCount; 18 | } 19 | } 20 | 21 | public int Id { get; } 22 | public static int InstanceCount { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/IServiceProviderIsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Extensions.DependencyInjection 4 | { 5 | /// 6 | /// Optional service used to determine if the specified type is available from the . 7 | /// 8 | public interface IServiceProviderIsService 9 | { 10 | /// 11 | /// Determines if the specified service type is available from the . 12 | /// 13 | /// An object that specifies the type of service object to test. 14 | /// true if the specified service is a available, false if it is not. 15 | bool IsService(Type serviceType); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("nanoFramework.DependencyInjection")] 8 | [assembly: AssemblyCompany("nanoFramework Contributors")] 9 | [assembly: AssemblyProduct(".NET nanoframework nanoFramework.DependencyInjection")] 10 | [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /tests/Fakes/InstanceCountServices/SingletonInstanceCountService.cs: -------------------------------------------------------------------------------- 1 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes.InstanceCountServices 2 | { 3 | internal interface ISingletonInstanceCountService 4 | { 5 | int Id { get; } 6 | } 7 | 8 | internal class SingletonInstanceCountService : ISingletonInstanceCountService 9 | { 10 | private readonly ITransientInstanceCountService _transientInstanceCountService; 11 | private readonly object _syncLock = new(); 12 | 13 | public SingletonInstanceCountService(ITransientInstanceCountService transientInstanceCountService) 14 | { 15 | _transientInstanceCountService = transientInstanceCountService; 16 | 17 | lock (_syncLock) 18 | { 19 | InstanceCount += 1; 20 | Id = InstanceCount; 21 | } 22 | } 23 | 24 | public int Id { get; } 25 | public static int InstanceCount { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceLifetime.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace Microsoft.Extensions.DependencyInjection 7 | { 8 | /// 9 | /// Specifies the lifetime of a service in an . 10 | /// 11 | public enum ServiceLifetime 12 | { 13 | /// 14 | /// Specifies that a single instance of the service will be created. 15 | /// 16 | Singleton, 17 | 18 | /// 19 | /// Specifies that a new instance of the service will be created every time it is requested. 20 | /// 21 | Transient, 22 | 23 | /// 24 | /// Specifies that a single instance of the service will be created within a scope. 25 | /// 26 | Scoped 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /assets/readme.txt: -------------------------------------------------------------------------------- 1 | _____ _ 2 | _ __ __ _ _ __ ___ | ___| __ __ _ _ __ ___ _____ _____ _ __| | __ 3 | | '_ \ / _` | '_ \ / _ \| |_ | '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / 4 | | | | | (_| | | | | (_) | _|| | | (_| | | | | | | __/\ V V / (_) | | | < 5 | |_| |_|\__,_|_| |_|\___/|_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\ 6 | 7 | =================================================================================== 8 | 9 | API docs: https://docs.nanoframework.net/api/nanoFramework.DependencyInjection.html 10 | 11 | Browse our samples repository: https://github.com/nanoframework/samples 12 | 13 | Check our documentation online: https://docs.nanoframework.net/ 14 | 15 | Join our lively Discord community: https://discord.gg/gCyBu8T 16 | 17 | Report issues: https://github.com/nanoframework/Home/issues 18 | 19 | Follow us on Twitter: https://twitter.com/nanoframework 20 | 21 | Follow our YouTube channel: https://www.youtube.com/c/nanoFramework 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("nanoFramework.DependencyInjection.Tests")] 8 | [assembly: AssemblyCompany("nanoFramework Contributors")] 9 | [assembly: AssemblyProduct(".NET nanoframework nanoFramework.DependencyInjection Tests")] 10 | [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] 11 | 12 | ////////////////////////////////////////////////////// 13 | // this assembly does NOT have a native counterpart // 14 | ////////////////////////////////////////////////////// 15 | //////////////////////////////////////////////////////////////// 16 | [assembly: AssemblyNativeVersion("0.0.0.0")] 17 | //////////////////////////////////////////////////////////////// 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /tests/Fakes/ClassWithAmbiguousCtors.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 7 | { 8 | public class ClassWithAmbiguousCtors 9 | { 10 | public ClassWithAmbiguousCtors(string data) 11 | { 12 | CtorUsed = "string"; 13 | } 14 | 15 | public ClassWithAmbiguousCtors(IFakeService service, string data) 16 | { 17 | CtorUsed = "IFakeService, string"; 18 | } 19 | 20 | public ClassWithAmbiguousCtors(IFakeService service, int data) 21 | { 22 | CtorUsed = "IFakeService, int"; 23 | } 24 | 25 | public ClassWithAmbiguousCtors(IFakeService service, string data1, int data2) 26 | { 27 | FakeService = service; 28 | Data1 = data1; 29 | Data2 = data2; 30 | 31 | CtorUsed = "IFakeService, string, string"; 32 | } 33 | 34 | public IFakeService FakeService { get; } 35 | 36 | public string Data1 { get; } 37 | 38 | public int Data2 { get; } 39 | public string CtorUsed { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Fakes/ClassWithNestedReferencesToProvider.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | public class ClassWithNestedReferencesToProvider : IDisposable 11 | { 12 | private IServiceProvider _serviceProvider; 13 | private ClassWithNestedReferencesToProvider _nested; 14 | 15 | public ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider) 16 | { 17 | _serviceProvider = serviceProvider; 18 | _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, 0); 19 | } 20 | 21 | private ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider, int level) 22 | { 23 | _serviceProvider = serviceProvider; 24 | if (level > 1) 25 | { 26 | _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, level + 1); 27 | } 28 | } 29 | 30 | public void Dispose() 31 | { 32 | _nested?.Dispose(); 33 | (_serviceProvider as IDisposable)?.Dispose(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceProviderOptions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Options for configuring various behaviors of the default implementation. 12 | /// 13 | public class ServiceProviderOptions 14 | { 15 | // Avoid allocating objects in the default case 16 | internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions(); 17 | 18 | /// 19 | /// to perform check verifying that scoped services never gets resolved from root provider; otherwise . Defaults to . 20 | /// 21 | public bool ValidateScopes { get; set; } 22 | 23 | /// 24 | /// to perform check verifying that all services can be created during BuildServiceProvider call; otherwise . Defaults to . 25 | /// 26 | public bool ValidateOnBuild { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Fakes/RootService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | internal class RootService : IRootService 11 | { 12 | private readonly IService1 _service1; 13 | private readonly IService2 _service2; 14 | 15 | public string StringProperty { get; set; } 16 | 17 | public int IntProperty { get; set; } 18 | 19 | internal IService1 Service1 => _service1; 20 | 21 | internal IService2 Service2 => _service2; 22 | 23 | public RootService(IService1 service1, IService2 service2) 24 | : this(service1, service2, "default", 2000) 25 | { 26 | } 27 | 28 | public RootService(IService1 service1, IService2 service2, string stringProperty, int intProperty) 29 | { 30 | if (service1 == null) 31 | { 32 | throw new ArgumentNullException(nameof(service1)); 33 | } 34 | 35 | if (service2 == null) 36 | { 37 | throw new ArgumentNullException(nameof(service2)); 38 | } 39 | 40 | _service1 = service1; 41 | _service2 = service2; 42 | StringProperty = stringProperty; 43 | IntProperty = intProperty; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/System/IServiceProvider.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace System 7 | { 8 | /// 9 | /// Defines a mechanism for retrieving a service object; that is, an object that provides custom support to other objects. 10 | /// 11 | public interface IServiceProvider 12 | { 13 | /// 14 | /// Gets the service object of the specified type. 15 | /// 16 | /// An object that specifies the type of service object to get. 17 | /// 18 | /// A service object of type . -or- null if there is no service object of type . 19 | /// 20 | object GetService(Type serviceType); 21 | 22 | /// 23 | /// Gets the service objects of the specified type. 24 | /// 25 | /// An array object that specifies the type of service object to get. 26 | /// 27 | /// A service object array of type . -or- array empty if there is no service object of type . 28 | /// 29 | object[] GetService(Type[] serviceType); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Fakes/ClassWithMultipleCtors.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System.Collections; 7 | 8 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 9 | { 10 | public class ClassWithMultipleCtors 11 | { 12 | public ClassWithMultipleCtors(string data) 13 | { 14 | CtorUsed = 0; 15 | } 16 | 17 | public ClassWithMultipleCtors(IFakeService service, string data) 18 | { 19 | CtorUsed = 1; 20 | } 21 | 22 | public ClassWithMultipleCtors(IFakeService service, string data1, int data2) 23 | { 24 | FakeService = service; 25 | Data1 = data1; 26 | Data2 = data2; 27 | 28 | CtorUsed = 2; 29 | } 30 | 31 | public ClassWithMultipleCtors(IFakeService service, ICollection collection, string data1, int data2) 32 | { 33 | FakeService = service; 34 | Data1 = data1; 35 | Data2 = data2; 36 | Collection = collection; 37 | CtorUsed = 3; 38 | } 39 | 40 | public IFakeService FakeService { get; } 41 | 42 | public string Data1 { get; } 43 | 44 | public int Data2 { get; } 45 | 46 | public int CtorUsed { get; set; } 47 | 48 | public ICollection Collection { get; set; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/ServiceProviderTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using nanoFramework.TestFramework; 3 | using nanoFramework.DependencyInjection.UnitTests.Fakes.InstanceCountServices; 4 | 5 | namespace nanoFramework.DependencyInjection.UnitTests 6 | { 7 | [TestClass] 8 | public class ServiceProviderTests 9 | { 10 | [Cleanup] 11 | public void Cleanup() 12 | { 13 | SingletonInstanceCountService.InstanceCount = 0; 14 | TransientInstanceCountService.InstanceCount = 0; 15 | } 16 | 17 | [TestMethod] 18 | public void GetService_should_only_create_a_single_instance_of_transient_dependencies() 19 | { 20 | // Arrange 21 | var serviceCollection = new ServiceCollection(); 22 | serviceCollection.AddSingleton(typeof(ISingletonInstanceCountService), typeof(SingletonInstanceCountService)); 23 | serviceCollection.AddTransient(typeof(ITransientInstanceCountService), typeof(TransientInstanceCountService)); 24 | 25 | var sut = serviceCollection.BuildServiceProvider(); 26 | 27 | // Act 28 | var service = (ISingletonInstanceCountService) sut.GetRequiredService(typeof(ISingletonInstanceCountService)); 29 | 30 | // Assert 31 | Assert.AreEqual(1, SingletonInstanceCountService.InstanceCount); 32 | Assert.AreEqual(1, TransientInstanceCountService.InstanceCount); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | namespace Microsoft.Extensions.DependencyInjection 5 | { 6 | /// 7 | /// Contains extension methods for . 8 | /// 9 | internal static class TypeExtensions 10 | { 11 | /// 12 | /// Compares this instance to a specified type and returns an indication if resolvable value. 13 | /// 14 | /// The current 15 | public static bool IsResolvable(this Type type) 16 | { 17 | return type == typeof(string) 18 | || type == typeof(bool) 19 | || type == typeof(byte) 20 | || type == typeof(sbyte) 21 | || type == typeof(short) 22 | || type == typeof(ushort) 23 | || type == typeof(int) 24 | || type == typeof(uint) 25 | || type == typeof(long) 26 | || type == typeof(ulong) 27 | || type == typeof(double) 28 | || type == typeof(float) 29 | || type == typeof(object) 30 | || type == typeof(DateTime) 31 | || type == typeof(TimeSpan) 32 | || type == typeof(Guid) 33 | || type == typeof(Array) 34 | || type == typeof(ArrayList); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceScope.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Diagnostics; 8 | 9 | namespace Microsoft.Extensions.DependencyInjection 10 | { 11 | /// 12 | /// An implementation that implements . 13 | /// 14 | [DebuggerDisplay("{ServiceProvider,nq}")] 15 | public readonly struct ServiceScope : IServiceScope 16 | { 17 | private readonly IServiceScope _serviceScope; 18 | 19 | /// 20 | /// Initializes a new instance of the struct. 21 | /// Wraps an instance of . 22 | /// 23 | /// The instance to wrap. 24 | public ServiceScope(IServiceScope serviceScope) 25 | { 26 | if (serviceScope == null) 27 | { 28 | throw new ArgumentNullException(); 29 | } 30 | 31 | _serviceScope = serviceScope; 32 | } 33 | 34 | /// 35 | public IServiceProvider ServiceProvider => _serviceScope.ServiceProvider; 36 | 37 | /// 38 | public void Dispose() 39 | { 40 | _serviceScope.Dispose(); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /.github/.changelog-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "categories": [ 3 | { 4 | "title": "## New Features and enhancements", 5 | "labels": [ 6 | "Type: enhancement" 7 | ], 8 | "exhaustive": true 9 | }, 10 | { 11 | "title": "## Bug Fixes", 12 | "labels": [ 13 | "Type: bug" 14 | ], 15 | "exhaustive": true 16 | }, 17 | { 18 | "title": "## Documentation", 19 | "labels": [ 20 | "Type: documentation" 21 | ], 22 | "exhaustive": true 23 | }, 24 | { 25 | "title": "## ⚠️ Breaking Changes", 26 | "labels": [ 27 | "Breaking-Change" 28 | ], 29 | "exhaustive": true 30 | }, 31 | { 32 | "title": "## Updated dependencies", 33 | "labels": [ 34 | "Type: dependencies" 35 | ], 36 | "exhaustive": true 37 | } 38 | ], 39 | "sort": "ASC", 40 | "template": "${{CHANGELOG}}\n\n**Full Changelog:** ${{RELEASE_DIFF}}\n\nThe following NuGet package is available from this release:\n\n:package: [nanoFramework.DependencyInjection](https://www.nuget.org/packages/nanoFramework.DependencyInjection/)", 41 | "pr_template": "* ${{TITLE}} by @${{AUTHOR}} in #${{NUMBER}}", 42 | "empty_template": "- no changes", 43 | "max_tags_to_fetch": 200, 44 | "max_pull_requests": 200 45 | } 46 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionContainerBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace Microsoft.Extensions.DependencyInjection 7 | { 8 | /// 9 | /// Extension methods for building a from an . 10 | /// 11 | public static class ServiceCollectionContainerBuilderExtensions 12 | { 13 | /// 14 | /// Creates a containing services from the provided . 15 | /// 16 | /// The containing service descriptors. 17 | /// The . 18 | public static ServiceProvider BuildServiceProvider(this IServiceCollection services) 19 | { 20 | return services.BuildServiceProvider(ServiceProviderOptions.Default); 21 | } 22 | 23 | /// 24 | /// Creates a containing services from the provided 25 | /// optionally enabling scope validation. 26 | /// 27 | /// The containing service descriptors. 28 | /// Configures various service provider behaviors. 29 | /// The . 30 | public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options) 31 | { 32 | return new ServiceProvider(services, options); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | nanoFramework.DependencyInjection 5 | $version$ 6 | nanoFramework.DependencyInjection 7 | nanoframework 8 | false 9 | LICENSE.md 10 | 11 | 12 | docs\README.md 13 | false 14 | https://github.com/nanoframework/nanoFramework.DependencyInjection 15 | images\nf-logo.png 16 | 17 | Copyright (c) .NET Foundation and Contributors 18 | This package includes the nanoFramework.DependencyInjection assembly for .NET nanoFramework C# projects. 19 | nanoFramework C# csharp netmf netnf dependencyinjection 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/Fakes/ClassWithPrimitiveBinding.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | 4 | using System; 5 | using System.Collections; 6 | 7 | namespace nanoFramework.DependencyInjection.UnitTests.Fakes 8 | { 9 | public class ClassWithPrimitiveBinding 10 | { 11 | public string Str { get; set; } 12 | 13 | public bool Boolean { get; set; } 14 | 15 | public byte Byte { get; set; } 16 | 17 | public sbyte SByte { get; set; } 18 | 19 | public short Short { get; set; } 20 | 21 | public ushort Ushort { get; set; } 22 | 23 | public int Int { get; set; } 24 | 25 | public uint UInt { get; set; } 26 | 27 | public long Long { get; set; } 28 | 29 | public ulong Ulong { get; set; } 30 | 31 | public double Double { get; set; } 32 | 33 | public float Float { get; set; } 34 | 35 | public object Obj { get; set; } 36 | 37 | public DateTime DateTime { get; set; } 38 | 39 | public TimeSpan TimeSpan { get; set; } 40 | 41 | public Guid Guid { get; set; } 42 | 43 | public Array Array { get; set; } 44 | 45 | public ArrayList ArrayList { get; set; } 46 | 47 | public ClassWithPrimitiveBinding( 48 | string str, 49 | bool boolean, 50 | byte @byte, 51 | sbyte sByte, 52 | short @short, 53 | ushort @ushort, 54 | int @int, 55 | uint uInt, 56 | long @long, 57 | ulong @ulong, 58 | double @double, 59 | float @float, 60 | object obj, 61 | DateTime dateTime, 62 | TimeSpan timeSpan, 63 | Guid guid, 64 | Array array, 65 | ArrayList arrayList) 66 | { 67 | Str = str; 68 | Boolean = boolean; 69 | Byte = @byte; 70 | SByte = sByte; 71 | Short = @short; 72 | Ushort = @ushort; 73 | Int = @int; 74 | UInt = uInt; 75 | Long = @long; 76 | Ulong = @ulong; 77 | Double = @double; 78 | Float = @float; 79 | Obj = obj; 80 | DateTime = dateTime; 81 | TimeSpan = timeSpan; 82 | Guid = guid; 83 | Array = array; 84 | ArrayList = arrayList; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /tests/AggregateExceptionTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Collections; 8 | using nanoFramework.TestFramework; 9 | 10 | namespace nanoFramework.DependencyInjection.UnitTests 11 | { 12 | [TestClass] 13 | public class AggregateExceptionTests 14 | { 15 | [TestMethod] 16 | public static void ConstructorBasic() 17 | { 18 | AggregateException ex = new AggregateException(); 19 | Assert.AreEqual(0, ex.InnerExceptions.Count); 20 | Assert.IsTrue(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor is used, expected a default message"); 21 | 22 | ex = new AggregateException("message"); 23 | Assert.AreEqual(0, ex.InnerExceptions.Count); 24 | Assert.IsTrue(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor(string) is used"); 25 | 26 | ex = new AggregateException("message", new Exception()); 27 | Assert.AreEqual(1, ex.InnerExceptions.Count); 28 | Assert.IsTrue(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor(string, Exception) is used"); 29 | } 30 | 31 | [TestMethod] 32 | public static void ConstructorInvalidArguments() 33 | { 34 | Assert.ThrowsException(typeof(ArgumentNullException), () => new AggregateException("message", (Exception)null)); 35 | Assert.ThrowsException(typeof(ArgumentNullException), () => new AggregateException("message", new ArrayList() { null })); 36 | } 37 | 38 | [TestMethod] 39 | public static void Message() 40 | { 41 | Exception exceptionA = new Exception("A"); 42 | Exception exceptionB = new Exception("B"); 43 | Exception exceptionC = new Exception("C"); 44 | 45 | AggregateException aggExceptionBase = new AggregateException("message", exceptionA, exceptionB, exceptionC); 46 | Assert.AreEqual("message (A) (B) (C)", aggExceptionBase.Message); 47 | //Assert.Equal("message (A) (B) (C)\n---> (Inner Exception #0) System.Exception: A <---\n---> (Inner Exception #1) System.Exception: B <---\n---> (Inner Exception #2) System.Exception: C <---\n", aggExceptionBase.ToString()); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32519.379 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.DependencyInjection", "nanoFramework.DependencyInjection\nanoFramework.DependencyInjection.nfproj", "{A2B2222C-0553-4877-8CF1-4458B30C0081}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5CA8DDDF-50C5-4044-A78C-170228780423}" 9 | ProjectSection(SolutionItems) = preProject 10 | .runsettings = .runsettings 11 | nanoframework.DependencyInjection.nuspec = nanoframework.DependencyInjection.nuspec 12 | README.md = README.md 13 | version.json = version.json 14 | EndProjectSection 15 | EndProject 16 | Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.DependencyInjection.UnitTests", "tests\nanoFramework.DependencyInjection.UnitTests.nfproj", "{547A718F-591B-4D7F-A144-8D57C0F98276}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 27 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {A2B2222C-0553-4877-8CF1-4458B30C0081}.Release|Any CPU.Deploy.0 = Release|Any CPU 30 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 33 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {547A718F-591B-4D7F-A144-8D57C0F98276}.Release|Any CPU.Deploy.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {F36078E1-F784-459A-B4A7-330B3F2BBEA0} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceProvider.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Collections; 8 | 9 | namespace Microsoft.Extensions.DependencyInjection 10 | { 11 | /// 12 | /// The default . 13 | /// 14 | /// Some services are not able to be constructed. 15 | public sealed class ServiceProvider : IServiceProvider, IServiceProviderIsService, IDisposable 16 | { 17 | private bool _disposed; 18 | 19 | internal ServiceProviderEngine Engine { get; } 20 | 21 | internal ServiceProvider(IServiceCollection services, ServiceProviderOptions options) 22 | { 23 | if (services == null) 24 | { 25 | throw new ArgumentNullException(); 26 | } 27 | 28 | if (options == null) 29 | { 30 | throw new ArgumentNullException(); 31 | } 32 | 33 | Engine = GetEngine(); 34 | Engine.Services = services; 35 | Engine.Services.Add(new ServiceDescriptor(typeof(IServiceProvider), this)); 36 | Engine.Options = options; 37 | 38 | if (options.ValidateOnBuild) 39 | { 40 | ArrayList exceptions = null; 41 | 42 | foreach (ServiceDescriptor descriptor in services) 43 | { 44 | try 45 | { 46 | Engine.ValidateService(descriptor); 47 | } 48 | catch (Exception ex) 49 | { 50 | exceptions ??= new ArrayList(); 51 | exceptions.Add(ex); 52 | } 53 | } 54 | 55 | if (exceptions != null) 56 | { 57 | throw new AggregateException(string.Empty, exceptions); 58 | } 59 | } 60 | } 61 | 62 | /// 63 | public object GetService(Type serviceType) 64 | { 65 | if (_disposed) 66 | { 67 | throw new ObjectDisposedException(); 68 | } 69 | 70 | return Engine.GetService(serviceType); 71 | } 72 | 73 | /// 74 | public object[] GetService(Type[] serviceType) 75 | { 76 | if (_disposed) 77 | { 78 | throw new ObjectDisposedException(); 79 | } 80 | 81 | return Engine.GetService(serviceType); 82 | } 83 | 84 | /// 85 | public IServiceScope CreateScope() 86 | { 87 | return new ServiceProviderEngineScope(this); 88 | } 89 | 90 | /// 91 | public void Dispose() 92 | { 93 | if (_disposed) 94 | { 95 | return; 96 | } 97 | 98 | _disposed = true; 99 | Engine.DisposeServices(); 100 | } 101 | 102 | private ServiceProviderEngine GetEngine() 103 | { 104 | return ServiceProviderEngine.Instance; 105 | } 106 | 107 | /// 108 | public bool IsService(Type serviceType) 109 | { 110 | return Engine.IsService(serviceType); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/IServiceCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System.Collections; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Default implementation of IServiceCollection. 12 | /// 13 | public interface IServiceCollection 14 | { 15 | /// 16 | /// Gets or sets the at the specified index. 17 | /// 18 | /// The zero-based index of the item to add. 19 | ServiceDescriptor this[int index] { get; set; } 20 | 21 | /// 22 | /// Gets a value indicating whether the collection is read-only. 23 | /// 24 | bool IsReadOnly { get; } 25 | 26 | /// 27 | /// Gets the number of elements contained in the collection. 28 | /// 29 | int Count { get; } 30 | 31 | /// 32 | /// Adds an item to the collection. 33 | /// 34 | /// The to add. 35 | int Add(ServiceDescriptor item); 36 | 37 | /// 38 | /// Removes all from the collection. 39 | /// 40 | void Clear(); 41 | 42 | /// 43 | /// Determines whether the collection contains a specific value. 44 | /// 45 | /// The to locate in the collection. 46 | bool Contains(ServiceDescriptor item); 47 | 48 | /// 49 | /// Copies the elements of the collection to an Array starting at a particular Array index. 50 | /// 51 | /// The one-dimensional Array that is the destination of the elements copied from. The Array must have zero-based indexing. 52 | /// The zero-based index in array at which copying begins. 53 | void CopyTo(ServiceDescriptor[] array, int arrayIndex); 54 | 55 | /// 56 | /// Returns an enumerator that iterates through a collection. 57 | /// 58 | IEnumerator GetEnumerator(); 59 | 60 | /// 61 | /// Determines the index of a specific item in the collection. 62 | /// 63 | /// The to get the index of. 64 | int IndexOf(ServiceDescriptor item); 65 | 66 | /// 67 | /// Inserts an item to the collection at the specified index. 68 | /// 69 | /// The zero-based index at which should be inserted. 70 | /// The to insert. 71 | void Insert(int index, ServiceDescriptor item); 72 | 73 | /// 74 | /// Removes the first occurrence of a specific object from the collection. 75 | /// 76 | /// The to remove. 77 | void Remove(ServiceDescriptor item); 78 | 79 | /// 80 | /// Removes the item at the specified index. 81 | /// 82 | /// The zero-based index of the item to remove. 83 | void RemoveAt(int index); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) .NET Foundation and Contributors 2 | # See LICENSE file in the project root for full license information. 3 | 4 | trigger: 5 | branches: 6 | include: 7 | - main 8 | - develop 9 | - release-* 10 | paths: 11 | exclude: 12 | - .gitignore 13 | - CHANGELOG.md 14 | - LICENSE.md 15 | - README.md 16 | - NuGet.Config 17 | - assets/* 18 | - .github/* 19 | 20 | tags: 21 | include: 22 | - v* 23 | 24 | # PR always trigger build 25 | pr: 26 | autoCancel: true 27 | 28 | # add nf-tools repo to resources (for Azure Pipelines templates) 29 | resources: 30 | repositories: 31 | - repository: templates 32 | type: github 33 | name: nanoframework/nf-tools 34 | endpoint: nanoframework 35 | 36 | variables: 37 | - name: nugetPackageName 38 | value: 'nanoFramework.DependencyInjection' 39 | - name: DOTNET_NOLOGO 40 | value: true 41 | 42 | jobs: 43 | 44 | ############################## 45 | - job: Build_Library 46 | condition: >- 47 | and( 48 | not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')), 49 | or( 50 | eq(variables['UPDATE_DEPENDENTS'], 'false'), 51 | eq(variables['StartReleaseCandidate'], 'true') 52 | ) 53 | ) 54 | pool: 55 | vmImage: 'windows-latest' 56 | 57 | variables: 58 | - group: sign-client-credentials 59 | - name: buildPlatform 60 | value: 'Any CPU' 61 | - name: buildConfiguration 62 | value: 'Release' 63 | - name: solution 64 | value: 'nanoFramework.DependencyInjection.sln' 65 | 66 | steps: 67 | 68 | # step from template @ nf-tools repo 69 | # all build, update and publish steps 70 | - template: azure-pipelines-templates/class-lib-build.yml@templates 71 | parameters: 72 | sonarCloudProject: 'nanoframework_nanoFramework.DependencyInjection' 73 | runUnitTests: true 74 | unitTestRunsettings: '$(System.DefaultWorkingDirectory)\tests\nano.runsettings' 75 | 76 | ############################## 77 | - job: Update_Dependents 78 | condition: >- 79 | or( 80 | and( 81 | startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), 82 | eq(variables['StartReleaseCandidate'], 'false') 83 | ), 84 | and( 85 | contains(variables['getCommitMessage.COMMIT_MESSAGE'], '***UPDATE_DEPENDENTS***'), 86 | eq(variables['StartReleaseCandidate'], 'false') 87 | ), 88 | eq(variables['UPDATE_DEPENDENTS'], 'true') 89 | ) 90 | 91 | pool: 92 | vmImage: 'windows-latest' 93 | 94 | steps: 95 | # need this here in order to persist GitHub credentials 96 | - checkout: self 97 | fetchDepth: 1 98 | 99 | # update dependents 100 | - template: azure-pipelines-templates/update-dependents.yml@templates 101 | parameters: 102 | packageName: '$(nugetPackageName)' 103 | repositoriesToUpdate: | 104 | nanoFramework.Hosting 105 | 106 | ################################## 107 | # report build failure to Discord 108 | - job: Report_Build_Failure 109 | 110 | dependsOn: 111 | - Build_Library 112 | - Update_Dependents 113 | condition: >- 114 | or( 115 | failed('Build_Library'), 116 | failed('Update_Dependents') 117 | ) 118 | 119 | pool: 120 | vmImage: 'windows-latest' 121 | 122 | steps: 123 | 124 | - checkout: self 125 | 126 | # step from template @ nf-tools repo 127 | # report error 128 | - template: azure-pipelines-templates/discord-webhook-task.yml@templates 129 | parameters: 130 | status: 'failure' 131 | webhookUrl: '$(DiscordWebhook)' 132 | message: '' 133 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System.Collections; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Default implementation of . 12 | /// 13 | public class ServiceCollection : IServiceCollection 14 | { 15 | private readonly object _syncLock = new(); 16 | private readonly ArrayList _descriptors = []; 17 | 18 | /// 19 | public bool IsReadOnly => false; 20 | 21 | /// 22 | public int Count 23 | { 24 | get 25 | { 26 | lock (_syncLock) 27 | { 28 | return _descriptors.Count; 29 | } 30 | } 31 | } 32 | 33 | /// 34 | public ServiceDescriptor this[int index] 35 | { 36 | get 37 | { 38 | lock (_syncLock) 39 | { 40 | return (ServiceDescriptor)_descriptors[index]; 41 | } 42 | } 43 | 44 | set 45 | { 46 | lock (_syncLock) 47 | { 48 | _descriptors[index] = value; 49 | } 50 | } 51 | } 52 | 53 | /// 54 | public int Add(ServiceDescriptor item) 55 | { 56 | lock (_syncLock) 57 | { 58 | return _descriptors.Add(item); 59 | } 60 | } 61 | 62 | /// 63 | public void Clear() 64 | { 65 | lock (_syncLock) 66 | { 67 | _descriptors.Clear(); 68 | } 69 | } 70 | 71 | /// 72 | public bool Contains(ServiceDescriptor item) 73 | { 74 | lock (_syncLock) 75 | { 76 | return _descriptors.Contains(item); 77 | } 78 | } 79 | 80 | /// 81 | public void CopyTo(ServiceDescriptor[] array, int arrayIndex) 82 | { 83 | lock (_syncLock) 84 | { 85 | _descriptors.CopyTo(array, arrayIndex); 86 | } 87 | } 88 | 89 | /// 90 | public void Remove(ServiceDescriptor item) 91 | { 92 | lock (_syncLock) 93 | { 94 | _descriptors.Remove(item); 95 | } 96 | } 97 | 98 | /// 99 | public IEnumerator GetEnumerator() 100 | { 101 | lock (_syncLock) 102 | { 103 | return _descriptors.GetEnumerator(); 104 | } 105 | } 106 | 107 | /// 108 | public int IndexOf(ServiceDescriptor item) 109 | { 110 | lock (_syncLock) 111 | { 112 | return _descriptors.IndexOf(item); 113 | } 114 | } 115 | 116 | /// 117 | public void Insert(int index, ServiceDescriptor item) 118 | { 119 | lock (_syncLock) 120 | { 121 | _descriptors.Insert(index, item); 122 | } 123 | } 124 | 125 | /// 126 | public void RemoveAt(int index) 127 | { 128 | lock (_syncLock) 129 | { 130 | _descriptors.RemoveAt(index); 131 | } 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/System/Activator.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | namespace System 7 | { 8 | /// 9 | /// Contains methods to create types of objects locally. This class cannot be inherited. 10 | /// 11 | public static class Activator 12 | { 13 | /// 14 | /// Creates an instance of the type whose name is specified, using the named assembly. 15 | /// 16 | /// The fully qualified name of the type to create an instance of. 17 | public static object CreateInstance(string typename) 18 | { 19 | Type type = Type.GetType(typename); 20 | 21 | if (type != null) 22 | { 23 | return CreateInstance(type); 24 | } 25 | 26 | return null; 27 | } 28 | 29 | /// 30 | /// Creates an instance of the specified type using that type's parameterless constructor. 31 | /// 32 | /// The type of object to create. 33 | public static object CreateInstance(Type type) 34 | { 35 | return CreateInstance(type, new Type[] { }, new object[] { }); 36 | } 37 | 38 | /// 39 | /// Creates an instance of the specified type using the constructor that best matches the specified parameters. 40 | /// 41 | /// The type of object to create. 42 | /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. 43 | /// If is an empty array or null, the constructor that takes no parameters (the parameterless constructor) is invoked. 44 | public static object CreateInstance(Type type, params object[] args) 45 | { 46 | Type[] types = args != null ? new Type[args.Length] : new Type[] { }; 47 | 48 | for (int index = types.Length - 1; index >= 0; index--) 49 | { 50 | types[index] = args?[index]?.GetType(); 51 | } 52 | 53 | return CreateInstance(type, types, args); 54 | } 55 | 56 | /// 57 | /// Creates an instance of the specified type using the constructor that best matches the specified parameters. 58 | /// 59 | /// The type of object to create. 60 | /// An array of Type objects representing the number, order, and type of the parameters for the desired constructor. 61 | /// If types is an empty array or null, to get constructor that takes no parameters. 62 | /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. 63 | /// If is an empty array or null, the constructor that takes no parameters (the parameterless constructor) is invoked. 64 | /// can't be null. 65 | public static object CreateInstance(Type type, Type[] types, params object[] args) 66 | { 67 | if (type == null) 68 | { 69 | throw new ArgumentNullException(); 70 | } 71 | 72 | if (types == null) 73 | { 74 | types = new Type[] { }; 75 | } 76 | 77 | if (args == null) 78 | { 79 | args = new object[] { }; 80 | } 81 | 82 | return type.GetConstructor(types).Invoke(args); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceProviderEngineScope.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// The method ends the scope lifetime. Once Dispose 12 | /// is called, any scoped services that have been resolved from 13 | /// will be disposed. 14 | /// 15 | internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider 16 | { 17 | private bool _disposed; 18 | 19 | private readonly IServiceCollection _scopeServices = new ServiceCollection(); 20 | 21 | /// 22 | /// The root service provider used to resolve dependencies from the scope. 23 | /// 24 | internal ServiceProvider RootProvider { get; } 25 | 26 | /// 27 | /// Creates instance of . 28 | /// 29 | /// The root service provider used to resolve dependencies from the scope. 30 | internal ServiceProviderEngineScope(ServiceProvider provider) 31 | { 32 | RootProvider = provider; 33 | 34 | CloneScopeServices(); 35 | } 36 | 37 | /// 38 | /// The resolved from the scope. 39 | /// 40 | public IServiceProvider ServiceProvider => this; 41 | 42 | /// 43 | public object GetService(Type serviceType) 44 | { 45 | if (_disposed) 46 | { 47 | throw new ObjectDisposedException(); 48 | } 49 | 50 | return RootProvider.Engine.GetService(serviceType, _scopeServices); 51 | } 52 | 53 | /// 54 | public object[] GetService(Type[] serviceType) 55 | { 56 | if (_disposed) 57 | { 58 | throw new ObjectDisposedException(); 59 | } 60 | 61 | return RootProvider.Engine.GetService(serviceType, _scopeServices); 62 | } 63 | 64 | /// 65 | public IServiceScope CreateScope() 66 | { 67 | return new ServiceProviderEngineScope(RootProvider); 68 | } 69 | 70 | /// 71 | public void Dispose() 72 | { 73 | if (_disposed) 74 | { 75 | return; 76 | } 77 | 78 | _disposed = true; 79 | DisposeServices(); 80 | } 81 | 82 | private void CloneScopeServices() 83 | { 84 | foreach (ServiceDescriptor descriptor in RootProvider.Engine.Services) 85 | { 86 | if (descriptor.Lifetime == ServiceLifetime.Scoped) 87 | { 88 | _scopeServices.Add(new ServiceDescriptor( 89 | descriptor.ServiceType, descriptor.ImplementationType, ServiceLifetime.Scoped)); 90 | } 91 | } 92 | } 93 | 94 | private void DisposeServices() 95 | { 96 | for (int index = _scopeServices.Count - 1; index >= 0; index--) 97 | { 98 | if (_scopeServices[index].ImplementationInstance is IDisposable disposable) 99 | { 100 | #pragma warning disable S3966 //services must be disposed explicitly, otherwise ServiceRegisteredWithScopeIsDisposedWhenScopeIsDisposed test fails 101 | disposable.Dispose(); 102 | #pragma warning restore S3966 103 | } 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/ActivatorTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | using nanoFramework.TestFramework; 9 | 10 | namespace nanoFramework.DependencyInjection.UnitTests 11 | { 12 | [TestClass] 13 | public class ActivatorTests 14 | { 15 | [TestMethod] 16 | public static void CreateInstance() 17 | { 18 | Choice c = (Choice)(Activator.CreateInstance(typeof(Choice))); 19 | Assert.AreEqual(1, c.I); 20 | 21 | c = (Choice)(Activator.CreateInstance(typeof(Choice).FullName)); 22 | Assert.AreEqual(1, c.I); 23 | 24 | c = (Choice)(Activator.CreateInstance(typeof(Choice), null)); 25 | Assert.AreEqual(1, c.I); 26 | 27 | c = (Choice)(Activator.CreateInstance(typeof(Choice), null, null)); 28 | Assert.AreEqual(1, c.I); 29 | 30 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { })); 31 | Assert.AreEqual(1, c.I); 32 | 33 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { 42 })); 34 | Assert.AreEqual(2, c.I); 35 | 36 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { "Hello" })); 37 | Assert.AreEqual(3, c.I); 38 | 39 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { 5.1, "Hello" })); 40 | Assert.AreEqual(4, c.I); 41 | } 42 | 43 | [TestMethod] 44 | public static void CreateInstanceConstructorWithParamsParameter() 45 | { 46 | Choice c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarArgs(), new object[] { } })); 47 | Assert.AreEqual(5, c.I); 48 | 49 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarArgs(), new object[] { "P1" } })); 50 | Assert.AreEqual(5, c.I); 51 | 52 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarArgs(), new object[] { "P1", "P2" } })); 53 | Assert.AreEqual(5, c.I); 54 | 55 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarStringArgs(), new string[] { } })); 56 | Assert.AreEqual(6, c.I); 57 | 58 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarStringArgs(), new string[] { "P1" } })); 59 | Assert.AreEqual(6, c.I); 60 | 61 | // TODO:? c = (Choice1)(Activator.CreateInstance(typeof(Choice1), new object[] { new VarStringArgs(), "P1", "P2" })); 62 | c = (Choice)(Activator.CreateInstance(typeof(Choice), new object[] { new VarStringArgs(), new string[] { "P1", "P2" } })); 63 | Assert.AreEqual(6, c.I); 64 | } 65 | 66 | [TestMethod] 67 | public void CreateInstanceNullTypeThrowsArgumentNullException() 68 | { 69 | Assert.ThrowsException(typeof(ArgumentNullException), () => Activator.CreateInstance(null, new object[0])); 70 | } 71 | 72 | public class Choice 73 | { 74 | public Choice() 75 | { 76 | I = 1; 77 | } 78 | 79 | public Choice(int i) 80 | { 81 | I = 2; 82 | } 83 | 84 | public Choice(string s) 85 | { 86 | I = 3; 87 | } 88 | 89 | public Choice(double d, string optionalS = "Hey") 90 | { 91 | I = 4; 92 | } 93 | 94 | public Choice(VarArgs varArgs, params object[] parameters) 95 | { 96 | I = 5; 97 | } 98 | 99 | public Choice(VarStringArgs varArgs, params string[] parameters) 100 | { 101 | I = 6; 102 | } 103 | 104 | public Choice(VarIntArgs varArgs, params int[] parameters) 105 | { 106 | I = 7; 107 | } 108 | 109 | public int I; 110 | } 111 | 112 | public class VarArgs { } 113 | 114 | public class VarStringArgs { } 115 | 116 | public class VarIntArgs { } 117 | } 118 | } -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceProviderServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Extension methods for getting services from an . 12 | /// 13 | public static class ServiceProviderServiceExtensions 14 | { 15 | /// 16 | /// Get an enumeration of services of type from the . 17 | /// 18 | /// The to retrieve the services from. 19 | /// An object that specifies the type of service object to get. 20 | /// An array of services of type . 21 | public static object[] GetServices(this IServiceProvider provider, Type serviceType) 22 | { 23 | if (provider == null) 24 | { 25 | throw new ArgumentNullException(); 26 | } 27 | 28 | return provider.GetService(new Type[] { serviceType }); 29 | } 30 | 31 | /// 32 | /// Get an enumeration of services of type from the . 33 | /// 34 | /// The to retrieve the services from. 35 | /// An array of object that specifies the type of service object to get. 36 | /// An array of services of type . 37 | /// 'provider' or 'serviceType' can't be . 38 | public static object[] GetServices(this IServiceProvider provider, Type[] serviceType) 39 | { 40 | if (provider == null) 41 | { 42 | throw new ArgumentNullException(); 43 | } 44 | 45 | if (serviceType == null) 46 | { 47 | throw new ArgumentNullException(); 48 | } 49 | 50 | return provider.GetService(serviceType); 51 | } 52 | 53 | /// 54 | /// Get service of type from the . 55 | /// 56 | /// The to retrieve the service object from. 57 | /// An object that specifies the type of service object to get. 58 | /// A service object of type . 59 | /// There is no service of type . 60 | /// or can't be . 61 | public static object GetRequiredService(this IServiceProvider provider, Type serviceType) 62 | { 63 | if (provider == null) 64 | { 65 | throw new ArgumentNullException(); 66 | } 67 | 68 | if (serviceType == null) 69 | { 70 | throw new ArgumentNullException(); 71 | } 72 | 73 | object service = provider.GetService(serviceType); 74 | 75 | if (service == null) 76 | { 77 | throw new InvalidOperationException(); 78 | } 79 | 80 | return service; 81 | } 82 | 83 | /// 84 | /// Creates a new that can be used to resolve scoped services. 85 | /// 86 | /// The to create the scope from. 87 | /// An that can be used to resolve scoped services. 88 | /// can't be . 89 | public static IServiceScope CreateScope(this IServiceProvider provider) 90 | { 91 | if (provider == null) 92 | { 93 | throw new ArgumentNullException(); 94 | } 95 | 96 | var service = (ServiceProvider)provider.GetRequiredService(typeof(IServiceProvider)); 97 | 98 | return new ServiceScope(service.CreateScope()); 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /tests/ServiceProviderExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using Microsoft.Extensions.DependencyInjection; 7 | using nanoFramework.TestFramework; 8 | using System; 9 | using System.Collections; 10 | 11 | namespace nanoFramework.DependencyInjection.UnitTests 12 | { 13 | [TestClass] 14 | public class ServiceProviderExtensionsTests 15 | { 16 | [TestMethod] 17 | public void GetServiceReturnsCorrectService() 18 | { 19 | var serviceProvider = CreateTestServiceProvider(1); 20 | var service = serviceProvider.GetService(typeof(IFoo)); 21 | 22 | Assert.IsType(typeof(Foo1), service); 23 | } 24 | 25 | [TestMethod] 26 | public void GetRequiredServiceReturnsCorrectService() 27 | { 28 | var serviceProvider = CreateTestServiceProvider(1); 29 | var service = serviceProvider.GetRequiredService(typeof(IFoo)); 30 | 31 | Assert.IsType(typeof(Foo1), service); 32 | } 33 | 34 | [TestMethod] 35 | public void GetRequiredServiceThrowsWhenNoServiceRegistered() 36 | { 37 | var serviceProvider = CreateTestServiceProvider(0); 38 | 39 | var expectedMessage = $"No service for type 'nanoFramework.DependencyInjection.UnitTests.ServiceProviderExtensionsTest+IFoo' has been registered."; 40 | Assert.ThrowsException(typeof(InvalidOperationException), 41 | () => serviceProvider.GetRequiredService(typeof(IFoo)) 42 | ); 43 | } 44 | 45 | [TestMethod] 46 | public void GetServicesReturnsMultipleServices() 47 | { 48 | var serviceProvider = CreateTestServiceProvider(4); 49 | 50 | var types = new Type[] { typeof(IFoo), typeof(IBar) }; 51 | object[] services = ((ServiceProvider)serviceProvider).GetService(types); 52 | 53 | Assert.IsType(typeof(Foo1), services[0].GetType()); 54 | Assert.IsType(typeof(Foo2), services[1].GetType()); 55 | Assert.IsType(typeof(Bar1), services[2].GetType()); 56 | Assert.IsType(typeof(Bar2), services[3].GetType()); 57 | Assert.AreEqual(4, services.Length); 58 | } 59 | 60 | [TestMethod] 61 | public void GetServicesReturnsAllServices() 62 | { 63 | var serviceProvider = CreateTestServiceProvider(2); 64 | object[] services = serviceProvider.GetServices(typeof(IFoo)); 65 | 66 | Assert.IsType(typeof(Foo1), services[0].GetType()); 67 | Assert.IsType(typeof(Foo2), services[1].GetType()); 68 | Assert.AreEqual(2, services.Length); 69 | } 70 | 71 | [TestMethod] 72 | public void GetServicesReturnsSingleService() 73 | { 74 | var serviceProvider = CreateTestServiceProvider(1); 75 | object[] services = serviceProvider.GetServices(typeof(IFoo)); 76 | 77 | Assert.IsType(typeof(Foo1), services[0].GetType()); 78 | Assert.AreEqual(1, services.Length); 79 | } 80 | 81 | [TestMethod] 82 | public void GetServicesReturnsCorrectTypes() 83 | { 84 | var serviceProvider = CreateTestServiceProvider(4); 85 | object[] services = serviceProvider.GetServices(typeof(IBar)); 86 | 87 | Assert.IsType(typeof(Bar1), services[0].GetType()); 88 | Assert.IsType(typeof(Bar2), services[1].GetType()); 89 | Assert.AreEqual(2, services.Length); 90 | } 91 | 92 | [TestMethod] 93 | public void GetServicesReturnsEmptyArrayWhenNoServicesAvailable() 94 | { 95 | var serviceProvider = CreateTestServiceProvider(0); 96 | object[] services = serviceProvider.GetServices(typeof(IFoo)); 97 | 98 | //Assert.IsType(typeof(object[]), services); 99 | Assert.AreEqual(0, services.Length); 100 | } 101 | 102 | [TestMethod] 103 | public void GetServicesWithBuildServiceProviderReturnsEmptyListWhenNoServicesAvailable() 104 | { 105 | var serviceCollection = new ServiceCollection(); 106 | serviceCollection.AddSingleton(typeof(IFoo), new ArrayList()); 107 | var serviceProvider = serviceCollection.BuildServiceProvider(); 108 | 109 | object[] services = serviceProvider.GetServices(typeof(IBar)); 110 | 111 | //Assert.IsType(typeof(object[]), services.GetType()); 112 | Assert.AreEqual(0, services.Length); 113 | } 114 | 115 | 116 | private static IServiceProvider CreateTestServiceProvider(int count) 117 | { 118 | var serviceCollection = new ServiceCollection(); 119 | 120 | if (count > 0) 121 | { 122 | serviceCollection.AddTransient(typeof(IFoo), typeof(Foo1)); 123 | } 124 | 125 | if (count > 1) 126 | { 127 | serviceCollection.AddTransient(typeof(IFoo), typeof(Foo2)); 128 | } 129 | 130 | if (count > 2) 131 | { 132 | serviceCollection.AddTransient(typeof(IBar), typeof(Bar1)); 133 | } 134 | 135 | if (count > 3) 136 | { 137 | serviceCollection.AddTransient(typeof(IBar), typeof(Bar2)); 138 | } 139 | 140 | return serviceCollection.BuildServiceProvider(); 141 | } 142 | 143 | public interface IFoo { } 144 | 145 | public class Foo1 : IFoo { } 146 | 147 | public class Foo2 : IFoo { } 148 | 149 | public interface IBar { } 150 | 151 | public class Bar1 : IBar { } 152 | 153 | public class Bar2 : IBar { } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /tests/nanoFramework.DependencyInjection.UnitTests.nfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildExtensionsPath)\nanoFramework\v1.0\ 5 | 6 | 7 | 8 | 9 | 10 | 11 | Debug 12 | AnyCPU 13 | {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 547a718f-591b-4d7f-a144-8d57c0f98276 15 | Library 16 | Properties 17 | 512 18 | nanoFramework.DependencyInjection.UnitTests 19 | NFUnitTest 20 | False 21 | true 22 | UnitTest 23 | v1.0 24 | true 25 | true 26 | 27 | 28 | 29 | $(MSBuildProjectDirectory)\nano.runsettings 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ..\packages\nanoFramework.CoreLibrary.1.17.11\lib\mscorlib.dll 76 | 77 | 78 | ..\packages\nanoFramework.TestFramework.3.0.77\lib\nanoFramework.TestFramework.dll 79 | 80 | 81 | ..\packages\nanoFramework.TestFramework.3.0.77\lib\nanoFramework.UnitTestLauncher.exe 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/nanoFramework.DependencyInjection.nfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(MSBuildExtensionsPath)\nanoFramework\v1.0\ 6 | 7 | 8 | 9 | Debug 10 | AnyCPU 11 | {11B8DD76-328B-46DF-9F39-F559912D0360};{FAC04EC0-301F-11D3-BF4B-00C04F79EFBC} 12 | {A2B2222C-0553-4877-8CF1-4458B30C0081} 13 | Library 14 | Properties 15 | 512 16 | nanoFramework.DependencyInjection 17 | v1.0 18 | True 19 | bin\$(Configuration)\nanoFramework.DependencyInjection.xml 20 | default 21 | true 22 | true 23 | 24 | 25 | true 26 | 27 | 28 | key.snk 29 | 30 | 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ..\packages\nanoFramework.CoreLibrary.1.17.11\lib\mscorlib.dll 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [**Changes available only in 'Preview' NuGet packages:**](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.1.1...HEAD) 6 | 7 | **Documentation and other chores:** 8 | 9 | - Update 2 NuGet dependencies [\#34](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/34) 10 | 11 | ## [v1.1.1](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.1.1) (2023-11-06) 12 | 13 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.35...v1.1.1) 14 | 15 | **Implemented enhancements:** 16 | 17 | - Implemented IServiceProviderIsService [\#33](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/33) 18 | 19 | ## [v1.0.35](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.35) (2023-10-04) 20 | 21 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.22...v1.0.35) 22 | 23 | **Implemented enhancements:** 24 | 25 | - Add support for "Scoped" lifetime [\#31](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/31) 26 | - Instance references aren't stored in ServiceDescriptor if lifetime is Transient [\#30](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/30) 27 | 28 | **Documentation and other chores:** 29 | 30 | - Eliminate deprecated asserts in test cases [\#32](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/32) 31 | - Update 1 NuGet dependencies [\#29](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/29) 32 | - Update 1 NuGet dependencies [\#28](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/28) 33 | - Update 2 NuGet dependencies [\#27](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/27) 34 | - Update 1 NuGet dependencies [\#26](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/26) 35 | - Update 1 NuGet dependencies [\#25](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/25) 36 | - Update 1 NuGet dependencies [\#24](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/24) 37 | - Update 1 NuGet dependencies [\#23](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/23) 38 | 39 | ## [v1.0.22](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.22) (2022-12-23) 40 | 41 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.12...v1.0.22) 42 | 43 | **Documentation and other chores:** 44 | 45 | - Update 2 NuGet dependencies [\#22](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/22) 46 | - Update 1 NuGet dependencies [\#21](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/21) 47 | - Update 1 NuGet dependencies [\#20](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/20) 48 | - Update 1 NuGet dependencies [\#19](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/19) 49 | - Update 1 NuGet dependencies [\#18](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/18) 50 | - Update 1 NuGet dependencies [\#17](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/17) 51 | - Update 1 NuGet dependencies [\#16](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/16) 52 | - Update 1 NuGet dependencies [\#15](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/15) 53 | 54 | ## [v1.0.12](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.12) (2022-10-12) 55 | 56 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.5...v1.0.12) 57 | 58 | **Fixed bugs:** 59 | 60 | - Fixed missing parameters in api footprint [\#14](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/14) 61 | 62 | **Documentation and other chores:** 63 | 64 | - Update 1 NuGet dependencies [\#13](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/13) 65 | - Update 1 NuGet dependencies [\#12](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/12) 66 | - Update 1 NuGet dependencies [\#11](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/11) 67 | - Fix running unit tests locally [\#10](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/10) 68 | 69 | ## [v1.0.5](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.5) (2022-08-04) 70 | 71 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.2...v1.0.5) 72 | 73 | **Implemented enhancements:** 74 | 75 | - Add type checking to constructor parameters [\#9](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/9) 76 | 77 | ## [v1.0.2](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.2) (2022-07-14) 78 | 79 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/v1.0.0.11...v1.0.2) 80 | 81 | **Implemented enhancements:** 82 | 83 | - Resolved issue where service provider did not dispose correctly [\#8](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/8) 84 | 85 | ## [v1.0.0.11](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/v1.0.0.11) (2022-06-30) 86 | 87 | [Full Changelog](https://github.com/nanoframework/nanoFramework.DependencyInjection/compare/cd621ea3e1b6198ac9c4fdb42ef082d60ae3d4e1...v1.0.0.11) 88 | 89 | **Implemented enhancements:** 90 | 91 | - Adjusting exceptions and small review [\#3](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/3) 92 | 93 | **Fixed bugs:** 94 | 95 | - Various code fixes [\#6](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/6) 96 | 97 | **Documentation and other chores:** 98 | 99 | - Fixes in code style and comments [\#5](https://github.com/nanoframework/nanoFramework.DependencyInjection/pull/5) 100 | 101 | 102 | 103 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 104 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ActivatorUtilities.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Reflection; 8 | 9 | namespace Microsoft.Extensions.DependencyInjection 10 | { 11 | /// 12 | /// Helper code for the various activator services. 13 | /// 14 | public static class ActivatorUtilities 15 | { 16 | /// 17 | /// Instantiate a type with constructor arguments provided directly and/or from an . 18 | /// 19 | /// The service provider used to resolve dependencies. 20 | /// The type to activate. 21 | /// Constructor arguments not provided by the . 22 | /// An activated object of type . 23 | /// A suitable constructor for type could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments. Also ensure no extraneous arguments are provided. 24 | public static object CreateInstance(IServiceProvider provider, Type instanceType, params object[] parameters) 25 | { 26 | int bestLength = -1; 27 | 28 | ConstructorMatcher bestMatcher = default; 29 | 30 | if (!instanceType.IsAbstract) 31 | { 32 | foreach (ConstructorInfo constructor in instanceType.GetConstructors()) 33 | { 34 | var matcher = new ConstructorMatcher(constructor); 35 | int length = matcher.Match(parameters); 36 | 37 | if (bestLength < length) 38 | { 39 | bestLength = length; 40 | bestMatcher = matcher; 41 | } 42 | } 43 | } 44 | 45 | if (bestLength == -1) 46 | { 47 | throw new InvalidOperationException(); 48 | } 49 | 50 | return bestMatcher.CreateInstance(provider); 51 | } 52 | 53 | /// 54 | /// Retrieve an instance of the given type from the service provider. If one is not found then instantiate it directly. 55 | /// 56 | /// The service provider. 57 | /// The type of the service. 58 | /// Constructor arguments not provided by the . 59 | /// The resolved service or created instance. 60 | /// Unable to resolve a service while attempting to activate a constructor. 61 | public static object GetServiceOrCreateInstance(IServiceProvider provider, Type type, params object[] parameters) 62 | { 63 | return provider.GetService(type) ?? CreateInstance(provider, type, parameters); 64 | } 65 | 66 | private struct ConstructorMatcher 67 | { 68 | private readonly object[] _parameterValues; 69 | private readonly ParameterInfo[] _parameters; 70 | private readonly ConstructorInfo _constructor; 71 | 72 | public ConstructorMatcher(ConstructorInfo constructor) 73 | { 74 | _constructor = constructor; 75 | _parameters = _constructor.GetParameters(); 76 | _parameterValues = new object[_parameters.Length]; 77 | } 78 | 79 | public int Match(object[] givenParameters) 80 | { 81 | int applyIndexStart = 0; 82 | int applyExactLength = 0; 83 | 84 | for (int givenIndex = 0; givenIndex != givenParameters.Length; givenIndex++) 85 | { 86 | Type givenType = givenParameters[givenIndex].GetType(); 87 | bool givenMatched = false; 88 | 89 | for (int applyIndex = applyIndexStart; !givenMatched && applyIndex != _parameters.Length; ++applyIndex) 90 | { 91 | if (_parameterValues[applyIndex] == null 92 | && _parameters[applyIndex].ParameterType.Equals(givenType)) 93 | { 94 | givenMatched = true; 95 | _parameterValues[applyIndex] = givenParameters[givenIndex]; 96 | 97 | if (applyIndexStart == applyIndex) 98 | { 99 | applyIndexStart++; 100 | 101 | if (applyIndex == givenIndex) 102 | { 103 | applyExactLength = applyIndex; 104 | } 105 | } 106 | } 107 | } 108 | 109 | if (!givenMatched) 110 | { 111 | return -1; 112 | } 113 | } 114 | return applyExactLength; 115 | } 116 | 117 | public object CreateInstance(IServiceProvider provider) 118 | { 119 | for (int index = 0; index != _parameters.Length; index++) 120 | { 121 | if (_parameterValues[index] == null) 122 | { 123 | object value = provider.GetService(_parameters[index].ParameterType); 124 | 125 | if (value == null) 126 | { 127 | throw new InvalidOperationException($"'{_parameters[index].ParameterType}'->'{_constructor.DeclaringType}'."); 128 | } 129 | else 130 | { 131 | _parameterValues[index] = value; 132 | } 133 | } 134 | } 135 | 136 | return _constructor.Invoke(_parameterValues); 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/System/AggregateException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System.Collections; 7 | using System.Diagnostics; 8 | 9 | namespace System 10 | { 11 | /// Initializes a new instance of the class with a system-supplied message that describes the error. 12 | /// 13 | /// is used to consolidate multiple failures into a single, throwable 14 | /// exception object. 15 | /// 16 | [Serializable] 17 | [DebuggerDisplay("Count = {InnerExceptionCount}")] 18 | public class AggregateException : Exception 19 | { 20 | private readonly Exception[] _innerExceptions; 21 | private static readonly string _defaultMessage = "One or more errors occurred."; 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | public AggregateException() 27 | : this(_defaultMessage) 28 | { 29 | } 30 | 31 | /// 32 | /// Initializes a new instance of the class with 33 | /// a specified error message. 34 | /// 35 | /// The error message that explains the reason for the exception. 36 | public AggregateException(string message) 37 | : base(message) 38 | { 39 | _innerExceptions = new Exception[0]; 40 | } 41 | 42 | /// 43 | /// Initializes a new instance of the class with 44 | /// a specified error message. 45 | /// 46 | /// The error message that explains the reason for the exception. 47 | /// The exceptions that are the cause of the current exception. 48 | /// One of the is . 49 | public AggregateException(string message, params Exception[] innerException) 50 | : base(message) 51 | { 52 | foreach(Exception ex in innerException) 53 | { 54 | if (ex == null) 55 | { 56 | throw new ArgumentNullException(); 57 | } 58 | } 59 | 60 | _innerExceptions = innerException; 61 | } 62 | 63 | /// 64 | /// Initializes a new instance of the class with 65 | /// a specified error message. 66 | /// 67 | /// The error message that explains the reason for the exception. 68 | /// An array list of object exceptions that is the cause of the current exception. 69 | /// An element of innerExceptions not of Exception type. 70 | /// One of the is . 71 | public AggregateException(string message, ArrayList innerException) 72 | : base(message) 73 | { 74 | foreach (Exception ex in innerException) 75 | { 76 | if (ex == null) 77 | { 78 | throw new ArgumentNullException(); 79 | } 80 | } 81 | 82 | try 83 | { 84 | _innerExceptions = (Exception[])innerException.ToArray(typeof(Exception)); 85 | } 86 | catch 87 | { 88 | throw new ArgumentException(); 89 | } 90 | } 91 | 92 | /// 93 | /// Gets an of the exception instances that caused the current exception. 94 | /// 95 | public ArrayList InnerExceptions 96 | { 97 | get 98 | { 99 | var execptions = new ArrayList(); 100 | foreach(Exception ex in _innerExceptions) 101 | { 102 | execptions.Add(ex); 103 | } 104 | 105 | return execptions; 106 | } 107 | } 108 | 109 | /// 110 | /// Gets a message that describes the exception. 111 | /// 112 | public override string Message 113 | { 114 | get 115 | { 116 | if (_innerExceptions.Length == 0) 117 | { 118 | return base.Message; 119 | } 120 | 121 | var msg = $"{ base.Message } "; 122 | 123 | var count = _innerExceptions.Length; 124 | for (int index = 0; index < count; index++) 125 | { 126 | if (index < count - 1) 127 | { 128 | msg = string.Concat(msg, $"({ _innerExceptions[index].Message }) "); 129 | } 130 | else 131 | { 132 | msg = string.Concat(msg, $"({ _innerExceptions[index].Message })"); 133 | } 134 | } 135 | 136 | return msg; 137 | } 138 | } 139 | 140 | /// 141 | /// Creates and returns a string representation of the current . 142 | /// 143 | /// A string representation of the current exception. 144 | public override string ToString() 145 | { 146 | string msg = base.ToString(); 147 | 148 | for (int index = 0; index < _innerExceptions.Length; index++) 149 | { 150 | if (index == 0) 151 | { 152 | msg = string.Concat(msg, "\n"); 153 | } 154 | 155 | if (_innerExceptions[index] == InnerException) 156 | { 157 | // Already logged in base.ToString() 158 | continue; 159 | } 160 | 161 | msg = string.Concat(msg, $"---> (Inner Exception #{index}) {_innerExceptions[index]} <---\n"); 162 | } 163 | 164 | return msg; 165 | } 166 | 167 | internal int InnerExceptionCount => _innerExceptions.Length; 168 | } 169 | } -------------------------------------------------------------------------------- /tests/ServiceCollectionDescriptorExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using nanoFramework.DependencyInjection.UnitTests.Fakes; 4 | using nanoFramework.TestFramework; 5 | 6 | // ReSharper disable InvokeAsExtensionMethod 7 | namespace nanoFramework.DependencyInjection.UnitTests 8 | { 9 | [TestClass] 10 | public class ServiceCollectionDescriptorExtensionsTests 11 | { 12 | private static ServiceDescriptor CreateSingletonServiceDescriptor() => ServiceDescriptor.Singleton(typeof(IService1), typeof(Service1)); 13 | private static ServiceDescriptor CreateTransientServiceDescriptor() => ServiceDescriptor.Transient(typeof(IService1), typeof(Service1)); 14 | 15 | [TestMethod] 16 | public void Add_adds_descriptor() 17 | { 18 | var descriptor = CreateSingletonServiceDescriptor(); 19 | 20 | var collection = new ServiceCollection(); 21 | 22 | ServiceCollectionDescriptorExtensions.Add(collection, descriptor); 23 | 24 | Assert.AreEqual(1, collection.Count); 25 | Assert.IsTrue(collection.Contains(descriptor)); 26 | } 27 | 28 | [TestMethod] 29 | public void Add_adds_descriptors() 30 | { 31 | var singletonDescriptor = CreateSingletonServiceDescriptor(); 32 | var transientDescriptor = CreateTransientServiceDescriptor(); 33 | var descriptors = new[] { singletonDescriptor, transientDescriptor }; 34 | 35 | var collection = new ServiceCollection(); 36 | 37 | ServiceCollectionDescriptorExtensions.Add(collection, descriptors); 38 | 39 | Assert.AreEqual(2, collection.Count); 40 | Assert.IsTrue(collection.Contains(singletonDescriptor)); 41 | Assert.IsTrue(collection.Contains(transientDescriptor)); 42 | } 43 | 44 | [TestMethod] 45 | public void Add_throws_when_collection_is_null() 46 | { 47 | var test = new object[]{}; 48 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Add(null!, CreateSingletonServiceDescriptor())); 49 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Add(null!, new ServiceDescriptor[]{})); 50 | } 51 | 52 | [TestMethod] 53 | public void Add_throws_when_descriptor_is_null() 54 | { 55 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Add(new ServiceCollection(), ((ServiceDescriptor)null)!)); 56 | } 57 | 58 | [TestMethod] 59 | public void Add_throws_when_descriptors_contains_invalid_type() 60 | { 61 | var descriptors = new[] 62 | { 63 | CreateSingletonServiceDescriptor(), 64 | CreateTransientServiceDescriptor(), 65 | new object() 66 | }; 67 | 68 | Assert.ThrowsException(typeof(ArgumentException), () => ServiceCollectionDescriptorExtensions.Add(new ServiceCollection(), descriptors)); 69 | } 70 | 71 | [TestMethod] 72 | public void Add_throws_when_descriptors_is_null() 73 | { 74 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Add(new ServiceCollection(), ((ServiceDescriptor[])null)!)); 75 | } 76 | 77 | [TestMethod] 78 | public void RemoveAll_removes_descriptors() 79 | { 80 | var serviceA = ServiceDescriptor.Scoped(typeof(IService1), typeof(Service1)); 81 | var serviceB = ServiceDescriptor.Singleton(typeof(IService1), typeof(Service1)); 82 | var serviceC = ServiceDescriptor.Transient(typeof(IService1), typeof(Service1)); 83 | var serviceD = ServiceDescriptor.Singleton(typeof(IService2), typeof(Service2)); 84 | 85 | var collection = new ServiceCollection(); 86 | 87 | collection.Add(serviceA); 88 | collection.Add(serviceB); 89 | collection.Add(serviceC); 90 | collection.Add(serviceD); 91 | 92 | Assert.AreEqual(4, collection.Count); 93 | Assert.IsTrue(collection.Contains(serviceA)); 94 | Assert.IsTrue(collection.Contains(serviceB)); 95 | Assert.IsTrue(collection.Contains(serviceC)); 96 | Assert.IsTrue(collection.Contains(serviceD)); 97 | 98 | ServiceCollectionDescriptorExtensions.RemoveAll(collection, typeof(IService1)); 99 | 100 | Assert.AreEqual(1, collection.Count); 101 | Assert.IsFalse(collection.Contains(serviceA)); 102 | Assert.IsFalse(collection.Contains(serviceB)); 103 | Assert.IsFalse(collection.Contains(serviceC)); 104 | Assert.IsTrue(collection.Contains(serviceD)); 105 | } 106 | 107 | [TestMethod] 108 | public void RemoveAll_throws_when_collection_is_null() 109 | { 110 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.RemoveAll(null!, typeof(IService1))); 111 | } 112 | 113 | [TestMethod] 114 | public void RemoveAll_throws_when_serviceType_is_null() 115 | { 116 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.RemoveAll(new ServiceCollection(), null!)); 117 | } 118 | 119 | [TestMethod] 120 | public void Replace_replaces_descriptor() 121 | { 122 | var singletonDescriptor = CreateSingletonServiceDescriptor(); 123 | var transientDescriptor = CreateTransientServiceDescriptor(); 124 | var otherDescriptor = ServiceDescriptor.Singleton(typeof(IService2), typeof(Service2)); 125 | 126 | var collection = new ServiceCollection(); 127 | 128 | collection.Add(singletonDescriptor); 129 | collection.Add(otherDescriptor); 130 | 131 | Assert.AreEqual(2, collection.Count); 132 | Assert.IsTrue(collection.Contains(singletonDescriptor)); 133 | Assert.IsFalse(collection.Contains(transientDescriptor)); 134 | Assert.IsTrue(collection.Contains(otherDescriptor)); 135 | 136 | ServiceCollectionDescriptorExtensions.Replace(collection, transientDescriptor); 137 | 138 | Assert.AreEqual(2, collection.Count); 139 | Assert.IsFalse(collection.Contains(singletonDescriptor)); 140 | Assert.IsTrue(collection.Contains(transientDescriptor)); 141 | Assert.IsTrue(collection.Contains(otherDescriptor)); 142 | } 143 | 144 | [TestMethod] 145 | public void Replace_throws_when_collection_is_null() 146 | { 147 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Replace(null!, CreateSingletonServiceDescriptor())); 148 | } 149 | 150 | [TestMethod] 151 | public void Replace_throws_when_descriptor_is_null() 152 | { 153 | Assert.ThrowsException(typeof(ArgumentNullException), () => ServiceCollectionDescriptorExtensions.Replace(new ServiceCollection(), null!)); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | #Sonarcloud 366 | .sonarqube 367 | 368 | #VS Code 369 | .vscode 370 | -------------------------------------------------------------------------------- /tests/ActivatorUtilitiesTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using nanoFramework.TestFramework; 8 | using nanoFramework.DependencyInjection.UnitTests.Fakes; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace nanoFramework.DependencyInjection.UnitTests 12 | { 13 | [TestClass] 14 | public class ActivatorUtilitiesTests 15 | { 16 | [TestMethod] 17 | public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocContainer() 18 | { 19 | var serviceProvider = new ServiceCollection() 20 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 21 | .BuildServiceProvider(); 22 | 23 | var instance = (AnotherClass)ActivatorUtilities.CreateInstance(serviceProvider, typeof(AnotherClass)); 24 | 25 | Assert.IsNotNull(instance.FakeService); 26 | } 27 | 28 | 29 | [TestMethod] 30 | public void TypeActivatorAcceptsAnyNumberOfAdditionalConstructorParametersToProvide() 31 | { 32 | var serviceProvider = new ServiceCollection() 33 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 34 | .BuildServiceProvider(); 35 | 36 | var instance = (AnotherClassAcceptingData)ActivatorUtilities.CreateInstance( 37 | serviceProvider, 38 | typeof(AnotherClassAcceptingData), 39 | "1", 40 | "2"); 41 | 42 | Assert.IsNotNull(instance.FakeService); 43 | Assert.AreEqual("1", instance.One); 44 | Assert.AreEqual("2", instance.Two); 45 | } 46 | 47 | [TestMethod] 48 | public void TypeActivatorCanDisambiguateConstructorsWithUniqueArguments() 49 | { 50 | var serviceProvider = new ServiceCollection() 51 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 52 | .BuildServiceProvider(); 53 | 54 | var instance = (ClassWithAmbiguousCtors)ActivatorUtilities.CreateInstance(serviceProvider, typeof(ClassWithAmbiguousCtors), "1", 2); 55 | 56 | Assert.IsNotNull(instance); 57 | Assert.IsNotNull(instance.FakeService); 58 | Assert.AreEqual("1", instance.Data1); 59 | Assert.AreEqual(2, instance.Data2); 60 | } 61 | 62 | [TestMethod] 63 | [DataRow("", "string")] 64 | [DataRow(5, "IFakeService, int")] 65 | public void TypeActivatorCreateInstanceUsesFirstMathchedConstructor(object value, string ctor) 66 | { 67 | var serviceProvider = new ServiceCollection() 68 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 69 | .BuildServiceProvider(); 70 | 71 | var instance = (ClassWithAmbiguousCtors)ActivatorUtilities.CreateInstance(serviceProvider, typeof(ClassWithAmbiguousCtors), value); 72 | 73 | Assert.AreEqual(ctor, instance.CtorUsed); 74 | } 75 | 76 | [TestMethod] 77 | public void TypeActivatorRethrowsOriginalExceptionFromConstructor() 78 | { 79 | Assert.ThrowsException(typeof(Exception), 80 | () => 81 | { 82 | try 83 | { 84 | ActivatorUtilities.CreateInstance(null, typeof(ClassWithThrowingCtor), new object[] { new FakeService() }); 85 | } 86 | catch (Exception ex) 87 | { 88 | if (string.Equals(nameof(ClassWithThrowingCtor), ex.Message)) 89 | { 90 | throw new Exception(); 91 | } 92 | else 93 | { 94 | throw new NullReferenceException(); 95 | } 96 | } 97 | } 98 | ); 99 | 100 | Assert.ThrowsException(typeof(Exception), 101 | () => 102 | { 103 | try 104 | { 105 | ActivatorUtilities.CreateInstance(null, typeof(ClassWithThrowingEmptyCtor)); 106 | } 107 | catch (Exception ex) 108 | { 109 | if (string.Equals(nameof(ClassWithThrowingEmptyCtor), ex.Message)) 110 | { 111 | throw new Exception(); 112 | } 113 | else 114 | { 115 | throw new NullReferenceException(); 116 | } 117 | } 118 | } 119 | ); 120 | } 121 | 122 | [TestMethod] 123 | public void TypeActivatorRequiresAllArgumentsCanBeAccepted() 124 | { 125 | var serviceProvider = new ServiceCollection() 126 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 127 | .BuildServiceProvider(); 128 | 129 | Assert.ThrowsException(typeof(InvalidOperationException), 130 | () => ActivatorUtilities.CreateInstance(serviceProvider, typeof(AnotherClassAcceptingData), "1", "2", "3") 131 | ); 132 | 133 | Assert.ThrowsException(typeof(InvalidOperationException), 134 | () => ActivatorUtilities.CreateInstance(serviceProvider, typeof(AnotherClassAcceptingData), 1, 2) 135 | ); 136 | } 137 | 138 | [TestMethod] 139 | public void GetServiceOrCreateInstanceRegisteredServiceTransient() 140 | { 141 | // Reset the count because test order is not guaranteed 142 | lock (CreationCountFakeService.InstanceLock) 143 | { 144 | CreationCountFakeService.InstanceCount = 0; 145 | 146 | var serviceProvider = new ServiceCollection() 147 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 148 | .AddTransient(typeof(CreationCountFakeService)) 149 | .BuildServiceProvider(); 150 | 151 | var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 152 | Assert.IsNotNull(service); 153 | Assert.AreEqual(1, service.InstanceId); 154 | Assert.AreEqual(1, CreationCountFakeService.InstanceCount); 155 | 156 | service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 157 | Assert.IsNotNull(service); 158 | Assert.AreEqual(2, service.InstanceId); 159 | Assert.AreEqual(2, CreationCountFakeService.InstanceCount); 160 | } 161 | } 162 | 163 | [TestMethod] 164 | public void GetServiceOrCreateInstanceRegisteredServiceSingleton() 165 | { 166 | // Reset the count because test order is not guaranteed 167 | lock (CreationCountFakeService.InstanceLock) 168 | { 169 | CreationCountFakeService.InstanceCount = 0; 170 | 171 | var serviceProvider = new ServiceCollection() 172 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 173 | .AddSingleton(typeof(CreationCountFakeService)) 174 | .BuildServiceProvider(); 175 | 176 | var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 177 | Assert.IsNotNull(service); 178 | Assert.AreEqual(1, service.InstanceId); 179 | Assert.AreEqual(1, CreationCountFakeService.InstanceCount); 180 | 181 | service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 182 | Assert.IsNotNull(service); 183 | Assert.AreEqual(1, service.InstanceId); 184 | Assert.AreEqual(1, CreationCountFakeService.InstanceCount); 185 | } 186 | } 187 | 188 | [TestMethod] 189 | public void GetServiceOrCreateInstanceUnregisteredService() 190 | { 191 | // Reset the count because test order is not guaranteed 192 | lock (CreationCountFakeService.InstanceLock) 193 | { 194 | CreationCountFakeService.InstanceCount = 0; 195 | 196 | var serviceProvider = new ServiceCollection() 197 | .AddTransient(typeof(IFakeService), typeof(FakeService)) 198 | .BuildServiceProvider(); 199 | 200 | var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 201 | Assert.IsNotNull(service); 202 | Assert.AreEqual(1, service.InstanceId); 203 | Assert.AreEqual(1, CreationCountFakeService.InstanceCount); 204 | 205 | service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typeof(CreationCountFakeService)); 206 | Assert.IsNotNull(service); 207 | Assert.AreEqual(2, service.InstanceId); 208 | Assert.AreEqual(2, CreationCountFakeService.InstanceCount); 209 | } 210 | } 211 | 212 | [TestMethod] 213 | public void UnRegisteredServiceAsConstructorParameterThrowsException() 214 | { 215 | var serviceProvider = new ServiceCollection() 216 | .AddSingleton(typeof(CreationCountFakeService)) 217 | .BuildServiceProvider(); 218 | 219 | Assert.ThrowsException(typeof(InvalidOperationException), 220 | () => ActivatorUtilities.CreateInstance(serviceProvider, typeof(CreationCountFakeService)) 221 | ); 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /tests/ServiceCollectionTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using Microsoft.Extensions.DependencyInjection; 7 | using nanoFramework.DependencyInjection.UnitTests.Fakes; 8 | using nanoFramework.TestFramework; 9 | using System; 10 | using System.Collections; 11 | 12 | namespace nanoFramework.DependencyInjection.UnitTests 13 | { 14 | [TestClass] 15 | public class ServiceCollectionTests 16 | { 17 | [TestMethod] 18 | public static void ServiceDescriptorDescribe() 19 | { 20 | var serviceDescriptor = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 21 | 22 | Assert.IsInstanceOfType(serviceDescriptor.ServiceType, typeof(IFakeObject)); 23 | Assert.IsInstanceOfType(serviceDescriptor.ImplementationType, typeof(FakeObject)); 24 | Assert.IsTrue(serviceDescriptor.Lifetime == ServiceLifetime.Singleton); 25 | } 26 | 27 | [TestMethod] 28 | public static void ServiceDescriptorToString() 29 | { 30 | var expectedMessage = "ServiceType: nanoFramework.DependencyInjection.UnitTests.Fakes.IFakeObject Lifetime: 0 ImplementationType: nanoFramework.DependencyInjection.UnitTests.Fakes.FakeObject."; 31 | var serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 32 | 33 | Assert.IsInstanceOfType(serviceDescriptor.ServiceType, typeof(IFakeObject)); 34 | Assert.IsInstanceOfType(serviceDescriptor.ImplementationType, typeof(FakeObject)); 35 | Assert.IsTrue(serviceDescriptor.Lifetime == ServiceLifetime.Singleton); 36 | Assert.Contains(serviceDescriptor.ToString(), expectedMessage); 37 | } 38 | 39 | [TestMethod] 40 | public static void ServiceCollectionAdd() 41 | { 42 | var serviceCollection = new ServiceCollection(); 43 | var serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 44 | 45 | serviceCollection.Add(serviceDescriptor); 46 | Assert.AreEqual(1, serviceCollection.Count); 47 | 48 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeObject)); 49 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeObject)); 50 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Singleton); 51 | } 52 | 53 | [TestMethod] 54 | public static void ServiceCollectionReplace() 55 | { 56 | var serviceCollection = new ServiceCollection(); 57 | var serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 58 | 59 | serviceCollection.Add(serviceDescriptor); 60 | Assert.AreEqual(1, serviceCollection.Count); 61 | 62 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeObject)); 63 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeObject)); 64 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Singleton); 65 | 66 | serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 67 | 68 | serviceCollection.Replace(serviceDescriptor); 69 | Assert.AreEqual(1, serviceCollection.Count); 70 | 71 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeObject)); 72 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeObject)); 73 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Transient); 74 | } 75 | 76 | [TestMethod] 77 | public static void ServiceCollectionAddSingleton() 78 | { 79 | var serviceCollection = new ServiceCollection(); 80 | 81 | serviceCollection.AddSingleton(typeof(IFakeObject), typeof(FakeObject)); 82 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Singleton); 83 | } 84 | 85 | [TestMethod] 86 | public static void ServiceCollectionAddTransient() 87 | { 88 | var serviceCollection = new ServiceCollection(); 89 | 90 | serviceCollection.AddTransient(typeof(IFakeObject), typeof(FakeObject)); 91 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Transient); 92 | } 93 | 94 | [TestMethod] 95 | public static void ServiceCollectionTryAdd() 96 | { 97 | var serviceCollection = new ServiceCollection(); 98 | var serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 99 | 100 | serviceCollection.TryAdd(serviceDescriptor); 101 | serviceCollection.TryAdd(serviceDescriptor); 102 | Assert.AreEqual(1, serviceCollection.Count); 103 | 104 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Transient); 105 | } 106 | 107 | [TestMethod] 108 | public static void ServiceCollectionTryAddEnumerable() 109 | { 110 | var serviceCollection = new ServiceCollection(); 111 | var serviceDescriptor = new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 112 | 113 | serviceCollection.TryAddEnumerable(serviceDescriptor); 114 | Assert.AreEqual(1, serviceCollection.Count); 115 | 116 | var serviceDescriptors = new ArrayList 117 | { 118 | new ServiceDescriptor(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient), 119 | new ServiceDescriptor(typeof(IFakeService), typeof(FakeService), ServiceLifetime.Singleton), 120 | new ServiceDescriptor(typeof(IFakeService), typeof(FakeService), ServiceLifetime.Singleton) 121 | }; 122 | 123 | serviceCollection.TryAddEnumerable(serviceDescriptors); 124 | Assert.AreEqual(2, serviceCollection.Count); 125 | } 126 | 127 | [TestMethod] 128 | public static void ServiceCollectionInterfaceThrowsArgumentException() 129 | { 130 | var serviceCollection = new ServiceCollection(); 131 | 132 | Assert.ThrowsException(typeof(ArgumentException), 133 | () => serviceCollection.AddSingleton(typeof(IFakeObject), typeof(IFakeObject)) 134 | ); 135 | } 136 | 137 | [TestMethod] 138 | public static void ServiceCollectionRemove() 139 | { 140 | var serviceCollection = new ServiceCollection(); 141 | var serviceDescriptor = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 142 | 143 | serviceCollection.Add(serviceDescriptor); 144 | Assert.AreEqual(1, serviceCollection.Count); 145 | 146 | serviceCollection.Remove(serviceDescriptor); 147 | Assert.IsTrue(serviceCollection.Count == 0); 148 | } 149 | 150 | [TestMethod] 151 | public static void ServiceCollectionRemoveAll() 152 | { 153 | var serviceCollection = new ServiceCollection(); 154 | 155 | serviceCollection.AddTransient(typeof(IFakeObject), typeof(FakeObject)); 156 | serviceCollection.AddSingleton(typeof(IFakeObject), typeof(FakeObject)); 157 | serviceCollection.AddSingleton(typeof(IFakeService), typeof(FakeService)); 158 | Assert.AreEqual(3, serviceCollection.Count); 159 | 160 | serviceCollection.RemoveAll(typeof(IFakeObject)); 161 | Assert.AreEqual(1, serviceCollection.Count); 162 | 163 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeService)); 164 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeService)); 165 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Singleton); 166 | } 167 | 168 | [TestMethod] 169 | public static void ServiceCollectionRemoveAt() 170 | { 171 | var serviceCollection = new ServiceCollection(); 172 | 173 | serviceCollection.AddTransient(typeof(IFakeObject), typeof(FakeObject)); 174 | serviceCollection.AddSingleton(typeof(IFakeObject), typeof(FakeObject)); 175 | serviceCollection.AddSingleton(typeof(IFakeService), typeof(FakeService)); 176 | Assert.AreEqual(3, serviceCollection.Count); 177 | 178 | serviceCollection.RemoveAt(1); 179 | Assert.AreEqual(2, serviceCollection.Count); 180 | 181 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeObject)); 182 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeObject)); 183 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Transient); 184 | Assert.IsInstanceOfType(serviceCollection[1].ServiceType, typeof(IFakeService)); 185 | Assert.IsInstanceOfType(serviceCollection[1].ImplementationType, typeof(FakeService)); 186 | Assert.IsTrue(serviceCollection[1].Lifetime == ServiceLifetime.Singleton); 187 | } 188 | 189 | [TestMethod] 190 | public static void ServiceCollectionInsert() 191 | { 192 | var serviceCollection = new ServiceCollection(); 193 | var serviceDescriptor1 = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 194 | var serviceDescriptor2 = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 195 | var serviceDescriptor3 = ServiceDescriptor.Describe(typeof(IFakeService), typeof(FakeService), ServiceLifetime.Singleton); 196 | 197 | serviceCollection.Add(serviceDescriptor1); 198 | serviceCollection.Add(serviceDescriptor2); 199 | serviceCollection.Insert(0, serviceDescriptor3); 200 | Assert.AreEqual(3, serviceCollection.Count); 201 | 202 | Assert.IsInstanceOfType(serviceCollection[0].ServiceType, typeof(IFakeService)); 203 | Assert.IsInstanceOfType(serviceCollection[0].ImplementationType, typeof(FakeService)); 204 | Assert.IsTrue(serviceCollection[0].Lifetime == ServiceLifetime.Singleton); 205 | } 206 | 207 | [TestMethod] 208 | public static void ServiceCollectionContains() 209 | { 210 | var serviceCollection = new ServiceCollection(); 211 | var serviceDescriptor1 = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Transient); 212 | var serviceDescriptor2 = ServiceDescriptor.Describe(typeof(IFakeObject), typeof(FakeObject), ServiceLifetime.Singleton); 213 | 214 | serviceCollection.Add(serviceDescriptor1); 215 | Assert.AreEqual(1, serviceCollection.Count); 216 | 217 | Assert.IsTrue(serviceCollection.Contains(serviceDescriptor1)); 218 | Assert.IsFalse(serviceCollection.Contains(serviceDescriptor2)); 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_nanoFramework.DependencyInjection&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_nanoFramework.DependencyInjection) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_nanoFramework.DependencyInjection&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_nanoFramework.DependencyInjection) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.DependencyInjection.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.DependencyInjection/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T) 2 | 3 | ![nanoFramework logo](https://raw.githubusercontent.com/nanoframework/Home/main/resources/logo/nanoFramework-repo-logo.png) 4 | 5 | ----- 6 | 7 | # Welcome to the .NET nanoFramework Dependency Injection Library repository 8 | 9 | Provides Dependency Injection (DI) for Inversion of Control (IoC) between classes and their dependencies built for .NET nanoFramework. 10 | 11 | ## Build status 12 | 13 | | Component | Build Status | NuGet Package | 14 | |:-|---|---| 15 | | nanoFramework.DependencyInjection | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.DependencyInjection/_apis/build/status/nanoFramework.DependencyInjection?branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.DependencyInjection/_build/latest?definitionId=95&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.DependencyInjection.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.DependencyInjection/) | 16 | 17 | ## Samples 18 | 19 | [Dependency Injection Samples](https://github.com/nanoframework/Samples/tree/main/samples/DependencyInjection) 20 | 21 | [Dependency Injection Unit Tests](https://github.com/nanoframework/nanoFramework.DependencyInjection/tree/main/tests) 22 | 23 | ## Dependency Injection Container 24 | 25 | A Dependency Injection (DI) Container provides functionality and automates many of the tasks involved in Object Composition, Interception, and Lifetime Management. It's an engine that resolves and manages object graphs. These DI Containers depend on the static information compiled into all classes. Then using reflection they can analyze the requested class and figure out which Dependencies are required. 26 | 27 | This API mirrors as close as possible the official .NET [DependencyInjection](https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection). Exceptions are mainly derived from the lack of generics support in .NET nanoFramework. 28 | 29 | The .NET nanoFramework [Generic Host](https://github.com/nanoframework/nanoFramework.Hosting) provides convenience methods for creating dependency injection (DI) application containers with preconfigured defaults. 30 | 31 | ## Usage 32 | 33 | ### Service Collection 34 | 35 | Creating a dependency injection container required three basic components. 36 | 37 | - Object Composition - A object composition defining a set of objects to create and couple. 38 | - Registering Services - Define an instance of the ServiceCollection and register the object composition with a specific service lifetime. 39 | - Service Provider - Creating a service provider to retrieve the object. 40 | 41 | ### Object Composition 42 | 43 | Define an object composition to create and couple. 44 | 45 | Note: You can not currently define your objects as 'struct' or include array type parameters (ie. byte[] bytes) as constructor parameters. Doing so will create a null execption when trying to activate object. 46 | 47 | ```csharp 48 | public class RootObject 49 | { 50 | public int One { get; } 51 | 52 | public string Two { get; } 53 | 54 | public ServiceObject ServiceObject { get; protected set; } 55 | 56 | public RootObject(ServiceObject serviceObject) 57 | { 58 | ServiceObject = serviceObject; 59 | } 60 | 61 | // constructor with the most parameters will be used for activation 62 | public RootObject(ServiceObject serviceObject, int one, string two) 63 | { 64 | ServiceObject = serviceObject; 65 | One = one; 66 | Two = two; 67 | } 68 | } 69 | 70 | public class ServiceObject 71 | { 72 | public string Three { get; set; } 73 | } 74 | ``` 75 | 76 | ### Registering Services 77 | 78 | Create a Service Collection and register singleton or transient type services to the collection. 79 | 80 | ```csharp 81 | var serviceProvider = new ServiceCollection() 82 | .AddSingleton(typeof(ServiceObject)) 83 | .AddSingleton(typeof(RootObject)) 84 | .BuildServiceProvider(); 85 | ``` 86 | ### Service Provider 87 | 88 | Create a Service Provider to access or update an object. 89 | 90 | ```csharp 91 | var service = (RootObject)serviceProvider.GetService(typeof(RootObject)); 92 | service.ServiceObject.Three = "3"; 93 | ``` 94 | 95 | Create a scoped Service Provider providing convient access to crate and distroy scoped object. 96 | 97 | ```csharp 98 | var serviceProvider = new ServiceCollection() 99 | .AddScoped(typeof(typeof(ServiceObject)) 100 | .BuildServiceProvider(); 101 | 102 | using (var scope = serviceProvider.CreateScope()) 103 | { 104 | var service = scope.ServiceProvider.GetServices(typeof(ServiceObject)); 105 | service.ServiceObject.Three = "3"; 106 | } 107 | ``` 108 | 109 | ## Activator Utilities 110 | 111 | An instance of an object can be created by calling its constructor with any dependencies resolved through the service provider. Automatically instantiate a type with constructor arguments provided from an IServiceProvider without having to register the type with the DI Container. 112 | 113 | ```csharp 114 | var instance = (RootObject)ActivatorUtilities.CreateInstance( 115 | serviceProvider, typeof(RootObject), 1, "2" 116 | ); 117 | 118 | Debug.WriteLine($"One: {instance.One}"); 119 | Debug.WriteLine($"Two: {instance.Two}"); 120 | Debug.WriteLine($"Three: {instance.ServiceObject.Three}"); 121 | Debug.WriteLine($"Name: {instance.ServiceObject.GetType().Name}"); 122 | ``` 123 | 124 | ### Validate On Build 125 | 126 | A check is performed to ensure that all services registered with the container can actually be created. This can be particularly useful during development to fail fast and allow developers to fix the issue. Validate on build is configured false by default. 127 | 128 | ```csharp 129 | var serviceProvider = new ServiceCollection() 130 | .AddSingleton(typeof(IServiceObject), typeof(ServiceObject)) 131 | .BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true }); 132 | ``` 133 | 134 | ### Validate Scopes 135 | 136 | A check verifying that scoped services never gets resolved from root provider. Validate on build is configured false by default. 137 | 138 | ```csharp 139 | var serviceProvider = new ServiceCollection() 140 | .AddSingleton(typeof(IServiceObject), typeof(ServiceObject)) 141 | .BuildServiceProvider(new ServiceProviderOptions() { ValidateScopes = true }); 142 | ``` 143 | 144 | ## Example Application Container 145 | 146 | ```csharp 147 | using System; 148 | using System.Device.Gpio; 149 | using System.Threading; 150 | 151 | using nanoFramework.Logging.Debug; 152 | using nanoFramework.DependencyInjection; 153 | 154 | using Microsoft.Extensions.Logging; 155 | 156 | nanoFramework.DiApplication 157 | { 158 | public class Program 159 | { 160 | public static void Main() 161 | { 162 | var services = ConfigureServices(); 163 | var application = (Application)services.GetRequiredService(typeof(Application)); 164 | 165 | application.Run(); 166 | } 167 | 168 | private static ServiceProvider ConfigureServices() 169 | { 170 | return new ServiceCollection() 171 | .AddSingleton(typeof(Application)) 172 | .AddSingleton(typeof(IHardwareService), typeof(HardwareService)) 173 | .AddSingleton(typeof(ILoggerFactory), typeof(DebugLoggerFactory)) 174 | .BuildServiceProvider(); 175 | } 176 | } 177 | 178 | internal class Application 179 | { 180 | private readonly ILogger _logger; 181 | private readonly IHardwareService _hardware; 182 | private readonly IServiceProvider _provider; 183 | 184 | public Application( 185 | IServiceProvider provider, 186 | IHardwareService hardware, 187 | ILoggerFactory loggerFactory) 188 | { 189 | _provider = provider; 190 | _hardware = hardware; 191 | _logger = loggerFactory.CreateLogger(nameof(Application)); 192 | 193 | _logger.LogInformation("Initializing application..."); 194 | } 195 | 196 | public void Run() 197 | { 198 | var ledPin = 23; // Set pin number to blink 15=ESP32; 23=STM32 199 | 200 | _logger.LogInformation($"Started blinking led on pin {ledPin}."); 201 | _hardware.StartBlinking(ledPin); 202 | } 203 | } 204 | 205 | internal interface IHardwareService 206 | { 207 | public void StartBlinking(int ledPin) { } 208 | } 209 | 210 | internal class HardwareService : IHardwareService, IDisposable 211 | { 212 | private Thread _thread; 213 | private readonly ILogger _logger; 214 | private readonly GpioController _gpioController; 215 | 216 | public HardwareService() 217 | { 218 | _gpioController = new GpioController(); 219 | 220 | var loggerFactory = new DebugLoggerFactory(); 221 | _logger = loggerFactory.CreateLogger(nameof(HardwareService)); 222 | } 223 | 224 | public HardwareService(ILoggerFactory loggerFactory) 225 | { 226 | _gpioController = new GpioController(); 227 | _logger = loggerFactory.CreateLogger(nameof(HardwareService)); 228 | } 229 | 230 | public void StartBlinking(int ledPin) 231 | { 232 | GpioPin led = _gpioController.OpenPin(ledPin, PinMode.Output); 233 | led.Write(PinValue.Low); 234 | 235 | _thread = new Thread(() => 236 | { 237 | while (true) 238 | { 239 | Thread.Sleep(2000); 240 | 241 | led.Write(PinValue.High); 242 | _logger.LogInformation("Led status: on"); 243 | 244 | Thread.Sleep(2000); 245 | 246 | led.Write(PinValue.Low); 247 | _logger.LogInformation("Led status: off"); 248 | } 249 | }); 250 | 251 | _thread.Start(); 252 | } 253 | 254 | public void Dispose() 255 | { 256 | _gpioController.Dispose(); 257 | } 258 | } 259 | } 260 | ``` 261 | 262 | ## Feedback and documentation 263 | 264 | For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home). 265 | 266 | Join our Discord community [here](https://discord.gg/gCyBu8T). 267 | 268 | ## Credits 269 | 270 | The list of contributors to this project can be found at [CONTRIBUTORS](https://github.com/nanoframework/Home/blob/main/CONTRIBUTORS.md). 271 | 272 | ## License 273 | 274 | The **nanoFramework** Class Libraries are licensed under the [MIT license](LICENSE.md). 275 | 276 | ## Code of Conduct 277 | 278 | This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behaviour in our community. 279 | For more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 280 | 281 | ## .NET Foundation 282 | 283 | This project is supported by the [.NET Foundation](https://dotnetfoundation.org). 284 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | /// 11 | /// Extension methods for adding services to an . 12 | /// 13 | public static class ServiceCollectionServiceExtensions 14 | { 15 | /// 16 | /// Adds a transient service of the type specified in with an 17 | /// implementation of the type specified in to the 18 | /// specified . 19 | /// 20 | /// The to add the service to. 21 | /// The type of the service to register. 22 | /// The implementation type of the service. 23 | /// A reference to this instance after the operation has completed. 24 | /// 25 | public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Type implementationType) 26 | { 27 | ArgumentNullException.ThrowIfNull(services); 28 | ArgumentNullException.ThrowIfNull(serviceType); 29 | ArgumentNullException.ThrowIfNull(implementationType); 30 | 31 | return Add(services, serviceType, implementationType, ServiceLifetime.Transient); 32 | } 33 | 34 | /// 35 | /// Adds a transient service of the type specified in with a 36 | /// factory specified in to the 37 | /// specified . 38 | /// 39 | /// The to add the service to. 40 | /// The type of the service to register. 41 | /// The factory that creates the service. 42 | /// A reference to this instance after the operation has completed. 43 | /// 44 | public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, ImplementationFactoryDelegate implementationFactory) 45 | { 46 | ArgumentNullException.ThrowIfNull(services); 47 | ArgumentNullException.ThrowIfNull(serviceType); 48 | ArgumentNullException.ThrowIfNull(implementationFactory); 49 | 50 | return Add(services, serviceType, implementationFactory, ServiceLifetime.Transient); 51 | } 52 | 53 | /// 54 | /// Adds a transient service of the type specified in to the 55 | /// specified . 56 | /// 57 | /// The to add the service to. 58 | /// The type of the service to register and the implementation to use. 59 | /// A reference to this instance after the operation has completed. 60 | /// 61 | public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType) 62 | { 63 | ArgumentNullException.ThrowIfNull(services); 64 | ArgumentNullException.ThrowIfNull(serviceType); 65 | 66 | return services.AddTransient(serviceType, serviceType); 67 | } 68 | 69 | /// 70 | /// Adds a scoped service of the type specified in with an 71 | /// implementation of the type specified in to the 72 | /// specified . 73 | /// 74 | /// The to add the service to. 75 | /// The type of the service to register. 76 | /// The implementation type of the service. 77 | /// A reference to this instance after the operation has completed. 78 | /// 79 | public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType, Type implementationType) 80 | { 81 | ArgumentNullException.ThrowIfNull(services); 82 | ArgumentNullException.ThrowIfNull(serviceType); 83 | ArgumentNullException.ThrowIfNull(implementationType); 84 | 85 | return Add(services, serviceType, implementationType, ServiceLifetime.Scoped); 86 | } 87 | 88 | /// 89 | /// Adds a scoped service of the type specified in with a 90 | /// factory specified in to the 91 | /// specified . 92 | /// 93 | /// The to add the service to. 94 | /// The type of the service to register. 95 | /// The factory that creates the service. 96 | /// A reference to this instance after the operation has completed. 97 | /// 98 | public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType, ImplementationFactoryDelegate implementationFactory) 99 | { 100 | ArgumentNullException.ThrowIfNull(services); 101 | ArgumentNullException.ThrowIfNull(serviceType); 102 | ArgumentNullException.ThrowIfNull(implementationFactory); 103 | 104 | return Add(services, serviceType, implementationFactory, ServiceLifetime.Scoped); 105 | } 106 | 107 | /// 108 | /// Adds a scoped service of the type specified in to the 109 | /// specified . 110 | /// 111 | /// The to add the service to. 112 | /// The type of the service to register and the implementation to use. 113 | /// A reference to this instance after the operation has completed. 114 | /// 115 | public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType) 116 | { 117 | ArgumentNullException.ThrowIfNull(services); 118 | ArgumentNullException.ThrowIfNull(serviceType); 119 | 120 | return services.AddScoped(serviceType, serviceType); 121 | } 122 | 123 | /// 124 | /// Adds a singleton service of the type specified in with an 125 | /// implementation of the type specified in to the 126 | /// specified . 127 | /// 128 | /// The to add the service to. 129 | /// The type of the service to register. 130 | /// The implementation type of the service. 131 | /// A reference to this instance after the operation has completed. 132 | /// 133 | public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, Type implementationType) 134 | { 135 | ArgumentNullException.ThrowIfNull(services); 136 | ArgumentNullException.ThrowIfNull(serviceType); 137 | ArgumentNullException.ThrowIfNull(implementationType); 138 | 139 | return Add(services, serviceType, implementationType, ServiceLifetime.Singleton); 140 | } 141 | 142 | /// 143 | /// Adds a singleton service of the type specified in with a 144 | /// factory specified in to the 145 | /// specified . 146 | /// 147 | /// The to add the service to. 148 | /// The type of the service to register. 149 | /// The factory that creates the service. 150 | /// A reference to this instance after the operation has completed. 151 | /// 152 | public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, ImplementationFactoryDelegate implementationFactory) 153 | { 154 | ArgumentNullException.ThrowIfNull(services); 155 | ArgumentNullException.ThrowIfNull(serviceType); 156 | ArgumentNullException.ThrowIfNull(implementationFactory); 157 | 158 | return Add(services, serviceType, implementationFactory, ServiceLifetime.Singleton); 159 | } 160 | 161 | /// 162 | /// Adds a singleton service of the type specified in to the 163 | /// specified . 164 | /// 165 | /// The to add the service to. 166 | /// The type of the service to register and the implementation to use. 167 | /// A reference to this instance after the operation has completed. 168 | /// 169 | public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType) 170 | { 171 | ArgumentNullException.ThrowIfNull(services); 172 | ArgumentNullException.ThrowIfNull(serviceType); 173 | 174 | return services.AddSingleton(serviceType, serviceType); 175 | } 176 | 177 | /// 178 | /// Adds a singleton service of the type specified in with an 179 | /// instance specified in to the 180 | /// specified . 181 | /// 182 | /// The to add the service to. 183 | /// The type of the service to register. 184 | /// The instance of the service. 185 | /// A reference to this instance after the operation has completed. 186 | /// 187 | public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, object implementationInstance) 188 | { 189 | ArgumentNullException.ThrowIfNull(services); 190 | ArgumentNullException.ThrowIfNull(serviceType); 191 | ArgumentNullException.ThrowIfNull(implementationInstance); 192 | 193 | var serviceDescriptor = new ServiceDescriptor(serviceType, implementationInstance); 194 | services.Add(serviceDescriptor); 195 | return services; 196 | } 197 | 198 | private static IServiceCollection Add(IServiceCollection collection, Type serviceType, Type implementationType, ServiceLifetime lifetime) 199 | { 200 | var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime); 201 | collection.Add(descriptor); 202 | return collection; 203 | } 204 | 205 | private static IServiceCollection Add(IServiceCollection collection, Type serviceType, ImplementationFactoryDelegate implementationFactory, ServiceLifetime lifetime) 206 | { 207 | var descriptor = new ServiceDescriptor(serviceType, implementationFactory, lifetime); 208 | collection.Add(descriptor); 209 | return collection; 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceDescriptor.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Diagnostics; 8 | 9 | namespace Microsoft.Extensions.DependencyInjection 10 | { 11 | /// 12 | /// Service Factory method delegate 13 | /// 14 | public delegate object ImplementationFactoryDelegate(IServiceProvider serviceProvider); 15 | 16 | /// 17 | /// Describes a service with its service type, implementation, and lifetime. 18 | /// 19 | [DebuggerDisplay("Lifetime = {Lifetime}, ServiceType = {ServiceType}, ImplementationType = {ImplementationType}")] 20 | public class ServiceDescriptor 21 | { 22 | /// 23 | /// Initializes a new instance of with the specified . 24 | /// 25 | /// The of the service. 26 | /// The implementing the service. 27 | /// The of the service. 28 | /// or can't be null 29 | /// Implementation type cannot be an abstract or interface class. 30 | public ServiceDescriptor(Type serviceType, Type implementationType, ServiceLifetime lifetime): this(serviceType, lifetime) 31 | { 32 | ArgumentNullException.ThrowIfNull(serviceType); 33 | ArgumentNullException.ThrowIfNull(implementationType); 34 | 35 | if (implementationType.IsAbstract || implementationType.IsInterface) 36 | { 37 | throw new ArgumentException(); 38 | } 39 | 40 | ImplementationType = implementationType; 41 | } 42 | 43 | /// 44 | /// Initializes a new instance of with the specified 45 | /// as a . 46 | /// 47 | /// The of the service. 48 | /// The instance implementing the service. 49 | /// or can't be 50 | public ServiceDescriptor(Type serviceType, object instance): this(serviceType, ServiceLifetime.Singleton) 51 | { 52 | ArgumentNullException.ThrowIfNull(serviceType); 53 | ArgumentNullException.ThrowIfNull(instance); 54 | 55 | ImplementationInstance = instance; 56 | ImplementationType = instance.GetType(); 57 | } 58 | 59 | /// 60 | /// Initializes a new instance of with the specified . 61 | /// 62 | /// The of the service. 63 | /// A factory used for creating service instances. 64 | /// The of the service. 65 | /// can't be null 66 | /// can't be null 67 | /// Implementation type cannot be an abstract or interface class. 68 | public ServiceDescriptor(Type serviceType, ImplementationFactoryDelegate implementationFactory, ServiceLifetime lifetime): this(serviceType, lifetime) 69 | { 70 | ArgumentNullException.ThrowIfNull(serviceType); 71 | ArgumentNullException.ThrowIfNull(implementationFactory); 72 | 73 | ImplementationFactory = implementationFactory; 74 | } 75 | 76 | private ServiceDescriptor(Type serviceType, ServiceLifetime lifetime) 77 | { 78 | ServiceType = serviceType; 79 | Lifetime = lifetime; 80 | } 81 | 82 | /// 83 | /// The of the service. 84 | /// 85 | public ServiceLifetime Lifetime { get; } 86 | 87 | /// 88 | /// The of the service. 89 | /// 90 | public Type ServiceType { get; } 91 | 92 | /// 93 | /// The implementing the service. 94 | /// 95 | public Type ImplementationType { get; } 96 | 97 | /// 98 | /// The instance of the implementation. 99 | /// 100 | public object ImplementationInstance { get; set; } 101 | 102 | /// 103 | /// Gets the factory used for creating service instances. 104 | /// 105 | public ImplementationFactoryDelegate ImplementationFactory { get; set; } 106 | 107 | /// 108 | /// Returns a string that represents the current object. 109 | /// 110 | public override string ToString() 111 | { 112 | string lifetime = $"{nameof(ServiceType)}: {ServiceType} {nameof(Lifetime)}: {Lifetime} "; 113 | 114 | if (ImplementationType != null) 115 | { 116 | return lifetime + $"{nameof(ImplementationType)}: {ImplementationType}"; 117 | } 118 | 119 | return lifetime + $"{nameof(ImplementationInstance)}: {ImplementationInstance}"; 120 | } 121 | 122 | /// 123 | /// Returns the implementing the instance. 124 | /// 125 | public Type GetImplementationType() 126 | { 127 | if (ImplementationType != null) 128 | { 129 | return ImplementationType; 130 | } 131 | else if (ImplementationInstance != null) 132 | { 133 | return ImplementationInstance.GetType(); 134 | } 135 | // TODO: This case is not currently handled which means we cannot currently support factories in the TryAdd methods. 136 | // A possible solution would be to require the implementation type to be supplied with the factory. 137 | /* 138 | else if (ImplementationFactory != null) 139 | { 140 | Type[]? typeArguments = ImplementationFactory.GetType().GenericTypeArguments; 141 | 142 | Debug.Assert(typeArguments.Length == 2); 143 | 144 | return typeArguments[1]; 145 | } 146 | */ 147 | 148 | Debug.Assert(false, "ImplementationType and ImplementationInstance must be non null"); 149 | 150 | return null; 151 | } 152 | 153 | /// 154 | /// Creates an instance of with the specified 155 | /// , , 156 | /// and . 157 | /// 158 | /// The type of the service. 159 | /// The type of the implementation. 160 | /// The lifetime of the service. 161 | /// A new instance of . 162 | public static ServiceDescriptor Describe(Type serviceType, Type implementationType, ServiceLifetime lifetime) 163 | { 164 | ArgumentNullException.ThrowIfNull(serviceType); 165 | ArgumentNullException.ThrowIfNull(implementationType); 166 | 167 | return new ServiceDescriptor(serviceType, implementationType, lifetime); 168 | } 169 | 170 | /// 171 | /// Creates an instance of with the specified 172 | /// , , 173 | /// and . 174 | /// 175 | /// The type of the service. 176 | /// A factory to create new instances of the service implementation. 177 | /// The lifetime of the service. 178 | /// A new instance of . 179 | public static ServiceDescriptor Describe(Type serviceType, ImplementationFactoryDelegate implementationFactory, ServiceLifetime lifetime) 180 | { 181 | ArgumentNullException.ThrowIfNull(serviceType); 182 | ArgumentNullException.ThrowIfNull(implementationFactory); 183 | 184 | return new ServiceDescriptor(serviceType, implementationFactory, lifetime); 185 | } 186 | 187 | /// 188 | /// Creates an instance of with the specified 189 | /// and 190 | /// and the lifetime. 191 | /// 192 | /// The type of the service. 193 | /// The type of the implementation. 194 | /// A new instance of . 195 | public static ServiceDescriptor Scoped(Type service, Type implementationType) 196 | { 197 | return Describe(service, implementationType, ServiceLifetime.Scoped); 198 | } 199 | 200 | /// 201 | /// Creates an instance of with the specified 202 | /// and 203 | /// and the lifetime. 204 | /// 205 | /// The type of the service. 206 | /// A factory to create new instances of the service implementation. 207 | /// A new instance of . 208 | public static ServiceDescriptor Scoped(Type service, ImplementationFactoryDelegate implementationFactory) 209 | { 210 | return Describe(service, implementationFactory, ServiceLifetime.Scoped); 211 | } 212 | 213 | /// 214 | /// Creates an instance of with the specified 215 | /// and 216 | /// and the lifetime. 217 | /// 218 | /// The type of the service. 219 | /// The type of the implementation. 220 | /// A new instance of . 221 | public static ServiceDescriptor Singleton(Type service, Type implementationType) 222 | { 223 | return Describe(service, implementationType, ServiceLifetime.Singleton); 224 | } 225 | 226 | /// 227 | /// Creates an instance of with the specified 228 | /// and 229 | /// and the lifetime. 230 | /// 231 | /// The type of the service. 232 | /// A factory to create new instances of the service implementation. 233 | /// A new instance of . 234 | public static ServiceDescriptor Singleton(Type service, ImplementationFactoryDelegate implementationFactory) 235 | { 236 | return Describe(service, implementationFactory, ServiceLifetime.Singleton); 237 | } 238 | 239 | /// 240 | /// Creates an instance of with the specified 241 | /// and 242 | /// and the lifetime. 243 | /// 244 | /// The type of the service. 245 | /// The type of the implementation. 246 | /// A new instance of . 247 | public static ServiceDescriptor Transient(Type service, Type implementationType) 248 | { 249 | return Describe(service, implementationType, ServiceLifetime.Transient); 250 | } 251 | 252 | /// 253 | /// Creates an instance of with the specified 254 | /// and 255 | /// and the lifetime. 256 | /// 257 | /// The type of the service. 258 | /// A factory to create new instances of the service implementation. 259 | /// A new instance of . 260 | public static ServiceDescriptor Transient(Type service, ImplementationFactoryDelegate implementationFactory) 261 | { 262 | return Describe(service, implementationFactory, ServiceLifetime.Transient); 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /nanoFramework.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceProviderEngine.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) .NET Foundation and Contributors 3 | // See LICENSE file in the project root for full license information. 4 | // 5 | 6 | using System; 7 | using System.Reflection; 8 | using System.Collections; 9 | 10 | namespace Microsoft.Extensions.DependencyInjection 11 | { 12 | /// 13 | /// Defines an engine for managing services that provides custom support to other objects. 14 | /// 15 | internal sealed class ServiceProviderEngine 16 | { 17 | internal static ServiceProviderEngine Instance { get; } = new ServiceProviderEngine(); 18 | 19 | private ServiceProviderEngine() { } 20 | 21 | /// 22 | /// A collection of implemented services. 23 | /// 24 | internal IServiceCollection Services { get; set; } 25 | 26 | /// 27 | /// ServiceProvider Options instance 28 | /// 29 | internal ServiceProviderOptions Options { get; set; } 30 | 31 | /// 32 | /// Validate service by attempting to activate all dependent services. 33 | /// 34 | internal void ValidateService(ServiceDescriptor descriptor) 35 | { 36 | GetService(descriptor.GetImplementationType()); 37 | } 38 | 39 | /// 40 | /// Dispose of all service descriptors in services. 41 | /// 42 | internal void DisposeServices() 43 | { 44 | for (int index = Services.Count - 1; index >= 0; index--) 45 | { 46 | if (Services[index].ImplementationInstance is IDisposable disposable) 47 | { 48 | disposable.Dispose(); 49 | } 50 | } 51 | } 52 | 53 | /// 54 | /// Gets the last added service object of the specified type. 55 | /// 56 | /// An object that specifies the type of service object to get. 57 | /// Services collection from current scope. 58 | internal object GetService(Type serviceType, IServiceCollection scopeServices = null) 59 | { 60 | var services = GetServiceObjects(serviceType, scopeServices); 61 | 62 | if (services.Length == 0) 63 | { 64 | return null; 65 | } 66 | 67 | // returns the last added service of this type 68 | return services[services.Length - 1]; 69 | } 70 | 71 | /// 72 | /// Gets the service objects of the specified type. 73 | /// 74 | /// An object that specifies the type of service object to get. 75 | /// Services collection from current scope. 76 | /// can't be . 77 | /// can't be empty. 78 | internal object[] GetService(Type[] serviceType, IServiceCollection scopeServices = null) 79 | { 80 | if (serviceType == null) 81 | { 82 | throw new ArgumentNullException(); 83 | } 84 | 85 | if (serviceType.Length == 0) 86 | { 87 | throw new ArgumentException(); 88 | } 89 | 90 | // optimized for single item service type 91 | if (serviceType.Length == 1) 92 | { 93 | var services = GetServiceObjects(serviceType[0], scopeServices); 94 | 95 | if (services.Length > 0) 96 | { 97 | return services; 98 | } 99 | 100 | return new object[0]; 101 | } 102 | 103 | // multiple service type items 104 | object[] array = new object[0]; 105 | 106 | foreach (Type type in serviceType) 107 | { 108 | var services = GetServiceObjects(type, scopeServices); 109 | 110 | if (services.Length > 0) 111 | { 112 | var newArray = new object[array.Length + services.Length]; 113 | 114 | Array.Copy(array, newArray, array.Length); 115 | Array.Copy(services, 0, newArray, array.Length, services.Length); 116 | 117 | array = newArray; 118 | } 119 | } 120 | 121 | return array.Length != 0 ? array : new object[0]; 122 | } 123 | 124 | /// 125 | /// Gets the service objects of the specified type. 126 | /// 127 | /// An object that specifies the type of service object to get. 128 | /// Services collection from current scope. 129 | private object[] GetServiceObjects(Type serviceType, IServiceCollection scopeServices) 130 | { 131 | ArrayList services = new ArrayList(); 132 | 133 | if (scopeServices != null) 134 | { 135 | foreach (ServiceDescriptor descriptor in scopeServices) 136 | { 137 | if (descriptor.ServiceType != serviceType) continue; 138 | 139 | descriptor.ImplementationInstance ??= 140 | descriptor.ImplementationFactory?.Invoke((IServiceProvider)GetService(typeof(IServiceProvider))) 141 | ?? Resolve(descriptor.ImplementationType); 142 | services.Add(descriptor.ImplementationInstance); 143 | } 144 | } 145 | 146 | foreach (ServiceDescriptor descriptor in Services) 147 | { 148 | if (descriptor.ServiceType != serviceType) continue; 149 | 150 | switch (descriptor.Lifetime) 151 | { 152 | case ServiceLifetime.Singleton: 153 | descriptor.ImplementationInstance ??= 154 | descriptor.ImplementationFactory?.Invoke((IServiceProvider)GetService(typeof(IServiceProvider))) 155 | ?? Resolve(descriptor.ImplementationType); 156 | services.Add(descriptor.ImplementationInstance); 157 | break; 158 | 159 | case ServiceLifetime.Transient: 160 | services.Add(descriptor.ImplementationFactory?.Invoke((IServiceProvider)GetService(typeof(IServiceProvider))) 161 | ?? Resolve(descriptor.ImplementationType)); 162 | break; 163 | 164 | case ServiceLifetime.Scoped: 165 | if (scopeServices == null && Options.ValidateScopes) 166 | { 167 | throw new InvalidOperationException(); 168 | } 169 | break; 170 | } 171 | } 172 | 173 | return (object[])services.ToArray(typeof(object)); 174 | } 175 | 176 | /// 177 | /// Resolve and activates the specified implementation type. 178 | /// 179 | /// An object that specifies the implementation type of service object to get. 180 | /// A suitable constructor for type could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor. 181 | /// Unable to resolve service for type while attempting to activate. 182 | private object Resolve(Type implementationType) 183 | { 184 | object instance; 185 | 186 | ParameterInfo[] constructorParameters = GetParameters(implementationType); 187 | 188 | if (constructorParameters == null) 189 | { 190 | throw new InvalidOperationException( 191 | $"Constructor for '{implementationType}' could not be located."); 192 | } 193 | 194 | if (constructorParameters.Length == 0) 195 | { 196 | instance = Activator.CreateInstance(implementationType); 197 | } 198 | else 199 | { 200 | Type[] types = new Type[constructorParameters.Length]; 201 | object[] parameters = new object[constructorParameters.Length]; 202 | 203 | for (int index = 0; index < constructorParameters.Length; index++) 204 | { 205 | var parameterType = constructorParameters[index].ParameterType; 206 | 207 | if (parameterType.IsResolvable()) 208 | { 209 | types[index] = parameterType; 210 | parameters[index] = GetResolvableDefault(parameterType); 211 | } 212 | else 213 | { 214 | var service = parameterType.IsArray ? 215 | GetServiceObjects(parameterType.GetElementType(), null) : 216 | GetService(parameterType); 217 | 218 | if (service == null) 219 | { 220 | throw new InvalidOperationException( 221 | $"Unable to resolve service for '{parameterType}'."); 222 | } 223 | 224 | types[index] = parameterType; 225 | parameters[index] = service; 226 | } 227 | } 228 | 229 | instance = Activator.CreateInstance(implementationType, types, parameters); 230 | } 231 | 232 | return instance; 233 | } 234 | 235 | /// 236 | /// Gets the parameters from the constructor with the most parameters that can be resolved. 237 | /// 238 | /// An object that specifies the implementation type of service object to get. 239 | /// Multiple constructors accepting all given argument types have been found in type . There should only be one applicable constructor. 240 | private ParameterInfo[] GetParameters(Type implementationType) 241 | { 242 | int bestLength = -1; 243 | 244 | ParameterInfo[] bestParameters = null; 245 | ConstructorInfo[] constructors = implementationType.GetConstructors(); 246 | 247 | // step 1: check for multiple constructors with same number of arguments 248 | for (int i = 0; i < constructors.Length; i++) 249 | { 250 | for (int j = i; j < constructors.Length - 1; j++) 251 | { 252 | if (constructors[j].GetParameters().Length == constructors[j + 1].GetParameters().Length) 253 | { 254 | throw new InvalidOperationException( 255 | $"Multiple constructors found in '{implementationType}'."); 256 | } 257 | } 258 | } 259 | 260 | // step 2: get the constructor with the most resolvable parameters 261 | foreach (ConstructorInfo constructor in constructors) 262 | { 263 | ParameterInfo[] parameters = constructor.GetParameters(); 264 | 265 | int length = parameters.Length; 266 | 267 | foreach (ParameterInfo parameter in parameters) 268 | { 269 | Type type = parameter.ParameterType; 270 | 271 | if (type.IsResolvable()) 272 | { 273 | // check for simple binding first 274 | } 275 | else 276 | { 277 | if (!IsService(type)) 278 | { 279 | // binding could not be resolved ignore constructor 280 | length = -1; 281 | break; 282 | } 283 | 284 | } 285 | } 286 | 287 | if (bestLength < length) 288 | { 289 | bestLength = length; 290 | bestParameters = parameters; 291 | } 292 | } 293 | 294 | return bestParameters; 295 | } 296 | 297 | /// 298 | /// Get primitive default type. 299 | /// 300 | private static object GetResolvableDefault(Type type) 301 | { 302 | // This list dosn't match the IsResolvable() because 303 | // we only check for items we know are not null by default 304 | if (type == typeof(object)) return default; 305 | if (type == typeof(int)) return default(int); 306 | if (type == typeof(uint)) return default(uint); 307 | if (type == typeof(bool)) return default(bool); 308 | if (type == typeof(char)) return default(char); 309 | if (type == typeof(byte)) return default(byte); 310 | if (type == typeof(sbyte)) return default(sbyte); 311 | if (type == typeof(short)) return default(short); 312 | if (type == typeof(ushort)) return default(ushort); 313 | if (type == typeof(long)) return default(long); 314 | if (type == typeof(ulong)) return default(ulong); 315 | if (type == typeof(double)) return default(double); 316 | if (type == typeof(float)) return default(float); 317 | if (type == typeof(Guid)) return default(Guid); 318 | if (type == typeof(DateTime)) return default(DateTime); 319 | if (type == typeof(TimeSpan)) return default(TimeSpan); 320 | 321 | return null; 322 | } 323 | 324 | /// 325 | /// Determines if the specified service type is available from the . 326 | /// 327 | /// An object that specifies the type of service object to test. 328 | /// true if the specified service is a available, false if it is not. 329 | internal bool IsService(Type serviceType) 330 | { 331 | if (serviceType.IsArray) 332 | { 333 | serviceType = serviceType.GetElementType(); 334 | } 335 | 336 | foreach (ServiceDescriptor descriptor in Services) 337 | { 338 | if (descriptor.ServiceType == serviceType) 339 | { 340 | return true; 341 | } 342 | } 343 | 344 | return false; 345 | } 346 | } 347 | } 348 | --------------------------------------------------------------------------------