Create C# Class from SQL

I hate doing plumbing code. Especially entity model classes that are exact replicas of SQL tables. I do this all the time when using Dapper. So I did some googling and found some SQL statements that you can run in your SQL Server Management Studio and have a table as a C# class in the output. I combined the best ones into this chunk of SQL:

-- This is the schema name
DECLARE @Schema VARCHAR(MAX) = 'Dbo' 
-- This is the table name. Write your own table name here
DECLARE @Table VARCHAR(MAX) = 'TableName' 

DECLARE @result varchar(max) = ''
SET    @result = @result + 'namespace ' + @Schema  + CHAR(13) + '{' + CHAR(13) 
SET    @result = @result + '    public class ' + @Table + CHAR(13) + '    {' + CHAR(13) 
SELECT @result = @result + '        public ' + DataType + ' ' + PropertyName + ' { get; set; } ' + CHAR(13)
FROM (SELECT
    UPPER(left(c.COLUMN_NAME,1))+SUBSTRING(c.COLUMN_NAME,2,LEN(c.COLUMN_NAME)) AS PropertyName,
    CASE c.DATA_TYPE
        WHEN 'bigint'           THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'long?' ELSE 'long' END
        WHEN 'binary'           THEN 'Byte[]'
        WHEN 'bit'              THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'bool?' ELSE 'bool' END
        WHEN 'char'             THEN 'string'
        WHEN 'date'             THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END
        WHEN 'datetime'         THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END
        WHEN 'datetime2'        THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END
        WHEN 'datetimeoffset'   THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'DateTimeOffset?' ELSE 'DateTimeOffset' END
        WHEN 'decimal'          THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'decimal?' ELSE 'decimal' END
        WHEN 'float'            THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'double?' ELSE 'double' END
        WHEN 'image'            THEN 'Byte[]'
        WHEN 'int'              THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'int?' ELSE 'int' END
        WHEN 'money'            THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'decimal?' ELSE 'decimal' END
        WHEN 'nchar'            THEN 'string'
        WHEN 'ntext'            THEN 'string'
        WHEN 'numeric'          THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'decimal?' ELSE 'decimal' END
        WHEN 'nvarchar'         THEN 'string'
        WHEN 'real'             THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'double?' ELSE 'double' END
        WHEN 'smalldatetime'    THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END
        WHEN 'smallint'         THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'short?' ELSE 'short' END
        WHEN 'smallmoney'       THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'decimal?' ELSE 'decimal' END
        WHEN 'text'             THEN 'string'
        WHEN 'time'             THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'TimeSpan?' ELSE 'TimeSpan' END
        WHEN 'timestamp'        THEN 'Byte[]'
        WHEN 'tinyint'          THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'Byte?' ELSE 'Byte' END
        WHEN 'uniqueidentifier' THEN CASE C.IS_NULLABLE WHEN 'YES' THEN 'Guid?' ELSE 'Guid' END
        WHEN 'varbinary'        THEN 'Byte[]'
        WHEN 'varchar'          THEN 'string'
        ELSE 'Object'
    END AS DataType, c.ORDINAL_POSITION
    FROM INFORMATION_SCHEMA.COLUMNS c
    WHERE c.TABLE_NAME = @Table
    AND ISNULL(@Schema, c.TABLE_SCHEMA) = c.TABLE_SCHEMA) t
ORDER BY t.ORDINAL_POSITION

SET @result = @result  + '    }' + CHAR(13)
SET @result = @result + '}' 

PRINT @result

HOW TO USE IT:

Replace the @Schema with your schema value (usually Dbo) and the @Table value with the name of the table and run the statement. It will then output the table as a C# model class.

EXAMPLE:

This is my table:

CREATE TABLE [dbo].[Favorites](
	[rowId] [int] IDENTITY(1,1) NOT NULL,
	[userKey] [int] NOT NULL,
	[favoriteId] [nvarchar](255) NULL,
	[lastModified] [datetime] NULL,
	[isDeleted] [bit] NULL,
	[created] [datetime] NULL,
 CONSTRAINT [PK_Favorites] PRIMARY KEY CLUSTERED 
(
	[rowID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

I set the 2 variables in the first SQL statement:

-- This is the schema name
DECLARE @Schema VARCHAR(MAX) = 'Dbo' 
-- This is the table name. Write your own table name here
DECLARE @Table VARCHAR(MAX) = 'Favorites' 

And run it, and voila! The table is now a C# Dto class. It will even uppercase the first letter in the property name for you:

namespace Dbo
{
    public class Favorites
    {
        public int RowId { get; set; } 
        public int UserKey { get; set; } 
        public string FavoriteId { get; set; } 
        public DateTime? LastModified { get; set; } 
        public bool? IsDeleted { get; set; } 
        public DateTime? Created { get; set; } 
    }
}

That’s it. You are now not only a C# expert, but also a SQL shark. Happy plumbing. And coding.

MORE TO READ:

Posted in .net, c# | Tagged , , , , , | Leave a comment

C# Thread Safe File Writer and Reader

Previously I wrote the article Write to file from multiple threads async with C# and .NET Core, which explains how to use a ConcurrentQueue to append lines to a text file. And the ConcurrentQueue is great for the fire-and-forget scenarios of log file writing, where you really do not read from the files you write.

But if you are reading the files you are writing, you need some kind of locking mechanism to ensure that the code block reading and writing the file are accessed by one thread at a time.

There are many options including lock, semaphors and ReaderWriterLock. In this article I will use the good old Mutex class.

STEP 1: THE CODE

using System;
using System.Threading;
using System.IO;
					
public class ThreadSafeFileWriter
{
	public string ReadFile(string filePathAndName)
	{
      // This block will be protected area
      using (var mutex = new Mutex(false, filePathAndName.Replace("\\", "")))
      {
        var hasHandle = false;
        try
        {
          // Wait for the muted to be available
          hasHandle = mutex.WaitOne(Timeout.Infinite, false);
          // Do the file read
          if (!File.Exists(filePathAndName))
            return string.Empty;
		  return File.ReadAllText(filePathAndName);
        }
        catch (Exception)
        {
          throw;
        }
        finally
        {
          // Very important! Release the mutex
          // Or the code will be locked forever
          if (hasHandle)
            mutex.ReleaseMutex();
        }
      }
	}
	
    public void WriteFile(string fileContents, string filePathAndName)
    {
      using (var mutex = new Mutex(false, filePathAndName.Replace("\\", "")))
      {
        var hasHandle = false;
        try
        {
          hasHandle = mutex.WaitOne(Timeout.Infinite, false);
          if (File.Exists(filePathAndName))
            return;
		  File.WriteAllText(filePathAndName, fileContents);
        }
        catch (Exception)
        {
          throw;
        }
        finally
        {
          if (hasHandle)
            mutex.ReleaseMutex();
        }
      }
    }	
}

SO WHAT’S UP WITH THE MUTEX?

The Mutex will let threads wait for the mutex handle in a queue until the mutex is released. So if 3 threads will write to the same file, they will wait in line nicely until they are granted access.

It is very important that the code releases the mutex as well, or the code will be locked forever.

Mutexes can be named, like in the example above. This locks the shared resource system wide. So if another process tries to access the same code, that process will also wait in line. Backslashes in mutex names are a reserved character and must be removed.

Taht’s it. You are now a multi-thread expert. Happy coding.

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , , , , | Leave a comment

C# Log to Application Insights and File from your .NET 6 Application

So why would you ever log to Application Insights AND File log at the same time? Well, if you are hosting your own applications on your own machine, it can be great to have a file version of what’s happened. The file will be updated immediately, whereas Application Insights are sometimes up to 5 minutes behind.
Also, it gives you the opportunity to log at different levels. Application Insights is not cheap, so having Application Insights log only warnings and errors, but the file logging debug can be a money saver.
And, when developing, the file log is far superior to Application Insights.

My colleague Kim Schiøtt whiffed up this extension method to make the configuration easier.

STEP 1: THE NUGET PACKAGES

You need the following packages:

STEP 2: THE CONFIGURATION

This will configure the logging:

"ApplicationInsights": {
    "InstrumentationKey": "[The instrumentation key]"
  },
"Logging": {
    "PathFormat": "[The path and file format used in file logging, e.g.: c:\\log-{Date}.txt]",
    "LogLevel": {
      "Default": "Information"
    },
    "ApplicationInsightsLoggerProvider": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }

The “Logging” section configures the different log levels for file and Application Insights.

STEP 3: THE EXTENSION METHOD

This method allows you to add logging easily:

using Microsoft.ApplicationInsights.AspNetCore.Extensions;

namespace MyCode
{
    public static class WebApplicationBuilderExtensions
    {
        public static void AddLogging(this WebApplicationBuilder builder)
        {
            // Add file logging
            builder.Host.ConfigureLogging(logging =>
                {
                    logging.AddFile(builder.Configuration.GetSection("Logging"));
                }
            );
            // Add Application Insights Logging
            var options = new ApplicationInsightsServiceOptions();
            options.InstrumentationKey = builder.Configuration["ApplicationInsights:InstrumentationKey"];
            builder.Services.AddApplicationInsightsTelemetry(options);
        }
    }
}

STEP 4: CALL THE METHOD WHEN BUILDING YOUR APPLICATION

This is an example where I configure my logging:

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;

var webApplicationOptions = new WebApplicationOptions();
var builder = WebApplication.CreateBuilder(webApplicationOptions);
builder.AddLogging();
...
...
...
builder.Build();

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET, Microsoft Azure | Tagged , , , | 2 Comments

Get Users from IdentityServer using .NET Core

If you wish to poke around in the IdentityServer users database directly, the API seems a little bit fishy. This is because the direct data access are very low level, and consists of HttpClient extension methods. They are, in fact, so low level that you think that you are doing something wrong. But you are not, this is the way. So here’s the quick guide to getting started.

STEP 1: THE NUGET PACKAGES

Start with these packages:

STEP 2: CREATE AN ACCESSTOKEN REPOSITORY

IdentityServer have 2 types of access: Client access is the one we use and will grant us access to all users, and user access with will grant individual users access to their own data.

You need to know the URL to your IdentityServer, the client ID (usually a neat readable string) and a client secret (usually an unreadable guid-like string):

using IdentityModel.Client;

namespace IdentityServer.Repositories
{
  public class AccessTokenRepository 
  {
    private readonly IHttpClientFactory _httpClientFactory;

    public AccessTokenRepository(IHttpClientFactory httpClientFactory)
    {
      _httpClientFactory = httpClientFactory;
    }

    public async Task<string> GetClientAccessTokenAsync()
    {
      var tokenRequest = new ClientCredentialsTokenRequest
      {
        Address = $"[IdentityServerUrl]/connect/token",
        ClientId = "[IdentityServer Client ID]",
        ClientSecret = "[IdentityServer Client Secret]"
      };

      var client = _httpClientFactory.CreateClient("HttpClient");
      var response = await client.RequestClientCredentialsTokenAsync(tokenRequest);
      if (response.IsError)
        throw new Exception($"{GetType()}.GetClientAccessToken failed: {response.ErrorDescription} ({response.HttpStatusCode}) ");

      return response.AccessToken;
    }
  }
}

STEP 3: CREATE A USER REPOSITORY

With an Client Access Token in hand, we are allowed to access the IdentityServer database.

using System.Net;
using System.Net.Http.Headers;

namespace IdentityServer.Repositories
{
  public class UserRepository 
  {
    private IHttpClientFactory _httpClientFactory;
    private AccessTokenRepository _accessTokenRepository;

    public UserRepository(IHttpClientFactory httpClientFactory, AccessTokenRepository accessTokenRepository) 
    {
      _httpClientFactory = httpClientFactory;
      _accessTokenRepository = accessTokenRepository;
    }

    public async Task<string?> GetUserAsync(string username)
    {
      var client = _httpClientFactory.CreateClient("HttpClient");
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _accessTokenRepository.GetClientAccessTokenAsync());

      var responseMessage = await client.GetAsync($"[IdentityServerUrl]/localapi/users/{username}");
      if (responseMessage.StatusCode == HttpStatusCode.NotFound)
        return null;  
      if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
        throw new Exception("Unauthorized");
      if (!responseMessage.IsSuccessStatusCode)
        throw new Exception($"{responseMessage.StatusCode}");
      var userJson = await responseMessage.Content.ReadAsStringAsync();
      return userJson;
    }
  }
}

The above code will return the bare-bone Json output from IdentityServer. You will need to parse the output accordingly. The reason this code does not do this is that you can design your own user database, so there is not really a standard data format.

STEP 4: USE THE USERREPOSITORY

The code expects an IHttpClientFactory, so we need to hook up such a thing, and we need to hook up the 2 repositories in our dependency injection framework. Hereafter, the repos will be available:

builder.Services.AddHttpClient("HttpClient");
builder.Services.AddSingleton<AccessTokenRepository>();
builder.Services.AddSingleton<UserRepository>();

...
...

// Example on how to use the userRepository:
if (await _userRepository.GetUserAsync(userName) == null)
  return BadRequest();

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , , , , | Leave a comment

Host .net core 6.0 WebApplication as Kestrel Windows Service

If you create a .NET Core 6.0 Web Application as default, the application will run as an App Service just fine. But if you wish to host the application yourself, you can run the application as a Windows Service.

This is how you usually initialize the Web Application in .NET Core 6:

var builder = WebApplication.CreateBuilder(args);

To implement Windows Service capabilities, you need the following Nuget package:

Microsoft.Extensions.Hosting.WindowsServices

And you need to change the WebApplication.CreateBuilder:

var webApplicationOptions = new WebApplicationOptions() { 
  Args = args,
  ContentRootPath = AppContext.BaseDirectory, 
  ApplicationName = System.Diagnostics.Process.GetCurrentProcess().ProcessName 
};
var builder = WebApplication.CreateBuilder(webApplicationOptions);
builder.Host.UseWindowsService();

Windows services are rooted in the System32 folder, which is why the WebApplicationOptions changes the content root path back to the base directory of the application itself.

That’s it. You are now a .NET Core 6.0 expert. Happy coding.

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , , | Leave a comment

C# .NET Core API Versioning with Microsoft.AspNetCore.Mvc.Versioning

.NET Core allows you to control versions of your APIs. To do so you need the following NuGet package:

But lets try to version our API.

STEP 1: CREATE A CONTROLLER

using Microsoft.AspNetCore.Mvc;
using System;

namespace Controllers.V1
{
  [Route("v{version:apiVersion}/[controller]")]
  public class HelloWorldController : Controller
  {
    [HttpGet]
    public async Task<IActionResult> HelloWorld()
    {
      // This is a stupid example, but just an example.
      // You would of course have a real async method here
      return await Task.Run(() => Ok("Hello world"));
    }
  }
}

Notice how I in line 6 defines the route as v{version:apiVersion}/[controller]? The {version:apiVersion} will define the versioning that we use later on.

STEP 2: ADD VERSIONING TO THE SERVICES

In your startup code, add the versioning to the services:

using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.AspNetCore.Mvc;

...
...

services.AddApiVersioning(
  options =>
  {
    options.ReportApiVersions = true;
    options.Conventions.Controller<Controllers.V1.HelloWorldController>().HasApiVersion(new ApiVersion(1, 0));
  });

Here we have now defined that the Controllers.V1.HelloWorldController have version 1.

STEP 3: CALL YOUR ENDPOINT

The endpoint will now respond to the following URL:

  • /v1/helloworld

WHY NOT JUST HARDCODING THE API VERSION TO THE CONTROLLER ROUTE?

Versioning have several advantages. This is not all it can do:

You can deprecate versions by adding the following attribute to the controller:

[Route("v{version:apiVersion}/[controller]")]
[ApiVersion("1.0", Deprecated = true)]
public class HelloWorldController : Controller

You can map a specific method in a controller to a specific version by adding the following attribute to the method. So one controller can have several versions of an endpoint:

[HttpGet]
[MapToApiVersion("1.0")]
public async Task<IActionResult> HelloWorld()

And you can do a whole lot of other version related stuff. But this will get you started.

Please note that versioning is not supported when using .NET 6 Miminal API’s, but there is a plan to implement it later.

You are now an API versioning expert. Happy coding.

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , | Leave a comment

Read and Update Azure App Configuration settings with C#

Azure App Configuration is a nifty way of storing configuration settings in the cloud, and with the live reload feature you can change the config settings and they will automatically update in your app without a need for redeploy.

But the configuration explorer is not the best tool in the world. It’s simple and does not give a very good overview of your settings. Especially if you use the labels feature.

This simple interface is not good. Especially with labels enabled.

But fear not. If you are an automation geek or just want to update the settings using code, this is – of course – possible.

STEP 1: THE NUGET PACKAGE

You will need this NuGet package:

STEP 2: CONNECT TO AZURE APP CONFIGURATION

// Connect to an App Configuration Client using a connectionstring
private static readonly string _connectionString = "Endpoint=https://mtaz-appconfig.azconfig.io...=";
private readonly ConfigurationClient _client = new ConfigurationClient(_connectionString);

STEP 3: READ ALL SETTINGS USING A FILTER

Filters use * notation to identity wildcards. In this example all my settings are named MySetting:[something], for example MySetting:FixCasing or MySetting:HideInSearch:

var settingsSelector = new SettingSelector() { KeyFilter = "MySetting:*" };
var settings = _client.GetConfigurationSettings(settingsSelector);

If you use labels, you can first sort by label, then get all settings:

public dynamic GetAllSettings()
{
  var settingsSelector = new SettingSelector() { KeyFilter = "MySetting:*" };
  var settings = _client.GetConfigurationSettings(settingsSelector);
  var labels = settings.GroupBy(s => s.Label);

  List<dynamic> list = new List<dynamic>();
  foreach (var label in labels)
  {
    dynamic s = new ExpandoObject();
    s.label = label.Key != null ? label.Key : string.Empty;
    var setingsByLabel = settings.Where(s => s.Label == label.Key);
    var values = new Dictionary<string, object>();
    foreach (var setting in setingsByLabel)
    {
      values.Add(setting.Key, setting.Value);
    }
    s.values = values;
    list.Add(s);
  }
  return list;
}

When serialized, the above returns the following output:

[
  {
    "label": "Development",
    "values": {
      "MySetting:ConvertCategoryToGroup": "false",
      "MySetting:FieldToGetCategoryFrom": "title",
      "MySetting:FixCasing": "false"
    }
  },
  {
    "label": "Production",
    "values": {
      "MySetting:ConvertCategoryToGroup": "false",
      "MySetting:FieldToGetCategoryFrom": "description",
      "MySetting:FixCasing": "false"
    }
  }
]

STEP 4: ADD, UPDATE AND DELETE SETTINGS

This is equally easy:

// Will add a setting it the setting is not already there
public void AddConfiguration(string key, string, value, string label)
{
  _client.AddConfigurationSetting(value.Key, value.Value, label);
}

// Will add a setting it the setting is not already there, 
// or update the setting if it already exist  
public void UpdateConfiguration(string key, string, value, string label)
{
  _client.SetConfigurationSetting(value.Key, value.Value, label);
}

// Deletes a single configuration setting
public void DeleteConfiguration(string key, string label)
{
  _client.DeleteConfigurationSetting(setting.Key, label);
}

// Deletes all settings matching my filter from a labeled section	
public void DeleteEntireConfigurationSection(string label)
{
  var settingsSelector = new SettingSelector() { KeyFilter = "MySetting:*", LabelFilter = label };
  var settings = _client.GetConfigurationSettings(settingsSelector);
  foreach (var setting in settings)
    _client.DeleteConfigurationSetting(setting.Key, label);
}

The DeleteEntireConfigurationSection is especially nifty, as you can wipe all settings from an entire labeled section.

That’s it. You are now an Azure App Configuration Expert. Happy coding.

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET, Microsoft Azure | Tagged , , , , | Leave a comment

C# Deserialize JSON to dynamic ExpandoObject()

The Microsoft System.Text.Json.Serialization.JsonSerializer cannot (yet) convert JSON into dynamic objects. But good ole Newtonsoft.Json can.

The conversion is simple too:

// This is my json string
string s = "
{
    "label": "MyLabel",
    "values": {
      "Key1": "Value1",
      "Key2": "Value2",
      "Key2": "Value3",
    }
  }";
  
// This is the conversion
dynamic json = 
  JsonConvert.DeserializeObject<ExpandoObject>(
    s, 
    new ExpandoObjectConverter()
  );

After the conversion, you can work with the dynamic object as you wish:

string label = json.label;
foreach (var value in json.values)
  Console.WriteLine($"{value.Key}: {value.Value}");

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , , , | Leave a comment

.NET 6.0 and Simple (minimal) Api’s: Create an Api without controllers

Have you always dreamt of skipping the controllers in your Web Api? Are you the lazy type? And have you always wanted to return data directly from your repositories?

Feat not, .NET 6.0 to your rescue. The new “Minimal Api” feature have you covered. No more controller boilerplate code just to return a simple value. Fewer lines of code means less code to maintain. And it’s probably easier to find all the endpoints as they can be found one place.

STEP 1: CREATE AN ASP.NET CORE WEB API

You must create an ASP.NET Core Web Api, and select .NET 6.0 as your platform.

See here how to create a Web Api Project.

STEP 2: CREATE A REPOSITORY

This silly mock repository will return a string.

namespace SimpleApi.Repositories
{
  public class MyRepository
  {
    public async Task<string> HelloWorldAsync()
    {
      // This is a stupid example, but just an example.
      // You would of course have a real async method here
      return await Task.Run(() => "Hello world");
    }

    public string HelloWorldNoAsync()
    {
      // Just an example to prove that you don't need
      // async methods. It's just that it is best practice to
      // do so, it's not required.
      return "Hello World";
    }

    public async Task<string> HelloAsync(string who)
    {
      // This is a stupid example, but just an example.
      // You would of course have a real async method here
      return await Task.Run(() => $"Hello {who}");
    }
  }
}

STEP 3: ADD ENDPOINTS TO Program.cs

using SimpleApi.Repositories;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add my own repository to the service collection
builder.Services.AddSingleton<MyRepository>(new MyRepository());

// Build the app
var app = builder.Build();

// Add Swagger when in development mode
if (app.Environment.IsDevelopment())
{
  app.UseSwagger();
  app.UseSwaggerUI();
}

// And always use https
app.UseHttpsRedirection();

// Add 1st enpoint: An example without async
app.MapGet("/api/helloworld-noasync", (MyRepository myRep) => myRep.HelloWorldNoAsync()).WithName("Hello World Without Async");
// Add 2nd endpoint: An example with async
app.MapGet("/api/helloworld-async", async (MyRepository myRep) => await myRep.HelloWorldAsync()).WithName("Hello World With Async");
// Add 3rd endpoint: An example with parameter and async
app.MapGet("/api/hello/{who}", async (string who, MyRepository myRep) => await myRep.HelloAsync(who)).WithName("Hello Who With Async");

// Start the api website
app.Run();

SO WHAT’S HAPPENING HERE?

Well, In.NET 6.0 you no longer need a public static void Main(string[] args), not a namespace. Not that it’s not there, it’s just implicitly added by the compiler.

The first lines of code (3-24) will do the plumbing, add Swagger and set up https.

Line 27-29-31 adds the endpoints. This is the interesting part. These are the 3 endpoints that my API will expose. I have made 3 examples.

The app.MapGet() will create GET methods on the implied path. You can use app.MapPost(), app.MapPut() and many more to create POST, PUT or any method you wish.

  • The first endpoint is how to call a method without async. This is generally not recommended, async is the preferred method.
  • The second endpoint is how to call an async method. This will just return “Hello World” but serves as an example on how to call an async method,
  • The last endpoint shows how to add parameters to the endpoint. This will return “Hello {who}” where {who} is the parameter in the endpoint.

That’s it. You are now a Minimal API expert. Happy coding.

MORE TO READ:

Posted in .net, .NET Core, c#, General .NET | Tagged , , , | 1 Comment