Skip to content

Commit

Permalink
Merge branch 'asyncapi#196-Publish-a-global-dotnet-tool' into asyncap…
Browse files Browse the repository at this point in the history
…i#197-more-logging

# Conflicts:
#	Saunter.sln
#	examples/StreetlightsAPI/StreetlightsAPI.csproj
#	src/AsyncAPI.Saunter.Generator.Cli/ToFile/ServiceProviderBuilder.cs
#	src/AsyncAPI.Saunter.Generator.Cli/readme.md
#	test/AsyncAPI.Saunter.Generator.Cli.Tests/AsyncAPI.Saunter.Generator.Cli.Tests.csproj
#	test/AsyncAPI.Saunter.Generator.Cli.Tests/IntegrationTests.cs
  • Loading branch information
Senn Geerts authored and Senn Geerts committed Jul 13, 2024
2 parents e16fcf1 + 74260a8 commit e937716
Show file tree
Hide file tree
Showing 19 changed files with 336 additions and 51 deletions.
18 changes: 18 additions & 0 deletions Saunter.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Saunter.Tests", "test\Saunter.Tests\Saunter.Tests.csproj", "{3ADB27EF-7C80-40EB-AFC6-5D06D415FFAB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{6ABD4842-47AF-49A5-B057-0EBA64416789}"
ProjectSection(SolutionItems) = preProject
examples\.gitignore = examples\.gitignore
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreetlightsAPI", "examples\StreetlightsAPI\StreetlightsAPI.csproj", "{F188D4A7-BBCB-464F-A370-2BD84D18EA79}"
ProjectSection(ProjectDependencies) = postProject
Expand Down Expand Up @@ -57,6 +60,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Cli.Tests", "test\AsyncAPI.Saunter.Generator.Cli.Tests\AsyncAPI.Saunter.Generator.Cli.Tests.csproj", "{18AD0249-0436-4A26-9972-B97BA6905A54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreetlightsAPI.TopLevelStatement", "examples\StreetlightsAPI.TopLevelStatement\StreetlightsAPI.TopLevelStatement.csproj", "{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Build", "src\AsyncAPI.Saunter.Generator.Build\AsyncAPI.Saunter.Generator.Build.csproj", "{A320E670-5CB0-4815-AF67-D8D09FC92A2A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Build.Tests", "test\AsyncAPI.Saunter.Generator.Build.Tests\AsyncAPI.Saunter.Generator.Build.Tests.csproj", "{61142B10-7B49-436E-AE32-2737658BD1E5}"
Expand Down Expand Up @@ -155,6 +160,18 @@ Global
{18AD0249-0436-4A26-9972-B97BA6905A54}.Release|x64.Build.0 = Release|Any CPU
{18AD0249-0436-4A26-9972-B97BA6905A54}.Release|x86.ActiveCfg = Release|Any CPU
{18AD0249-0436-4A26-9972-B97BA6905A54}.Release|x86.Build.0 = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|x64.ActiveCfg = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|x64.Build.0 = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|x86.ActiveCfg = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Debug|x86.Build.0 = Debug|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|Any CPU.Build.0 = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|x64.ActiveCfg = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|x64.Build.0 = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|x86.ActiveCfg = Release|Any CPU
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA}.Release|x86.Build.0 = Release|Any CPU
{A320E670-5CB0-4815-AF67-D8D09FC92A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A320E670-5CB0-4815-AF67-D8D09FC92A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A320E670-5CB0-4815-AF67-D8D09FC92A2A}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -193,6 +210,7 @@ Global
{E8FACA22-CFED-4710-89E4-D55F31BF96B3} = {D8CB9C0D-9605-457B-979F-C8994B20A926}
{6C102D4D-3DA4-4763-B75E-C15E33E7E94A} = {28D4C365-FDED-49AE-A97D-36202E24A55A}
{18AD0249-0436-4A26-9972-B97BA6905A54} = {6491E321-2D02-44AB-9116-D722FE169595}
{6F6B8B03-9045-46EC-AE12-E7ADA492F9FA} = {6ABD4842-47AF-49A5-B057-0EBA64416789}
{A320E670-5CB0-4815-AF67-D8D09FC92A2A} = {28D4C365-FDED-49AE-A97D-36202E24A55A}
{61142B10-7B49-436E-AE32-2737658BD1E5} = {6491E321-2D02-44AB-9116-D722FE169595}
EndGlobalSection
Expand Down
4 changes: 4 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
specs/
streetlights.json
streetlights.yml
streetlights.yaml
79 changes: 79 additions & 0 deletions examples/StreetlightsAPI.TopLevelStatement/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NLog;
using NLog.Web;
using Saunter;
using Saunter.AsyncApiSchema.v2;
using StreetlightsAPI;

LogManager.Setup().LoadConfigurationFromAppSettings();

var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddSimpleConsole(console => console.SingleLine = true);
builder.Host.UseNLog();

// Add Saunter to the application services.
builder.Services.AddAsyncApiSchemaGeneration(options =>
{
options.AssemblyMarkerTypes = [typeof(StreetlightMessageBus)];

options.Middleware.UiTitle = "Streetlights API";

options.AsyncApi = new AsyncApiDocument
{
Info = new Info("Streetlights API", "1.0.0")
{
Description = "The Smartylighting Streetlights API allows you to remotely manage the city lights.",
License = new License("Apache 2.0")
{
Url = "https://www.apache.org/licenses/LICENSE-2.0"
}
},
Servers =
{
["mosquitto"] = new Server("test.mosquitto.org", "mqtt"),
["webapi"] = new Server("localhost:5000", "http"),
},
};
});

builder.Services.AddScoped<IStreetlightMessageBus, StreetlightMessageBus>();
builder.Services.AddControllers();

var app = builder.Build();

app.UseDeveloperExceptionPage();

app.UseRouting();
app.UseCors(configure => configure.AllowAnyOrigin().AllowAnyMethod());

// to be fixed with issue #173
#pragma warning disable ASP0014 // Suggest using top level route registrations instead of UseEndpoints
app.UseEndpoints(endpoints =>
{
endpoints.MapAsyncApiDocuments();
endpoints.MapAsyncApiUi();

endpoints.MapControllers();
});
#pragma warning restore ASP0014 // Suggest using top level route registrations instead of UseEndpoints

await app.StartAsync();

// Print the AsyncAPI doc location
var logger = app.Services.GetService<ILoggerFactory>().CreateLogger<Program>();
var options = app.Services.GetService<IOptions<AsyncApiOptions>>();
var addresses = app.Urls;
logger.LogInformation("AsyncAPI doc available at: {URL}", $"{addresses.FirstOrDefault()}{options.Value.Middleware.Route}");
logger.LogInformation("AsyncAPI UI available at: {URL}", $"{addresses.FirstOrDefault()}{options.Value.Middleware.UiBaseRoute}");

// Redirect base url to AsyncAPI UI
app.Map("/", () => Results.Redirect("index.html"));
app.Map("/index.html", () => Results.Redirect(options.Value.Middleware.UiBaseRoute));

await app.WaitForShutdownAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<!-- This project is targeting .NET8 intentionally (The 'old school' Startup-class project is .NET6), to prove that
the AsyncAPI.Saunter.Generator.Cli tool can generate specs for projects targetting .NET6 and .NET8. -->
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>

<!-- Example settings for "AsyncAPI.Saunter.Generator.Build", they are all option though -->
<AsyncAPIGenerateDocumentsOnBuild>true</AsyncAPIGenerateDocumentsOnBuild>
<AsyncAPIDocumentFormats>json,yml</AsyncAPIDocumentFormats>
<AsyncAPIDocumentFilename>streetlights.{extension}</AsyncAPIDocumentFilename>
<AsyncAPIDocumentOutputPath>specs</AsyncAPIDocumentOutputPath>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DocumentationFile>bin\Debug\StreetlightsAPI.TopLevelStatement.xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DocumentationFile>bin\Release\StreetlightsAPI.TopLevelStatement.xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>

<!-- Get the latest local build nuget package from source code, from the local nuget packages source as configured in nuget.config
999.* are the 'special' version number for local builds -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="AsyncAPI.Saunter.Generator.Build" Version="999.*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<!-- For release: use a real published nuget package -->
<ItemGroup Condition=" '$(Configuration)' == 'Release' ">
<PackageReference Include="AsyncAPI.Saunter.Generator.Build" Version="*-*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Saunter\Saunter.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="specs\" />

<Compile Include="../StreetlightsAPI/API.cs" />
<Compile Include="../StreetlightsAPI/Messaging.cs" />

<None Include="../StreetlightsAPI/nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<PackageReference Include="NLog" Version="5.3.2" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.11" />
</ItemGroup>

</Project>
19 changes: 19 additions & 0 deletions examples/StreetlightsAPI.TopLevelStatement/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},

"AllowedHosts": "*",

"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://localhost:5001"
}
}
}
}
7 changes: 6 additions & 1 deletion examples/StreetlightsAPI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using Saunter;
using Saunter.AsyncApiSchema.v2;

Expand All @@ -15,17 +17,20 @@ public class Program
{
public static void Main(string[] args)
{
LogManager.Setup().LoadConfigurationFromAppSettings();

CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging => logging.AddSimpleConsole(console => console.SingleLine = true))
.UseNLog()
.ConfigureWebHostDefaults(web =>
{
web.UseStartup<Startup>();
web.UseUrls("http://localhost:5000");
web.UseUrls("http://localhost:5001");
});
}
}
Expand Down
15 changes: 13 additions & 2 deletions examples/StreetlightsAPI/StreetlightsAPI.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- This project is targeting .NET6 intentionally (The top level statement project is .NET8), to prove that
the AsyncAPI.Saunter.Generator.Cli tool can generate specs for projects targetting .NET6 and .NET8. -->
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>

<!-- Example settings for "AsyncAPI.Saunter.Generator.Build", they are all option though -->
Expand Down Expand Up @@ -44,6 +46,15 @@

<ItemGroup>
<Folder Include="specs\" />

<Content Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>


<ItemGroup>
<PackageReference Include="NLog" Version="5.3.2" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.11" />
</ItemGroup>

</Project>
23 changes: 23 additions & 0 deletions examples/StreetlightsAPI/nlog.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">

<variable name="BaseDir" value="./" />

<!-- the targets to write to -->
<targets>
<!-- File Target for all log messages with basic details -->
<target xsi:type="File" name="allfile" fileName="${BaseDir}/streetlights.nlog"
layout="${longdate}|${level:uppercase=true}|${activity:property=TraceId}|${logger}|${message} ${exception:format=tostring}"
maxArchiveFiles="5" archiveAboveSize="104857600" archiveNumbering="DateAndSequence" archiveDateFormat="yyyy-MM-dd" archiveFileName="${BaseDir}/streetlights-{#}.nlog" />

<!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
<target xsi:type="Console" name="lifetimeConsole" layout="${MicrosoftConsoleLayout}" />
</targets>

<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Debug" writeTo="allfile" />
</rules>
</nlog>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>12</LangVersion>
<RootNamespace>AsyncAPI.Saunter.Generator.Cli</RootNamespace>
<NoWarn>$(NoWarn);EF1001</NoWarn>

<Description>AsyncAPI Command Line Tools: Dotnet tool to generate AsyncAPI spec file(s) from dotnet startup assembly.</Description>
<Authors>AsyncAPI Initiative</Authors>
Expand Down Expand Up @@ -42,8 +43,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.7" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="NSwag.Commands" Version="14.0.8" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/AsyncAPI.Saunter.Generator.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
var app = ConsoleApp.Create();
app.Add<ToFileCommand>();
app.Run(args);

Environment.ExitCode = 0;
22 changes: 22 additions & 0 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/DependencyResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Reflection;

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal static class DependencyResolver
{
public static void Init(string startupAssemblyBasePath)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var requestedAssembly = new AssemblyName(args.Name);
var fullPath = Path.Combine(startupAssemblyBasePath, $"{requestedAssembly.Name}.dll");
if (File.Exists(fullPath))
{
var assembly = Assembly.LoadFile(fullPath);
return assembly;
}
Console.WriteLine($"Could not resolve assembly: {args.Name}, requested by {args.RequestingAssembly?.FullName}");
return default;
};
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reflection;
using System.Runtime.Loader;
using System.Runtime.Loader;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.Extensions.Logging;

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;
Expand All @@ -13,12 +14,20 @@ internal class ServiceProviderBuilder(ILogger<ServiceProviderBuilder> logger) :
{
public IServiceProvider BuildServiceProvider(string startupAssembly)
{
var fullPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), startupAssembly));
var fullPath = Path.GetFullPath(startupAssembly);
var basePath = Path.GetDirectoryName(fullPath);
DependencyResolver.Init(basePath);

logger.LogInformation($"Loading startup assembly: {fullPath}");
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(fullPath);
var nswagCommandsAssembly = Assembly.LoadFrom(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(ServiceProviderBuilder).Assembly.Location), "NSwag.Commands.dll")));
var nswagServiceProvider = nswagCommandsAssembly.GetType("NSwag.Commands.ServiceProviderResolver");
var serviceProvider = (IServiceProvider)nswagServiceProvider.InvokeMember("GetServiceProvider", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, null, [assembly]);
var reporter = new OperationReporter(new OperationReportHandler(
m => logger.LogError(m),
m => logger.LogWarning(m),
m => logger.LogInformation(m),
m => logger.LogDebug(m)));
var appServiceProvider = new AppServiceProviderFactory(assembly, reporter);
var serviceProvider = appServiceProvider.Create([]);

return serviceProvider;
}
}
Loading

0 comments on commit e937716

Please sign in to comment.