Category: NetCoreUsefullEndpoints

NetCoreUsefullEndpoints–part 7–restart application

In order to do the shutdown, I have added the following extension

public static CancellationTokenSource cts=new ();

public static void MapShutdown(this IEndpointRouteBuilder route, string? corsPolicy = null, string[]? authorization = null)
        {
            ArgumentNullException.ThrowIfNull(route);
            var rh = route.MapPost(“api/usefull/shutdown/”,
                (HttpContext httpContext) =>
                {
                    var h= cts.Token.GetHashCode();
                    cts?.Cancel();                   
                    return h;
                   
                });

           rh.AddDefault(corsPolicy, authorization);

        }

This code defines a static field called “cts” in the “UsefullExtensions” class. “cts” is an instance of the “CancellationTokenSource” class, which is used to create a CancellationToken that can be used to stop the application gracefully.

The “MapShutdown” method is an extension method for IEndpointRouteBuilder that creates a new endpoint for a POST request to the “api/usefull/shutdown/” URL. When the request is received, the method cancels the “cts” CancellationTokenSource if it is not null, and returns the hash code of the CancellationToken. The method also sets the “corsPolicy” and “authorization” parameters for the endpoint.

You can call with

app.MapUsefullAll();

or with

app.MapShutdown

Anyway , the runAsync should be modified with

await app.RunAsync(UsefullExtensions.UsefullExtensions.cts.Token);

The “RunAsync” method of the “app” object is used to start the application and listen for incoming requests. The method takes a CancellationToken as an argument, which allows the application to be stopped gracefully by cancelling the token. In this case, the token is provided by the “cts” field of the “UsefullExtensions” class. The code uses the “await” keyword to wait for the task returned by “RunAsync” to complete before continuing.

NetCoreUsefullEndpoints–part 6–passing to .NET 7

So  .NET 7 has appeared and I decided to pass NetCoreUsefullEndpoints to .NET 7 .

Also, for RateLimiter , I have considered that is good to know if the request is local or remote … so I decided to add connection ( remote IP, local IP, and more details) to the nuget package.

So I have created for .NET 6 this :

So , first things first : modify the version from  6.2022.1203.1551 to  7.2022.1203.1551 ( my versioning scheme is .NETCore version compliant of the package.year.MMdd.HHmm  – pretty stable and easy to decide what package you should add)

Then I want to profit to show in swagger the return type with TypedResults – so , as an example , I have modified from

route.MapGet(“api/usefull/httpContext/Connection”, (HttpContext httpContext) =>
{
var con = httpContext.Connection;
if (con == null)
{
     return Results.NoContent();
}
var conSerialize = new
{
     LocalIpAddress = con.LocalIpAddress?.ToString(),
     RemoteIpAddress = con.RemoteIpAddress?.ToString(),
     con.RemotePort,
     con.LocalPort,
     con.ClientCertificate,
     con.Id
};
return Results.Ok(conSerialize);

})

to

route.MapGet(“api/usefull/httpContext/Connection”,

Results<NoContent, Ok<object>>
(HttpContext httpContext) =>
{
var con = httpContext.Connection;
if (con == null)
{
     return TypedResults.NoContent();
}
var conSerialize = new
{
     LocalIpAddress = con.LocalIpAddress?.ToString(),
     RemoteIpAddress = con.RemoteIpAddress?.ToString(),
     con.RemotePort,
     con.LocalPort,
     con.ClientCertificate,
     con.Id
};
return TypedResults.Ok((object)conSerialize);
})

As you see , a pretty easy modification – indicating the INesteHttpResult Results<NoContent, Ok<object>>  ( so the swagger understand the 2 different return types )  and returning TypedResults instead of Results

Also the github ci must add the .NET Core and Azure App Service should be going to .NET 7 STS

[Nuget] dotnet-run-script

I found this awesome package – https://github.com/xt0rted/dotnet-run-script . It is good to make macros in global.json, then execute in a CICD scenario.

For example, NetCoreUsefullEndpoints used this in yaml ( pretty standard )

# – name: Restore dependencies

#   run: |

#     cd src

#     cd UsefullEndpoints

#     dotnet tool restore

#     dotnet pwsh readme.ps1

#     dotnet restore

# – name: Build

#   run: |

#     cd src

#     cd UsefullEndpoints

#     dotnet build –no-restore

# – name: Pack

#   run: |

#     cd src

#     cd UsefullEndpoints

#     cd UsefullExtensions

#     dotnet pack -o ../nugetPackages  –include-symbols –include-source

Now I have a global.json

{

“scripts”: {

“make_readme”:”dotnet pwsh readme.ps1″,

“prebuild”:”dotnet restore”,

“build”: “dotnet build –no-restore”,

“test”: “dotnet test –configuration Release”,

“prepack”:”dotnet r build”,

“pack”: “cd UsefullExtensions &&  dotnet pack -o ../nugetPackages  –include-symbols –include-source”

}

}

and the yaml is

– name: Restore dependencies

run: |

cd src

cd UsefullEndpoints

dotnet tool restore

dotnet r make_readme

dotnet r pack

Pretty easy  -and can be reproduced on local if you want, not just in CICD actions on source control…

NetCoreUsefullEndpoints-5 Endpoints summary

So for now the package https://www.nuget.org/packages/NetCoreUsefullEndpoints/ has the following endpoints:

GET=>/api/usefull/user/authorization

GET=>/api/usefull/user/noAuthorization

GET=>/api/usefull/environment

GET=>/api/usefull/errorWithILogger

GET=>/api/usefull/errorPure

GET=>/api/usefull/date

GET=>/api/usefull/endpoints/graph ( this calls https://github.com/dotnet/aspnetcore/blob/8bf447aa3f9719f6f162598708020dd4b420b49d/src/Http/Routing/src/Internal/DfaGraphWriter.cs#L22 )

GET=>/api/usefull/endpoints/text

GET=>/api/usefull/configuration ( this calls https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.configurationrootextensions.getdebugview?view=dotnet-plat-ext-6.0 )

You can see in practice at https://netcoreusefullendpoints.azurewebsites.net/swagger/

NetCoreUsefullEndpoints-4 Nuget package

or NugetPackages there is a simple .NET Pack CLI command  and many configurations

However, it is not so simple . See https://docs.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices .

In practice, I have a readme.md file ( for showing on nuget.org ) and a readme.txt file( for the programmer to show help after installing the package) THis is what I have in the csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<ItemGroup>
		<FrameworkReference Include="Microsoft.AspNetCore.App" />
		 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />   
		<PackageReference Include="RSCG_Static" Version="2021.12.18.2037" PrivateAssets="all" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
		<None Include="../../../README.md" Pack="true" PackagePath="\" />
		<None Include="../../../docs/nuget.png" Pack="true" PackagePath="\" />    
		<None Include="../readme.txt" Pack="true" PackagePath="\" />
	</ItemGroup>
	<PropertyGroup>
		<Version>6.2022.722.712</Version>
		<Authors>Andrei Ignat</Authors>
		
		<Description>Some usefull extensions: error, environment, user</Description>
		<Title>NetCoreUsefullEndpoints</Title>
		<PackageId>NetCoreUsefullEndpoints</PackageId>
		<PackageTags>C#;.NET;ASP.NET Core;</PackageTags>
		<PackageReadmeFile>README.md</PackageReadmeFile>
		<RepositoryUrl>https://github.com/ignatandrei/NetCoreUsefullEndpoints</RepositoryUrl>
		<PackageProjectUrl>https://github.com/ignatandrei/NetCoreUsefullEndpoints</PackageProjectUrl>
		<RepositoryType>GIT</RepositoryType>
		<Copyright>MIT</Copyright>
		<PackageLicenseExpression>MIT</PackageLicenseExpression>
		<IncludeSymbols>true</IncludeSymbols>
		<PublishRepositoryUrl>true</PublishRepositoryUrl>
		<EmbedUntrackedSources>true</EmbedUntrackedSources>
		<Deterministic>true</Deterministic>
		<DebugType>embedded</DebugType>

	</PropertyGroup>
	<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
		<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
	</PropertyGroup>
	<PropertyGroup>
	  <TreatWarningsAsErrors>False</TreatWarningsAsErrors>
	  <PackageIcon>nuget.png</PackageIcon>
	</PropertyGroup>

</Project>

Also, the versioning will be a mixture of patron major version + calendar version FOr example there are 2 versions of https://www.nuget.org/packages/NetCoreUsefullEndpoints : 6.2022.722.712 – means for ASP.NET Core 6, on year 2022, month 7, day 22, hour 7, min 12 6.2022.721.1154 – means for ASP.NET Core 6, on year 2022, month 7, day 21, hour 11, min 54

You can see

  1. as Swagger at https://netcoreusefullendpoints.azurewebsites.net/swagger

  2. As BlocklyAutomation at https://netcoreusefullendpoints.azurewebsites.net/BlocklyAutomation

  3. As package at https://www.nuget.org/packages/NetCoreUsefullEndpoints

NetCoreUsefullEndpoints-3 CICD

Now I find usefull that, every time that I push some code, the code is build and the nuget package is attached . So GitHub Actions to the rescue.

There will be 2 GitHub actions – one for build and package , other for deploying to the Azure a test application This is the code for building. ( The code for azure is automatically generated by Azure … so no need to put here)

name: .NET

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Setup .NET
      uses: actions/setup-dotnet@v2
      with:
        dotnet-version: 6.0.x
    - name: Restore dependencies
      run: |
        cd src 
        cd UsefullEndpoints
        dotnet tool restore
        dotnet pwsh readme.ps1        
        dotnet restore
    - name: Build
      run: |
        cd src
        cd UsefullEndpoints
        
        dotnet build --no-restore
    - name: Pack
      run: |
        cd src
        cd UsefullEndpoints
        cd UsefullExtensions
        dotnet pack -o ../nugetPackages  --include-symbols --include-source

    - name: 'Upload nuget'
      #if: ${{ github.ref == 'refs/heads/main' }}
      uses: actions/upload-artifact@v2
      with:
        name: UsefullEndpoints_${{github.run_number}}
        path: src/UsefullEndpoints/nugetPackages
        retention-days: 1

You can see

  1. as Swagger at https://netcoreusefullendpoints.azurewebsites.net/swagger

  2. As BlocklyAutomation at https://netcoreusefullendpoints.azurewebsites.net/BlocklyAutomation

  3. As package at https://www.nuget.org/packages/NetCoreUsefullEndpoints

NetCoreUsefullEndpoints-2–MVP

So let’s start the implementation for user / error / environment.

The only difficulty resides in the fact that IEndpointRouteBuilder is not defined into a usual library, but the dll csproj must contain

	<ItemGroup>
		<FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>

Otherwise , it is work as usual. For example, for seeing a user

 public static void MapUser(this IEndpointRouteBuilder route)
{
    ArgumentNullException.ThrowIfNull(route);
    route.MapGet("api/usefull/user/", (HttpContext httpContext) =>
    {
        return Results.Ok(httpContext.User?.Identity?.Name);
    }).RequiresAuthorization();
}

More difficult was for Environment – that is a Static class. Hopefully, there is a NUGET for this – https://www.nuget.org/packages/rscg_static – that allows to generate an interface from a static class. So I have added this

	<ItemGroup>
		<FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>

And code for generating the interface

public partial class Helper
{
    public partial ISystem_Environment FromStaticEnvironment();

}

So, when I want to get the values from Environment, I use this

public static void MapUsefullEnvironment(this IEndpointRouteBuilder route, string? corsPolicy = null, string[]? authorization = null)
{
    ArgumentNullException.ThrowIfNull(route);

    var rh=route.MapGet("api/usefull/environment/", (HttpContext httpContext) =>
    {
        return Results.Ok(new Helper().FromStaticEnvironment());
    });
    rh.AddDefault(corsPolicy, authorization);

}

You can see

  1. as Swagger at https://netcoreusefullendpoints.azurewebsites.net/swagger

  2. As BlocklyAutomation at https://netcoreusefullendpoints.azurewebsites.net/BlocklyAutomation

  3. As package at https://www.nuget.org/packages/NetCoreUsefullEndpoints

NetCoreUsefullEndpoints–1- Idea

For every web Api that I produce I want to see if it is well configured . That means

  1. The error flows how it should, where it should ? ( API for error )

  2. The user is authorized and authenticated ?
  3. What is the current environment that I have ? ( name of the host )

Maybe it is good to have the current date of the PC and the configuration

And – why repeat when you can create this ?

You can see the Nuget result at NuGet Package

You can see

  1. as Swagger at https://netcoreusefullendpoints.azurewebsites.net/swagger

  2. As BlocklyAutomation at https://netcoreusefullendpoints.azurewebsites.net/BlocklyAutomation

  3. As package at https://www.nuget.org/packages/NetCoreUsefullEndpoints

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.