Tutorial
Duration: 30 minutes
This tutorial takes you from a basic installation to a working application using the framework which gets you hand on experience with the frameworks most commonly used modules.
Each chapter builds on the previous one.
Prerequisite
- You've followed the Installation instructions
- You have an
appsettings.jsonfile with at least an app name:
{
"systemLibraryCommonFramework": {
"app": {
"name": "company_unique_appname"
}
}
}
Chapter 1: Setup
Choose one of the four startup approaches depending on how much control you need.
Four different Programs.cs:
Application Start Minimal API (1)
Application.Start();
Application Start API (2)
var options = new FrameworkOptions();
Application.Start<Hooks>(AppType.Web, options, AppHosting.Kestrel);
public class Hooks : IFrameworkHooks
{
public void OnConfigureServices(IServiceCollection services, EnvironmentType env)
{
}
}
Application Build API (3)
var options = new FrameworkOptions();
var urls = new[] { "http://localhost:5010" };
var builder = Application.Build<Hooks>(AppType.Web, AppHosting.Kestrel, options, urls);
var app = builder.Build();
app.Run();
public class Hooks : IFrameworkHooks
{
public void OnConfigureServices(IServiceCollection services, EnvironmentType env)
{
}
}
Framework Extension API (4)
Warning
IFrameworkHooks is not invoked when using the Framework Extension API, as this gives you full control as now you invoke only extension methods.
var options = new FrameworkOptions();
var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureFrameworkLogging();
builder.ConfigureServices((context, services) =>
{
services = services.AddFrameworkServices(AppType.Web, options);
});
builder = builder.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.Configure(app =>
{
app.UseFrameworkBeginMiddlewares(AppType.Web);
app.UseFrameworkEndMiddlewares(AppType.Web);
});
});
var app = builder.Build();
app.Run();
Chapter 2: Configuration
There are three ways to configure the framework:
appsettings.json (1)
appsettings.json for global module settings which might differ per environment, to support transformations.
{
"systemLibraryCommonFramework": {
"app": {
"name": "company_public_website"
}
}
}
FrameworkOptions (2)
Controls which services and middleware are registered on startup.
var options = new FrameworkOptions
{
UseDeveloperPage = true,
UseHttpsRedirection = false
};
Public framework interfaces (3)
Some framework behaviors can be replaced by implementing and registering an interface in your DI container.
Example: ILogWriter – implement it to control where log messages are written:
services.AddSingleton<ILogWriter, MyCustomLogWriter>();
Chapter 3: Log
Log is globally available in the global namespace, simply write anywhere:
Log.Error(any);
Log.Warning(any);
Messages are queued and written on a background thread.
appsettings.json:
{
"systemLibraryCommonFramework": {
"log": {
"level": "Warning", // optional, defaults to Logging:LogLevel:Default
"format": "Text"
}
}
}
ILogWriter
Implement the interface to control where messages go, without an implementation all log methods goes to stderr and stdout by default.
public class LogWriter : ILogWriter
{
public void Write(LogLevel level, string message)
{
Console.WriteLine(message);
}
}
Register it as a singleton:
public class Hooks : IFrameworkHooks
{
public void OnConfigureServices(IServiceCollection services, EnvironmentType env)
{
services.AddSingleton<ILogWriter, TLogWriter>();
}
}
Chapter 4: Controllers and Views
Setup controller and a matching view as a feature/module component. We will put controller and view in the same folder.
Add ~/Content/Home/HomeController.cs:
public class HomeController : Controller
{
public IActionResult Index()
{
Log.Error("Hello home controller " + DateTime.Now);
object model = "Hello world " + DateTime.Now;
return View(model);
}
}
Add ~/Content/Home/Index.cshtml
@model object
<h1>Title: @Model.ToString()</h1>
Run your application and visit
- http://localhost:5010/
- http://localhost:5010/Home
Warning
If you already have a Index view in ~/Pages/Index.cshtml then razor pages will pick up that instead.
Chapter 5: Static Files
All asset folders can be used as a root of the website to host assets (files).
Let's create the folder ~/wwwroot and add a image.png inside: ~/wwwroot/image.png
This image is now available on url http://localhost:5010/image.png
Note that static files can be placed in any asset folders named:
"public", "static", "dist", "frontend", "assets", "files", "public", "assets", "files" and last and probably most default one: "wwwroot"
All asset folders host files with a 7 days cache on client side by default.
Chapter 6: Config
Load typed configuration from json, xml or config files automatically.
Note: files and classes are not case sensitive.
Example
Add ~/Configs/pokemonConfig.json:
{
"url": "",
"cacheDuration": 10
}
And add transformation ~/Configs/PokemonConfig.Development.json:
{
"url": "https://localhost:5010/api",
"cacheDuration": 4
}
Add ~/Configs/PokemonConfig.cs:
public class PokemonConfig : Config<PokemonConfig>
{
public string Url { get; set; }
public int CacheDuration { get; set; }
}
Usage
var url = PokemonConfig.Current.Url;
Chapter 7: Api Controllers
Add ~/Api/PokemonApiController.cs
public class PokemonApiController : BaseApiController
{
public IActionResult Pikachu()
{
return Json("Hello Pikachu");
}
}
Run your application, visit:
- http://localhost:5010/api/pokemonapi/pikachu
- http://localhost:5010/api/pokemonapi/docs
Classes inheriting BaseApiController routes are prefixed with /api/. The Controller suffix is always stripped, and the Api suffix is optional, so both /api/pokemon/ and /api/pokemonapi/ resolve to the same controller.
Chapter 8: Client
Use the Client for any HTTP request.
public class PokemonApiController : BaseApiController
{
public IActionResult Pikachu()
{
var url = PokemonConfig.Current.Url + "/pokemon/pikachu"
var client = new Client();
var response = client.Get<dynamic>(url);
// Optionally: use the client's fluent api
//var name = url.GetRequest<dynamic>().Data?.name;
var name = response.Data?.name;
return Json("Hello " + name);
}
}
Chapter 9: Cache
Three cache types available depending on your use case, in this tutorial we just go over the in-memory cache.
In-memory cache
Wraps any result in memory. Skip cache for admins by default.
Navigate to ~/Api/PokemonApiController.cs
public IActionResult Pikachu()
{
var duration = PokemonConfig.Current.CacheDuration;
if(duration == 0)
{
duration = (int)CacheDuration.XS;
}
var name = Cache.Get(() =>
{
var client = new Client();
var apiUrl = PokemonConfig.Current.Url;
var response = client.Get<dynamic>(apiUrl + "/pokemon/pikachu");
var name = response.Data?.name + " " + DateTime.Now.Second;
return name;
}, duration);
return Json("Hello " + name);
}
Chapter 10: Modules and Extensions
The framework includes many additional modules, classes, and extensions. For more in-depth information, see the framework documentation.
Here are some worth highlighting:
Modules:
Assemblies // read embedded resources
Methods // run async or in parallel
Metrics // count function calls and view its pie chart out of the box
Extensions:
ToBase64, FromBase64
ToBase62, FromBase62
Encrypt, Decrypt,
ToServerPath,
Json, PartialJson,
Xml,
Is, IsNot,
ToMd5, ToSha256,
GetFingerprint, GetSampledKey,
ToEnumValue, ToEnumText, ToEnum
ToDateTime, ToDateTimeOffset,
Compress, Decompress
Types:
EnumValue-attribute // add metadata to Enum Keys, retrieve through ToEnumValue()
EnumText-attribute // add metadata to Enum Keys, retrieve through ToEnumText()
SystemType // pre-made 'typeof' calls
EnvironmentConfig.Current // built-in to figure out the env name and more
Documentations
- Documentation — behavior, features and caveats per module
- API Documentation — public API with signatures, summaries and examples
Suggestions
email: support@systemlibrary.com