Skip to content

Commit 0cd68f5

Browse files
authored
Merge pull request #52 from godrose/feat-assembly-load
More cleanup and assembly load support
2 parents 6613e36 + 53e922b commit 0cd68f5

File tree

18 files changed

+351
-61
lines changed

18 files changed

+351
-61
lines changed

Solid.Core/DependenciesAttribute.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22

33
namespace Solid.Core
44
{
5+
/// <summary>
6+
/// The dependencies attribute. Use it to describe the list of dependencies for the current type.
7+
/// </summary>
58
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
69
public sealed class DependenciesAttribute : Attribute
710
{
11+
/// <summary>
12+
/// Creates an instance of <see cref="DependenciesAttribute"/>
13+
/// </summary>
14+
/// <param name="dependencies"></param>
815
public DependenciesAttribute(string[] dependencies = null)
916
{
1017
Dependencies = dependencies ?? (new string[] { });
1118
}
19+
20+
/// <summary>
21+
/// The collection of dependencies
22+
/// </summary>
1223
public string[] Dependencies { get; }
1324
}
1425
}

Solid.Core/IdAttribute.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22

33
namespace Solid.Core
44
{
5-
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
5+
/// <summary>
6+
/// The identity attribute. Use it to assign a unique identifiable value to the type.
7+
/// </summary>
8+
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
69
public sealed class IdAttribute : Attribute
710
{
11+
/// <summary>
12+
/// Creates an instance of <see cref="IdAttribute"/>
13+
/// </summary>
14+
/// <param name="id"></param>
815
public IdAttribute(string id)
916
{
1017
Id = id;
1118
}
19+
20+
/// <summary>
21+
/// The id.
22+
/// </summary>
1223
public string Id { get; }
1324
}
1425
}

Solid.Core/TopologicalSortExtensions.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,37 @@ public static class TopologicalSortExtensions
1313
/// Sorts the items topologically
1414
/// </summary>
1515
/// <typeparam name="TItem">The type of the item.</typeparam>
16+
/// <param name="items">The items.</param>
17+
/// <returns></returns>
18+
public static IEnumerable<TItem> SortTopologically<TItem>(
19+
this IEnumerable<TItem> items)
20+
{
21+
return SortTopologicallyImpl(items, r => r.ExtractDependencies(), r => r.ExtractId());
22+
}
23+
24+
/// <summary>
25+
/// Sorts the items topologically using the provides means.
26+
/// </summary>
27+
/// <typeparam name="TItem">The type of the item.</typeparam>
1628
/// <typeparam name="TId">The type of the identity.</typeparam>
1729
/// <param name="items">The items.</param>
18-
/// <param name="extractDeps">The means for extracting the deps.</param>
30+
/// <param name="extractDeps">The means for extracting the dependencies.</param>
1931
/// <param name="extractId">The means for extracting the id.</param>
2032
/// <returns></returns>
2133
public static IEnumerable<TItem> SortTopologically<TItem, TId>(
2234
this IEnumerable<TItem> items,
2335
Func<TItem, IEnumerable<TId>> extractDeps,
2436
Func<TItem, TId> extractId)
37+
{
38+
return SortTopologicallyImpl(items, extractDeps, extractId);
39+
}
40+
41+
private static IEnumerable<TItem> SortTopologicallyImpl<TItem, TId>(IEnumerable<TItem> items, Func<TItem, IEnumerable<TId>> extractDeps, Func<TItem, TId> extractId)
2542
{
2643
const string sameKeyPrefix = "An item with the same key has already been added. Key: ";
2744
try
28-
{
29-
var sortedItems = TopologicalSort.Sort(items, extractDeps, extractId, ignoreCycles: false);
45+
{
46+
var sortedItems = TopologicalSort.Sort(items, extractDeps, extractId, ignoreCycles: false);
3047
return sortedItems;
3148
}
3249
catch (ArgumentException e)
@@ -46,6 +63,7 @@ public static IEnumerable<TItem> SortTopologically<TItem, TId>(
4663
{
4764
throw new Exception($"Missing dependency {parts[1]}");
4865
}
66+
4967
throw;
5068
}
5169
}
@@ -67,7 +85,7 @@ public static string ExtractId(this object @object)
6785
}
6886

6987
/// <summary>
70-
/// Extracts deps from the specified object.
88+
/// Extracts dependencies from the specified object.
7189
/// </summary>
7290
/// <param name="object">The object.</param>
7391
/// <returns></returns>

Solid.Extensibility/AspectsWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void UseCoreAspects(IEnumerable<IAspect> coreAspects)
3333
public void Initialize()
3434
{
3535
_aspects.AddRange(_coreAspects);
36-
var sortedAspects = _aspects.SortTopologically(x => x.Dependencies, x => x.Id);
36+
var sortedAspects = _aspects.SortTopologically();
3737
_aspects.Clear();
3838
_aspects.AddRange(sortedAspects);
3939
foreach (var aspect in _aspects)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Reflection;
5+
using BoDi;
6+
using FluentAssertions;
7+
using McMaster.NETCore.Plugins;
8+
using Solid.Common;
9+
using Solid.IoC.Adapters.BoDi;
10+
using Solid.Practices.Composition.Contracts;
11+
using Solid.Practices.Composition.IntegrationTests.Contracts;
12+
using Solid.Practices.IoC;
13+
using Solid.Practices.Modularity;
14+
using Xunit;
15+
16+
namespace Solid.Practices.Composition.IntegrationTests.App
17+
{
18+
public class CompositionContainerTests
19+
{
20+
static CompositionContainerTests()
21+
{
22+
PlatformProvider.Current = new NetStandardPlatformProvider();
23+
AssemblyLoader.LoadAssembliesFromPaths = Loader.Get;
24+
}
25+
26+
[Fact]
27+
public void RootPathContainsCompositionModules_CompositionModulesAreImported()
28+
{
29+
var rootPath = Directory.GetCurrentDirectory();
30+
31+
ICompositionContainer<ICompositionModule<IDependencyRegistrator>> compositionContainer = new CompositionContainer<ICompositionModule<IDependencyRegistrator>>(new ActivatorCreationStrategy(),
32+
new FileSystemBasedAssemblyLoadingStrategy(rootPath, prefixes: new []{ "Solid" }, namespaces: null, extensions: AssemblyLoadingManager.Extensions().ToArray()));
33+
compositionContainer.Compose();
34+
35+
var modules = compositionContainer.Modules;
36+
var registrator = new ObjectContainerAdapter(new ObjectContainer());
37+
var singleModule = modules.SingleOrDefault();
38+
singleModule.RegisterModule(registrator);
39+
40+
var placeHolder = registrator.Resolve<IPlaceholder>();
41+
var length = placeHolder.Length;
42+
length.Should().Be(5);
43+
}
44+
}
45+
46+
class Loader
47+
{
48+
public static IEnumerable<Assembly> Get(IEnumerable<string> paths)
49+
{
50+
return paths.Select(path =>
51+
PluginLoader.CreateFromAssemblyFile(assemblyFile: Path.Combine(Directory.GetCurrentDirectory(), path),
52+
loaderOptions: PluginLoaderOptions.PreferSharedTypes
53+
).LoadDefaultAssembly());
54+
}
55+
}
56+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using FluentAssertions;
2+
using Solid.Common;
3+
using Xunit;
4+
5+
namespace Solid.Practices.Composition.IntegrationTests.App
6+
{
7+
public class DiscoveryAspectTests
8+
{
9+
[Fact]
10+
public void Initialize_PrefixesAreSet_OnlyMatchingAssembliesAreLoaded()
11+
{
12+
var compositionOptions = new CompositionOptions
13+
{
14+
Prefixes = new[] { "Solid" }
15+
};
16+
PlatformProvider.Current = new NetStandardPlatformProvider();
17+
var discoveryAspect = new DiscoveryAspect(compositionOptions);
18+
discoveryAspect.Initialize();
19+
20+
var assemblies = discoveryAspect.Assemblies;
21+
assemblies.Should().Contain(t => t.FullName.Contains("Solid.Practices.Composition.IntegrationTests.Lib"));
22+
}
23+
}
24+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
5+
<TargetFramework>netcoreapp2.2</TargetFramework>
6+
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
7+
</PropertyGroup>
8+
9+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
10+
<OutputPath>..\tests\bin\debug\composition</OutputPath>
11+
</PropertyGroup>
12+
13+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
14+
<OutputPath>..\tests\bin\composition</OutputPath>
15+
</PropertyGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="FluentAssertions" Version="5.6.0" />
19+
<PackageReference Include="McMaster.NETCore.Plugins" Version="0.2.4" />
20+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
21+
<PackageReference Include="xunit.core" Version="2.4.1" />
22+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
23+
<PrivateAssets>all</PrivateAssets>
24+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
25+
</PackageReference>
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<ProjectReference Include="..\Solid.IoC.Adapters.BoDi\Solid.IoC.Adapters.BoDi.csproj" />
30+
<ProjectReference Include="..\Solid.Practices.Composition.IntegrationTests.Contracts\Solid.Practices.Composition.IntegrationTests.Contracts.csproj" />
31+
<ProjectReference Include="..\Solid.Practices.Composition\Solid.Practices.Composition.csproj" />
32+
<ProjectReference Include="..\Solid.Practices.IoC\Solid.Practices.IoC.csproj" />
33+
<ProjectReference Include="..\Solid.Practices.Modularity\Solid.Practices.Modularity.csproj" />
34+
</ItemGroup>
35+
36+
</Project>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Solid.Practices.Composition.IntegrationTests.Contracts
2+
{
3+
public interface IPlaceholder
4+
{
5+
int Length { get; }
6+
}
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
6+
</PropertyGroup>
7+
8+
</Project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Moq;
2+
using Solid.Practices.Composition.IntegrationTests.Contracts;
3+
using Solid.Practices.IoC;
4+
using Solid.Practices.Modularity;
5+
6+
namespace Solid.Practices.Composition.IntegrationTests.Lib
7+
{
8+
class Module : ICompositionModule<IDependencyRegistrator>
9+
{
10+
public void RegisterModule(IDependencyRegistrator dependencyRegistrator)
11+
{
12+
var mock = new Mock<IPlaceholder>();
13+
mock.Setup(t => t.Length).Returns(5);
14+
dependencyRegistrator.RegisterInstance(mock.Object);
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)