LogoAPI Framework is a new open source project (Apache License 2.0) for ASP.NET Core with the aim of bringing more flexibility and more options to building ASP.NET Core based OpenAPI backends. With API Framework your code and your resourcesbecome the OpenAPI endpoints.

With API Framework the endpoints can be build using POCOs, Roslyn Script and Delegates and the reusable APIs can be distributed as plugins using Nuget. The APIs can be added runtime, without having to restart or to rebuild the application. The flexible plugin system with a built-in support for plugins means that API Framework can be used as the secure OpenAPI gateway into other systems. With plugins you can generate OpenAPI endpoints from databases, file systems, Azure blob storage, and more.

API Framework version 1.0.0 is now available from Nuget: https://www.nuget.org/packages/weikio.apiframework.aspnetcore. The project’s home pages is available from https://weik.io/apiframework.

Main Features

“Everything is an OpenAPI” mentality means that there’s multiple ways of building your backend’s endpoints. Plain C# and delegates are supported but so are your database and your browser and many more. Your code and your resources are the OpenAPI endpoints.

You can also integrate API Framework with your existing Controller & Action based app. API Framework is built on top of the MVC-functionality meaning it can take advantage of many of the features provided by ASP.NET Core.

Here’s a short summary of the major features of API Framework:

  • Everything is an OpenAPI:The API can be anything: Database, local files. Even the web browser. APIs can be created with C#, Roslyn Scripts and using delegates. These endpoint provide the full OpenAPI specs, meaning if you have a table called Inventory in your database, your OpenAPI specification will have the same Inventory available for use.
  • Runtime Changes: APIs and endpoints can be configured runtime, when the application is running. No need to restart the system to add a new endpoint.
  • Plugin Support:API Frameworks supports plugins. Nuget.org contains multiple ready made plugins, like SQL Server and Local Files. Custom plugins can be created and shared using Nuget.

There’s many more features, including support for health checks and async JSON streams. More information is available from the project’s home pages.

Terminology & Main Concepts

With API Framework there’s two main concepts:

API

In API Framework each API has two properties: Name and Version. And the actual functionality they provide.

Most often API is a C# class or a .NET type. But you can also use assemblies, Nuget packages, Roslyn scripts and delegates as APIs. Often the aim is to make APIs reusable and they can be shared using Nuget.

Endpoint

An API itself is not accessible through a web request. That's the work of an Endpoint. Endpoint gives your API a route (for example '/helloworld') and a configuration (if needed).

You can create multiple endpoints from each API and every endpoint can have different configuration.

Quick Start

Here’s a quick start, adapted from the documentation at https://docs.weik.io/apiframework/quickstart.html. The starting point is a blank ASP.NET Core 3.1 web api app.

This quick start shows how to build integration/data hub style backend using API Framework’s plugins. When the quick start is ready, we have an ASP.NET Core based backend which provides access to SQL Server and to an another OpenAPI backend (the PetShop).

In this quick start the APIs and Endpoints are added through code. Configuration through appsettings.json (IConfiguration) and through runtime REST endpoints are also supported.

1. Add the required package for API Framework:

        <PackageReference Include="Weikio.ApiFramework.AspNetCore.StarterKit" Version="1.0.0"/>

2. Add the SQL Server and OpenAPI plugins:

        <PackageReference Include="Weikio.ApiFramework.Plugins.SqlServer" Version="2.0.0" />
        <PackageReference Include="Weikio.ApiFramework.Plugins.OpenApi" Version="1.0.0" />

3. Modify Startup.Configure by adding API Framework & required APIs and Endpoints:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddApiFrameworkStarterKit()
                .AddOpenApi("/pets", new ApiOptions()
                {
                    SpecificationUrl = "https://petstore3.swagger.io/api/v3/openapi.json",
                    ApiUrl = "https://petstore3.swagger.io/api/v3"
                })
                .AddSqlServer("/eshop",
                    new SqlServerOptions()
                    {
                        // This provides a read only access to the db used in the documentations
                        ConnectionString =
                            "Server=tcp:adafydevtestdb001.database.windows.net,1433;User ID=docs;Password=3h1@*6PXrldU4F95;Integrated Security=false;Initial Catalog=adafyweikiodevtestdb001;"
                    });
        }

4. Run the application, wait a few second (the endpoints are generated on the background) and navigate tohttps://localhost:5001/swagger

image

The SQL Server database can be queried and filtered and the OpenAPI specs contains the schema for the database:

image

Getting Started

The quick start above show one approach for using API Framework. Best way to learn more about API Framework is through the following resources:

Use Cases

As API Framework adds more flexibility into building and running ASP.NET Core backends, there’s different use cases where it can be helpful:

  • 24/7 Backends:API Framework can be used to create ASP.NET Core backends which can be updated runtime. APIs and endpoints can be added and updated when the system is running. As an example, it’s possible to install API through Nuget and then configure one or more endpoints based on that API. All this runtime.
  • Integration Layers:API Framework can be used as the secure OpenAPI gateway into other systems. With plugins you can generate OpenAPI endpoints from databases, file systems, Azure blob storage, and more. This is helpful in scenarios where you want build integration/data hub style application.
  • More options for building APIs:As mentioned, with API Framework it is possible to build APIs using Roslyn, Delegates and more. This means it is entirely possible to create a backend using a folder of Roslyn Script files.

Current Status

Today is the day of the 1.0.0 release. The work continues, especially with the samples and with documentation. Currently there’s about 12 samples available, showcasing many of the features but there’s more to add. The documentation is little farther behind.

Some of the plugins released today are more advanced than the others. For example the database plugins are quite advanced but something like the Files-plugin is currently very barebones.

Project Home

API Framework can be found from Github and from https://weik.io/ApiFramework.

0 Comments

This post shows how to encrypt and decrypt string in ASP.NET Core.


Encrypt decrypt output

Lately I’ve been working with ASP.NET Core. The .NET Core moves things around a little bit, at least until .NET Standard 2.0 arrives. Here’s some simple code which I’ve been using to encrypt and decrypt a string in ASP.NET Core using a static key.

First, the example console app:

        public static void Main(string[] args)
        {
            var content = "Example test";
            var key = "E546C8DF278CD5931069B522E695D4F2";

            var encrypted = EncryptString(content, key);
            Console.WriteLine(encrypted);

            var decrypted = DecryptString(encrypted, key);
            Console.WriteLine(decrypted);

            Console.ReadLine();
        }

Secondly, the source code for EncryptString and DecryptString:

        public static string EncryptString(string text, string keyString)
        {
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }

                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        return Convert.ToBase64String(result);
                    }
                }
            }
        }

        public static string DecryptString(string cipherText, string keyString)
        {
            var fullCipher = Convert.FromBase64String(cipherText);

            var iv = new byte[16];
            var cipher = new byte[16];

            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
        }

image

0 Comments

Azure’s REST API requires Date or x-ms-date header. As specified by HTTP protocol, the Date (or x-ms-date) header must be in RFC 1123 format.

Example of Date in RFC 1123 format

Wed, 09 Dec 2015 18:59:42 GMT

Converting DateTime to RFC 1123 in C#

In C# DateTime can be converted to RFC 1123 using the “r” format. Example:

var result = DateTime.Now.ToUniversalTime().ToString("r");

Web Tool

Perhaps the easiest way to get the current date time in RFC 1123 format is through the http://http-date.com/. This web tool, created by Leonard Wallentin, provides not just the current date time in correct format but also "30 days from now" and “365 days from now". The tool has proven itself really useful in the last few days when working with the Azure blobs using the REST API.

0 Comments

Recently I blogged about the VB.NET String Concatenation Weirdness. That’s not the only thing which can hit you if you mainly code in C#. Here’s an another example, as pointed out by my co-worker Panu Oksala. This time the weirdness is related to If and nullable fields.

Here’s some simple code:

        Dim myDate As DateTime?

        myDate = Nothing

        If (myDate Is Nothing) Then
            Console.WriteLine("Date is null")
        Else
            Console.WriteLine(myDate)
        End If

As expected, this outputs “Date is null”:

image

But, if we include If-statement in the myDate-assignment:

        Dim myDate As DateTime?

        myDate = If(True, Nothing, DateTime.Today)

        If (myDate Is Nothing) Then
            Console.WriteLine("Date is null")
        Else
            Console.WriteLine(myDate)
        End If

And then run the app, things get interesting:

image

So, we’re not getting “Date is null”. And we’re not getting the other if-option which is DateTime.Today. Instead, myDate is initialized as DateTime.MinValue:

image

Solution to the issue is to use new DateTime? instead of Nothing:

image

The following StackOverflow question contains more info about why this is happening.

0 Comments

Creating strings inside loops in VB.NET can cause subtle and easy-to-miss bugs. Here’s a simple example:

    Sub Main()

        For i As Integer = 1 To 4 Step 1

            Dim text As String
            text = text & i.ToString

            Console.WriteLine(text)

        Next

        Console.ReadLine()

    End Sub

As we are creating the textvariable inside the for loop, one would presume that this would ouput:

1

2

3

4

Instead, when run, we get this:

image

Check the compiler warnings and you’ll see:

Variable 'text' is used before it has been assigned a value. A null reference exception could result at runtime.

The problem can be easily fixed by assigning an empty value to text when it is declared:

image

Still, this can cause interesting issues if you don’t play close attention to compiler warnings.