mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-15 14:19:29 +00:00
Merge 7a764a5929 into 5aaa0d318a
This commit is contained in:
@@ -4,6 +4,9 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -18,7 +21,8 @@ jobs:
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: SystemExtensions.sln
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.Tests.csproj
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
||||
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
||||
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
@@ -41,12 +45,20 @@ jobs:
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Build Slim project
|
||||
- name: Build SystemExtensions.NetStandard project
|
||||
run: dotnet build SystemExtensions.NetStandard -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.DependencyInjection project
|
||||
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
|
||||
|
||||
- name: Push nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
|
||||
|
||||
- name: Push nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
@@ -20,7 +20,8 @@ jobs:
|
||||
|
||||
env:
|
||||
Solution_Path: SystemExtensions.sln
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.Tests.csproj
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
||||
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
||||
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
@@ -41,6 +42,9 @@ jobs:
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
- name: Execute DI Unit Tests
|
||||
run: dotnet test $env:DI_Test_Project_Path
|
||||
|
||||
- name: Restore Project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class DefaultOptionsManagerTests
|
||||
{
|
||||
private readonly DefaultOptionsManager optionsManager = new();
|
||||
|
||||
[TestMethod]
|
||||
public void GetOptions_ReturnsDefault()
|
||||
{
|
||||
var options = this.optionsManager.GetOptions<string>();
|
||||
|
||||
options.Should().BeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOptions_Succeeds()
|
||||
{
|
||||
this.optionsManager.UpdateOptions(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
public sealed class DummyOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class LiveOptionsResolverTests
|
||||
{
|
||||
private readonly LiveOptionsResolver liveOptionsResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILiveOptions_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(ILiveOptions<string>);
|
||||
|
||||
var canResolve = this.liveOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var canResolve = this.liveOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_ILiveOptions_ReturnsILiveOptions()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
var liveOptions = this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveOptions<string>));
|
||||
|
||||
liveOptions.Should().BeAssignableTo<ILiveOptions<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_AnythingElse_Throws()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.liveOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
private void SetupServiceProvider()
|
||||
{
|
||||
this.serviceProviderMock
|
||||
.Setup(u => u.GetService<IOptionsManager>())
|
||||
.Returns(this.optionsManagerMock.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class LiveUpdateableOptionsResolverTests
|
||||
{
|
||||
private readonly LiveUpdateableOptionsResolver liveUpdateableOptionsResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILiveUpdateableOptions_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(ILiveUpdateableOptions<string>);
|
||||
|
||||
var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(object), typeof(string), typeof(LiveOptionsResolverTests), typeof(int) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var canResolve = this.liveUpdateableOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_ILiveUpdateableOptions_ReturnsILiveUpdateableOptions()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
var liveOptions = this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(ILiveUpdateableOptions<string>));
|
||||
|
||||
liveOptions.Should().BeAssignableTo<ILiveUpdateableOptions<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_AnythingElse_Throws()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.liveUpdateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
private void SetupServiceProvider()
|
||||
{
|
||||
this.serviceProviderMock
|
||||
.Setup(u => u.GetService<IOptionsManager>())
|
||||
.Returns(this.optionsManagerMock.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class LiveUpdateableOptionsWrapperTests
|
||||
{
|
||||
private LiveUpdateableOptionsWrapper<string> optionsWrapper;
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.optionsWrapper = new LiveUpdateableOptionsWrapper<string>(this.optionsManagerMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetValue_ReturnsValue()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.GetOptions<string>())
|
||||
.Returns("hello");
|
||||
|
||||
var value = this.optionsWrapper.Value;
|
||||
|
||||
value.Should().Be("hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOption_CallsOptionsManager()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
|
||||
.Verifiable();
|
||||
|
||||
this.optionsWrapper.UpdateOption();
|
||||
|
||||
this.optionsManagerMock.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class OptionsResolverTests
|
||||
{
|
||||
private readonly OptionsResolver optionsResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
public Mock<IOptionsManager> OptionsManagerMock => optionsManagerMock;
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILiveOptions_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(IOptions<string>);
|
||||
|
||||
var canResolve = this.optionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(object), typeof(string), typeof(OptionsResolverTests), typeof(int) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var canResolve = this.optionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_IOptions_ReturnsIOptions()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
var liveOptions = this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IOptions<string>));
|
||||
|
||||
liveOptions.Should().BeAssignableTo<IOptions<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_AnythingElse_Throws()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.optionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
private void SetupServiceProvider()
|
||||
{
|
||||
this.serviceProviderMock
|
||||
.Setup(u => u.GetService<IOptionsManager>())
|
||||
.Returns(this.OptionsManagerMock.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class UpdateableOptionsResolverTests
|
||||
{
|
||||
private readonly UpdateableOptionsResolver updateableOptionsResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILiveOptions_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(IUpdateableOptions<string>);
|
||||
|
||||
var canResolve = this.updateableOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(object), typeof(string), typeof(UpdateableOptionsResolverTests), typeof(int) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var canResolve = this.updateableOptionsResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_IUpdateableOptions_ReturnsIUpdateableOptions()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
var liveOptions = this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(IUpdateableOptions<string>));
|
||||
|
||||
liveOptions.Should().BeAssignableTo<IUpdateableOptions<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_AnythingElse_Throws()
|
||||
{
|
||||
this.SetupServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.updateableOptionsResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
private void SetupServiceProvider()
|
||||
{
|
||||
this.serviceProviderMock
|
||||
.Setup(u => u.GetService<IOptionsManager>())
|
||||
.Returns(this.optionsManagerMock.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Extensions.Configuration;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||
{
|
||||
[TestClass]
|
||||
public class UpdateableOptionsWrapperTests
|
||||
{
|
||||
private const string Value = "hello";
|
||||
|
||||
private UpdateableOptionsWrapper<string> optionsWrapper;
|
||||
private readonly Mock<IOptionsManager> optionsManagerMock = new();
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.optionsWrapper = new UpdateableOptionsWrapper<string>(optionsManagerMock.Object, Value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetValue_ReturnsValue()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.GetOptions<string>())
|
||||
.Throws<Exception>();
|
||||
|
||||
var value = this.optionsWrapper.Value;
|
||||
|
||||
value.Should().Be(Value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOption_CallsOptionsManager()
|
||||
{
|
||||
this.optionsManagerMock
|
||||
.Setup(u => u.UpdateOptions<string>(It.IsAny<string>()))
|
||||
.Verifiable();
|
||||
|
||||
this.optionsWrapper.UpdateOption();
|
||||
|
||||
this.optionsManagerMock.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Http;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Http
|
||||
{
|
||||
[TestClass]
|
||||
public class HttpClientResolverTests
|
||||
{
|
||||
private readonly HttpClientResolver httpClientResolver = new();
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_IHttpClient_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(IHttpClient<>);
|
||||
|
||||
var canResolve = this.httpClientResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(HttpClient), typeof(object), typeof(string), typeof(HttpClientResolverTests), typeof(int) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var canResolve = this.httpClientResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_TypedClient_ReturnsIHttpClient()
|
||||
{
|
||||
var client = this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<string>));
|
||||
|
||||
client.Should().BeAssignableTo<IHttpClient<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_NonGenericType_Throws()
|
||||
{
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(IHttpClient<>));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_RandomType_Throws()
|
||||
{
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.httpClientResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class CVLoggerProviderTests
|
||||
{
|
||||
private readonly Mock<ILogsWriter> logsWriterMock = new();
|
||||
private CVLoggerProvider cVLoggerProvider;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.cVLoggerProvider = new CVLoggerProvider(this.logsWriterMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateLogger_CreatesNewLogger()
|
||||
{
|
||||
var logger = this.cVLoggerProvider.CreateLogger(string.Empty);
|
||||
|
||||
logger.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LogEntry_CallsLogWriter()
|
||||
{
|
||||
this.cVLoggerProvider.LogEntry(new Log());
|
||||
|
||||
this.logsWriterMock.Verify();
|
||||
}
|
||||
|
||||
private void SetupLogsWriter()
|
||||
{
|
||||
this.logsWriterMock
|
||||
.Setup(u => u.WriteLog(It.IsAny<Log>()))
|
||||
.Verifiable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class CVLoggerTests
|
||||
{
|
||||
private readonly Mock<ICVLoggerProvider> cvLoggerProviderMock = new();
|
||||
private CVLogger cVLogger;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.cVLogger = new CVLogger(string.Empty, this.cvLoggerProviderMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void BeginScope_ReturnsNull()
|
||||
{
|
||||
var scope = this.cVLogger.BeginScope(string.Empty);
|
||||
|
||||
scope.Should().BeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow(LogLevel.Debug)]
|
||||
[DataRow(LogLevel.Trace)]
|
||||
[DataRow(LogLevel.Information)]
|
||||
[DataRow(LogLevel.Warning)]
|
||||
[DataRow(LogLevel.Error)]
|
||||
[DataRow(LogLevel.Critical)]
|
||||
public void IsEnabled_OnAllLogLevels_ReturnsTrue(LogLevel logLevel)
|
||||
{
|
||||
var enabled = this.cVLogger.IsEnabled(logLevel);
|
||||
|
||||
enabled.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Log_CallsFormatter()
|
||||
{
|
||||
var called = false;
|
||||
Func<string, Exception, string> messageFormatter = new((state, exception) =>
|
||||
{
|
||||
called = true;
|
||||
return string.Empty;
|
||||
});
|
||||
|
||||
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), messageFormatter);
|
||||
|
||||
called.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Log_CallsLogsProvider()
|
||||
{
|
||||
this.SetupLoggerProvider();
|
||||
|
||||
this.cVLogger.Log(LogLevel.Debug, new EventId(), "Some message", new Exception(), new Func<string, Exception, string>((s, e) => string.Empty));
|
||||
|
||||
this.cvLoggerProviderMock.Verify();
|
||||
}
|
||||
|
||||
private void SetupLoggerProvider()
|
||||
{
|
||||
this.cvLoggerProviderMock
|
||||
.Setup(u => u.LogEntry(It.IsAny<Log>()))
|
||||
.Verifiable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class DebugLogsWriterTests
|
||||
{
|
||||
private readonly DebugLogsWriter logsWriter = new();
|
||||
|
||||
[TestMethod]
|
||||
public void WriteLog_Succeeds()
|
||||
{
|
||||
this.logsWriter.WriteLog(new Log());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullLog_Throws()
|
||||
{
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.logsWriter.WriteLog(null);
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Logging;
|
||||
using System.Windows.Extensions.Logging;
|
||||
|
||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||
{
|
||||
[TestClass]
|
||||
public class LoggerResolverTests
|
||||
{
|
||||
private readonly Mock<Slim.IServiceProvider> serviceProviderMock = new();
|
||||
private readonly Mock<ILoggerFactory> loggerFactoryMock = new();
|
||||
private readonly Mock<ILogger> loggerMock = new();
|
||||
private readonly LoggerResolver loggerResolver = new();
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_ILogger_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(ILogger);
|
||||
|
||||
var canResolve = this.loggerResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_GenericILogger_ReturnsTrue()
|
||||
{
|
||||
var type = typeof(ILogger<string>);
|
||||
|
||||
var canResolve = this.loggerResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CanResolve_AnythingElse_ReturnsFalse()
|
||||
{
|
||||
var types = new Type[] { typeof(CVLogger), typeof(object), typeof(string), typeof(LoggerResolverTests), typeof(int) };
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
var canResolve = this.loggerResolver.CanResolve(type);
|
||||
|
||||
canResolve.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_ILogger_ReturnsILogger()
|
||||
{
|
||||
this.SetupIServiceProvider();
|
||||
|
||||
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger));
|
||||
|
||||
logger.Should().BeAssignableTo<ILogger>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_TypedILogger_ReturnsTypedILogger()
|
||||
{
|
||||
this.SetupIServiceProvider();
|
||||
|
||||
var logger = this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<string>));
|
||||
|
||||
logger.Should().BeAssignableTo<ILogger<string>>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_RandomType_Throws()
|
||||
{
|
||||
this.SetupIServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(string));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Resolve_NonTypedGeneric_Throws()
|
||||
{
|
||||
this.SetupIServiceProvider();
|
||||
|
||||
Action action = new(() =>
|
||||
{
|
||||
this.loggerResolver.Resolve(this.serviceProviderMock.Object, typeof(ILogger<>));
|
||||
});
|
||||
|
||||
action.Should().Throw<Exception>();
|
||||
}
|
||||
|
||||
private void SetupIServiceProvider()
|
||||
{
|
||||
this.serviceProviderMock
|
||||
.Setup(u => u.GetService<ILoggerFactory>())
|
||||
.Returns(this.loggerFactoryMock.Object);
|
||||
|
||||
this.loggerFactoryMock
|
||||
.Setup(u => u.CreateLogger(It.IsAny<string>()))
|
||||
.Returns(this.loggerMock.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class DefaultOptionsManager : IOptionsManager
|
||||
{
|
||||
public T GetOptions<T>() where T : class
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public void UpdateOptions<T>(T value) where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public interface ILiveOptions<T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public interface IOptionsManager
|
||||
{
|
||||
T GetOptions<T>()
|
||||
where T : class;
|
||||
void UpdateOptions<T>(T value)
|
||||
where T : class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public interface IUpdateableOptions<out T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
|
||||
/// </summary>
|
||||
void UpdateOption();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class LiveOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
private T value;
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
this.value = this.configurationManager.GetOptions<T>();
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
}
|
||||
|
||||
public void UpdateOption()
|
||||
{
|
||||
this.configurationManager.UpdateOptions<T>(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class OptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(OptionsWrapper<>);
|
||||
private static readonly Type configurationType = typeof(IOptionsManager);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
var optionsValue = configurationType
|
||||
.GetMethod(nameof(IOptionsManager.GetOptions))
|
||||
.MakeGenericMethod(type.GetGenericArguments())
|
||||
.Invoke(configurationManager, Array.Empty<object>());
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, optionsValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class UpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
|
||||
private static readonly Type configurationType = typeof(IOptionsManager);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
var optionsValue = configurationType
|
||||
.GetMethod(nameof(IOptionsManager.GetOptions))
|
||||
.MakeGenericMethod(type.GetGenericArguments())
|
||||
.Invoke(configurationManager, Array.Empty<object>());
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Extensions.Configuration
|
||||
{
|
||||
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
public T Value { get; }
|
||||
|
||||
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.Value = options;
|
||||
}
|
||||
|
||||
public void UpdateOption()
|
||||
{
|
||||
this.configurationManager.UpdateOptions(this.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim;
|
||||
using System.Extensions;
|
||||
using System.Extensions.Configuration;
|
||||
using System.Http;
|
||||
using System.Logging;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class ServiceManagerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
|
||||
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="IOptionsManager"/>.
|
||||
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsManager<T>(this IServiceManager serviceManager)
|
||||
where T : IOptionsManager
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, T>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
|
||||
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns><see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(new OptionsResolver());
|
||||
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
|
||||
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
|
||||
where TLogsWriter : ILogsWriter
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
|
||||
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
|
||||
return factory;
|
||||
});
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
|
||||
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
|
||||
where TLogsWriter : TILogsWriter
|
||||
where TILogsWriter : class, ILogsWriter
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
|
||||
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
var factory = new LoggerFactory();
|
||||
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
|
||||
return factory;
|
||||
});
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(new HttpClientResolver());
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(
|
||||
new HttpClientResolver()
|
||||
.WithHttpMessageHandlerFactory(handlerFactory));
|
||||
return serviceManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Slim.Resolvers;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace System.Http
|
||||
{
|
||||
public sealed class HttpClientResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type clientType = typeof(HttpClient<>);
|
||||
|
||||
/// <summary>
|
||||
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
|
||||
/// </summary>
|
||||
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
|
||||
/// </summary>
|
||||
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
|
||||
/// <returns></returns>
|
||||
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
|
||||
{
|
||||
this.HttpMessageHandlerFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
|
||||
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
|
||||
var httpClient = handler is null ?
|
||||
Activator.CreateInstance(typedClientType) :
|
||||
Activator.CreateInstance(typedClientType, new object[] { handler });
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class CVLogger : ILogger
|
||||
{
|
||||
private readonly string category;
|
||||
private readonly ICVLoggerProvider cvLoggerProvider;
|
||||
|
||||
public CVLogger(string category, ICVLoggerProvider cvLoggerProvider)
|
||||
{
|
||||
this.category = category;
|
||||
this.cvLoggerProvider = cvLoggerProvider.ThrowIfNull(nameof(cvLoggerProvider));
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
var message = formatter(state, exception);
|
||||
|
||||
var log = new Log
|
||||
{
|
||||
Exception = exception,
|
||||
LogLevel = logLevel,
|
||||
EventId = eventId.Name,
|
||||
Message = message,
|
||||
Category = category,
|
||||
LogTime = DateTime.Now
|
||||
};
|
||||
|
||||
this.cvLoggerProvider.LogEntry(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.CorrelationVector;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class CVLoggerProvider : ICVLoggerProvider
|
||||
{
|
||||
private readonly ILogsWriter logsManager;
|
||||
private CorrelationVector correlationVector;
|
||||
|
||||
public CVLoggerProvider(ILogsWriter logsWriter)
|
||||
{
|
||||
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
|
||||
this.correlationVector = new CorrelationVector();
|
||||
}
|
||||
|
||||
public void LogEntry(Log log)
|
||||
{
|
||||
if (this.correlationVector is not null)
|
||||
{
|
||||
log.CorrelationVector = this.correlationVector.Value.ToString();
|
||||
this.correlationVector.Increment();
|
||||
}
|
||||
|
||||
this.logsManager.WriteLog(log);
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
if (this.correlationVector is not null)
|
||||
{
|
||||
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
|
||||
}
|
||||
|
||||
return new CVLogger(categoryName, this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed class DebugLogsWriter : ILogsWriter
|
||||
{
|
||||
public void WriteLog(Log log)
|
||||
{
|
||||
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public interface ICVLoggerProvider : ILoggerProvider
|
||||
{
|
||||
void LogEntry(Log log);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace System.Logging
|
||||
{
|
||||
public interface ILogsWriter
|
||||
{
|
||||
void WriteLog(Log log);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Slim.Resolvers;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Windows.Extensions.Logging
|
||||
{
|
||||
public sealed class LoggerResolver : IDependencyResolver
|
||||
{
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
|
||||
type == typeof(ILogger))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
|
||||
{
|
||||
return ResolveScopedLogger(serviceProvider, type);
|
||||
}
|
||||
else if (type == typeof(ILogger))
|
||||
{
|
||||
return ResolveLogger(serviceProvider, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(LoggerResolver)} cannot resolve an object of type {type.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||
var categoryTypes = type.GetGenericArguments();
|
||||
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
|
||||
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
|
||||
}
|
||||
|
||||
private static object ResolveLogger(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||
return loggerFactory.CreateLogger(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace System.Logging
|
||||
{
|
||||
public sealed record Log
|
||||
{
|
||||
public Exception Exception { get; set; }
|
||||
public DateTime LogTime { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string EventId { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string CorrelationVector { get; set; }
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>System.DependencyInjection</RootNamespace>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE" Link="LICENSE">
|
||||
<PackagePath></PackagePath>
|
||||
<Pack>True</Pack>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Slim" Version="1.5.1" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -16,14 +16,14 @@ namespace SystemExtensionsTests.Http
|
||||
{
|
||||
private const string resourceUrl = "resource";
|
||||
|
||||
private readonly Uri TestAddressUrl = new Uri("https://helloworld.xyz");
|
||||
private readonly MockHttpMessageHandler handler = new MockHttpMessageHandler();
|
||||
private static readonly Uri TestAddressUrl = new("https://helloworld.xyz");
|
||||
private readonly MockHttpMessageHandler handler = new();
|
||||
private IHttpClient<object> httpClient;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.httpClient = new HttpClient<object>(handler, false)
|
||||
this.httpClient = new HttpClient<object>(this.handler, false)
|
||||
{
|
||||
BaseAddress = TestAddressUrl
|
||||
};
|
||||
|
||||
+13
-1
@@ -5,11 +5,15 @@ VisualStudioVersion = 16.0.31005.135
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard", "SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj", "{4CE9E55C-6016-4631-B8D4-4D763DD05F23}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemExtensions.Tests", "SystemExtensions.Tests\SystemExtensions.Tests.csproj", "{33F9C404-EEFF-4EA8-B35C-1B3EA33025A6}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.Tests", "SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj", "{33F9C404-EEFF-4EA8-B35C-1B3EA33025A6}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4CE9E55C-6016-4631-B8D4-4D763DD05F23} = {4CE9E55C-6016-4631-B8D4-4D763DD05F23}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.DependencyInjection", "SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj", "{53510F19-2E51-423A-BE79-5DE66103E7FC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.DependencyInjection.Tests", "SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj", "{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -24,6 +28,14 @@ Global
|
||||
{33F9C404-EEFF-4EA8-B35C-1B3EA33025A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{33F9C404-EEFF-4EA8-B35C-1B3EA33025A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{33F9C404-EEFF-4EA8-B35C-1B3EA33025A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{53510F19-2E51-423A-BE79-5DE66103E7FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53510F19-2E51-423A-BE79-5DE66103E7FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53510F19-2E51-423A-BE79-5DE66103E7FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53510F19-2E51-423A-BE79-5DE66103E7FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user