├── .github └── FUNDING.yml ├── src ├── package.snk ├── Properties │ └── AssemblyInfo.cs ├── ServiceLocatorProvider.cs ├── Exceptions │ ├── ActivationException.Desktop.cs │ └── ActivationException.cs ├── ServiceLocator.cs ├── CommonServiceLocator.csproj ├── IServiceLocator.cs ├── net40 │ └── TypeInfo.cs └── ServiceLocatorImplBase.cs ├── codecov.yml ├── test ├── Components │ ├── ILogger.cs │ ├── SimpleLogger.cs │ └── AdvancedLogger.cs ├── CommonServiceLocator.Tests.csproj ├── MockServiceLocator.cs ├── ServiceLocatorFixture.cs └── ServiceLocatorAdapterFixture.cs ├── package.props ├── appveyor.yml ├── azure-pipelines-pr.yml ├── azure-pipelines-test.yml ├── package.sln ├── azure-pipelines.yml ├── LICENSE ├── README.md └── .gitignore /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [ENikS] 2 | open_collective: unity-container 3 | -------------------------------------------------------------------------------- /src/package.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unitycontainer/commonservicelocator/HEAD/src/package.snk -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security; 3 | 4 | [assembly:CLSCompliant(true)] 5 | [assembly:SecurityTransparent] 6 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "tests/*" # Ignore tests 3 | - "src/Utility/*" # Ignore utilities 4 | - "**/*.Designer.cs" # Ignore generated code 5 | -------------------------------------------------------------------------------- /test/Components/ILogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 | 3 | namespace ServiceLocation.Tests.Components 4 | { 5 | public interface ILogger 6 | { 7 | void Log(string msg); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Components/SimpleLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 | 3 | using System; 4 | 5 | namespace ServiceLocation.Tests.Components 6 | { 7 | public class SimpleLogger : ILogger 8 | { 9 | public void Log(string msg) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Components/AdvancedLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 | 3 | using System; 4 | 5 | namespace ServiceLocation.Tests.Components 6 | { 7 | public class AdvancedLogger : ILogger 8 | { 9 | public void Log(string msg) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ServiceLocatorProvider.cs: -------------------------------------------------------------------------------- 1 | namespace CommonServiceLocator 2 | { 3 | /// 4 | /// This delegate type is used to provide a method that will 5 | /// return the current container. Used with the 6 | /// static accessor class. 7 | /// 8 | /// An . 9 | public delegate IServiceLocator ServiceLocatorProvider(); 10 | } 11 | -------------------------------------------------------------------------------- /package.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.0.7 5 | netcoreapp3.0;netcoreapp2.0;netcoreapp1.0;netstandard1.0;netstandard2.0;netstandard2.1;net46;net47;net48;net50;net6.0;net7.0 6 | 7 | 8 | 9 | This release contains targets for .NET 4.7, and 4.8, 5.0, 6.0, 7.0 .NET Core 1.0, 2.0 and 3.0, .NET Standard 1.0, .NET Standard 2.0 and .NET Standard 2.1 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/CommonServiceLocator.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2022 2 | configuration: Release 3 | 4 | install: 5 | - ps: $env:build_version = (Select-Xml -Path ".\src\CommonServiceLocator.csproj" -XPath "/Project/PropertyGroup/Version" | Select-Object -ExpandProperty Node).InnerText 6 | - ps: Update-AppveyorBuild -Version "$env:build_version.$env:APPVEYOR_BUILD_NUMBER" 7 | 8 | before_build: 9 | - cmd: dotnet restore 10 | 11 | build: 12 | project: package.sln 13 | parallel: true 14 | verbosity: minimal 15 | 16 | dotnet_csproj: 17 | patch: false 18 | 19 | artifacts: 20 | - path: '**\CommonServiceLocator.*.nupkg' 21 | name: 'CommonServiceLocator' 22 | -------------------------------------------------------------------------------- /azure-pipelines-pr.yml: -------------------------------------------------------------------------------- 1 | # Pull Request build 2 | 3 | pr: 4 | branches: 5 | include: 6 | - master 7 | 8 | pool: 9 | vmImage: 'windows-latest' 10 | 11 | variables: 12 | solution: '**/*.sln' 13 | buildPlatform: 'Any CPU' 14 | buildConfiguration: 'Release' 15 | 16 | steps: 17 | - task: NuGetToolInstaller@1 18 | 19 | - task: NuGetCommand@2 20 | inputs: 21 | restoreSolution: '$(solution)' 22 | 23 | - task: VSBuild@1 24 | inputs: 25 | solution: '$(solution)' 26 | platform: '$(buildPlatform)' 27 | configuration: '$(buildConfiguration)' 28 | 29 | - task: VSTest@2 30 | inputs: 31 | platform: '$(buildPlatform)' 32 | configuration: '$(buildConfiguration)' 33 | -------------------------------------------------------------------------------- /azure-pipelines-test.yml: -------------------------------------------------------------------------------- 1 | # Build pipeline 2 | 3 | trigger: 4 | - master 5 | 6 | pool: 7 | vmImage: 'windows-latest' 8 | 9 | variables: 10 | solution: '**/*.csproj' 11 | buildPlatform: 'Any CPU' 12 | buildConfiguration: 'Release' 13 | OutputPath: '$(build.artifactstagingdirectory)' 14 | 15 | steps: 16 | - task: NuGetToolInstaller@1 17 | 18 | - task: NuGetCommand@2 19 | inputs: 20 | restoreSolution: '$(solution)' 21 | 22 | - task: VSBuild@1 23 | inputs: 24 | solution: '$(solution)' 25 | platform: '$(buildPlatform)' 26 | configuration: '$(buildConfiguration)' 27 | 28 | - task: VSTest@2 29 | inputs: 30 | platform: '$(buildPlatform)' 31 | configuration: '$(buildConfiguration)' 32 | 33 | - task: PublishBuildArtifacts@1 34 | displayName: 'Publish Artifact' 35 | inputs: 36 | PathtoPublish: '$(build.artifactstagingdirectory)' 37 | ArtifactName: 'Package' 38 | 39 | -------------------------------------------------------------------------------- /test/MockServiceLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using CommonServiceLocator; 5 | 6 | namespace ServiceLocation.Tests.Mocks 7 | { 8 | public class MockServiceLocator : ServiceLocatorImplBase 9 | { 10 | private readonly IEnumerable _objects; 11 | 12 | public MockServiceLocator(IEnumerable list) 13 | { 14 | _objects = list; 15 | } 16 | 17 | 18 | 19 | protected override object DoGetInstance(Type serviceType, string key) 20 | { 21 | return null == key ? _objects.First(o => serviceType.IsAssignableFrom(o.GetType())) 22 | : _objects.First(o => serviceType.IsAssignableFrom(o.GetType()) && Equals(key, o.GetType().FullName)); 23 | } 24 | 25 | protected override IEnumerable DoGetAllInstances(Type serviceType) 26 | { 27 | return _objects.Where(o => serviceType.IsAssignableFrom(o.GetType())); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/ServiceLocatorFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CommonServiceLocator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using ServiceLocation.Tests.Mocks; 5 | 6 | namespace ServiceLocation.Tests 7 | { 8 | [TestClass] 9 | public class ServiceLocatorFixture 10 | { 11 | [TestInitialize] 12 | public void TestInit() 13 | { 14 | ServiceLocator.SetLocatorProvider(null); 15 | } 16 | 17 | [TestMethod] 18 | public void ServiceLocatorIsLocationProviderSetReturnsTrueWhenSet() 19 | { 20 | ServiceLocator.SetLocatorProvider(() => new MockServiceLocator(null)); 21 | 22 | Assert.IsTrue(ServiceLocator.IsLocationProviderSet); 23 | } 24 | 25 | [TestMethod] 26 | public void ServiceLocatorIsLocationProviderSetReturnsFalseWhenNotSet() 27 | { 28 | Assert.IsFalse(ServiceLocator.IsLocationProviderSet); 29 | } 30 | 31 | [TestMethod] 32 | [ExpectedException(typeof(InvalidOperationException))] 33 | public void ServiceLocatorCurrentThrowsWhenLocationProviderNotSet() 34 | { 35 | var currentServiceLocator = ServiceLocator.Current; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Exceptions/ActivationException.Desktop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace CommonServiceLocator 5 | { 6 | [Serializable] 7 | public partial class ActivationException 8 | { 9 | /// 10 | /// Initializes a new instance of the class with serialized data. 11 | /// 12 | /// 13 | /// The that holds the serialized object data about the exception being thrown. 14 | /// 15 | /// 16 | /// The that contains contextual information about the source or destination. 17 | /// 18 | /// 19 | /// The parameter is null. 20 | /// 21 | /// 22 | /// The class name is null or is zero (0). 23 | /// 24 | protected ActivationException(SerializationInfo info, StreamingContext context) 25 | : base(info, context) {} 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/ServiceLocatorAdapterFixture.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 | 3 | using System; 4 | using CommonServiceLocator; 5 | using ServiceLocation.Tests.Components; 6 | using ServiceLocation.Tests.Mocks; 7 | using Microsoft.VisualStudio.TestTools.UnitTesting; 8 | 9 | namespace ServiceLocation.Tests 10 | { 11 | 12 | [TestClass] 13 | public class ServiceLocatorAdapterFixture 14 | { 15 | protected IServiceLocator locator; 16 | 17 | [TestInitialize] 18 | public void InitAdapterFixture() 19 | { 20 | locator = new MockServiceLocator(new object[] { new SimpleLogger(), 21 | new AdvancedLogger(), 22 | new NullReferenceException() }); 23 | } 24 | 25 | [TestMethod] 26 | public void GetInstance() 27 | { 28 | ILogger instance = locator.GetInstance(); 29 | Assert.IsNotNull(instance); 30 | } 31 | 32 | 33 | [TestMethod] 34 | public void GetNamedInstance() 35 | { 36 | ILogger instance = locator.GetInstance(typeof(AdvancedLogger).FullName); 37 | Assert.IsInstanceOfType(instance, typeof(AdvancedLogger)); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ServiceLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CommonServiceLocator 4 | { 5 | /// 6 | /// This class provides the ambient container for this application. If your 7 | /// framework defines such an ambient container, use ServiceLocator.Current 8 | /// to get it. 9 | /// 10 | public static class ServiceLocator 11 | { 12 | private static ServiceLocatorProvider _currentProvider; 13 | 14 | /// 15 | /// The current ambient container. 16 | /// 17 | public static IServiceLocator Current 18 | { 19 | get 20 | { 21 | if (!IsLocationProviderSet) throw new InvalidOperationException(" ServiceLocationProvider must be set."); 22 | 23 | return _currentProvider(); 24 | } 25 | } 26 | 27 | /// 28 | /// Set the delegate that is used to retrieve the current container. 29 | /// 30 | /// Delegate that, when called, will return 31 | /// the current ambient container. 32 | public static void SetLocatorProvider(ServiceLocatorProvider newProvider) 33 | { 34 | _currentProvider = newProvider; 35 | } 36 | 37 | public static bool IsLocationProviderSet => _currentProvider != null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Exceptions/ActivationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CommonServiceLocator 4 | { 5 | /// 6 | /// The standard exception thrown when a ServiceLocator has an error in resolving an object. 7 | /// 8 | public partial class ActivationException : Exception 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public ActivationException() {} 14 | 15 | /// 16 | /// Initializes a new instance of the class with a specified error message. 17 | /// 18 | /// 19 | /// The message that describes the error. 20 | /// 21 | public ActivationException(string message) : base(message) {} 22 | 23 | /// 24 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. 25 | /// 26 | /// 27 | /// The error message that explains the reason for the exception. 28 | /// 29 | /// 30 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. 31 | /// 32 | public ActivationException(string message, Exception innerException) : base(message, innerException) {} 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33403.182 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonServiceLocator", "src\CommonServiceLocator.csproj", "{FAF6D6B2-1EC9-4A1B-83BB-48F772E948CF}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonServiceLocator.Tests", "test\CommonServiceLocator.Tests.csproj", "{69BC47D2-947A-43BC-A3AB-B810CB2FAE62}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{48F538EA-AD83-42AD-AB2E-4787331C946A}" 11 | ProjectSection(SolutionItems) = preProject 12 | package.props = package.props 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {FAF6D6B2-1EC9-4A1B-83BB-48F772E948CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {FAF6D6B2-1EC9-4A1B-83BB-48F772E948CF}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {FAF6D6B2-1EC9-4A1B-83BB-48F772E948CF}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {FAF6D6B2-1EC9-4A1B-83BB-48F772E948CF}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {69BC47D2-947A-43BC-A3AB-B810CB2FAE62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {69BC47D2-947A-43BC-A3AB-B810CB2FAE62}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {69BC47D2-947A-43BC-A3AB-B810CB2FAE62}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {69BC47D2-947A-43BC-A3AB-B810CB2FAE62}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {72B4A8E1-7322-442A-8D97-5FAB12C9B0FC} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Build pipeline 2 | 3 | trigger: 4 | - master 5 | - refs/tags/* 6 | 7 | pool: 8 | vmImage: 'windows-latest' 9 | 10 | variables: 11 | solution: '**/*.csproj' 12 | buildPlatform: 'Any CPU' 13 | buildConfiguration: 'Release' 14 | BuildVersion: 0 15 | 16 | steps: 17 | - task: PowerShell@2 18 | displayName: 'Set Build Version' 19 | inputs: 20 | targetType: 'inline' 21 | script: | 22 | $timestamp = git log -1 --pretty="format:%ct" 23 | Write-Host "Build Version: $timestamp" 24 | Write-Host "##vso[task.setvariable variable=BuildVersion]$($timestamp)" 25 | $isTag = [regex]::IsMatch($Env:BUILD_SOURCEBRANCH, "^(refs\/tags\/)") 26 | Write-Host "##vso[task.setvariable variable=isTag]$($isTag)" 27 | 28 | - task: CmdLine@2 29 | inputs: 30 | script: 'set' 31 | 32 | #- task: PowerShell@2 33 | # displayName: 'Version Info' 34 | # inputs: 35 | # targetType: 'inline' 36 | # script: | 37 | # $version = (Select-Xml -Path ".\package.props" -XPath "/Project/PropertyGroup/VersionBase" | Select-Object -ExpandProperty Node).InnerText 38 | # $timestamp = git log -1 --pretty="format:%ct" 39 | # Write-Host "Version: $version" 40 | # Write-Host "Time Stamp: $timestamp" 41 | # Write-Host "##vso[task.setvariable variable=STAGE_VERSION]$($version)-$($timestamp)" 42 | 43 | 44 | - task: NuGetToolInstaller@1 45 | displayName: 'Install NuGet' 46 | 47 | - task: NuGetCommand@2 48 | displayName: 'Restore Dependencies' 49 | inputs: 50 | restoreSolution: '$(solution)' 51 | 52 | - task: VSBuild@1 53 | displayName: 'Build' 54 | inputs: 55 | solution: '$(solution)' 56 | platform: '$(buildPlatform)' 57 | configuration: '$(buildConfiguration)' 58 | 59 | - task: VSTest@2 60 | displayName: 'Test' 61 | inputs: 62 | platform: '$(buildPlatform)' 63 | configuration: '$(buildConfiguration)' 64 | searchFolder: '$(system.defaultworkingdirectory)\test' 65 | 66 | - task: PublishBuildArtifacts@1 67 | displayName: 'Publish Artifact' 68 | inputs: 69 | PathtoPublish: '$(system.defaultworkingdirectory)\src\bin\$(buildPlatform)\$(buildConfiguration)' 70 | ArtifactName: 'Binaries' 71 | 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Microsoft Public License (MS-PL) 2 | This license governs use of the accompanying software. If you use the software, you 3 | accept this license. If you do not accept the license, do not use the software. 4 | 5 | 1. Definitions 6 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the 7 | same meaning here as under U.S. copyright law. 8 | A "contribution" is the original software, or any additions or changes to the software. 9 | A "contributor" is any person that distributes its contribution under this license. 10 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 11 | 12 | 2. Grant of Rights 13 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 14 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 15 | 16 | 3. Conditions and Limitations 17 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 18 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 19 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 20 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 21 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 22 | -------------------------------------------------------------------------------- /src/CommonServiceLocator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(Version).0 7 | CommonServiceLocator 8 | The Common Service Locator library contains a shared interface for service location. The library provides an abstraction over IoC containers and service locators. 9 | The library provides an abstraction over IoC containers and service locators. Using the library allows an application to indirectly access the capabilities without relying on hard references. 10 | Copyright © .NET Foundation and Contributors. All Rights Reserved 11 | https://github.com/unitycontainer/commonservicelocator 12 | https://opensource.org/licenses/MS-PL 13 | https://github.com/unitycontainer/commonservicelocator 14 | https://avatars1.githubusercontent.com/u/12849707 15 | Unity Container unitycontainer Microsoft.Practices.Unity IoC Microsoft.Practices.ServiceLocation Service Location 16 | Microsoft.Practices.ServiceLocation 17 | git 18 | .NET Foundation and Contributors 19 | .NET Foundation and Contributors 20 | true 21 | package.snk 22 | false 23 | CommonServiceLocator 24 | 25 | 26 | 27 | $(Version).0 28 | $(Version).$(BuildVersion) 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | true 49 | Portable 50 | 51 | 52 | 53 | Full 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/IServiceLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CommonServiceLocator 5 | { 6 | /// 7 | /// The generic Service Locator interface. This interface is used 8 | /// to retrieve services (instances identified by type and optional 9 | /// name) from a container. 10 | /// 11 | [CLSCompliant(true)] 12 | public interface IServiceLocator : IServiceProvider 13 | { 14 | /// 15 | /// Get an instance of the given . 16 | /// 17 | /// Type of object requested. 18 | /// if there is an error resolving 19 | /// the service instance. 20 | /// The requested service instance. 21 | object GetInstance(Type serviceType); 22 | 23 | /// 24 | /// Get an instance of the given named . 25 | /// 26 | /// Type of object requested. 27 | /// Name the object was registered with. 28 | /// if there is an error resolving 29 | /// the service instance. 30 | /// The requested service instance. 31 | object GetInstance(Type serviceType, string key); 32 | 33 | /// 34 | /// Get all instances of the given currently 35 | /// registered in the container. 36 | /// 37 | /// Type of object requested. 38 | /// if there is are errors resolving 39 | /// the service instance. 40 | /// A sequence of instances of the requested . 41 | IEnumerable GetAllInstances(Type serviceType); 42 | 43 | /// 44 | /// Get an instance of the given . 45 | /// 46 | /// Type of object requested. 47 | /// if there is are errors resolving 48 | /// the service instance. 49 | /// The requested service instance. 50 | TService GetInstance(); 51 | 52 | /// 53 | /// Get an instance of the given named . 54 | /// 55 | /// Type of object requested. 56 | /// Name the object was registered with. 57 | /// if there is are errors resolving 58 | /// the service instance. 59 | /// The requested service instance. 60 | TService GetInstance(string key); 61 | 62 | /// 63 | /// Get all instances of the given currently 64 | /// registered in the container. 65 | /// 66 | /// Type of object requested. 67 | /// if there is are errors resolving 68 | /// the service instance. 69 | /// A sequence of instances of the requested . 70 | IEnumerable GetAllInstances(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![license](https://img.shields.io/badge/license-ms-pl.svg)](https://opensource.org/licenses/MS-PL) 2 | [![NuGet](https://img.shields.io/nuget/dt/commonservicelocator.svg)](https://www.nuget.org/packages/CommonServiceLocator) 3 | [![NuGet](https://img.shields.io/nuget/v/commonservicelocator.svg)](https://www.nuget.org/packages/CommonServiceLocator) 4 | 5 | This file explains the expected semantics IServiceLocator implementations must implement to properly conform to this interface, and a few implementation notes. 6 | 7 | ### Specification 8 | 9 | ```GetInstance(Type, string)``` 10 | 11 | This is the core method for retrieving a single instance from the container. 12 | 13 | This method MUST NOT return null. It MUST return either an instance that implements the requested type or throw an ActivationException. 14 | No other exception type is allowed (except for the usual CLR rules for things like ThreadAbortException). 15 | 16 | The implementation should be designed to expect a null for the string key parameter, and MUST interpret this as a request to get the "default" instance for the requested type. The meaning of "default" depends on the underlying container and how it is configured. A string of length 0 is considered to be different from a null, and implementers are free to choose what a string of length 0 as a key means. 17 | 18 | ```GetAllInstances(Type)``` 19 | 20 | This is the core method for retrieving multiple instances from the container. 21 | 22 | If the container contains no instances of the requested type, this method MUST return an enumerator of length 0 instead of throwing an exception. 23 | 24 | If an exception occurs while activating instances during enumeration, this method SHOULD throw an ActivationException and abort the enumeration. However, it may also choose to simply skip that object and continue enumerating. 25 | 26 | ### Overload Behavior 27 | 28 | A call to: 29 | 30 | object IServiceLocator.GetInstance(serviceType) 31 | 32 | MUST be exactly equivalent to a call to: 33 | 34 | object IServiceLocator.GetInstance(serviceType, null) 35 | 36 | A call to: 37 | 38 | TService IServiceLocator.GetInstance() 39 | 40 | MUST be exactly equivalent to a call to: 41 | 42 | (TService)IServiceLocator.GetInstance(typeof(TService), null) 43 | 44 | A call to: 45 | 46 | TService IServiceLocator.GetInstance(key) 47 | 48 | MUST be exactly equivalent to a call to: 49 | 50 | (TService)IServiceLocator.GetInstance(typeof(TService), key) 51 | 52 | A call to: 53 | 54 | IEnumerable IServiceLocator.GetAllInstances() 55 | 56 | Must be exactly equivalent to a call to: 57 | 58 | IEnumerable IServiceLocator.GetAllInstances(typeof(TService)) 59 | 60 | with the exception that the objects returned by the enumerator are already cast to type TService. 61 | 62 | ### Throwing ActivationException 63 | 64 | When throwing an ActivationException, the message string is explicitly undefined by this specification; the adapter implementors may format this message in any way they choose. 65 | 66 | When throwing an ActivationException, the original exception MUST be returned as the value of the InnerException property. 67 | 68 | ### ServiceLocatorImplBase 69 | 70 | This class is not part of the specification; consumers should only reference the IServiceLocator interface. ServiceLocatorImplBase is provided as a convenience for implementors of IServiceLocator. It implements the correct overload semantics and exception wrapping behavior defined above. You just need to implement the two protected methods DoGetInstance and DoGetAllInstances and the rest will just work. In addition, the two protected methods FormatActivationExceptionMessage and FormatActivateAllExceptionMessage are provided if you wish to customize the error message reported in the exceptions. 71 | 72 | ### Why is ActivationException a partial class? 73 | 74 | Implementing ISerializable for exceptions is a .NET best practice for the desktop CLR. However, portable library does not support classic binary serialization. By making this a partial class and segregating the serialization details into a separate file, a portable port can simply leave the .Desktop.cs file out of the project and the incompatible code will be seamlessly removed. 75 | -------------------------------------------------------------------------------- /.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 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | [Ll]ib/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # .NET Core 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | **/Properties/launchSettings.json 51 | 52 | *_i.c 53 | *_p.c 54 | *_i.h 55 | *.ilk 56 | *.meta 57 | *.obj 58 | *.pch 59 | *.pdb 60 | *.pgc 61 | *.pgd 62 | *.rsp 63 | *.sbr 64 | *.tlb 65 | *.tli 66 | *.tlh 67 | *.tmp 68 | *.tmp_proj 69 | *.log 70 | *.vspscc 71 | *.vssscc 72 | .builds 73 | *.pidb 74 | *.svclog 75 | *.scc 76 | 77 | # Chutzpah Test files 78 | _Chutzpah* 79 | 80 | # Visual C++ cache files 81 | ipch/ 82 | *.aps 83 | *.ncb 84 | *.opendb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | *.VC.db 89 | *.VC.VC.opendb 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | *.sap 96 | 97 | # TFS 2012 Local Workspace 98 | $tf/ 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | *.DotSettings.user 107 | 108 | # JustCode is a .NET coding add-in 109 | .JustCode 110 | 111 | # TeamCity is a build add-in 112 | _TeamCity* 113 | 114 | # DotCover is a Code Coverage Tool 115 | *.dotCover 116 | 117 | # Visual Studio code coverage results 118 | *.coverage 119 | *.coveragexml 120 | 121 | # NCrunch 122 | _NCrunch_* 123 | .*crunch*.local.xml 124 | nCrunchTemp_* 125 | 126 | # MightyMoose 127 | *.mm.* 128 | AutoTest.Net/ 129 | 130 | # Web workbench (sass) 131 | .sass-cache/ 132 | 133 | # Installshield output folder 134 | [Ee]xpress/ 135 | 136 | # DocProject is a documentation generator add-in 137 | DocProject/buildhelp/ 138 | DocProject/Help/*.HxT 139 | DocProject/Help/*.HxC 140 | DocProject/Help/*.hhc 141 | DocProject/Help/*.hhk 142 | DocProject/Help/*.hhp 143 | DocProject/Help/Html2 144 | DocProject/Help/html 145 | 146 | # Click-Once directory 147 | publish/ 148 | 149 | # Publish Web Output 150 | *.[Pp]ublish.xml 151 | *.azurePubxml 152 | # TODO: Comment the next line if you want to checkin your web deploy settings 153 | # but database connection strings (with potential passwords) will be unencrypted 154 | *.pubxml 155 | *.publishproj 156 | 157 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 158 | # checkin your Azure Web App publish settings, but sensitive information contained 159 | # in these scripts will be unencrypted 160 | PublishScripts/ 161 | 162 | # NuGet Packages 163 | *.nupkg 164 | # The packages folder can be ignored because of Package Restore 165 | **/packages/* 166 | # except build/, which is used as an MSBuild target. 167 | !**/packages/build/ 168 | # Uncomment if necessary however generally it will be regenerated when needed 169 | #!**/packages/repositories.config 170 | # NuGet v3's project.json files produces more ignorable files 171 | *.nuget.props 172 | *.nuget.targets 173 | 174 | # Microsoft Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Microsoft Azure Emulator 179 | ecf/ 180 | rcf/ 181 | 182 | # Windows Store app package directories and files 183 | AppPackages/ 184 | BundleArtifacts/ 185 | Package.StoreAssociation.xml 186 | _pkginfo.txt 187 | 188 | # Visual Studio cache files 189 | # files ending in .cache can be ignored 190 | *.[Cc]ache 191 | # but keep track of directories ending in .cache 192 | !*.[Cc]ache/ 193 | 194 | # Others 195 | ClientBin/ 196 | ~$* 197 | *~ 198 | *.dbmdl 199 | *.dbproj.schemaview 200 | *.jfm 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /src/net40/TypeInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace System.Reflection 6 | { 7 | internal class TypeInfo 8 | { 9 | private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; 10 | private Type _type; 11 | 12 | 13 | internal TypeInfo(Type type) 14 | { 15 | _type = type ?? throw new ArgumentNullException(nameof(type)); 16 | } 17 | 18 | 19 | public Assembly Assembly => _type.Assembly; 20 | 21 | public bool IsGenericTypeDefinition => _type.IsGenericTypeDefinition; 22 | 23 | public Type[] GenericTypeArguments => _type.GetGenericArguments(); 24 | 25 | public Type[] GenericTypeParameters => _type.IsGenericTypeDefinition ? _type.GetGenericArguments() 26 | : Type.EmptyTypes; 27 | public string Name => _type.Name; 28 | 29 | public Type BaseType => _type.BaseType; 30 | 31 | public bool IsGenericType => _type.IsGenericType; 32 | 33 | public Type AsType() => _type; 34 | 35 | public bool IsAssignableFrom(TypeInfo typeInfo) => _type.IsAssignableFrom(typeInfo.AsType()); 36 | 37 | public bool IsGenericParameter => _type.IsGenericParameter; 38 | 39 | public bool IsInterface => _type.IsInterface; 40 | 41 | public bool IsAbstract => _type.IsAbstract; 42 | 43 | public bool IsSubclassOf(Type type) => _type.IsSubclassOf(type); 44 | 45 | public bool IsValueType => _type.IsValueType; 46 | 47 | public bool ContainsGenericParameters => _type.ContainsGenericParameters; 48 | 49 | #region moved over from Type 50 | 51 | //// Fields 52 | 53 | public virtual EventInfo GetDeclaredEvent(String name) 54 | { 55 | return _type.GetEvent(name, DeclaredOnlyLookup); 56 | } 57 | public virtual FieldInfo GetDeclaredField(String name) 58 | { 59 | return _type.GetField(name, DeclaredOnlyLookup); 60 | } 61 | public virtual MethodInfo GetDeclaredMethod(String name) 62 | { 63 | return _type.GetMethod(name, DeclaredOnlyLookup); 64 | } 65 | 66 | public virtual IEnumerable GetDeclaredMethods(String name) 67 | { 68 | foreach (MethodInfo method in _type.GetMethods(DeclaredOnlyLookup)) 69 | { 70 | if (method.Name == name) 71 | yield return method; 72 | } 73 | } 74 | 75 | public virtual System.Reflection.TypeInfo GetDeclaredNestedType(String name) 76 | { 77 | var nt = _type.GetNestedType(name, DeclaredOnlyLookup); 78 | if (nt == null) 79 | { 80 | return null; //the extension method GetTypeInfo throws for null 81 | } 82 | else 83 | { 84 | return nt.GetTypeInfo(); 85 | } 86 | } 87 | 88 | public virtual PropertyInfo GetDeclaredProperty(String name) 89 | { 90 | return _type.GetProperty(name, DeclaredOnlyLookup); 91 | } 92 | 93 | 94 | //// Properties 95 | 96 | public virtual IEnumerable DeclaredConstructors 97 | { 98 | get 99 | { 100 | return _type.GetConstructors(DeclaredOnlyLookup); 101 | } 102 | } 103 | 104 | public virtual IEnumerable DeclaredEvents 105 | { 106 | get 107 | { 108 | return _type.GetEvents(DeclaredOnlyLookup); 109 | } 110 | } 111 | 112 | public virtual IEnumerable DeclaredFields 113 | { 114 | get 115 | { 116 | return _type.GetFields(DeclaredOnlyLookup); 117 | } 118 | } 119 | 120 | public virtual IEnumerable DeclaredMembers 121 | { 122 | get 123 | { 124 | return _type.GetMembers(DeclaredOnlyLookup); 125 | } 126 | } 127 | 128 | public virtual IEnumerable DeclaredMethods 129 | { 130 | get 131 | { 132 | return _type.GetMethods(DeclaredOnlyLookup); 133 | } 134 | } 135 | public virtual IEnumerable DeclaredNestedTypes 136 | { 137 | get 138 | { 139 | foreach (var t in _type.GetNestedTypes(DeclaredOnlyLookup)) 140 | { 141 | yield return t.GetTypeInfo(); 142 | } 143 | } 144 | } 145 | 146 | public virtual IEnumerable DeclaredProperties 147 | { 148 | get 149 | { 150 | return _type.GetProperties(DeclaredOnlyLookup); 151 | } 152 | } 153 | 154 | 155 | public virtual IEnumerable ImplementedInterfaces 156 | { 157 | get 158 | { 159 | return _type.GetInterfaces(); 160 | } 161 | } 162 | 163 | 164 | #endregion 165 | 166 | public override int GetHashCode() 167 | { 168 | return _type.GetHashCode(); 169 | } 170 | 171 | public override bool Equals(object obj) 172 | { 173 | return _type.Equals(obj); 174 | } 175 | 176 | public static bool operator ==(TypeInfo left, TypeInfo right) 177 | { 178 | return left?.GetHashCode() == right?.GetHashCode(); 179 | } 180 | 181 | public static bool operator !=(TypeInfo left, TypeInfo right) 182 | { 183 | return left?.GetHashCode() != right?.GetHashCode(); 184 | } 185 | 186 | } 187 | 188 | 189 | internal static class IntrospectionExtensions 190 | { 191 | public static TypeInfo GetTypeInfo(this Type type) 192 | { 193 | if (type == null) 194 | { 195 | throw new ArgumentNullException("type"); 196 | } 197 | 198 | return new TypeInfo(type); 199 | } 200 | } 201 | } -------------------------------------------------------------------------------- /src/ServiceLocatorImplBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | 5 | namespace CommonServiceLocator 6 | { 7 | /// 8 | /// This class is a helper that provides a default implementation 9 | /// for most of the methods of . 10 | /// 11 | public abstract class ServiceLocatorImplBase : IServiceLocator 12 | { 13 | /// 14 | /// Implementation of . 15 | /// 16 | /// The requested service. 17 | /// if there is an error in resolving the service instance. 18 | /// The requested object. 19 | public virtual object GetService(Type serviceType) 20 | { 21 | return GetInstance(serviceType, null); 22 | } 23 | 24 | /// 25 | /// Get an instance of the given . 26 | /// 27 | /// Type of object requested. 28 | /// if there is an error resolving 29 | /// the service instance. 30 | /// The requested service instance. 31 | public virtual object GetInstance(Type serviceType) 32 | { 33 | return GetInstance(serviceType, null); 34 | } 35 | 36 | /// 37 | /// Get an instance of the given named . 38 | /// 39 | /// Type of object requested. 40 | /// Name the object was registered with. 41 | /// if there is an error resolving 42 | /// the service instance. 43 | /// The requested service instance. 44 | public virtual object GetInstance(Type serviceType, string key) 45 | { 46 | try 47 | { 48 | return DoGetInstance(serviceType, key); 49 | } 50 | catch (Exception ex) 51 | { 52 | throw new ActivationException( 53 | FormatActivationExceptionMessage(ex, serviceType, key), 54 | ex); 55 | } 56 | } 57 | 58 | /// 59 | /// Get all instances of the given currently 60 | /// registered in the container. 61 | /// 62 | /// Type of object requested. 63 | /// if there is are errors resolving 64 | /// the service instance. 65 | /// A sequence of instances of the requested . 66 | public virtual IEnumerable GetAllInstances(Type serviceType) 67 | { 68 | try 69 | { 70 | return DoGetAllInstances(serviceType); 71 | } 72 | catch (Exception ex) 73 | { 74 | throw new ActivationException( 75 | FormatActivateAllExceptionMessage(ex, serviceType), 76 | ex); 77 | } 78 | } 79 | 80 | /// 81 | /// Get an instance of the given . 82 | /// 83 | /// Type of object requested. 84 | /// if there is are errors resolving 85 | /// the service instance. 86 | /// The requested service instance. 87 | public virtual TService GetInstance() 88 | { 89 | return (TService)GetInstance(typeof(TService), null); 90 | } 91 | 92 | /// 93 | /// Get an instance of the given named . 94 | /// 95 | /// Type of object requested. 96 | /// Name the object was registered with. 97 | /// if there is are errors resolving 98 | /// the service instance. 99 | /// The requested service instance. 100 | public virtual TService GetInstance(string key) 101 | { 102 | return (TService)GetInstance(typeof(TService), key); 103 | } 104 | 105 | /// 106 | /// Get all instances of the given currently 107 | /// registered in the container. 108 | /// 109 | /// Type of object requested. 110 | /// if there is are errors resolving 111 | /// the service instance. 112 | /// A sequence of instances of the requested . 113 | public virtual IEnumerable GetAllInstances() 114 | { 115 | foreach (object item in GetAllInstances(typeof(TService))) 116 | { 117 | yield return (TService)item; 118 | } 119 | } 120 | 121 | /// 122 | /// When implemented by inheriting classes, this method will do the actual work of resolving 123 | /// the requested service instance. 124 | /// 125 | /// Type of instance requested. 126 | /// Name of registered service you want. May be null. 127 | /// The requested service instance. 128 | protected abstract object DoGetInstance(Type serviceType, string key); 129 | 130 | /// 131 | /// When implemented by inheriting classes, this method will do the actual work of 132 | /// resolving all the requested service instances. 133 | /// 134 | /// Type of service requested. 135 | /// Sequence of service instance objects. 136 | protected abstract IEnumerable DoGetAllInstances(Type serviceType); 137 | 138 | /// 139 | /// Format the exception message for use in an 140 | /// that occurs while resolving a single service. 141 | /// 142 | /// The actual exception thrown by the implementation. 143 | /// Type of service requested. 144 | /// Name requested. 145 | /// The formatted exception message string. 146 | protected virtual string FormatActivationExceptionMessage(Exception actualException, Type serviceType, string key) 147 | { 148 | return $"Activation error occurred while trying to get instance of type {serviceType.Name}, key \"{key}\""; 149 | } 150 | 151 | /// 152 | /// Format the exception message for use in an 153 | /// that occurs while resolving multiple service instances. 154 | /// 155 | /// The actual exception thrown by the implementation. 156 | /// Type of service requested. 157 | /// The formatted exception message string. 158 | protected virtual string FormatActivateAllExceptionMessage(Exception actualException, Type serviceType) 159 | { 160 | return $"Activation error occurred while trying to get all instances of type {serviceType.Name}"; 161 | } 162 | } 163 | } 164 | --------------------------------------------------------------------------------