Table of Contents

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

  1. You've followed the Installation instructions
  2. You have an appsettings.json file 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

Suggestions

email: support@systemlibrary.com