feat(sphistorianclient): add AddZbSpHistorianClient DI extension
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.7" />
|
||||
|
||||
<!-- Test -->
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ZB.MOM.WW.SPHistorianClient;
|
||||
|
||||
/// <summary>
|
||||
/// ZB.MOM.WW DI registration for <see cref="HistorianClient"/>. Mirrors the family's
|
||||
/// <c>AddZb*</c> convention. Because <see cref="HistorianClientOptions"/> is <c>required</c>/
|
||||
/// <c>init</c>-only, callers pass a fully-built options instance (bind it from configuration in the
|
||||
/// consuming app, e.g. <c>config.GetSection("Historian").Get<HistorianClientOptions>()</c>).
|
||||
/// </summary>
|
||||
public static class ZbSpHistorianClientServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddZbSpHistorianClient(
|
||||
this IServiceCollection services,
|
||||
HistorianClientOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
if (string.IsNullOrWhiteSpace(options.Host))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"HistorianClientOptions.Host must be set.", nameof(options));
|
||||
}
|
||||
|
||||
services.AddSingleton(options);
|
||||
// HistorianClient opens a fresh channel per operation and has a no-op DisposeAsync,
|
||||
// so transient is safe and avoids assuming the shared dialect is concurrency-safe.
|
||||
services.AddTransient<HistorianClient>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZB.MOM.WW.SPHistorianClient;
|
||||
|
||||
namespace ZB.MOM.WW.SPHistorianClient.Tests;
|
||||
|
||||
public class DependencyInjectionTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task AddZbSpHistorianClient_resolves_client_and_options()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var options = new HistorianClientOptions { Host = "localhost" };
|
||||
|
||||
services.AddZbSpHistorianClient(options);
|
||||
|
||||
// HistorianClient is IAsyncDisposable-only, so the container must be disposed
|
||||
// asynchronously (a synchronous `using` throws InvalidOperationException).
|
||||
await using var sp = services.BuildServiceProvider();
|
||||
Assert.Same(options, sp.GetRequiredService<HistorianClientOptions>());
|
||||
Assert.NotNull(sp.GetRequiredService<HistorianClient>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddZbSpHistorianClient_throws_when_host_missing()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var options = new HistorianClientOptions { Host = "" };
|
||||
|
||||
Assert.Throws<ArgumentException>(() => services.AddZbSpHistorianClient(options));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddZbSpHistorianClient_throws_on_null_options()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddZbSpHistorianClient(null!));
|
||||
}
|
||||
}
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" />
|
||||
<PackageReference Include="xunit" />
|
||||
|
||||
Reference in New Issue
Block a user