Skip to content

Neuen elego Backend-Service erstellen

Beispiele

Alle Beispiele basieren auf einer Anwendung MyDemo.

Projekt anlegen

Das neue .NET Projekt wird mit dotnet-Template web wie folgt angelegt:

dotnet new web -f net10.0 --use-program-main --name MyDemo.Service

und gemäss elego Projektstruktur eingebettet. Die Solution müsste danach wie in der untenstehenden Abbildung gezeigt aussehen.

Projektstruktur elego BackendService

Projektfile anpassen

Im Projektfile sind folgende Anpassungen vorzunehmen:

  • RootNamespace und AssemblyName im Projektfile (z.B. MyDemo.Service.csproj) anpassen. (Namenskonvention: Eis.[Projekt].Service, z.B. Eis.MyDemo.Service)
  • MSBuildProjectDirectory gemäss Beispiel einfügen. Damit wird bei jedem Build das Build-Datum in BuildDate.txt geschrieben.
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <AssemblyName>Eis.MyDemo.Service</AssemblyName>
    <RootNamespace>Eis.MyDemo.Service</RootNamespace>
  </PropertyGroup>

  <PropertyGroup>
    <BuildDate>$([System.DateTime]::UtcNow.ToString("O"))</BuildDate>
  </PropertyGroup>

  <ItemGroup>
    <AssemblyMetadata Include="BuildDate" Value="$(BuildDate)" />
  </ItemGroup>

</Project>

launchSettings.json anpassen

Die launchSettings werden gemäss untenstehendem Beispiel angepasst:

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
   "profiles": {
    "MyDemo.Service": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7115",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "launchUrl": "api/swagger"
    }
  }
}

Nuget Packages installieren

Folgende Nuget-Packages sind ab Package-Stream eis.azure.feed zu installieren:

  • Eis.Framework.Service.System (>= V52.0.0)

Program.cs anpassen

Program.cs ist wie folgt anzupassen:

using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using Eis.Framework.Business.Core.Persistence;
using Eis.Framework.Service.Core;
using Eis.Framework.Service.System;
using Eis.Framework.Service.System.Auth;
using Eis.Framework.Service.System.Extensions;
using NHibernate;
using Serilog;
using Serilog.Extensions.Logging;
using Log = Serilog.Log;

const string appName = "MyDemo";

var builder = WebApplication.CreateBuilder(args);

// -------------------------
// Logging
// -------------------------
ConfigureLogging(builder);

var msLogger = new SerilogLoggerFactory(Log.Logger).CreateLogger<Program>();
Log.Information("Start {AppName} Service", appName);

var loggerFactory = new NHibernate.Logging.Serilog.SerilogLoggerFactory();
NHibernateLogger.SetLoggersFactory(loggerFactory);

// -------------------------
// Configuration
// -------------------------
var cfg = builder.Configuration;

var connectionString = cfg.GetConnectionString(appName);
var settings = cfg.GetSection("Settings").Get<ServiceSettings>() 
               ?? new ServiceSettings();

var authConfig = cfg.GetSection("Authentication").Get<AuthenticationConfig>() 
                 ?? new AuthenticationConfig();

// -------------------------
// Services
// -------------------------
builder.Services.AddMemoryCache(); // elego service requires memory cache
builder.Services.AddSwagger(cfg);
builder.AddAuth(authConfig, args: args);

builder.AddElegoServicesAndHandleArguments(args, msLogger, conf =>
{
    conf.ApplicationName = appName;
    conf.ConnectionString = connectionString;
    conf.ServiceVersion = GetServiceVersion() ?? "1.0.0";
    conf.BuildDate = GetBuildDate();
    conf.EnvironmentType = settings.EnvironmentType;
    conf.DbEngineType = settings.DbEngineType;
    conf.UseAzureIdentityForConnectionString = settings.UseAzureIdentityForConnectionString;
    conf.HandleSqlStringParametersAsVarchar = settings.HandleSqlStringParametersAsVarchar;
});

var app = builder.Build();

// -------------------------
// Middleware / Pipeline
// -------------------------
app.UseSerilogRequestLogging();
app.UseExceptionHandling();

app.UseHttpsRedirection();

app.UsePathBase("/api");
app.UseRouting();

app.UseAndConfigureSwaggerUi(cfg["TitleApiInfo"] ?? appName);

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers()
   .RequireAuthorizationIf(authConfig.UseAuth, AuthConstants.DefaultPolicy);

app.RunElego();

// ============================================================================
// Helpers
// ============================================================================

static void ConfigureLogging(WebApplicationBuilder builder)
{
    builder.Logging.ClearProviders();

    Log.Logger = new LoggerConfiguration()
        .ReadFrom.Configuration(builder.Configuration)
        .CreateBootstrapLogger();

    builder.Host.UseSerilog(Log.Logger);
    builder.Logging.AddSerilog(Log.Logger);
}

static string? GetServiceVersion()
{
    return FileVersionInfo.GetVersionInfo(typeof(Program).Assembly.Location)
        .ProductVersion;
}

static DateTime GetBuildDate()
{
    var buildDateString = Assembly.GetExecutingAssembly()
        .GetCustomAttributes<AssemblyMetadataAttribute>()
        .FirstOrDefault(a => a.Key == "BuildDate")
        ?.Value;

    return DateTime.TryParse(
        buildDateString,
        CultureInfo.InvariantCulture,
        DateTimeStyles.RoundtripKind,
        out var buildDate)
        ? buildDate.ToLocalTime()
        : default;
}

// Small strongly-typed settings object (optional aber schön)
internal sealed class ServiceSettings
{
    public DbEngineType DbEngineType { get; init; }
    public string? EnvironmentType { get; init; }
    public bool UseAzureIdentityForConnectionString { get; init; }
    public bool HandleSqlStringParametersAsVarchar { get; init; }
}

// Fluent helper for conditional authorization
internal static class EndpointConventionBuilderExtensions
{
    public static TBuilder RequireAuthorizationIf<TBuilder>(
        this TBuilder builder, 
        bool condition, 
        string policy) 
        where TBuilder : IEndpointConventionBuilder
    {
        if (condition) builder.RequireAuthorization(policy);
        return builder;
    }
}

appsettings.json anpassen

appsettings.json ist gemäss elegoServiceApi appsettings.json anzupassen.

Minimal müssen für den DemoService MyDemo folgende Settings definiert sein :

{
  "TitleApiInfo": "MyDemo - API",
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MyDemo": "Data Source=.;Initial Catalog=MyDemo;Integrated Security=True"
  },
  "Settings": {
    "EnvironmentType": "Test",
    "DbEngineType": "MSSQL"
  },
  "Authentication": {
    "UseAuth": true,
    "ShowPII": true,
    "Authority": "https://devidp-eis.egeli-apps.dev",
    "Audience": "https://devidp-eis.egeli-apps.dev/resources",
    "Scopes": "elego_service_local openid profile",
    "SwaggerClientId": "elego_swagger_local"
  },
  "Serilog": {
    "MinimumLevel": "Information",
    "WriteTo": [
      {
        "Name": "Console"
      }
    ]
  }
}

Datenbank installieren

Die Service-Anwendung kann nun gebuildet werden.

Durch Aufruf der Service-Anwendung mit Argument install wird die in appsettings.json parametrierte Datenbank bereitgestellt.

   dotnet run -- install --configuration DEBUG --mode GenerateAndExecute

Weitere Infos zur Installation sind unter Installation dokumentiert.

Service API starten

Nach erfolgreicher Installation lässt sich das Service API wie folgt starten:

   dotnet run

Der Swagger-Endpunkt ist über den in den launchSettings definierten Port (z.B. https://localhost:7115/api/swagger) erreichbar.

Swagger-Seite für BackendService

Weiterentwicklung

Der Service ist nun für die Weiterentwicklung bereit.

Assembly-Prefix Eis

Alle Assembly-Namen müssen zwingend mit Eis. beginnen, sonst werden die eingebetteten Ressourcen nicht berücksichtigt!