Skip to content

Commit

Permalink
Merge pull request #18 from rena0157/adding-lifetime-options
Browse files Browse the repository at this point in the history
Adding lifetime options
  • Loading branch information
rena0157 authored Jan 7, 2022
2 parents 2127a41 + aa5b89a commit edc47ab
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 21 deletions.
30 changes: 26 additions & 4 deletions src/Mapr.DependencyInjection/MapperConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,18 @@ public MapperConfig(IServiceCollection services)
/// <inheritdoc />
public IMapperConfig AddMap<TSource, TDestination, TMap>() where TMap : class, IMap<TSource, TDestination>
{
_services.AddTransient<IMap<TSource, TDestination>, TMap>();
var type = typeof(TMap);
var mapAttribute = type.GetCustomAttribute<MapAttribute>() ?? new MapAttribute();

if (mapAttribute.Lifetime == MapLifetime.Singleton)
{
_services.AddSingleton<IMap<TSource, TDestination>, TMap>();
}
else
{
_services.AddTransient<IMap<TSource, TDestination>, TMap>();
}

return this;
}

Expand Down Expand Up @@ -56,8 +67,8 @@ public IMapperConfig Scan<T>()
private void RegisterDefaults()
{
_services.AddSingleton<IMapper, Mapper>();
_services.AddTransient<IMapLocator, MapLocator>();
_services.AddTransient<MapFactory>(provider => provider.GetService);
_services.AddSingleton<IMapLocator, MapLocator>();
_services.AddSingleton<MapFactory>(provider => provider.GetService);
}

private void RegisterType(Type type)
Expand All @@ -70,6 +81,17 @@ private void RegisterType(Type type)
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMap<,>));

foreach (var i in interfaces)
_services.AddTransient(i, type);
{
var mapAttribute = type.GetCustomAttribute<MapAttribute>() ?? new MapAttribute();

if (mapAttribute.Lifetime == MapLifetime.Singleton)
{
_services.AddSingleton(i, type);
}
else
{
_services.AddTransient(i, type);
}
}
}
}
33 changes: 33 additions & 0 deletions src/Mapr/MapAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;

namespace Mapr;

/// <summary>
/// Represents an attribute that can be placed on map classes to control their behavior
/// and registration.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MapAttribute : Attribute
{
/// <summary>
/// Gets or sets the lifetime for the map. Determining how it will be registered in the
/// DI container. The default is <see cref="MapLifetime.Transient"/>.
/// </summary>
public MapLifetime Lifetime { get; set; } = MapLifetime.Transient;
}

/// <summary>
/// Represents the different lifetimes that can be used to register a map.
/// </summary>
public enum MapLifetime
{
/// <summary>
/// Registers the map as a singleton.
/// </summary>
Singleton,

/// <summary>
/// Registers the map as a transient.
/// </summary>
Transient
}
2 changes: 2 additions & 0 deletions src/Mapr/MapLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public IMap<TSource, TDestination> LocateMapFor<TSource, TDestination>()
try
{
if (_mapFactory(mapType) is not IMap<TSource, TDestination> typeMap)
{
throw new MapNotFoundException(mapType);
}

return typeMap;
}
Expand Down
102 changes: 85 additions & 17 deletions tests/Mapr.DependencyInjection.Tests/MapperConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,24 @@ public void ShouldAdd_Defaults()
serviceCollection.AddMapr(_ => { });

serviceCollection.Should()
.Contain(s => s.ServiceType == typeof(IMapper) && s.ImplementationType == typeof(Mapper));
.Contain(
s => s.ServiceType == typeof(IMapper) &&
s.ImplementationType == typeof(Mapper) &&
s.Lifetime == ServiceLifetime.Singleton
);

serviceCollection.Should().Contain(
s => s.ServiceType == typeof(IMapLocator) && s.ImplementationType == typeof(MapLocator));
serviceCollection.Should()
.Contain(
s => s.ServiceType == typeof(IMapLocator) &&
s.ImplementationType == typeof(MapLocator) &&
s.Lifetime == ServiceLifetime.Singleton
);

serviceCollection.Should().Contain(s => s.ServiceType == typeof(MapFactory));
serviceCollection.Should()
.Contain(
s => s.ServiceType == typeof(MapFactory) &&
s.Lifetime == ServiceLifetime.Singleton
);
}

[Fact]
Expand All @@ -32,11 +44,26 @@ public void Scan_ShouldAddAllClassesFromAssemblyThat_InheritFromITypeMap()
config.Scan(typeof(TestMap).Assembly);
});

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<string, int>));
serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<string, int>) &&
s.Lifetime == ServiceLifetime.Transient
);

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<int, string>));
serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<int, string>) &&
s.Lifetime == ServiceLifetime.Transient
);

serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestSingletonMap) &&
s.ServiceType == typeof(IMap<string, string>) &&
s.Lifetime == ServiceLifetime.Singleton
);
}

[Fact]
Expand All @@ -49,15 +76,30 @@ public void Scan_WithT_ShouldAddAllClassesFromAssemblyThat_InheritFromITypeMap()
config.Scan<TestMap>();
});

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<string, int>));
serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<string, int>) &&
s.Lifetime == ServiceLifetime.Transient
);

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<int, string>));
serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<int, string>) &&
s.Lifetime == ServiceLifetime.Transient
);

serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestSingletonMap) &&
s.ServiceType == typeof(IMap<string, string>) &&
s.Lifetime == ServiceLifetime.Singleton
);
}

[Fact]
public void AddMap_ShouldAppMap()
public void AddMap_ShouldAddMap()
{
var serviceCollection = new ServiceCollection();

Expand All @@ -67,10 +109,36 @@ public void AddMap_ShouldAppMap()
.AddMap<int, string, TestMap>();
});

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<string, int>));
serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<string, int>) &&
s.Lifetime == ServiceLifetime.Transient
);

serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestMap) &&
s.ServiceType == typeof(IMap<int, string>) &&
s.Lifetime == ServiceLifetime.Transient
);
}

[Fact]
public void AddMap_ShouldAddSingletonMap_WhenAttributeIsPresent()
{
var serviceCollection = new ServiceCollection();

serviceCollection.Should().Contain(
s => s.ImplementationType == typeof(TestMap) && s.ServiceType == typeof(IMap<int, string>));
serviceCollection.AddMapr(config =>
{
config.AddMap<string, string, TestSingletonMap>();
});

serviceCollection.Should()
.Contain(
s => s.ImplementationType == typeof(TestSingletonMap) &&
s.ServiceType == typeof(IMap<string, string>) &&
s.Lifetime == ServiceLifetime.Singleton
);
}
}
11 changes: 11 additions & 0 deletions tests/Mapr.DependencyInjection.Tests/TestSingletonMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Mapr.DependencyInjection.Tests;

[Map(Lifetime = MapLifetime.Singleton)]
public class TestSingletonMap: IMap<string, string>
{
/// <inheritdoc />
public string Map(string source)
{
return source;
}
}

0 comments on commit edc47ab

Please sign in to comment.