Initial commit
This commit is contained in:
parent
a6a2e64688
commit
64484d4981
26 changed files with 670 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
###############
|
||||||
|
# folder #
|
||||||
|
###############
|
||||||
|
/**/DROP/
|
||||||
|
/**/TEMP/
|
||||||
|
/**/packages/
|
||||||
|
/**/bin/
|
||||||
|
/**/obj/
|
||||||
|
_site
|
||||||
|
.idea/
|
5
api/.gitignore
vendored
Normal file
5
api/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
###############
|
||||||
|
# temp file #
|
||||||
|
###############
|
||||||
|
*.yml
|
||||||
|
.manifest
|
2
api/index.md
Normal file
2
api/index.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# PLACEHOLDER
|
||||||
|
TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*!
|
1
articles/intro.md
Normal file
1
articles/intro.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# Add your introductions here!
|
2
articles/toc.yml
Normal file
2
articles/toc.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
- name: Introduction
|
||||||
|
href: intro.md
|
64
docfx.json
Normal file
64
docfx.json
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"src": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"src/**.csproj"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dest": "api",
|
||||||
|
"disableGitFeatures": false,
|
||||||
|
"disableDefaultFilter": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build": {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"api/**.yml",
|
||||||
|
"api/index.md"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"articles/**.md",
|
||||||
|
"articles/**/toc.yml",
|
||||||
|
"toc.yml",
|
||||||
|
"*.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resource": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"images/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"overwrite": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"apidoc/**.md"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"obj/**",
|
||||||
|
"_site/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dest": "_site",
|
||||||
|
"globalMetadataFiles": [],
|
||||||
|
"fileMetadataFiles": [],
|
||||||
|
"template": [
|
||||||
|
"statictoc"
|
||||||
|
],
|
||||||
|
"postProcessors": [],
|
||||||
|
"markdownEngineName": "markdig",
|
||||||
|
"noLangKeyword": false,
|
||||||
|
"keepFileLink": false,
|
||||||
|
"cleanupCacheHistory": false,
|
||||||
|
"disableGitFeatures": false
|
||||||
|
}
|
||||||
|
}
|
4
index.md
Normal file
4
index.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# This is the **HOMEPAGE**.
|
||||||
|
Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files.
|
||||||
|
## Quick Start Notes:
|
||||||
|
1. Add images to the *images* folder if the file is referencing an image.
|
35
src/tand/Tand.Core.Tests/LogTarget.cs
Normal file
35
src/tand/Tand.Core.Tests/LogTarget.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using Tand.Core.Models;
|
||||||
|
|
||||||
|
namespace Tand.Core.Tests
|
||||||
|
{
|
||||||
|
public class LogTarget<T> : ITandTarget<T>
|
||||||
|
{
|
||||||
|
private readonly Action<string> _logHandle;
|
||||||
|
|
||||||
|
public LogTarget(Action<string> logHandle)
|
||||||
|
{
|
||||||
|
_logHandle = logHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEnterMethod(CallEnterContext<T> enterContext)
|
||||||
|
{
|
||||||
|
_logHandle(enterContext.Instance.ToString());
|
||||||
|
foreach (var (name, val) in enterContext.Arguments)
|
||||||
|
{
|
||||||
|
_logHandle($"name: {name}, value: {val}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnLeaveMethod(CallLeaveContext<T> callLeaveContext)
|
||||||
|
{
|
||||||
|
_logHandle(callLeaveContext.Instance.ToString());
|
||||||
|
foreach (var (name, val) in callLeaveContext.Arguments)
|
||||||
|
{
|
||||||
|
_logHandle($"name: {name}, value: {val}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logHandle($"result: {callLeaveContext.CallResult}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/tand/Tand.Core.Tests/Tand.Core.Tests.csproj
Normal file
20
src/tand/Tand.Core.Tests/Tand.Core.Tests.csproj
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Tand.Core\Tand.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
60
src/tand/Tand.Core.Tests/TandSample.cs
Normal file
60
src/tand/Tand.Core.Tests/TandSample.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Tand.Core.Tests
|
||||||
|
{
|
||||||
|
public class TandTest
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public TandTest(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GenerateTand()
|
||||||
|
{
|
||||||
|
var tand = new Tand(new SampleResolver(_outputHelper));
|
||||||
|
|
||||||
|
var sample = tand.DecorateWithTand<ITAndSample, TandSample>(new TandSample());
|
||||||
|
var result = sample.LogMyParams("Hello, World", 42);
|
||||||
|
_outputHelper.WriteLine($"Got result: {result}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SampleResolver : IDependencyResolver
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public SampleResolver(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITandTarget<T> TargetOfType<T>(Type type)
|
||||||
|
{
|
||||||
|
return new LogTarget<T>(_outputHelper.WriteLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ITAndSample
|
||||||
|
{
|
||||||
|
[Tand(typeof(LogTarget<TandSample>))]
|
||||||
|
int LogMyParams(string s, int i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TandSample : ITAndSample
|
||||||
|
{
|
||||||
|
|
||||||
|
private int _counter;
|
||||||
|
public string ContextSample { get; set; }
|
||||||
|
|
||||||
|
public int LogMyParams(string s, int i)
|
||||||
|
{
|
||||||
|
return ++_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
src/tand/Tand.Core/CallEnterContext.cs
Normal file
23
src/tand/Tand.Core/CallEnterContext.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Tand.Core.Models;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
public readonly struct CallEnterContext<T>
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, object> _methodArgs;
|
||||||
|
|
||||||
|
public CallEnterContext(T instance, IDictionary<string, object> args)
|
||||||
|
{
|
||||||
|
Instance = instance;
|
||||||
|
_methodArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Instance { get; }
|
||||||
|
|
||||||
|
public object? this[string argName] => _methodArgs.ContainsKey(argName) ? _methodArgs[argName] : null;
|
||||||
|
|
||||||
|
public IEnumerable<MethodArgument> Arguments => _methodArgs.Select(kv => new MethodArgument(kv.Key, kv.Value));
|
||||||
|
}
|
||||||
|
}
|
9
src/tand/Tand.Core/IDependencyResolver.cs
Normal file
9
src/tand/Tand.Core/IDependencyResolver.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
public interface IDependencyResolver
|
||||||
|
{
|
||||||
|
ITandTarget<T> TargetOfType<T>(Type type);
|
||||||
|
}
|
||||||
|
}
|
11
src/tand/Tand.Core/ITandTarget.cs
Normal file
11
src/tand/Tand.Core/ITandTarget.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Tand.Core.Models;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
public interface ITandTarget<T>
|
||||||
|
{
|
||||||
|
void OnEnterMethod(CallEnterContext<T> enterContext);
|
||||||
|
|
||||||
|
void OnLeaveMethod(CallLeaveContext<T> leaveContext);
|
||||||
|
}
|
||||||
|
}
|
29
src/tand/Tand.Core/Models/CallLeaveContext.cs
Normal file
29
src/tand/Tand.Core/Models/CallLeaveContext.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Tand.Core.Models
|
||||||
|
{
|
||||||
|
public readonly struct CallLeaveContext<T>
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, object> _methodArgs;
|
||||||
|
|
||||||
|
public CallLeaveContext(
|
||||||
|
T instance,
|
||||||
|
IDictionary<string, object> args,
|
||||||
|
object callResult
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Instance = instance;
|
||||||
|
_methodArgs = args;
|
||||||
|
CallResult = callResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Instance { get; }
|
||||||
|
|
||||||
|
public object CallResult { get; }
|
||||||
|
|
||||||
|
public object? this[string argName] => _methodArgs.ContainsKey(argName) ? _methodArgs[argName] : null;
|
||||||
|
|
||||||
|
public IEnumerable<MethodArgument> Arguments => _methodArgs.Select(kv => new MethodArgument(kv.Key, kv.Value));
|
||||||
|
}
|
||||||
|
}
|
21
src/tand/Tand.Core/Models/MethodArgument.cs
Normal file
21
src/tand/Tand.Core/Models/MethodArgument.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
namespace Tand.Core.Models
|
||||||
|
{
|
||||||
|
public readonly struct MethodArgument
|
||||||
|
{
|
||||||
|
public MethodArgument(string name, object value)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public object Value { get; }
|
||||||
|
|
||||||
|
public void Deconstruct(out string name, out object value)
|
||||||
|
{
|
||||||
|
name = Name;
|
||||||
|
value = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/tand/Tand.Core/Tand.Core.csproj
Normal file
9
src/tand/Tand.Core/Tand.Core.csproj
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<LangVersion>8</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
38
src/tand/Tand.Core/Tand.cs
Normal file
38
src/tand/Tand.Core/Tand.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
public class Tand
|
||||||
|
{
|
||||||
|
private readonly IDependencyResolver _dependencyResolver;
|
||||||
|
|
||||||
|
public Tand(IDependencyResolver dependencyResolver)
|
||||||
|
{
|
||||||
|
_dependencyResolver = dependencyResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TService DecorateWithTand<TService, TImplementation>(TImplementation toBeDecorated)
|
||||||
|
where TService : class
|
||||||
|
where TImplementation : class, TService
|
||||||
|
{
|
||||||
|
var proxy = DispatchProxy.Create<TService, TandProxy<TService>>();
|
||||||
|
InitProxy<TService, TImplementation>(proxy, toBeDecorated);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitProxy<TService, TImplementation>(object proxyObj, TService toBeDecorated)
|
||||||
|
{
|
||||||
|
var proxy = proxyObj switch
|
||||||
|
{
|
||||||
|
TandProxy<TService> tp => tp,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (proxy == null) return;
|
||||||
|
|
||||||
|
proxy.Decorated = toBeDecorated;
|
||||||
|
proxy.ImplementationType = typeof(TImplementation);
|
||||||
|
proxy.DependencyResolver = _dependencyResolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/tand/Tand.Core/TandAttribute.cs
Normal file
16
src/tand/Tand.Core/TandAttribute.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public class TandAttribute : Attribute
|
||||||
|
{
|
||||||
|
|
||||||
|
public TandAttribute(Type targetType)
|
||||||
|
{
|
||||||
|
TargetType = targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type TargetType { get; }
|
||||||
|
}
|
||||||
|
}
|
73
src/tand/Tand.Core/TandProxy.cs
Normal file
73
src/tand/Tand.Core/TandProxy.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Tand.Core.Models;
|
||||||
|
|
||||||
|
namespace Tand.Core
|
||||||
|
{
|
||||||
|
public class TandProxy<T> : DispatchProxy
|
||||||
|
{
|
||||||
|
private readonly IDictionary<int, Type[]> _targetCache;
|
||||||
|
|
||||||
|
public TandProxy()
|
||||||
|
{
|
||||||
|
_targetCache = new ConcurrentDictionary<int, Type[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ImplementationType { get; set; }
|
||||||
|
public T Decorated { private get; set; }
|
||||||
|
|
||||||
|
public IDependencyResolver DependencyResolver { get; set; }
|
||||||
|
|
||||||
|
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
||||||
|
{
|
||||||
|
var mappedMethodArgs = CollectArgs(targetMethod, args);
|
||||||
|
var enterContext = new CallEnterContext<T>(Decorated, mappedMethodArgs);
|
||||||
|
var targets = TargetTypesForMethod(targetMethod);
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
target.OnEnterMethod(enterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = targetMethod.Invoke(Decorated, args);
|
||||||
|
|
||||||
|
var leaveContext = new CallLeaveContext<T>(Decorated, mappedMethodArgs, result);
|
||||||
|
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
target.OnLeaveMethod(leaveContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IDictionary<string, object> CollectArgs(MethodBase methodInfo, IReadOnlyList<object> argValues)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<string, object>();
|
||||||
|
var parameters = methodInfo.GetParameters();
|
||||||
|
for (var i = 0; i < parameters.Length && i < argValues.Count; i++)
|
||||||
|
{
|
||||||
|
result.Add(parameters[i].Name, argValues[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICollection<ITandTarget<T>> TargetTypesForMethod(MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
var hash = methodInfo.GetHashCode();
|
||||||
|
if (!_targetCache.ContainsKey(hash))
|
||||||
|
{
|
||||||
|
_targetCache[hash] = methodInfo.GetCustomAttributes<TandAttribute>()
|
||||||
|
.Select(attr => attr.TargetType)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _targetCache[hash]
|
||||||
|
.Select(type => DependencyResolver.TargetOfType<T>(type))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Tand.Extensions.DependencyInjection\Tand.Extensions.DependencyInjection.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Tand.Core;
|
||||||
|
using Tand.Core.Models;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Tand.Extensions.DependencyInjection.Tests
|
||||||
|
{
|
||||||
|
public class TandServiceExtensionsTests
|
||||||
|
{
|
||||||
|
public const string Greeting = "Hello, World!";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RegisterService_RegisterSampleService_SuccessfullyResolve()
|
||||||
|
{
|
||||||
|
var calledOnEnter = false;
|
||||||
|
var calledOnExit = false;
|
||||||
|
var servides = new ServiceCollection();
|
||||||
|
servides.AddTand();
|
||||||
|
servides.AddSingleton(new TestDecorator(_ => { calledOnEnter = true;}, _ => { calledOnExit = true;}));
|
||||||
|
servides.AddTandTransient<ISampleService, SampleServiceImpl>();
|
||||||
|
var provider = servides.BuildServiceProvider();
|
||||||
|
|
||||||
|
var sampleService = provider.GetService<ISampleService>();
|
||||||
|
Assert.NotNull(sampleService);
|
||||||
|
var result = sampleService.Greet();
|
||||||
|
|
||||||
|
Assert.Equal(Greeting, result);
|
||||||
|
Assert.True(calledOnEnter);
|
||||||
|
Assert.True(calledOnExit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestDecorator : ITandTarget<ISampleService>
|
||||||
|
{
|
||||||
|
private readonly Action<CallEnterContext<ISampleService>> _onEnterHandle;
|
||||||
|
private readonly Action<CallLeaveContext<ISampleService>> _onLeaveHandle;
|
||||||
|
|
||||||
|
public TestDecorator(Action<CallEnterContext<ISampleService>> onEnterHandle, Action<CallLeaveContext<ISampleService>> onLeaveHandle)
|
||||||
|
{
|
||||||
|
_onEnterHandle = onEnterHandle;
|
||||||
|
_onLeaveHandle = onLeaveHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEnterMethod(CallEnterContext<ISampleService> enterContext) => _onEnterHandle(enterContext);
|
||||||
|
|
||||||
|
public void OnLeaveMethod(CallLeaveContext<ISampleService> leaveContext) => _onLeaveHandle(leaveContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISampleService
|
||||||
|
{
|
||||||
|
[Tand(typeof(TestDecorator))]
|
||||||
|
string Greet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SampleServiceImpl : ISampleService
|
||||||
|
{
|
||||||
|
public string Greet() => TandServiceExtensionsTests.Greeting;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using Tand.Core;
|
||||||
|
|
||||||
|
namespace Tand.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public class DependencyResolverProxy : IDependencyResolver
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public DependencyResolverProxy(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITandTarget<T> TargetOfType<T>(Type type) => _serviceProvider.GetService(type) switch
|
||||||
|
{
|
||||||
|
ITandTarget<T> target => target,
|
||||||
|
_ => throw new ArgumentException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Tand.Core\Tand.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
||||||
|
namespace Tand.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public static class TandServiceExtensions
|
||||||
|
{
|
||||||
|
public static void AddTand(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton(sp => new Tand.Core.Tand(new DependencyResolverProxy(sp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddTandTransient<TService, TImplementation>(this IServiceCollection services)
|
||||||
|
where TService : class
|
||||||
|
where TImplementation : class, TService
|
||||||
|
{
|
||||||
|
services.AddTransient<TImplementation>();
|
||||||
|
services.AddTransient(GetTandForType<TService, TImplementation>);
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TService GetTandForType<TService, TImplementation>(IServiceProvider serviceProvider) where TImplementation : class, TService where TService : class
|
||||||
|
{
|
||||||
|
var tand = serviceProvider.GetService<Tand.Core.Tand>();
|
||||||
|
var instance = serviceProvider.GetService<TImplementation>();
|
||||||
|
var proxy = tand.DecorateWithTand<TService, TImplementation>(instance);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
src/tand/Tand.sln
Normal file
86
src/tand/Tand.sln
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26124.0
|
||||||
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Core", "Tand.Core\Tand.Core.csproj", "{994166B2-862B-451B-B3E5-B2797EFF7022}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4A0DFFF5-7BB2-481A-BB0F-152D89823F48}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C51CA370-A0C7-4229-90FA-ADF7B51DE021}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Core.Tests", "Tand.Core.Tests\Tand.Core.Tests.csproj", "{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Extensions.DependencyInjection", "Tand.Extensions.DependencyInjection\Tand.Extensions.DependencyInjection.csproj", "{C535C043-7A0E-4F17-89E4-493E7805CFAC}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tand.Extensions.DependencyInjection.Tests", "Tand.Extensions.DependencyInjection.Tests\Tand.Extensions.DependencyInjection.Tests.csproj", "{D1287B4D-319A-4D7A-BB5B-93C4E8320480}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{994166B2-862B-451B-B3E5-B2797EFF7022} = {4A0DFFF5-7BB2-481A-BB0F-152D89823F48}
|
||||||
|
{7CFEE412-6D6A-407B-9FAE-1640F74D98E7} = {C51CA370-A0C7-4229-90FA-ADF7B51DE021}
|
||||||
|
{C535C043-7A0E-4F17-89E4-493E7805CFAC} = {4A0DFFF5-7BB2-481A-BB0F-152D89823F48}
|
||||||
|
{D1287B4D-319A-4D7A-BB5B-93C4E8320480} = {C51CA370-A0C7-4229-90FA-ADF7B51DE021}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
5
toc.yml
Normal file
5
toc.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- name: Articles
|
||||||
|
href: articles/
|
||||||
|
- name: Api Documentation
|
||||||
|
href: api/
|
||||||
|
homepage: api/index.md
|
Loading…
Reference in a new issue