CSharp Rest API: Difference between revisions
Line 91: | Line 91: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
I really hate the hidden approach Microsoft was. We used MongoDbSettings because this is the section in appsettings.json. It magically reads the values from secrets manager. I would much prefer to have an indication of this somewhere. | I really hate the hidden approach Microsoft was. We used MongoDbSettings because this is the section in appsettings.json. It magically reads the values from secrets manager. I would much prefer to have an indication of this somewhere. | ||
=Health Checks= | |||
Next Health checks. Heartbeating etc | |||
<syntaxhighlight lang="cs"> | |||
// Add Service | |||
builder.Services.AddHealthChecks(); | |||
//HealthCheck Middleware | |||
app.MapHealthChecks("/healthz"); | |||
</syntaxhighlight> | |||
For MongoDb we have | |||
<syntaxhighlight lang="bash"> | |||
dotnet add package AspNetCore.HealthChecks.MongoDb | |||
</syntaxhighlight> | |||
And then | |||
<syntaxhighlight lang="cs"> | |||
</syntaxhighlight> | |||
==C# Extensions== | ==C# Extensions== | ||
I never used this a lot in the first 7 years of C#. For the last 3 it was all the rage. Basically they are functions which take this as the first argument | I never used this a lot in the first 7 years of C#. For the last 3 it was all the rage. Basically they are functions which take this as the first argument |
Revision as of 01:48, 9 November 2024
Introduction
This is a quick refresher for C# Rest API
Installation
I am now on SDK 8.0 and found the following issues
Use Apt not Snap
Using snap will mean your SDK cannot be found
sudo apt-get install dotnet-sdk-8.0
Create new Project
This is painless and can be done with
dotnet new webapi -n Catalog
Setting up Certificates
The next thing is run the project with F5. This warns you that you are not https. You fix this with the commands below but make sure you restart chrome
dotnet dev-certs https --clean
dotnet dev-certs https --check --trust
Dependency Injection DI
This just points out how to inject one service into another. With the example below we only use the Repository once so creating it as its own system is a bit silly. Anyway this is how to do it.
builder.Services.AddSingleton<IRepository>(provider =>
{
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
BsonSerializer.RegisterSerializer(new DateTimeOffsetSerializer(BsonType.String));
var mongoDbSettings = builder.Configuration.GetSection(nameof(MongoDbSettings)).Get<MongoDbSettings>();
var client = new MongoClient(mongoDbSettings.ConnectionString);
return new MongoDBItemsRepository(client);
});
builder.Services.AddSingleton<IItemService>(provider => new ItemService(provider.GetRequiredService<IRepository>()));
Express C# Style
This is an example of using the minimal api from Microsoft. The import thing is the minimal API is a new approach to reduce the code required to get going. The AddSingleton is a way to use Dependency Injection. I found the errors unreadable from the framework but maybe used to working at a lower level. Quite easy to see how to get going
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IItemService>(provider => new ItemService(new InMemItemsRepository()));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseStatusCodePages(async statusCodeContext
=> await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
.ExecuteAsync(statusCodeContext.HttpContext));
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/items", (IItemService itemService) =>
TypedResults.Ok(itemService.GetItems()))
.WithName("GetItems")
.WithOpenApi();
app.MapGet("/items/{id}", Results<Ok<ItemDto>, NotFound> (IItemService itemService, Guid id) =>
itemService.GetItem(id) is { } itemDto
? TypedResults.Ok(itemDto)
: TypedResults.NotFound()
)
.WithName("GetItemById")
.WithOpenApi();
app.Run();
C# Controllers Gotchas
In my examples we are using the minimal api approach. Previously for C# we used the Controller approach. The framework, by default relies on names of functions and when implemented with, for instance GetItemAsync this would cause a problem as it expects GetItem. To make the framework work you need to add the following to the ConfigServices. To me this seems a bit of a shoddy approach to a framework.
services.AddControllers(option => {
options.SuppressAsyncSuffixInActionNames = false;
})
Secrets Manager
With dotnet comes the secrets manager for storing ice cubes :) To use it we do
dotnet user-secrets init
dotnet user-secrets set MongoDbSettings:Password NotSaying!!!
I really hate the hidden approach Microsoft was. We used MongoDbSettings because this is the section in appsettings.json. It magically reads the values from secrets manager. I would much prefer to have an indication of this somewhere.
Health Checks
Next Health checks. Heartbeating etc
// Add Service
builder.Services.AddHealthChecks();
//HealthCheck Middleware
app.MapHealthChecks("/healthz");
For MongoDb we have
dotnet add package AspNetCore.HealthChecks.MongoDb
And then
C# Extensions
I never used this a lot in the first 7 years of C#. For the last 3 it was all the rage. Basically they are functions which take this as the first argument
namespace Catalog.Extensions;
using Catalog.Dtos;
using Catalog.Entities;
public static class Extensions
{
public static ItemDto AsDto(this Item item)
{
return new ItemDto
{
Id = item.Id,
Name = item.Name,
Price = item.Price,
CreatedDate = item.CreatedDate
};
}
}
So now you can do this
public IEnumerable<ItemDto> GetItems()
{
var itemDtos = repository.GetItems().Select(item => item.AsDto());
return itemDtos;
}