Code reformatting, documentation

This commit is contained in:
David Kaya
2017-09-09 23:14:12 +02:00
parent b5626dadb1
commit 8fec63485d
15 changed files with 182 additions and 26 deletions

View File

@@ -9,6 +9,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dependify", "src\Dependify\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dependify.Test", "src\Dependify.Test\Dependify.Test.csproj", "{BD19041B-FC13-456A-9F3E-7823B9EF5E70}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5A674CE8-0416-4D59-A9F9-CB5987FC21C8}"
ProjectSection(SolutionItems) = preProject
Dependify.sln.DotSettings = Dependify.sln.DotSettings
global.json = global.json
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@@ -1 +1,64 @@
# Dependify
# Dependify
Library that allows the developer to register his services by adding attributes to class or factory methods. Library works only with Microsoft's `Microsoft.Extensions.DependencyInjection` package.
Why the name? Because I wanted to contribute to the following [list](http://www.thenameinspector.com/wp-content/uploads/ify-names-chart-20141.pdf).
# Requirements
* `.netstandard 2.0`
* `Microsoft.Extensions.DependencyInjection`
# Usage
Let's have following interface and class
```c#
public interface ICar {
}
public class Audi : ICar {
}
```
## Class Attributes
### Single interface
If you want to add `Audi` as an implementation of `ICar` into `IServiceCollection` you just need to add `RegisterTransient`, `RegisterScoped` or `RegisterSingleton` attribute like
```c#
[RegisterTransient]
public class Audi : ICar {
}
```
and call
```c#
public void ConfigureServices(IServiceCollection services) {
services.AutoRegister();
}
```
### Multiple interfaces
If your class implements multiple interfaces, you can specify which one should be registered
```c#
[RegisterTransient(typeof(IFuelConsumer)]
public class Audi : ICar, IFuelConsumer {
}
```
## Factory method attributes
If you want to add `Audi` as an implementation of `ICar` using factory method, you can do following
```c#
[RegisterTransientFactory(typeof(ICar))]
public Audi CreateAudi(IServiceProvider provider) {
return new Audi();
}
```

View File

@@ -1,13 +1,16 @@
using System;
using Dependify;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Dependify.Attributes;
using ShouldRegisterScoped;
using ShouldRegisterSingleton;
using ShouldRegisterTransient;
public interface IInterface { }
public interface IInterface2 { }
public interface IInterface2 { }
namespace ShouldRegisterTransient {
[RegisterTransient]

View File

@@ -1,5 +1,10 @@
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using ShouldRegisterOneScoped;
@@ -9,9 +14,9 @@ using ShouldRegisterScoped;
using ShouldRegisterSingleton;
using ShouldRegisterTransient;
namespace Dependify.Test {
namespace Dependify.Test {
[TestFixture]
public class RegisterAttributeTests {
public class RegisterAttributeTests {
[TestCase(nameof(ShouldRegisterTransient), typeof(ImplementationTransient), typeof(IInterface), ServiceLifetime.Transient)]
[TestCase(nameof(ShouldRegisterSingleton), typeof(ImplementationSingleton), typeof(IInterface), ServiceLifetime.Singleton)]
[TestCase(nameof(ShouldRegisterScoped), typeof(ImplementationScoped), typeof(IInterface), ServiceLifetime.Scoped)]
@@ -20,15 +25,14 @@ namespace Dependify.Test {
[TestCase(nameof(ShouldRegisterOneScoped), typeof(ImplementationScopedOneInterface), typeof(IInterface2), ServiceLifetime.Scoped)]
public void RegisterAttribute_RegistersClass_WhenDefined(string @namespace, Type classType, Type interfaceType, ServiceLifetime serviceLifetime) {
IServiceCollection services = new ServiceCollection();
services.AutoRegister(@namespace);
services.AutoRegister(@namespace);
var service = services.First();
Assert.AreEqual(1, services.Count);
Assert.AreEqual(interfaceType, service.ServiceType);
Assert.AreEqual(interfaceType, service.ServiceType);
Assert.AreEqual(classType, service.ImplementationType);
Assert.AreEqual(serviceLifetime, service.Lifetime);
}
[TestCase(nameof(ShouldRegisterFactoryTransient), typeof(ImplementationTransient), typeof(IInterface), ServiceLifetime.Transient)]
[TestCase(nameof(ShouldRegisterFactorySingleton), typeof(ImplementationSingleton), typeof(IInterface), ServiceLifetime.Singleton)]
[TestCase(nameof(ShouldRegisterFactoryScoped), typeof(ImplementationScoped), typeof(IInterface), ServiceLifetime.Scoped)]
@@ -41,5 +45,5 @@ namespace Dependify.Test {
Assert.NotNull(service.ImplementationFactory);
Assert.AreEqual(serviceLifetime, service.Lifetime);
}
}
}
}

View File

@@ -1,4 +1,8 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using System.Collections.Generic;
namespace Dependify.Attributes {

View File

@@ -1,4 +1,8 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
namespace Dependify.Attributes {
[AttributeUsage(AttributeTargets.Method)]

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Classes with this attribute will be registered with <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RegisterScoped : Register {
public RegisterScoped() { }

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Methods with this attribute will be registered as factories for classes with <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class RegisterScopedFactory : RegisterFactory {
public RegisterScopedFactory(Type returnType) : base(returnType) { }

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Classes with this attribute will be registered with <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RegisterSingleton : Register {
public RegisterSingleton() { }

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Methods with this attribute will be registered as factories for classes with <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class RegisterSingletonFactory : RegisterFactory {
public RegisterSingletonFactory(Type returnType) : base(returnType) { }

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Classes with this attribute will be registered with <see cref="ServiceLifetime.Transient"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RegisterTransient : Register {
public RegisterTransient() { }

View File

@@ -1,6 +1,14 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Dependify.Attributes {
/// <summary>
/// Methods with this attribute will be registered as factories for classes with <see cref="ServiceLifetime.Transient"/> lifetime.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class RegisterTransientFactory : RegisterFactory {
public RegisterTransientFactory(Type returnType) : base(returnType) { }

View File

@@ -5,7 +5,4 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Helpers" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,8 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@@ -9,6 +13,11 @@ using Microsoft.Extensions.DependencyInjection;
namespace Dependify {
// ReSharper disable once InconsistentNaming
public static class IServiceCollectionExtensions {
/// <summary>
/// Adds all classes with <see cref="RegisterScoped"/>, <see cref="RegisterSingleton"/> or <see cref="RegisterTransient"/> attribute to <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">Service collection.</param>
/// <returns>Service collection.</returns>
public static IServiceCollection AutoRegister(this IServiceCollection services) {
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
services.AddFactories(DependifyUtils.GetFactoryMethods(assemblies));
@@ -16,12 +25,24 @@ namespace Dependify {
return services;
}
/// <summary>
/// Adds all classes from specified <paramref name="assemblies"/> with <see cref="RegisterScoped"/>, <see cref="RegisterSingleton"/> or <see cref="RegisterTransient"/> attribute to <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">Service collection.</param>
/// <param name="assemblies">Assemblies to scan</param>
/// <returns>Service collection.</returns>
public static IServiceCollection AutoRegister(this IServiceCollection services, params Assembly[] assemblies) {
services.AddFactories(DependifyUtils.GetFactoryMethods(assemblies));
services.AddClasses(DependifyUtils.GetClassTypes(assemblies));
return services;
}
/// <summary>
/// Adds all classes, from namespaces that start with <paramref name="namespace"/>, with <see cref="RegisterScoped"/>, <see cref="RegisterSingleton"/> or <see cref="RegisterTransient"/> attribute to <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services"></param>
/// <param name="namespace"></param>
/// <returns></returns>
public static IServiceCollection AutoRegister(this IServiceCollection services, string @namespace) {
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
services.AddFactories(DependifyUtils.GetFactoryMethodsFromNamespace(assemblies, @namespace));
@@ -51,7 +72,7 @@ namespace Dependify {
foreach (var classAttribute in classAttributes) {
var registrationType = classAttribute.GetType();
var interfaceTypes = classAttribute.InterfaceTypes == null || !classAttribute.InterfaceTypes.Any() ? classType.GetInterfaces() : classAttribute.InterfaceTypes;
foreach (var interfaceType in interfaceTypes) {
if (registrationType == typeof(RegisterTransient))
services.AddTransient(interfaceType, classType);

View File

@@ -1,4 +1,8 @@
using System;
// Copyright 2017 Dávid Kaya. All rights reserved.
// Use of this source code is governed by the MIT license,
// as found in the LICENSE file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;