Skip to content

Commit

Permalink
Fix #1644 + #1543
Browse files Browse the repository at this point in the history
  • Loading branch information
kbeaugrand committed Dec 6, 2022
1 parent 001194b commit 8766a31
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 159 deletions.
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ coverage:
target: auto # auto compares coverage to the previous base commit
ignore:
- "**/Startup.cs"
- "**/Startup/*.cs"
- "**/Program.cs"
- "**/PortalDbContext.cs"
- "**/Migrations/*.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,11 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<None Remove="Resources\default-template-icon.png" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Resources\default-template-icon.png" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.0" />
<PackageReference Include="Microsoft.Azure.Devices" Version="1.38.2" />
<PackageReference Include="Microsoft.Azure.Devices.Provisioning.Service" Version="1.18.2" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.0-preview1.22518.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) CGI France. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace AzureIoTHub.Portal.Application.Startup
{
using Microsoft.Extensions.DependencyInjection;

public static class IServiceCollectionExtension
{
public static IServiceCollection AddApplicationLayer(this IServiceCollection services)
{
return services.ConfigureMappingProfiles();
}

private static IServiceCollection ConfigureMappingProfiles(this IServiceCollection services)
{
return services.AddAutoMapper(typeof(IServiceCollectionExtension));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
Expand All @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<None Remove="Resources\default-template-icon.png" />
<None Remove="RouterConfigFiles\AS_923_925_1.json" />
<None Remove="RouterConfigFiles\AS_923_925_2.json" />
<None Remove="RouterConfigFiles\AS_923_925_3.json" />
Expand Down Expand Up @@ -90,6 +91,7 @@
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Resources\default-template-icon.png" />
<EmbeddedResource Include="RouterConfigFiles\CN_470_510_RP1.json" />
<EmbeddedResource Include="RouterConfigFiles\CN_470_510_RP2.json" />
<EmbeddedResource Include="RouterConfigFiles\EU_863_870.json" />
Expand Down Expand Up @@ -125,9 +127,14 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />
<PackageReference Include="EntityFrameworkCore.Exceptions.PostgreSQL" Version="6.0.3" />

</ItemGroup>

<ItemGroup>
Expand All @@ -137,4 +144,4 @@

</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright (c) CGI France. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace AzureIoTHub.Portal.Infrastructure.Startup
{
using System.Net;
using Azure.Storage.Blobs;
using AzureIoTHub.Portal.Application.Providers;
using AzureIoTHub.Portal.Application.Services;
using AzureIoTHub.Portal.Application.Wrappers;
using AzureIoTHub.Portal.Domain;
using AzureIoTHub.Portal.Domain.Options;
using AzureIoTHub.Portal.Infrastructure.Providers;
using AzureIoTHub.Portal.Infrastructure.Services;
using AzureIoTHub.Portal.Infrastructure.ServicesHealthCheck;
using AzureIoTHub.Portal.Infrastructure.Wrappers;
using EntityFramework.Exceptions.PostgreSQL;
using Microsoft.Azure.Devices.Provisioning.Service;
using Microsoft.Azure.Devices;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Polly;
using Polly.Extensions.Http;
using AzureIoTHub.Portal.Domain.Repositories;
using AzureIoTHub.Portal.Infrastructure.Repositories;
using AzureIoTHub.Portal.Application.Mappers;
using AzureIoTHub.Portal.Infrastructure.Mappers;
using AzureIoTHub.Portal.Models.v10.LoRaWAN;
using AzureIoTHub.Portal.Models.v10;
using AzureIoTHub.Portal.Application.Managers;
using AzureIoTHub.Portal.Infrastructure.Managers;
using Azure.Storage.Blobs.Models;
using Microsoft.Extensions.Configuration;

public static class IServiceCollectionExtension
{
public static IServiceCollection AddInfrastructureLayer(this IServiceCollection services, ConfigHandler configuration)
{
return services.ConfigureDatabase(configuration)
.ConfigureRepositories()
.ConfigureImageBlobStorage(configuration)
.AddLoRaWanSupport(configuration)
.ConfigureDeviceRegstryDependencies(configuration)
.ConfigureServices()
.ConfigureMappers()
.ConfigureHealthCheck();
}

private static IServiceCollection AddLoRaWanSupport(this IServiceCollection services, ConfigHandler configuration)
{
_ = services.Configure<LoRaWANOptions>(opts =>
{
opts.Enabled = configuration.IsLoRaEnabled;
opts.KeyManagementApiVersion = configuration.LoRaKeyManagementApiVersion;
opts.KeyManagementCode = configuration.LoRaKeyManagementCode;
opts.KeyManagementUrl = configuration.LoRaKeyManagementUrl;
});

if (!configuration.IsLoRaEnabled)
{
return services;
}

var transientHttpErrorPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(c => c.StatusCode == HttpStatusCode.NotFound)
.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(100));

_ = services.AddHttpClient("RestClient")
.AddPolicyHandler(transientHttpErrorPolicy);

_ = services.AddHttpClient<ILoRaWanManagementService, LoRaWanManagementService>((sp, client) =>
{
var opts = sp.GetService<IOptions<LoRaWANOptions>>().Value;

client.BaseAddress = new Uri(opts.KeyManagementUrl);
client.DefaultRequestHeaders.Add("x-functions-key", opts.KeyManagementCode);
client.DefaultRequestHeaders.Add("api-version", opts.KeyManagementApiVersion ?? "2022-03-04");
})
.AddPolicyHandler(transientHttpErrorPolicy);

return services;
}

private static IServiceCollection ConfigureDeviceRegstryDependencies(this IServiceCollection services, ConfigHandler configuration)
{
_ = services.AddTransient<IProvisioningServiceClient, ProvisioningServiceClientWrapper>();
_ = services.AddTransient<IDeviceRegistryProvider, AzureDeviceRegistryProvider>();

_ = services.AddScoped(_ => RegistryManager.CreateFromConnectionString(configuration.IoTHubConnectionString));
_ = services.AddScoped(_ => ServiceClient.CreateFromConnectionString(configuration.IoTHubConnectionString));
_ = services.AddScoped(_ => ProvisioningServiceClient.CreateFromConnectionString(configuration.DPSConnectionString));

return services;
}

private static IServiceCollection ConfigureDatabase(this IServiceCollection services, ConfigHandler configuration)
{
_ = services
.AddDbContextPool<PortalDbContext>(opts =>
{
_ = opts.UseNpgsql(configuration.PostgreSQLConnectionString);
_ = opts.UseExceptionProcessor();
});

if (string.IsNullOrEmpty(configuration.PostgreSQLConnectionString))
return services;

_ = services.AddScoped<IUnitOfWork, UnitOfWork<PortalDbContext>>();

var dbContextOptions = new DbContextOptionsBuilder<PortalDbContext>();
_ = dbContextOptions.UseNpgsql(configuration.PostgreSQLConnectionString);

using var ctx = new PortalDbContext(dbContextOptions.Options);
ctx.Database.Migrate();

return services;
}

private static IServiceCollection ConfigureRepositories(this IServiceCollection services)
{
return services.AddScoped<IDeviceModelPropertiesRepository, DeviceModelPropertiesRepository>()
.AddScoped<IDeviceTagRepository, DeviceTagRepository>()
.AddScoped<IEdgeDeviceModelRepository, EdgeDeviceModelRepository>()
.AddScoped<IEdgeDeviceModelCommandRepository, EdgeDeviceModelCommandRepository>()
.AddScoped<IDeviceModelRepository, DeviceModelRepository>()
.AddScoped<IDeviceRepository, DeviceRepository>()
.AddScoped<IEdgeDeviceRepository, EdgeDeviceRepository>()
.AddScoped<ILorawanDeviceRepository, LorawanDeviceRepository>()
.AddScoped<IDeviceTagValueRepository, DeviceTagValueRepository>()
.AddScoped<IDeviceModelCommandRepository, DeviceModelCommandRepository>()
.AddScoped<IConcentratorRepository, ConcentratorRepository>()
.AddScoped<ILoRaDeviceTelemetryRepository, LoRaDeviceTelemetryRepository>()
.AddScoped<ILabelRepository, LabelRepository>();
}

private static IServiceCollection ConfigureMappers(this IServiceCollection services)
{
_ = services.AddTransient<IDeviceModelImageManager, DeviceModelImageManager>();
_ = services.AddTransient<IConcentratorTwinMapper, ConcentratorTwinMapper>();
_ = services.AddTransient<IDeviceModelCommandMapper, DeviceModelCommandMapper>();

return services.AddTransient<IDeviceTwinMapper<DeviceListItem, DeviceDetails>, DeviceTwinMapper>()
.AddTransient<IDeviceTwinMapper<DeviceListItem, LoRaDeviceDetails>, LoRaDeviceTwinMapper>()
.AddTransient<IDeviceModelMapper<DeviceModelDto, DeviceModelDto>, DeviceModelMapper>()
.AddTransient<IDeviceModelMapper<DeviceModelDto, LoRaDeviceModelDto>, LoRaDeviceModelMapper>()
.AddTransient<IEdgeDeviceMapper, EdgeDeviceMapper>();
}

private static IServiceCollection ConfigureServices(this IServiceCollection services)
{
return services.AddTransient<ILoRaWanManagementService, LoRaWanManagementService>();
}

private static IServiceCollection ConfigureHealthCheck(this IServiceCollection services)
{
_ = services.AddHealthChecks()
.AddDbContextCheck<PortalDbContext>()
.AddCheck<IoTHubHealthCheck>("iothubHealth")
.AddCheck<StorageAccountHealthCheck>("storageAccountHealth")
.AddCheck<TableStorageHealthCheck>("tableStorageHealth")
.AddCheck<ProvisioningServiceClientHealthCheck>("dpsHealth")
.AddCheck<LoRaManagementKeyFacadeHealthCheck>("loraManagementFacadeHealth")
.AddCheck<DatabaseHealthCheck>("databaseHealthCheck");

return services;
}

private static IServiceCollection ConfigureImageBlobStorage(this IServiceCollection services, ConfigHandler configuration)
{
return services.AddTransient(_ => new BlobServiceClient(configuration.StorageAccountConnectionString))
.Configure<DeviceModelImageOptions>((opts) =>
{
var serviceClient = new BlobServiceClient(configuration.StorageAccountConnectionString);
var container = serviceClient.GetBlobContainerClient(opts.ImageContainerName);

_ = container.SetAccessPolicy(PublicAccessType.Blob);
_ = container.CreateIfNotExists();

opts.BaseUri = container.Uri;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
<PackageReference Include="Azure.Messaging.EventHubs.Processor" Version="5.7.5" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.14.1" />
<PackageReference Include="FluentValidation" Version="11.4.0" />
<PackageReference Include="EntityFrameworkCore.Exceptions.PostgreSQL" Version="6.0.3" />
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
Expand Down
Loading

0 comments on commit 8766a31

Please sign in to comment.