diff --git a/ExampleApplication/.gitignore b/ExampleApplication/.gitignore new file mode 100644 index 00000000..b7b62a0c --- /dev/null +++ b/ExampleApplication/.gitignore @@ -0,0 +1,39 @@ +# IDEs and editors +/.idea +.c9/ +*.sublime-workspace +.vs/ + +*.swp +*.*~ +project.lock.json +.DS_Store +*.pyc +nupkg/ + +# Visual Studio Code +.vscode + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +msbuild.log +msbuild.err +msbuild.wrn + +appsettings.Development.json diff --git a/ExampleApplication/AppSettings/AppSettings.cs b/ExampleApplication/AppSettings/AppSettings.cs new file mode 100644 index 00000000..72816397 --- /dev/null +++ b/ExampleApplication/AppSettings/AppSettings.cs @@ -0,0 +1,31 @@ +using System; + +namespace ExampleApplication +{ + public class AppSettings + { + public FiksIOConfig FiksIOConfig { get; set; } + } + + public class FiksIOConfig + { + public string ApiHost { get; set; } + public int ApiPort { get; set; } + public string ApiScheme { get; set; } + public string AmqpHost { get; set; } + public int AmqpPort { get; set; } + public Guid FiksIoAccountId { get; set; } + public Guid FiksIoIntegrationId { get; set; } + public string FiksIoIntegrationPassword { get; set; } + public string FiksIoIntegrationScope { get; set; } + public string FiksIoPrivateKey { get; set; } + public string MaskinPortenAudienceUrl { get; set; } + public string MaskinPortenCompanyCertificateThumbprint { get; set; } + public string MaskinPortenCompanyCertificatePath { get; set; } + public string MaskinPortenCompanyCertificatePassword { get; set; } + public string MaskinPortenIssuer { get; set; } + public string MaskinPortenTokenUrl { get; set; } + public string AsiceSigningPublicKey { get; set; } + public string AsiceSigningPrivateKey { get; set; } + } +} \ No newline at end of file diff --git a/ExampleApplication/AppSettings/AppSettingsBuilder.cs b/ExampleApplication/AppSettings/AppSettingsBuilder.cs new file mode 100644 index 00000000..915c07f2 --- /dev/null +++ b/ExampleApplication/AppSettings/AppSettingsBuilder.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.Configuration; + +namespace ExampleApplication +{ + public static class AppSettingsBuilder + { + public static AppSettings CreateAppSettings(IConfiguration configuration) + { + return configuration.GetSection("AppSettings").Get(); + } + } +} \ No newline at end of file diff --git a/ExampleApplication/ExampleApplication.csproj b/ExampleApplication/ExampleApplication.csproj index 07944b66..43aa81b2 100644 --- a/ExampleApplication/ExampleApplication.csproj +++ b/ExampleApplication/ExampleApplication.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 true true @@ -10,7 +10,11 @@ + + + + @@ -18,4 +22,12 @@ + + + + + Always + + + diff --git a/ExampleApplication/FiksIO/FiksIOConfigurationBuilder.cs b/ExampleApplication/FiksIO/FiksIOConfigurationBuilder.cs new file mode 100644 index 00000000..068a791b --- /dev/null +++ b/ExampleApplication/FiksIO/FiksIOConfigurationBuilder.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using KS.Fiks.IO.Client.Configuration; +using Ks.Fiks.Maskinporten.Client; + +namespace ExampleApplication.FiksIO +{ + public static class FiksIoConfigurationBuilder + { + + // Create configuration with the fluent builder + public static FiksIOConfiguration CreateConfiguration(AppSettings appSettings) + { + var accountId = appSettings.FiksIOConfig.FiksIoAccountId; + var privateKeyPath = appSettings.FiksIOConfig.FiksIoPrivateKey; + var integrationId = appSettings.FiksIOConfig.FiksIoIntegrationId; + var integrationPassword = appSettings.FiksIOConfig.FiksIoIntegrationPassword; + var issuer = appSettings.FiksIOConfig.MaskinPortenIssuer; + var certPath = appSettings.FiksIOConfig.MaskinPortenCompanyCertificatePath; + var certPassword = appSettings.FiksIOConfig.MaskinPortenCompanyCertificatePassword; + var asiceSigningPublicKey = appSettings.FiksIOConfig.AsiceSigningPublicKey; + var asiceSigningPrivateKey = appSettings.FiksIOConfig.AsiceSigningPrivateKey; + var host = appSettings.FiksIOConfig.AmqpHost; + var port = appSettings.FiksIOConfig.AmqpPort; + + return FiksIOConfigurationBuilder + .Init() + .WithAmqpConfiguration("fiks-io-client-dotnet-example-application", 1, true,20 * 1000) + .WithMaskinportenConfiguration(new X509Certificate2(certPath, certPassword), issuer) + .WithFiksIntegrasjonConfiguration(integrationId, integrationPassword) + .WithFiksKontoConfiguration(accountId, ReadFromFile(privateKeyPath)) + .WithAsiceSigningConfiguration(asiceSigningPublicKey, asiceSigningPrivateKey) + .BuildConfiguration(host, port); + } + + // Create a FiksIOConfiguration manually + public static FiksIOConfiguration CreateConfig(string issuer, string p12Filename, string p12Password, string fiksIoAccountId, + string fiksIoPrivateKeyPath, string integrasjonId, string integrasjonPassword) + { + // ID-porten machine to machine configuration + var maskinportenConfig = new MaskinportenClientConfiguration( + audience: @"https://ver2.maskinporten.no/", // ID-porten audience path + tokenEndpoint: @"https://ver2.maskinporten.no/token", // ID-porten token path + issuer: issuer, // KS issuer name + numberOfSecondsLeftBeforeExpire: 10, // The token will be refreshed 10 seconds before it expires + certificate: new X509Certificate2(p12Filename, p12Password)); + + // Fiks IO account configuration + var kontoConfig = new KontoConfiguration( + kontoId: Guid.Parse(fiksIoAccountId) /* Fiks IO accountId as Guid */, + privatNokkel: ReadFromFile( + fiksIoPrivateKeyPath) /* Private key in PEM format, paired with the public key supplied to Fiks IO account */); + + + // Id and password for integration associated to the Fiks IO account. + var integrasjonConfig = new IntegrasjonConfiguration( + Guid.Parse(integrasjonId) /* Integration id as Guid */, + integrasjonPassword /* Integration password */); + + var asiceSigningConfig = new AsiceSigningConfiguration(new X509Certificate2(p12Filename, p12Password)); + + + // Optional: Use custom api host (i.e. for connecting to test api) + var apiConfig = new ApiConfiguration( + scheme: "https", + host: "api.fiks.test.ks.no", + port: 443); + + // Optional: Use custom amqp host (i.e. for connection to test queue) + var amqpConfig = new AmqpConfiguration( + host: "io.fiks.test.ks.no", + port: 5671); + + // Combine all configurations + return new FiksIOConfiguration(kontoConfig, integrasjonConfig, maskinportenConfig, asiceSigningConfig, apiConfig, amqpConfig); + } + + private static string ReadFromFile(string path) + { + return File.ReadAllText(path, Encoding.UTF8); + } + } +} \ No newline at end of file diff --git a/ExampleApplication/FiksIO/FiksIOSubscriber.cs b/ExampleApplication/FiksIO/FiksIOSubscriber.cs new file mode 100644 index 00000000..7bd1b4c3 --- /dev/null +++ b/ExampleApplication/FiksIO/FiksIOSubscriber.cs @@ -0,0 +1,77 @@ +using System.Net; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using KS.Fiks.IO.Client; +using KS.Fiks.IO.Client.Models; +using Microsoft.Extensions.Hosting; +using Serilog; + +namespace ExampleApplication +{ + public class FiksIOSubscriber : BackgroundService + { + private IFiksIOClient _fiksIoClient; + private readonly AppSettings _appSettings; + private static readonly ILogger Log = Serilog.Log.ForContext(MethodBase.GetCurrentMethod()?.DeclaringType); + private Timer FiksIoClientStatusCheckTimer { get; set; } + private const int HealthCheckInterval = 15 * 1000; + + public FiksIOSubscriber(IFiksIOClient fiksIoClient, AppSettings appSettings) + { + _fiksIoClient = fiksIoClient; + _appSettings = appSettings; + + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + Log.Information("Application is starting subscribe"); + SubscribeToFiksIOClient(); + + Log.Information($"FiksIOSubscriber is starting timer for simple health checks with interval of {HealthCheckInterval} ms"); + + FiksIoClientStatusCheckTimer = new Timer(WriteStatusToLog, null, HealthCheckInterval, HealthCheckInterval); + + await Task.CompletedTask; + } + + private void WriteStatusToLog(object o) + { + Log.Information($"FiksIOSubscriber status check - FiksIOClient connection IsOpen status: {_fiksIoClient.IsOpen()}"); + Log.Information($"FiksIOSubscriber status check - Maskinporten reachable : {CheckMaskinportenIsReachable()}"); + } + + private bool CheckMaskinportenIsReachable() + { + var request = (HttpWebRequest) WebRequest.Create(_appSettings.FiksIOConfig.MaskinPortenAudienceUrl); + request.Timeout = 5 * 1000; + request.Method = "HEAD"; + try + { + using (HttpWebResponse response = (HttpWebResponse) request.GetResponse()) + { + return response.StatusCode == HttpStatusCode.OK; + } + } + catch (WebException) + { + return false; + } + } + + private void OnReceivedMelding(object sender, MottattMeldingArgs mottatt) + { + Log.Information("Message with messageId {MeldingId} and messagetype {MeldingsType} received. Message will be acked.", mottatt.Melding.MeldingId, + mottatt.Melding.MeldingType); + mottatt.SvarSender.Ack(); + } + + private void SubscribeToFiksIOClient() + { + var accountId = _appSettings.FiksIOConfig.FiksIoAccountId; + Log.Information($"Starting subscribe on account {accountId}..."); + _fiksIoClient.NewSubscription(OnReceivedMelding); + } + } +} \ No newline at end of file diff --git a/ExampleApplication/Program.cs b/ExampleApplication/Program.cs index 8a88570f..5c20408a 100644 --- a/ExampleApplication/Program.cs +++ b/ExampleApplication/Program.cs @@ -2,12 +2,18 @@ using System.IO; using System.Security.Cryptography.X509Certificates; using System.Text; -using System.Threading; using System.Threading.Tasks; +using ExampleApplication.FiksIO; using KS.Fiks.IO.Client; using KS.Fiks.IO.Client.Configuration; using KS.Fiks.IO.Client.Models; using Ks.Fiks.Maskinporten.Client; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Events; namespace ExampleApplication { @@ -15,103 +21,44 @@ class Program { public static async Task Main(string[] args) { - // Relative or absolute path to the *.p12-file containing the test certificate used to sign tokens for Maskinporten - var p12Filename = Environment.GetEnvironmentVariable("P12FILENAME"); + var configurationRoot = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true) + .AddJsonFile($"appsettings.Development.json", optional: true).Build(); - // Password required to use the certificate - var p12Password = Environment.GetEnvironmentVariable("P12PWD"); + var loggerFactory = InitSerilogConfiguration(); + var appSettings = AppSettingsBuilder.CreateAppSettings(configurationRoot); + var configuration = FiksIoConfigurationBuilder.CreateConfiguration(appSettings); + var fiksIoClient = await FiksIOClient.CreateAsync(configuration, loggerFactory); - // The issuer as defined in Maskinporten - var issuer = Environment.GetEnvironmentVariable("MASKINPORTEN_ISSUER"); - - // accountId as defined in the Fiks Forvaltning Interface - var fiksIoAccountId = Environment.GetEnvironmentVariable("FIKS_IO_ACCOUNT_ID"); - // private key corresponding to the public key uploaded in the Fiks Forvaltning Interface - var fiksIoPrivateKeyPath = Environment.GetEnvironmentVariable("FIKS_IO_PRIVATE_KEY_PATH"); - - // Values generated in Fiks Forvaltning when creating the "Integrasjon" - var integrasjonId = Environment.GetEnvironmentVariable("INTEGRASJON_ID"); - var integrasjonPassword = Environment.GetEnvironmentVariable("INTEGRASJON_PWD"); - - // Relative or absolute path to the public cert you want to use with the signing of the asice packages - var asiceCertFilepath = Environment.GetEnvironmentVariable("ASICE_CERT_FILENAME"); - // Relative or absolute path to the privatekey (that is created from the cert above) that you want to use with the signing of the asice packages - var asiceCertPrivateKeyPath = Environment.GetEnvironmentVariable("ASICE_CERT_PRIVATEKEY"); - - // Create configuration easy with the fluent configuration builder - var configuration = CreateConfigurationWithFluentBuilder(p12Filename, p12Password, issuer, integrasjonId, integrasjonPassword, fiksIoAccountId, fiksIoPrivateKeyPath, asiceCertFilepath, asiceCertPrivateKeyPath); - - // Or create the configuration manually - //var configuration = CreateConfig(issuer, p12Filename, p12Password, fiksIoAccountId, fiksIoPrivateKeyPath, integrasjonId, integrasjonPassword); - - using (var client = await FiksIOClient.CreateAsync(configuration)) - { - var konto = await client.Lookup(new LookupRequest("999999999", "no.ks.fiks.melding", 2)); - Console.Out.WriteLineAsync($"Konto hentet! Kontonavn: {konto.KontoNavn}"); - } - - } - - // Creates a FiksIOConfiguration using the fluent builder - private static FiksIOConfiguration CreateConfigurationWithFluentBuilder(string maskinportenCertFilename, string maskinportenCertPassword, string issuer, - string integrasjonId, string integrasjonPassword, string fiksIoAccountId, string fiksIoPrivateKeyPath, string asiceCertFilepath = null, string asiceCertPrivateKeyPath = null) - { - // Combine all configurations - return FiksIOConfigurationBuilder - .Init() - .WithAmqpConfiguration("fiks-io-klient-test-program-2", 1, false) - .WithMaskinportenConfiguration(new X509Certificate2(maskinportenCertFilename, maskinportenCertPassword), issuer) - .WithFiksIntegrasjonConfiguration(Guid.Parse(integrasjonId), integrasjonPassword) - .WithFiksKontoConfiguration(Guid.Parse(fiksIoAccountId), ReadFromFile(fiksIoPrivateKeyPath)) - .WithAsiceSigningConfiguration(asiceCertFilepath, asiceCertPrivateKeyPath) - .BuildTestConfiguration(); + await new HostBuilder() + .ConfigureHostConfiguration((configHost) => + { + configHost.AddEnvironmentVariables("DOTNET_"); + }) + .ConfigureServices((hostContext, services) => + { + services.AddSingleton(appSettings); + services.AddSingleton(loggerFactory); + services.AddSingleton(fiksIoClient); + services.AddHostedService(); + }) + .RunConsoleAsync(); } - - // Creates a FiksIOConfiguration manually - private static void CreateConfig(string issuer, string p12Filename, string p12Password, string fiksIoAccountId, - string fiksIoPrivateKeyPath, string integrasjonId, string integrasjonPassword) + + private static ILoggerFactory InitSerilogConfiguration() { - // ID-porten machine to machine configuration - var maskinportenConfig = new MaskinportenClientConfiguration( - audience: @"https://ver2.maskinporten.no/", // ID-porten audience path - tokenEndpoint: @"https://ver2.maskinporten.no/token", // ID-porten token path - issuer: issuer, // KS issuer name - numberOfSecondsLeftBeforeExpire: 10, // The token will be refreshed 10 seconds before it expires - certificate: new X509Certificate2(p12Filename, p12Password)); - - // Fiks IO account configuration - var kontoConfig = new KontoConfiguration( - kontoId: Guid.Parse(fiksIoAccountId) /* Fiks IO accountId as Guid */, - privatNokkel: ReadFromFile( - fiksIoPrivateKeyPath) /* Private key in PEM format, paired with the public key supplied to Fiks IO account */); - - - // Id and password for integration associated to the Fiks IO account. - var integrasjonConfig = new IntegrasjonConfiguration( - Guid.Parse(integrasjonId) /* Integration id as Guid */, - integrasjonPassword /* Integration password */); - - var asiceSigningConfig = new AsiceSigningConfiguration(new X509Certificate2(p12Filename, p12Password)); + var loggerConfiguration = new LoggerConfiguration() + .MinimumLevel.Debug() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.AspNetCore.Localization", LogEventLevel.Error) + .Enrich.FromLogContext() + .WriteTo.Console(outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level}] [{RequestId}] [{requestid}] - {Message} {NewLine} {Exception}"); + var logger = loggerConfiguration.CreateLogger(); + Log.Logger = logger; - // Optional: Use custom api host (i.e. for connecting to test api) - var apiConfig = new ApiConfiguration( - scheme: "https", - host: "api.fiks.test.ks.no", - port: 443); - - // Optional: Use custom amqp host (i.e. for connection to test queue) - var amqpConfig = new AmqpConfiguration( - host: "io.fiks.test.ks.no", - port: 5671); - - // Combine all configurations - var configuration = new FiksIOConfiguration(kontoConfig, integrasjonConfig, maskinportenConfig, asiceSigningConfig, apiConfig, amqpConfig); - } - - private static string ReadFromFile(string path) - { - return File.ReadAllText(path, Encoding.UTF8); + return LoggerFactory.Create(logging => logging.AddSerilog(logger)); } } } \ No newline at end of file diff --git a/ExampleApplication/appsettings.json b/ExampleApplication/appsettings.json new file mode 100644 index 00000000..6477d2b2 --- /dev/null +++ b/ExampleApplication/appsettings.json @@ -0,0 +1,24 @@ +{ + "AppSettings": { + "FiksIOConfig": { + "ApiHost": "api.fiks.test.ks.no", + "ApiPort": "443", + "ApiScheme": "https", + "AmqpHost": "io.fiks.test.ks.no", + "AmqpPort": "5671", + "FiksIoAccountId": "", + "FiksIoIntegrationId": "", + "FiksIoIntegrationPassword": "", + "FiksIoIntegrationScope": "ks:fiks", + "FiksIoPrivateKey": "", + "MaskinPortenAudienceUrl": "https://ver2.maskinporten.no/", + "MaskinPortenCompanyCertificateThumbprint": "", + "MaskinPortenCompanyCertificatePath": "", + "MaskinPortenCompanyCertificatePassword": "", + "MaskinPortenIssuer": "", + "MaskinPortenTokenUrl": "https://ver2.maskinporten.no/token", + "AsiceSigningPrivateKey": "", + "AsiceSigningPublicKey": "", + } + } +} \ No newline at end of file diff --git a/KS.Fiks.IO.Client.Tests/Amqp/AmqpHandlerFixture.cs b/KS.Fiks.IO.Client.Tests/Amqp/AmqpHandlerFixture.cs index 3499d460..9afb62c9 100644 --- a/KS.Fiks.IO.Client.Tests/Amqp/AmqpHandlerFixture.cs +++ b/KS.Fiks.IO.Client.Tests/Amqp/AmqpHandlerFixture.cs @@ -6,6 +6,7 @@ using KS.Fiks.IO.Client.Dokumentlager; using KS.Fiks.IO.Client.Send; using Ks.Fiks.Maskinporten.Client; +using Microsoft.Extensions.Logging; using Moq; using RabbitMQ.Client; using RabbitMQ.Client.Exceptions; @@ -90,6 +91,7 @@ internal IAmqpHandler CreateSut() amqpConfiguration, CreateIntegrationConfiguration(), new KontoConfiguration(_accountId, "dummy"), + null, ConnectionFactoryMock.Object, AmqpConsumerFactoryMock.Object).Result; @@ -107,6 +109,7 @@ internal Task CreateSutAsync() amqpConfiguration, CreateIntegrationConfiguration(), new KontoConfiguration(_accountId, "dummy"), + null, ConnectionFactoryMock.Object, AmqpConsumerFactoryMock.Object); diff --git a/KS.Fiks.IO.Client.Tests/FiksIOClientFixture.cs b/KS.Fiks.IO.Client.Tests/FiksIOClientFixture.cs index ecc47d35..09294b7d 100644 --- a/KS.Fiks.IO.Client.Tests/FiksIOClientFixture.cs +++ b/KS.Fiks.IO.Client.Tests/FiksIOClientFixture.cs @@ -10,6 +10,7 @@ using KS.Fiks.IO.Client.Send; using KS.Fiks.IO.Send.Client; using Ks.Fiks.Maskinporten.Client; +using Microsoft.Extensions.Logging; using Moq; using RabbitMQ.Client.Events; @@ -61,6 +62,7 @@ public FiksIOClient CreateSut() SetupMocks(); return FiksIOClient.CreateAsync( _configuration, + null, CatalogHandlerMock.Object, MaskinportenClientMock.Object, SendHandlerMock.Object, diff --git a/KS.Fiks.IO.Client.sln b/KS.Fiks.IO.Client.sln index cfbee27c..6399782d 100644 --- a/KS.Fiks.IO.Client.sln +++ b/KS.Fiks.IO.Client.sln @@ -4,7 +4,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KS.Fiks.IO.Client", "KS.Fik EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KS.Fiks.IO.Client.Tests", "KS.Fiks.IO.Client.Tests\KS.Fiks.IO.Client.Tests.csproj", "{8B45963D-3333-4CAF-98BC-102C6A3CCE8A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApplication", "ExampleApplication\ExampleApplication.csproj", "{7F12F632-DAB0-481B-9E7B-B10D461FDF03}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApplication", "ExampleApplication\ExampleApplication.csproj", "{49E2D85B-14FB-45CD-BFFC-2D81C9B90BCF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,10 +20,10 @@ Global {8B45963D-3333-4CAF-98BC-102C6A3CCE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU {8B45963D-3333-4CAF-98BC-102C6A3CCE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B45963D-3333-4CAF-98BC-102C6A3CCE8A}.Release|Any CPU.Build.0 = Release|Any CPU - {7F12F632-DAB0-481B-9E7B-B10D461FDF03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7F12F632-DAB0-481B-9E7B-B10D461FDF03}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7F12F632-DAB0-481B-9E7B-B10D461FDF03}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7F12F632-DAB0-481B-9E7B-B10D461FDF03}.Release|Any CPU.Build.0 = Release|Any CPU + {49E2D85B-14FB-45CD-BFFC-2D81C9B90BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49E2D85B-14FB-45CD-BFFC-2D81C9B90BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49E2D85B-14FB-45CD-BFFC-2D81C9B90BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49E2D85B-14FB-45CD-BFFC-2D81C9B90BCF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution EndGlobalSection diff --git a/KS.Fiks.IO.Client/Amqp/AmqpHandler.cs b/KS.Fiks.IO.Client/Amqp/AmqpHandler.cs index 389a0fe3..33406208 100644 --- a/KS.Fiks.IO.Client/Amqp/AmqpHandler.cs +++ b/KS.Fiks.IO.Client/Amqp/AmqpHandler.cs @@ -1,197 +1,240 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using KS.Fiks.IO.Client.Configuration; -using KS.Fiks.IO.Client.Dokumentlager; -using KS.Fiks.IO.Client.Exceptions; -using KS.Fiks.IO.Client.Models; -using KS.Fiks.IO.Client.Send; -using Ks.Fiks.Maskinporten.Client; -using RabbitMQ.Client; -using RabbitMQ.Client.Events; - -namespace KS.Fiks.IO.Client.Amqp -{ - internal class AmqpHandler : IAmqpHandler - { - private const string QueuePrefix = "fiksio.konto."; - - private const int HealthCheckInterval = 5 * 60 * 1000; - - private readonly IAmqpConsumerFactory _amqpConsumerFactory; - - private readonly IConnectionFactory _connectionFactory; - - private readonly KontoConfiguration _kontoConfiguration; - - private readonly IMaskinportenClient _maskinportenClient; - - private readonly AmqpConfiguration _amqpConfiguration; - - private readonly IntegrasjonConfiguration _integrasjonConfiguration; - - private readonly SslOption _sslOption; - - private readonly Timer _ensureAmqpConnectionIsOpenTimer; - - private IModel _channel; - - private IConnection _connection; - - private IAmqpReceiveConsumer _receiveConsumer; - - private AmqpHandler( - IMaskinportenClient maskinportenClient, - ISendHandler sendHandler, - IDokumentlagerHandler dokumentlagerHandler, - AmqpConfiguration amqpConfiguration, - IntegrasjonConfiguration integrasjonConfiguration, - KontoConfiguration kontoConfiguration, - IConnectionFactory connectionFactory = null, - IAmqpConsumerFactory consumerFactory = null) - { - _sslOption = amqpConfiguration.SslOption ?? new SslOption(); - _maskinportenClient = maskinportenClient; - _amqpConfiguration = amqpConfiguration; - _integrasjonConfiguration = integrasjonConfiguration; - _kontoConfiguration = kontoConfiguration; - _connectionFactory = connectionFactory ?? new ConnectionFactory(); - _amqpConsumerFactory = consumerFactory ?? new AmqpConsumerFactory(sendHandler, dokumentlagerHandler, _kontoConfiguration); - if (amqpConfiguration.KeepAlive) - { - _ensureAmqpConnectionIsOpenTimer = new Timer(Callback, null, HealthCheckInterval, HealthCheckInterval); - } - } - - public static async Task CreateAsync( - IMaskinportenClient maskinportenClient, - ISendHandler sendHandler, - IDokumentlagerHandler dokumentlagerHandler, - AmqpConfiguration amqpConfiguration, - IntegrasjonConfiguration integrasjonConfiguration, - KontoConfiguration kontoConfiguration, - IConnectionFactory connectionFactory = null, - IAmqpConsumerFactory consumerFactory = null) - { - var amqpHandler = new AmqpHandler(maskinportenClient, sendHandler, dokumentlagerHandler, amqpConfiguration, integrasjonConfiguration, kontoConfiguration, connectionFactory, consumerFactory); - - await amqpHandler.SetupConnectionAndConnect(integrasjonConfiguration, amqpConfiguration).ConfigureAwait(false); - return amqpHandler; - } - - public void AddMessageReceivedHandler( - EventHandler receivedEvent, - EventHandler cancelledEvent) - { - if (_receiveConsumer == null) - { - _receiveConsumer = _amqpConsumerFactory.CreateReceiveConsumer(_channel); - } - - _receiveConsumer.Received += receivedEvent; - - _receiveConsumer.ConsumerCancelled += cancelledEvent; - - _channel.BasicConsume(_receiveConsumer, GetQueueName()); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public bool IsOpen() - { - return _channel != null && _channel.IsOpen && _connection != null && _connection.IsOpen; - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _channel.Dispose(); - _connection.Dispose(); - _ensureAmqpConnectionIsOpenTimer?.Dispose(); - } - } - - private async Task SetupConnectionAndConnect(IntegrasjonConfiguration integrasjonConfiguration, AmqpConfiguration amqpConfiguration) - { - await SetupConnectionFactory(integrasjonConfiguration).ConfigureAwait(false); - _connection = CreateConnection(amqpConfiguration); - _channel = ConnectToChannel(amqpConfiguration); - } - - private async void Callback(object o) - { - await EnsureAmqpConnectionIsOpen().ConfigureAwait(false); - } - - private async Task EnsureAmqpConnectionIsOpen() - { - if (!IsOpen()) - { - var oldConnection = _connection; - var oldChannel = _channel; - try - { - await SetupConnectionAndConnect(_integrasjonConfiguration, _amqpConfiguration) - .ConfigureAwait(false); - } - finally - { - oldChannel?.Dispose(); - oldConnection?.Dispose(); - } - } - } - - private IModel ConnectToChannel(AmqpConfiguration configuration) - { - try - { - var channel = _connection.CreateModel(); - channel.BasicQos(0, configuration.PrefetchCount, false); - return channel; - } - catch (Exception ex) - { - throw new FiksIOAmqpConnectionFailedException("Unable to connect to channel", ex); - } - } - - private IConnection CreateConnection(AmqpConfiguration configuration) - { - try - { - var endpoint = new AmqpTcpEndpoint(configuration.Host, configuration.Port, _sslOption); - return _connectionFactory.CreateConnection(new List { endpoint }, configuration.ApplicationName); - } - catch (Exception ex) - { - throw new FiksIOAmqpConnectionFailedException($"Unable to create connection. Host: {configuration.Host}; Port: {configuration.Port}; UserName:{_connectionFactory.UserName}; SslOption.Enabled: {_sslOption?.Enabled};SslOption.ServerName: {_sslOption?.ServerName}", ex); - } - } - - private async Task SetupConnectionFactory(IntegrasjonConfiguration integrasjonConfiguration) - { - try - { - var maskinportenToken = await _maskinportenClient.GetAccessToken(integrasjonConfiguration.Scope).ConfigureAwait(false); - _connectionFactory.UserName = integrasjonConfiguration.IntegrasjonId.ToString(); - _connectionFactory.Password = $"{integrasjonConfiguration.IntegrasjonPassord} {maskinportenToken.Token}"; - } - catch (Exception ex) - { - throw new FiksIOAmqpSetupFailedException("Unable to setup connection factory.", ex); - } - } - - private string GetQueueName() - { - return $"{QueuePrefix}{_kontoConfiguration.KontoId}"; - } - } +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using KS.Fiks.IO.Client.Configuration; +using KS.Fiks.IO.Client.Dokumentlager; +using KS.Fiks.IO.Client.Exceptions; +using KS.Fiks.IO.Client.Models; +using KS.Fiks.IO.Client.Send; +using Ks.Fiks.Maskinporten.Client; +using Microsoft.Extensions.Logging; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; + +namespace KS.Fiks.IO.Client.Amqp +{ + internal class AmqpHandler : IAmqpHandler + { + private const string QueuePrefix = "fiksio.konto."; + + private static IConnectionFactory _connectionFactory; + + private static IMaskinportenClient _maskinportenClient; + + private static IntegrasjonConfiguration _integrasjonConfiguration; + + private static IConnection _connection; + + private static ILogger _logger; + + private readonly IAmqpConsumerFactory _amqpConsumerFactory; + + private readonly KontoConfiguration _kontoConfiguration; + + private readonly SslOption _sslOption; + + private readonly Timer _ensureAmqpConnectionIsOpenTimer; + + private IModel _channel; + + private IAmqpReceiveConsumer _receiveConsumer; + + private AmqpHandler( + IMaskinportenClient maskinportenClient, + ISendHandler sendHandler, + IDokumentlagerHandler dokumentlagerHandler, + AmqpConfiguration amqpConfiguration, + IntegrasjonConfiguration integrasjonConfiguration, + KontoConfiguration kontoConfiguration, + ILoggerFactory loggerFactory = null, + IConnectionFactory connectionFactory = null, + IAmqpConsumerFactory consumerFactory = null) + { + _sslOption = amqpConfiguration.SslOption ?? new SslOption(); + _maskinportenClient = maskinportenClient; + _integrasjonConfiguration = integrasjonConfiguration; + _kontoConfiguration = kontoConfiguration; + _connectionFactory = connectionFactory ?? new ConnectionFactory(); + _amqpConsumerFactory = consumerFactory ?? new AmqpConsumerFactory(sendHandler, dokumentlagerHandler, _kontoConfiguration); + + if (amqpConfiguration.KeepAlive) + { + _ensureAmqpConnectionIsOpenTimer = new Timer(Callback, null, amqpConfiguration.KeepAliveHealthCheckInterval, amqpConfiguration.KeepAliveHealthCheckInterval); + } + + if (loggerFactory != null) + { + _logger = loggerFactory.CreateLogger(); + } + } + + public static async Task CreateAsync( + IMaskinportenClient maskinportenClient, + ISendHandler sendHandler, + IDokumentlagerHandler dokumentlagerHandler, + AmqpConfiguration amqpConfiguration, + IntegrasjonConfiguration integrasjonConfiguration, + KontoConfiguration kontoConfiguration, + ILoggerFactory loggerFactory = null, + IConnectionFactory connectionFactory = null, + IAmqpConsumerFactory consumerFactory = null) + { + var amqpHandler = new AmqpHandler(maskinportenClient, sendHandler, dokumentlagerHandler, amqpConfiguration, integrasjonConfiguration, kontoConfiguration, loggerFactory, connectionFactory, consumerFactory); + await amqpHandler.SetupConnectionAndConnect(integrasjonConfiguration, amqpConfiguration).ConfigureAwait(false); + + _logger?.LogDebug("AmqpHandler CreateAsync done"); + return amqpHandler; + } + + public void AddMessageReceivedHandler( + EventHandler receivedEvent, + EventHandler cancelledEvent) + { + if (_receiveConsumer == null) + { + _receiveConsumer = _amqpConsumerFactory.CreateReceiveConsumer(_channel); + } + + _receiveConsumer.Received += receivedEvent; + + _receiveConsumer.ConsumerCancelled += cancelledEvent; + + _channel.BasicConsume(_receiveConsumer, GetQueueName()); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public bool IsOpen() + { + return _channel != null && _channel.IsOpen && _connection != null && _connection.IsOpen; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _channel.Dispose(); + _connection.Dispose(); + _ensureAmqpConnectionIsOpenTimer?.Dispose(); + } + } + + private async Task SetupConnectionAndConnect(IntegrasjonConfiguration integrasjonConfiguration, AmqpConfiguration amqpConfiguration) + { + await SetupConnectionFactory(integrasjonConfiguration).ConfigureAwait(false); + _connection = CreateConnection(amqpConfiguration); + _channel = ConnectToChannel(amqpConfiguration); + + // Handle events for debugging + _connection.ConnectionShutdown += HandleConnectionShutdown; + _connection.ConnectionBlocked += HandleConnectionBlocked; + _connection.ConnectionUnblocked += HandleConnectionUnblocked; + } + + private void HandleConnectionBlocked(object sender, EventArgs e) + { + _logger?.LogDebug("RabbitMQ Connection ConnectionBlocked event has been triggered"); + } + + private void HandleConnectionUnblocked(object sender, EventArgs e) + { + _logger?.LogDebug("RabbitMQ Connection ConnectionUnblocked event has been triggered"); + } + + private void HandleConnectionShutdown(object sender, EventArgs shutdownEventArgs) + { + _logger?.LogDebug($"RabbitMQ Connection ConnectionShutdown event has been triggered"); + } + + private async void Callback(object o) + { + await RefreshTokenIfNotOpen().ConfigureAwait(false); + } + + private async Task RefreshTokenIfNotOpen() + { + _logger?.LogDebug("AmqpHandler RefreshTokenIfNotOpen start"); + if (!IsOpen()) + { + _logger?.LogDebug("AmqpHandler RefreshTokenIfNotOpen - Connection according to IsOpen is not open and will try to fetch and update with new token"); + + try + { + await RefreshMaskinportenToken(_integrasjonConfiguration).ConfigureAwait(false); + _logger?.LogDebug("AmqpHandler EnsureAmqpConnectionIsOpen - Connection reconnected"); + } + catch (Exception e) + { + _logger?.LogWarning($"AmqpHandler RefreshTokenIfNotOpen - Something went wrong trying to refresh token. Error message: {e.Message}", e); + } + } + } + + private IModel ConnectToChannel(AmqpConfiguration configuration) + { + try + { + var channel = _connection.CreateModel(); + channel.BasicQos(0, configuration.PrefetchCount, false); + return channel; + } + catch (Exception ex) + { + throw new FiksIOAmqpConnectionFailedException("Unable to connect to channel", ex); + } + } + + private IConnection CreateConnection(AmqpConfiguration configuration) + { + try + { + var endpoint = new AmqpTcpEndpoint(configuration.Host, configuration.Port, _sslOption); + var connection = _connectionFactory.CreateConnection(new List { endpoint }, configuration.ApplicationName); + return connection; + } + catch (Exception ex) + { + throw new FiksIOAmqpConnectionFailedException($"Unable to create connection. Host: {configuration.Host}; Port: {configuration.Port}; UserName:{_connectionFactory.UserName}; SslOption.Enabled: {_sslOption?.Enabled};SslOption.ServerName: {_sslOption?.ServerName}", ex); + } + } + + private async Task SetupConnectionFactory(IntegrasjonConfiguration integrasjonConfiguration) + { + try + { + var maskinportenToken = await _maskinportenClient.GetAccessToken(integrasjonConfiguration.Scope).ConfigureAwait(false); + _connectionFactory.UserName = integrasjonConfiguration.IntegrasjonId.ToString(); + _connectionFactory.Password = $"{integrasjonConfiguration.IntegrasjonPassord} {maskinportenToken.Token}"; + } + catch (Exception ex) + { + _logger?.LogError("AmqpHandler - Unable to setup connection factory"); + throw new FiksIOAmqpSetupFailedException("Unable to setup connection factory.", ex); + } + } + + private async Task RefreshMaskinportenToken(IntegrasjonConfiguration integrasjonConfiguration) + { + try + { + var maskinportenToken = await _maskinportenClient.GetAccessToken(integrasjonConfiguration.Scope).ConfigureAwait(false); + _connectionFactory.Password = $"{integrasjonConfiguration.IntegrasjonPassord} {maskinportenToken.Token}"; + } + catch (Exception ex) + { + _logger?.LogError("AmqpHandler - Unable to refresh with latest maskinporten token"); + throw new FiksIOAmqpSetupFailedException("Unable to refresh with latest maskinporten token.", ex); + } + } + + private string GetQueueName() + { + return $"{QueuePrefix}{_kontoConfiguration.KontoId}"; + } + } } \ No newline at end of file diff --git a/KS.Fiks.IO.Client/Configuration/AmqpConfiguration.cs b/KS.Fiks.IO.Client/Configuration/AmqpConfiguration.cs index aca8e439..6905e19b 100644 --- a/KS.Fiks.IO.Client/Configuration/AmqpConfiguration.cs +++ b/KS.Fiks.IO.Client/Configuration/AmqpConfiguration.cs @@ -7,8 +7,9 @@ public class AmqpConfiguration { public const string ProdHost = "io.fiks.ks.no"; public const string TestHost = "io.fiks.test.ks.no"; - - public AmqpConfiguration(string host, int port = 5671, SslOption sslOption = null, string applicationName = "Fiks IO klient (dotnet)", ushort prefetchCount = 10, bool keepAlive = false) + public const int DefaultKeepAliveHealthCheckInterval = 1 * 60 * 1000; + + public AmqpConfiguration(string host, int port = 5671, SslOption sslOption = null, string applicationName = "Fiks IO klient (dotnet)", ushort prefetchCount = 10, bool keepAlive = true, int keepAliveCheckInterval = DefaultKeepAliveHealthCheckInterval) { Host = host; Port = port; @@ -21,6 +22,7 @@ public AmqpConfiguration(string host, int port = 5671, SslOption sslOption = nul ApplicationName = applicationName; PrefetchCount = prefetchCount; KeepAlive = keepAlive; + KeepAliveHealthCheckInterval = keepAliveCheckInterval; } public string Host { get; } @@ -41,6 +43,8 @@ public AmqpConfiguration(string host, int port = 5671, SslOption sslOption = nul public bool KeepAlive { get; } + public int KeepAliveHealthCheckInterval { get; } + public static AmqpConfiguration CreateProdConfiguration(bool keepAlive = false, string applicationName = null) { return new AmqpConfiguration(ProdHost, keepAlive: keepAlive, applicationName: applicationName); diff --git a/KS.Fiks.IO.Client/Configuration/FiksIOConfigurationBuilder.cs b/KS.Fiks.IO.Client/Configuration/FiksIOConfigurationBuilder.cs index 737ec78f..fa8e672a 100644 --- a/KS.Fiks.IO.Client/Configuration/FiksIOConfigurationBuilder.cs +++ b/KS.Fiks.IO.Client/Configuration/FiksIOConfigurationBuilder.cs @@ -10,7 +10,8 @@ public class FiksIOConfigurationBuilder private IntegrasjonConfiguration _integrasjonConfiguration; private KontoConfiguration _kontoConfiguration; private AsiceSigningConfiguration _asiceSigningConfiguration; - private bool ampqKeepAlive = false; + private bool ampqKeepAlive = true; + private int ampqKeepAliveHealthCheckInterval = AmqpConfiguration.DefaultKeepAliveHealthCheckInterval; private string amqpApplicationName = string.Empty; private ushort amqpPrefetchCount = 10; private string maskinportenIssuer = string.Empty; @@ -21,12 +22,25 @@ public static FiksIOConfigurationBuilder Init() return new FiksIOConfigurationBuilder(); } + public FiksIOConfiguration BuildConfiguration(string host, int port = 5671) + { + ValidateConfigurations(); + + return new FiksIOConfiguration( + amqpConfiguration: new AmqpConfiguration(host, port, applicationName: amqpApplicationName, prefetchCount: amqpPrefetchCount, keepAlive: ampqKeepAlive), + apiConfiguration: ApiConfiguration.CreateTestConfiguration(), + asiceSigningConfiguration: _asiceSigningConfiguration, + integrasjonConfiguration: _integrasjonConfiguration, + kontoConfiguration: _kontoConfiguration, + maskinportenConfiguration: FiksIOConfiguration.CreateMaskinportenTestConfig(maskinportenIssuer, maskinportenCertificate)); + } + public FiksIOConfiguration BuildTestConfiguration() { ValidateConfigurations(); return new FiksIOConfiguration( - amqpConfiguration: new AmqpConfiguration(AmqpConfiguration.TestHost, applicationName: amqpApplicationName, prefetchCount: amqpPrefetchCount, keepAlive: ampqKeepAlive), + amqpConfiguration: new AmqpConfiguration(AmqpConfiguration.TestHost, applicationName: amqpApplicationName, prefetchCount: amqpPrefetchCount, keepAlive: ampqKeepAlive, keepAliveCheckInterval: ampqKeepAliveHealthCheckInterval), apiConfiguration: ApiConfiguration.CreateTestConfiguration(), asiceSigningConfiguration: _asiceSigningConfiguration, integrasjonConfiguration: _integrasjonConfiguration, @@ -59,7 +73,7 @@ public FiksIOConfigurationBuilder WithAsiceSigningConfiguration(string certifica _asiceSigningConfiguration = new AsiceSigningConfiguration(certificatePath, certificatePrivateKeyPath); return this; } - + public FiksIOConfigurationBuilder WithAsiceSigningConfiguration(X509Certificate2 x509Certificate2) { _asiceSigningConfiguration = new AsiceSigningConfiguration(x509Certificate2); @@ -78,7 +92,7 @@ public FiksIOConfigurationBuilder WithFiksKontoConfiguration(Guid fiksKontoId, s return this; } - public FiksIOConfigurationBuilder WithAmqpConfiguration(string applicationName, ushort prefetchCount, bool keepAlive = false) + public FiksIOConfigurationBuilder WithAmqpConfiguration(string applicationName, ushort prefetchCount, bool keepAlive = true, int keepAliveHealthCheckInterval = AmqpConfiguration.DefaultKeepAliveHealthCheckInterval) { ampqKeepAlive = keepAlive; amqpApplicationName = applicationName; diff --git a/KS.Fiks.IO.Client/FiksIOClient.cs b/KS.Fiks.IO.Client/FiksIOClient.cs index 1ef3f5c4..91fb53c1 100644 --- a/KS.Fiks.IO.Client/FiksIOClient.cs +++ b/KS.Fiks.IO.Client/FiksIOClient.cs @@ -4,7 +4,6 @@ using System.Net.Http; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using KS.Fiks.ASiC_E.Crypto; using KS.Fiks.IO.Client.Amqp; using KS.Fiks.IO.Client.Asic; using KS.Fiks.IO.Client.Catalog; @@ -13,6 +12,7 @@ using KS.Fiks.IO.Client.Models; using KS.Fiks.IO.Client.Send; using Ks.Fiks.Maskinporten.Client; +using Microsoft.Extensions.Logging; using RabbitMQ.Client.Events; [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] @@ -23,28 +23,30 @@ namespace KS.Fiks.IO.Client { public class FiksIOClient : IFiksIOClient { - private readonly ICatalogHandler _catalogHandler; + private static ISendHandler _sendHandler; - private ISendHandler _sendHandler; + private static ILoggerFactory _loggerFactory; - private IAmqpHandler _amqpHandler; + private static IAmqpHandler _amqpHandler; - private IDokumentlagerHandler _dokumentlagerHandler; + private static IDokumentlagerHandler _dokumentlagerHandler; - private readonly IPublicKeyProvider _publicKeyProvider; + private static IMaskinportenClient _maskinportenClient; - private IMaskinportenClient _maskinportenClient; + private readonly ICatalogHandler _catalogHandler; private FiksIOClient( FiksIOConfiguration configuration, + ILoggerFactory loggerFactory = null, HttpClient httpClient = null, IPublicKeyProvider publicKeyProvider = null) - : this(configuration, null, null, null, null, null, httpClient, publicKeyProvider) + : this(configuration, loggerFactory, null, null, null, null, null, httpClient, publicKeyProvider) { } private FiksIOClient( FiksIOConfiguration configuration, + ILoggerFactory loggerFactory = null, ICatalogHandler catalogHandler = null, IMaskinportenClient maskinportenClient = null, ISendHandler sendHandler = null, @@ -64,12 +66,13 @@ private FiksIOClient( _maskinportenClient, httpClient); - _publicKeyProvider = publicKeyProvider ?? new CatalogPublicKeyProvider(_catalogHandler); - - var _asicEncrypter = asicEncrypter ?? new AsicEncrypter( - new AsiceBuilderFactory(), - new EncryptionServiceFactory(), - AsicSigningCertificateHolderFactory.Create(configuration.AsiceSigningConfiguration)); + if (asicEncrypter == null) + { + asicEncrypter = new AsicEncrypter( + new AsiceBuilderFactory(), + new EncryptionServiceFactory(), + AsicSigningCertificateHolderFactory.Create(configuration.AsiceSigningConfiguration)); + } _sendHandler = sendHandler ?? new SendHandler( @@ -78,8 +81,8 @@ private FiksIOClient( configuration.FiksIOSenderConfiguration, configuration.IntegrasjonConfiguration, httpClient, - _asicEncrypter, - _publicKeyProvider); + asicEncrypter, + publicKeyProvider ?? new CatalogPublicKeyProvider(_catalogHandler)); _dokumentlagerHandler = dokumentlagerHandler ?? new DokumentlagerHandler( configuration.DokumentlagerConfiguration, @@ -88,17 +91,24 @@ private FiksIOClient( httpClient: httpClient); _amqpHandler = amqpHandler; + + _loggerFactory = loggerFactory; } - public static async Task CreateAsync(FiksIOConfiguration configuration, HttpClient httpClient = null, IPublicKeyProvider publicKeyProvider = null) + public static async Task CreateAsync( + FiksIOConfiguration configuration, + ILoggerFactory loggerFactory = null, + HttpClient httpClient = null, + IPublicKeyProvider publicKeyProvider = null) { - var client = new FiksIOClient(configuration, httpClient, publicKeyProvider); - await client.InitializeAsync(configuration).ConfigureAwait(false); - + var client = new FiksIOClient(configuration, loggerFactory, httpClient, publicKeyProvider); + await InitializeAmqpHandlerAsync(configuration).ConfigureAwait(false); return client; } - internal static async Task CreateAsync(FiksIOConfiguration configuration, + internal static async Task CreateAsync( + FiksIOConfiguration configuration, + LoggerFactory loggerFactory = null, ICatalogHandler catalogHandler = null, IMaskinportenClient maskinportenClient = null, ISendHandler sendHandler = null, @@ -108,30 +118,34 @@ internal static async Task CreateAsync(FiksIOConfiguration configu IPublicKeyProvider publicKeyProvider = null, IAsicEncrypter asicEncrypter = null) { + var client = new FiksIOClient( configuration, - catalogHandler, - maskinportenClient, - sendHandler, - dokumentlagerHandler, + loggerFactory, + catalogHandler, + maskinportenClient, + sendHandler, + dokumentlagerHandler, amqpHandler, - httpClient, + httpClient, publicKeyProvider, asicEncrypter); - await client.InitializeAsync(configuration).ConfigureAwait(false); - + await InitializeAmqpHandlerAsync(configuration).ConfigureAwait(false); return client; } - private async Task InitializeAsync(FiksIOConfiguration configuration) + private static async Task InitializeAmqpHandlerAsync(FiksIOConfiguration configuration) { - _amqpHandler = _amqpHandler ?? await AmqpHandler.CreateAsync(_maskinportenClient, + _amqpHandler = _amqpHandler ?? await AmqpHandler.CreateAsync( + _maskinportenClient, _sendHandler, _dokumentlagerHandler, configuration.AmqpConfiguration, configuration.IntegrasjonConfiguration, - configuration.KontoConfiguration); + configuration.KontoConfiguration, + _loggerFactory, + connectionFactory: null).ConfigureAwait(false); } public Guid KontoId { get; } diff --git a/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj b/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj index e594f35a..ea239b37 100644 --- a/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj +++ b/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj @@ -46,6 +46,7 @@ + diff --git a/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj.DotSettings b/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj.DotSettings new file mode 100644 index 00000000..b9fd6ee4 --- /dev/null +++ b/KS.Fiks.IO.Client/KS.Fiks.IO.Client.csproj.DotSettings @@ -0,0 +1,2 @@ + + CSharp80 \ No newline at end of file diff --git a/README.md b/README.md index 45a04461..d0de27eb 100644 --- a/README.md +++ b/README.md @@ -232,7 +232,7 @@ var configuration = new FiksIOConfiguration( #### Fiks-IO Konto: - **privatNokkel**: The `privatNokkel` property expects a private key in PKCS#8 format. Private key which has a PKCS#1 will cause an exception. -#### Asice signering: +#### Asice signing: Asice signing is required since version 3.0.0 of this client. There are two ways of setting this up, either with a public/private key pair or a x509Certificate2 that also holds the private key. If you are reusing the x509Certificate2 from the `maskinporten` configuration you might have to inject the corresponding private key.