Refactoring
- cleanup structure and CI pipeline - Only publish if release with tag
This commit is contained in:
parent
5ec141c801
commit
e291f691f1
12 changed files with 148 additions and 89 deletions
|
@ -1,16 +1,11 @@
|
||||||
name: .NET Core
|
name: Publish
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
tags:
|
||||||
pull_request:
|
- '**'
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
deploy:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Setup .NET Core
|
- name: Setup .NET Core
|
||||||
|
@ -20,9 +15,6 @@ jobs:
|
||||||
source-url: https://nuget.pkg.github.com/baez90/index.json
|
source-url: https://nuget.pkg.github.com/baez90/index.json
|
||||||
env:
|
env:
|
||||||
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
- name: Build with dotnet
|
|
||||||
run: dotnet build --configuration Release
|
|
||||||
working-directory: ./src/tand/
|
|
||||||
- name: Pack for deploying package
|
- name: Pack for deploying package
|
||||||
run: dotnet pack --configuration Release
|
run: dotnet pack --configuration Release
|
||||||
working-directory: ./src/tand/
|
working-directory: ./src/tand/
|
26
.github/workflows/validate.yml
vendored
Normal file
26
.github/workflows/validate.yml
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
name: Validate
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ '**' ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ '**' ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup .NET Core
|
||||||
|
uses: actions/setup-dotnet@v1.4.0
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1.101
|
||||||
|
source-url: https://nuget.pkg.github.com/baez90/index.json
|
||||||
|
env:
|
||||||
|
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
- name: Build with dotnet
|
||||||
|
run: dotnet build --configuration Release
|
||||||
|
working-directory: ./src/tand/
|
||||||
|
- name: Run tests
|
||||||
|
run: dotnet test --configuration Release --no-build
|
||||||
|
working-directory: ./src/tand/
|
|
@ -5,31 +5,21 @@ namespace Tand.Core.Tests
|
||||||
{
|
{
|
||||||
public class LogTarget<T> : ITandTarget<T>
|
public class LogTarget<T> : ITandTarget<T>
|
||||||
{
|
{
|
||||||
private readonly Action<string> _logHandle;
|
private readonly Action<T> _instanceHandle;
|
||||||
|
|
||||||
public LogTarget(Action<string> logHandle)
|
public LogTarget(Action<T> instanceHandle)
|
||||||
{
|
{
|
||||||
_logHandle = logHandle;
|
_instanceHandle = instanceHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEnterMethod(CallEnterContext<T> enterContext)
|
public void OnEnterMethod(CallEnterContext<T> enterContext)
|
||||||
{
|
{
|
||||||
_logHandle(enterContext.Instance.ToString());
|
_instanceHandle(enterContext.Instance);
|
||||||
foreach (var (name, val) in enterContext.Arguments)
|
|
||||||
{
|
|
||||||
_logHandle($"name: {name}, value: {val}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnLeaveMethod(CallLeaveContext<T> callLeaveContext)
|
public void OnLeaveMethod(CallLeaveContext<T> callLeaveContext)
|
||||||
{
|
{
|
||||||
_logHandle(callLeaveContext.Instance.ToString());
|
_instanceHandle(callLeaveContext.Instance);
|
||||||
foreach (var (name, val) in callLeaveContext.Arguments)
|
|
||||||
{
|
|
||||||
_logHandle($"name: {name}, value: {val}");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logHandle($"result: {callLeaveContext.CallResult}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
27
src/tand/Tand.Core.Tests/ResolverMock.cs
Normal file
27
src/tand/Tand.Core.Tests/ResolverMock.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Tand.Core.Tests
|
||||||
|
{
|
||||||
|
internal class ResolverMock : IDependencyResolver
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IDictionary<Type, object> _targets;
|
||||||
|
|
||||||
|
|
||||||
|
internal ResolverMock(params object[] targets)
|
||||||
|
{
|
||||||
|
_targets = targets.ToDictionary(target => target.GetType(), target => target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITandTarget<T> TargetOfType<T>(Type type)
|
||||||
|
{
|
||||||
|
ResolvingCounter++;
|
||||||
|
return (ITandTarget<T>)_targets[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int ResolvingCounter { get; private set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<LangVersion>8</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,55 +1,17 @@
|
||||||
using System;
|
|
||||||
using Xunit;
|
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
namespace Tand.Core.Tests
|
namespace Tand.Core.Tests
|
||||||
{
|
{
|
||||||
public class TandTest
|
|
||||||
|
public interface ITandSample
|
||||||
{
|
{
|
||||||
private readonly ITestOutputHelper _outputHelper;
|
[Tand(typeof(LogTarget<ITandSample>))]
|
||||||
|
|
||||||
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);
|
int LogMyParams(string s, int i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TandSample : ITAndSample
|
public class TandSample : ITandSample
|
||||||
{
|
{
|
||||||
|
|
||||||
private int _counter;
|
private int _counter;
|
||||||
|
|
||||||
public string ContextSample { get; set; }
|
public string ContextSample { get; set; }
|
||||||
|
|
||||||
public int LogMyParams(string s, int i)
|
public int LogMyParams(string s, int i)
|
||||||
|
|
22
src/tand/Tand.Core.Tests/TandTests.cs
Normal file
22
src/tand/Tand.Core.Tests/TandTests.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Tand.Core.Tests
|
||||||
|
{
|
||||||
|
public class TandTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GenerateTand()
|
||||||
|
{
|
||||||
|
var handleCallCounter = 0;
|
||||||
|
var resolver = new ResolverMock(new LogTarget<ITandSample>(tandSample => handleCallCounter++));
|
||||||
|
var tand = new Tand(resolver);
|
||||||
|
|
||||||
|
var sample = tand.DecorateWithTand<ITandSample, TandSample>(new TandSample());
|
||||||
|
var result = sample.LogMyParams("Hello, World", 42);
|
||||||
|
Assert.Equal(1, result);
|
||||||
|
Assert.Equal(2, handleCallCounter);
|
||||||
|
Assert.Equal(1, resolver.ResolvingCounter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Tand.Core.Models;
|
using Tand.Core.Models;
|
||||||
|
|
||||||
namespace Tand.Core
|
namespace Tand.Core.Models
|
||||||
{
|
{
|
||||||
public readonly struct CallEnterContext<T>
|
public readonly struct CallEnterContext<T>
|
||||||
{
|
{
|
|
@ -10,9 +10,15 @@ namespace Tand.Core
|
||||||
public class TandProxy<T> : DispatchProxy
|
public class TandProxy<T> : DispatchProxy
|
||||||
{
|
{
|
||||||
private readonly IDictionary<int, Type[]> _targetCache;
|
private readonly IDictionary<int, Type[]> _targetCache;
|
||||||
|
private readonly Action<Exception>? _exceptionHandler;
|
||||||
|
|
||||||
public TandProxy()
|
public TandProxy() : this(null)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TandProxy(Action<Exception>? exceptionHandler)
|
||||||
|
{
|
||||||
|
_exceptionHandler = exceptionHandler;
|
||||||
_targetCache = new ConcurrentDictionary<int, Type[]>();
|
_targetCache = new ConcurrentDictionary<int, Type[]>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,23 +30,54 @@ namespace Tand.Core
|
||||||
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
||||||
{
|
{
|
||||||
var mappedMethodArgs = CollectArgs(targetMethod, args);
|
var mappedMethodArgs = CollectArgs(targetMethod, args);
|
||||||
var enterContext = new CallEnterContext<T>(Decorated, mappedMethodArgs);
|
|
||||||
var targets = TargetTypesForMethod(targetMethod);
|
var targets = TargetTypesForMethod(targetMethod);
|
||||||
foreach (var target in targets)
|
|
||||||
{
|
ProcessOnEntering(targets, new CallEnterContext<T>(Decorated, mappedMethodArgs));
|
||||||
target.OnEnterMethod(enterContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = targetMethod.Invoke(Decorated, args);
|
var result = targetMethod.Invoke(Decorated, args);
|
||||||
|
|
||||||
var leaveContext = new CallLeaveContext<T>(Decorated, mappedMethodArgs, result);
|
ProcessOnLeaving(targets, new CallLeaveContext<T>(Decorated, mappedMethodArgs, result));
|
||||||
|
return result;
|
||||||
foreach (var target in targets)
|
|
||||||
{
|
|
||||||
target.OnLeaveMethod(leaveContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
protected virtual void OnEnterMethod(ITandTarget<T> target, CallEnterContext<T> callEnterContext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
target.OnEnterMethod(callEnterContext);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_exceptionHandler?.Invoke(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnLeaveMethod(ITandTarget<T> target, CallLeaveContext<T> callLeaveContext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
target.OnLeaveMethod(callLeaveContext);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_exceptionHandler?.Invoke(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessOnEntering(IEnumerable<ITandTarget<T>> targets, CallEnterContext<T> callEnterContext)
|
||||||
|
{
|
||||||
|
foreach (var tandTarget in targets)
|
||||||
|
{
|
||||||
|
OnEnterMethod(tandTarget, callEnterContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessOnLeaving(IEnumerable<ITandTarget<T>> targets, CallLeaveContext<T> callLeaveContext)
|
||||||
|
{
|
||||||
|
foreach (var tandTarget in targets)
|
||||||
|
{
|
||||||
|
OnLeaveMethod(tandTarget, callLeaveContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IDictionary<string, object> CollectArgs(MethodBase methodInfo, IReadOnlyList<object> argValues)
|
private static IDictionary<string, object> CollectArgs(MethodBase methodInfo, IReadOnlyList<object> argValues)
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<LangVersion>8</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Tand.Core;
|
using Tand.Core;
|
||||||
|
using Tand.Core.Models;
|
||||||
|
|
||||||
namespace Tand.Extensions.DependencyInjection
|
namespace Tand.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Tand.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
public static void AddTand(this IServiceCollection serviceCollection)
|
public static void AddTand(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
serviceCollection.TryAddSingleton(sp => new Tand.Core.Tand(new DependencyResolverProxy(sp)));
|
serviceCollection.TryAddSingleton(sp => new Core.Tand(new DependencyResolverProxy(sp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddTandTransient<TService, TImplementation>(this IServiceCollection services)
|
public static IServiceCollection AddTandTransient<TService, TImplementation>(this IServiceCollection services)
|
||||||
|
@ -22,7 +22,7 @@ namespace Tand.Extensions.DependencyInjection
|
||||||
|
|
||||||
private static TService GetTandForType<TService, TImplementation>(IServiceProvider serviceProvider) where TImplementation : class, TService where TService : class
|
private static TService GetTandForType<TService, TImplementation>(IServiceProvider serviceProvider) where TImplementation : class, TService where TService : class
|
||||||
{
|
{
|
||||||
var tand = serviceProvider.GetService<Tand.Core.Tand>();
|
var tand = serviceProvider.GetService<Core.Tand>();
|
||||||
var instance = serviceProvider.GetService<TImplementation>();
|
var instance = serviceProvider.GetService<TImplementation>();
|
||||||
var proxy = tand.DecorateWithTand<TService, TImplementation>(instance);
|
var proxy = tand.DecorateWithTand<TService, TImplementation>(instance);
|
||||||
return proxy;
|
return proxy;
|
||||||
|
|
Loading…
Add table
Reference in a new issue