<feed xml:base="https://mikaelkoskinen.net/" xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Mikael Koskinen</title>
  <subtitle type="text">Latest blog posts</subtitle>
  <id>uuid:2ca34979-4726-4bb3-9ecb-78e540c158f9;id=5</id>
  <updated>2026-04-19T01:50:49Z</updated>
  <link href="https://mikaelkoskinen.net/" />
  <entry>
    <id>https://mikaelkoskinen.net/post/configure-deadletter-error-handler-in-apache-camel-yaml-dsl</id>
    <title type="text">Configure DeadLetter Error Handler in Apache Camel YAML DSL</title>
    <summary type="text">Here's how to configure Error Handler in Apache Camel YAML DSL</summary>
    <published>2022-12-30T09:39:18Z</published>
    <updated>2022-12-30T09:39:18Z</updated>
    <author>
      <name>miksu</name>
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/configure-deadletter-error-handler-in-apache-camel-yaml-dsl" />
    <content type="text">&lt;p&gt;Apache Camel's YAML DSL examples are currently in some parts lacking when compared to Java and XML samples. One thing I was trying to figure out was how to configure &lt;a href="https://camel.apache.org/manual/error-handler.html"&gt;error handler using YAML&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here's an example for future reference:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;- error-handler:&lt;br /&gt;    dead-letter-channel: &lt;br /&gt;      dead-letter-uri: "https://webhook.site/b7562774-4939-4e90-9337-5b9dd4d2ff1d"&lt;br /&gt;      redelivery-policy:&lt;br /&gt;        maximum-redeliveries: 3&lt;br /&gt;- route:&lt;br /&gt;    from:&lt;br /&gt;      uri: timer:timer&lt;br /&gt;      steps:&lt;br /&gt;        - setBody:&lt;br /&gt;            expression:&lt;br /&gt;              groovy:&lt;br /&gt;                expression: |-&lt;br /&gt;                  def obj = [:]&lt;br /&gt;                  obj.FirstName = "M"&lt;br /&gt;                  obj.LastName = "K"&lt;br /&gt;&lt;br /&gt;                  result = obj&lt;br /&gt;&lt;br /&gt;                  return result&lt;br /&gt;        - marshal:&lt;br /&gt;            json:&lt;br /&gt;              library: jackson&lt;br /&gt;              prettyPrint: true&lt;br /&gt;        - to:&lt;br /&gt;            uri: https://webhook.sitessss/b7562774-4939-4e90-9337-5b9dd4d2ff1d&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/cosmosdb-emulator-ssl-error-certificate-docker-linux</id>
    <title type="text">Allow invalid CosmosDB Emulator certificate with DocumentClient</title>
    <summary type="text">Getting around SSL issues when using CosmosDB's Docker-based emulator and the DocumentClient</summary>
    <published>2022-12-08T11:59:05Z</published>
    <updated>2022-12-08T11:59:06Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/cosmosdb-emulator-ssl-error-certificate-docker-linux" />
    <content type="text">&lt;p&gt;We have a project which is using the older DocumentClient based CosmosDB SDK. Getting this project to communicate with a Docker hosted CosmosDB emulator turned out to be a hassle.&lt;/p&gt; &lt;p&gt;The new SDK contains the following functionality for ignoring certificate issues:&lt;br&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
{
    HttpClientFactory = () =&amp;gt;
    {
        HttpMessageHandler httpMessageHandler = new HttpClientHandler()
        {
            ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
        };

        return new HttpClient(httpMessageHandler);
    },
    ConnectionMode = ConnectionMode.Gateway
};

CosmosClient client = new CosmosClient(endpoint, authKey, cosmosClientOptions);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;But the DocumentClient works little differently. But the good thing is that we can pass in a HttpClientHandler when creating the DocumentClient. So to ignore the cert issues when developing locally, one can use:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;                    var handler = new HttpClientHandler();
                    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
                    handler.ServerCertificateCustomValidationCallback = 
                        (httpRequestMessage, cert, cetChain, policyErrors) =&amp;gt;
                        {
                            return true;
                        };

                    client = new DocumentClient(
                        new Uri(endPointUrl),
                        primaryKey,
                        handler, connectionPolicy
                    );&lt;/pre&gt;
&lt;p&gt;If you need to configure serializer settings and the http client handler, things are a bit harder as there is not suitable public constructor in DocumentClient for configuring both. Reflection to rescue:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;                    var handler = new HttpClientHandler();
                    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
                    handler.ServerCertificateCustomValidationCallback = 
                        (httpRequestMessage, cert, cetChain, policyErrors) =&amp;gt;
                        {
                            return true;
                        };

                    client = new DocumentClient(
                        new Uri(endPointUrl),
                        primaryKey,
                        handler, connectionPolicy
                    );
                    
                    var prop = client.GetType().GetField("serializerSettings", System.Reflection.BindingFlags.NonPublic
                                                               | System.Reflection.BindingFlags.Instance);
                    prop.SetValue(client, serializerSettings);&lt;/pre&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/eventframework-cloudevents-netcore-net6-handle-create-publish</id>
    <title type="text">Event Framework beta release – CloudEvents for .NET</title>
    <summary type="text">Event Framework is a framework for creating, receiving, sending and handling CloudEvents in .NET.</summary>
    <published>2022-05-17T10:33:15Z</published>
    <updated>2022-05-17T10:33:16Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/eventframework-cloudevents-netcore-net6-handle-create-publish" />
    <content type="text">&lt;p&gt;&lt;img title="logo_2" style="float: right; display: inline" alt="logo_2" src="https://weik.io/wp-content/uploads/elementor/thumbs/logo_2-p4tpx63o3u44n7r3tex44ps9bmyd24q84muuoirug8.png" align="right"&gt;&lt;a href="https://weik.io/eventframework/" target="_blank"&gt;Event Framework&lt;/a&gt; is an Open Source CloudEvents Framework for .NET applications. You include it in your .NET Core 3.1/.NET 6 app and it helps you to create, receive, send and to handle CloudEvents. After reaching 1.0.0-alpha.0.100 (with the first alpha dating back to early 2020), Event Framework is now &lt;a href="https://www.nuget.org/packages/Weikio.EventFramework.AspNetCore" target="_blank"&gt;available in beta form, with the 1.0.0-beta.1.1 release&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;How to get started&lt;/h3&gt; &lt;p&gt;The easiest way to get started with Event Framework is to include the package &lt;a href="https://www.nuget.org/packages/Weikio.EventFramework.AspNetCore" target="_blank"&gt;Weikio.EventFramework.AspNetCore&lt;/a&gt; in your ASP.NET Core based application and then to register the required bits and pieces into service container:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;services.AddEventFramework()&lt;/pre&gt;
&lt;h3&gt;Main features&lt;/h3&gt;
&lt;p&gt;The main features of the Event Framework include:&lt;/p&gt;
&lt;p&gt;1. Create CloudEvents using CloudEventCreator&lt;br&gt;2. Send &amp;amp; Receive CloudEvents using Channels and Event Sources&lt;br&gt;3. Build Event Flows&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/ded5422c-38e3-483e-b753-309539344dd5.png"&gt;&lt;img title="Weikio Scenarios" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="Weikio Scenarios" src="https://mikaelkoskinen.net/posts/files/ead4e483-173a-424e-a7b3-f1b705927652.png" width="708" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s a short example of each of those:&lt;/p&gt;
&lt;h4&gt;Creating CloudEvents&lt;/h4&gt;
&lt;p&gt;Event Framework includes CloudEventCreator which can be used to transform .NET objects into CloudEvents. It can be customized and used through either a static CloudEventCreator.Create-method or using a CloudEventCreator instance.&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;var obj = new CustomerCreated(Guid.NewGuid(), "Test", "Customer");

// Object to event
var cloudEvent = CloudEventCreator.Create(obj);

// Object to event customization
var cloudEventCustomName = CloudEventCreator.Create(obj, eventTypeName: "custom-name");&lt;/pre&gt;
&lt;p&gt;For more examples, please see the following tests in the Github repo: &lt;a title="https://github.com/weikio/EventFramework/tree/master/tests/unit/Weikio.EventFramework.UnitTests" href="https://github.com/weikio/EventFramework/tree/master/tests/unit/Weikio.EventFramework.UnitTests"&gt;https://github.com/weikio/EventFramework/tree/master/tests/unit/Weikio.EventFramework.UnitTests&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Sending CloudEvents&lt;/h4&gt;
&lt;p&gt;Event Framework uses Channels when transporting and transforming events from a source to an endpoint. Channels have adapters, components and endpoints (+ interceptors) which are used to process an event. Channels can be build using a fluent builder or more manually. &lt;/p&gt;
&lt;p&gt;&lt;img alt="https://mermaid.ink/img/pako:eNp1UctOwzAQ_JXI57YSHHNAKhAEUgWI5ujLJt40RvE68gMEVf-dTd2UkghbsmbH45ldeS9qq1DkounsZ92CC9nmTdLquShXL9U71mG5vLlrgQg7SSfA1GNZvl7W6-_ocIvuQ9d4G70kH6udg77Nzo8zXko7ttSWjikDs1bQB3R-iLGmt4QUfLo6W4ya_zxSowk_FRQNOqg6TASSmthNc-aGG7vjfh50x6mJSZjJ0gH5xjozcf81ZVFBqrd6PsiEnwePgqu_5fVF2PEYtlgIHtSAVvx9-0EhRWjRoBQ5Q4UNxC5IIenA0tgrCFgoHawTeQOdx4WAGOz2i2qRBxdxFN1r4HbNSXX4AdpIuLI" src="https://mermaid.ink/img/pako:eNp1UctOwzAQ_JXI57YSHHNAKhAEUgWI5ujLJt40RvE68gMEVf-dTd2UkghbsmbH45ldeS9qq1DkounsZ92CC9nmTdLquShXL9U71mG5vLlrgQg7SSfA1GNZvl7W6-_ocIvuQ9d4G70kH6udg77Nzo8zXko7ttSWjikDs1bQB3R-iLGmt4QUfLo6W4ya_zxSowk_FRQNOqg6TASSmthNc-aGG7vjfh50x6mJSZjJ0gH5xjozcf81ZVFBqrd6PsiEnwePgqu_5fVF2PEYtlgIHtSAVvx9-0EhRWjRoBQ5Q4UNxC5IIenA0tgrCFgoHawTeQOdx4WAGOz2i2qRBxdxFN1r4HbNSXX4AdpIuLI"&gt;&lt;/p&gt;
&lt;p&gt;Here's an example where a channel is created using the fluent builder with a single HTTP endpoint. Every object sent to this channel is transformed to CloudEvent and then delivered using HTTP:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;var channel = await CloudEventsChannelBuilder.From("myHttpChannel")
    .Http("https://webhook.site/3bdf5c39-065b-48f8-8356-511b284de874")
    .Build(serviceProvider);

await channel.Send(new CustomerCreatedEvent() { Age = 50, Name = "Test User" });&lt;/pre&gt;
&lt;p&gt;In many situations in your applications you don’t send messages directly into the channel. Instead you inject ICloudEventPublisher into your controller/service and use it to publish events to a particular channel or to the default channel:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;public IntegrationEndpointService(ICloudEventPublisher eventPublisher)
{
    _eventPublisher = eventPublisher;
}

...

await _eventPublisher.Publish(new EndpointCreated()
{
    Name = endpoint.Name,
    Route = endpoint.Route,
    ApiName = endpoint.ApiName,
    ApiVersion = endpoint.ApiVersion,
    EndpointId = result.Id.GetValueOrDefault(),
});&lt;/pre&gt;
&lt;h4&gt;Receiving CloudEvents&lt;/h4&gt;
&lt;p&gt;Event Framework supports Event Sources. An event source can be used to receive events (for example: HTTP, Azure Service Bus) but an event source can also poll and watch changes happening in some other system (like local file system).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/7dd6c522-c676-4b29-916d-5b6ebb131803.gif"&gt;&lt;img title="es_gif" style="display: inline" alt="es_gif" src="https://mikaelkoskinen.net/posts/files/41a7368b-6096-4c96-9f7f-e0dbb889ad29.gif" width="677" height="381"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's an example where HTTP and Azure Service Bus are used to receive events in ASP.NET Core and then logged:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;services.AddEventFramework()
    .AddChannel(CloudEventsChannelBuilder.From("logChannel")
        .Logger())
    .AddHttpCloudEventSource("events")
    .AddAzureServiceBusCloudEventSource(
        "Endpoint=sb://sb.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=YDcvmuL4=",
        "myqueue");

services.Configure&amp;lt;DefaultChannelOptions&amp;gt;(options =&amp;gt; options.DefaultChannelName = "logChannel");&lt;/pre&gt;
&lt;h4&gt;Building Event Flows&lt;/h4&gt;
&lt;p&gt;Event Sources and Channels can be combined into Event Flows. Event Flows also support branching and subflows.&lt;/p&gt;
&lt;p&gt;Here's an example where an event source is used to track file changes in a local file system and then all the created files are reported using HTTP:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;var flow = EventFlowBuilder.From&amp;lt;FileSystemEventSource&amp;gt;(options =&amp;gt;
    {
        options.Configuration = new FileSystemEventSourceConfiguration() { Folder = @"c:\\temp\\myfiles", Filter = "*.bin" };
    })
    .Filter(ev =&amp;gt; ev.Type == "FileCreatedEvent" ? Filter.Continue : Filter.Skip)
    .Http("https://webhook.site/3bdf5c39-065b-48f8-8356-511b284de874");

services.AddEventFramework()
    .AddEventFlow(flow);&lt;/pre&gt;
&lt;h3&gt;Coming Next&lt;/h3&gt;
&lt;p&gt;Current document is lacking and samples also need work. The hope is to be able to include as many components and event sources as possible and for these, we’re looking at maybe using Apache Camel to bootstrap things.&lt;/p&gt;
&lt;h3&gt;Project Home&lt;/h3&gt;
&lt;p&gt;Please visit the project home site at &lt;a href="https://weik.io/eventframework"&gt;https://weik.io/eventframework&lt;/a&gt; for more details. Though for now, the details are quite thin.&lt;/p&gt;
&lt;h3&gt;Source code&lt;/h3&gt;
&lt;p&gt;Source code for Event Framework is available from &lt;a href="https://github.com/weikio/EventFramework"&gt;https://github.com/weikio/EventFramework&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/aspnet-core-runtime-changes-new-endpoint</id>
    <title type="text">Add new endpoint to ASP.NET Core application Runtime using API Framework</title>
    <summary type="text">In this blog post we create an ASP.NET Core application which uses API Framework to add support for runtime changes.</summary>
    <published>2021-10-15T07:50:28Z</published>
    <updated>2021-10-15T07:50:28Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/aspnet-core-runtime-changes-new-endpoint" />
    <content type="text">&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/b6e65507-0a0e-4724-8532-10106755f0ae.gif"&gt;&lt;img title="af_create" style="float: right; display: inline" alt="af_create" src="https://mikaelkoskinen.net/posts/files/e836ceb8-76d8-432a-981c-f4916c1673a9.gif" width="708" align="right" height="543"&gt;&lt;/a&gt;Recently I blogged about &lt;a href="https://mikaelkoskinen.net/post/introducing-api-framework-aspnet-core-openapi-runtime-plugins" target="_blank"&gt;API Framework&lt;/a&gt;, an open source project which aims to make building ASP.NET Core backends more flexible. One of the core functionalities API Framework provides is the ability to &lt;strong&gt;add new endpoints to the backend runtime, without having to rebuild and restart the system&lt;/strong&gt;. This blog introduces how this can be done.&lt;/p&gt; &lt;h3&gt;The Goal&lt;/h3&gt; &lt;p&gt;The goal is to have ASP.NET Core based app which can add new endpoints using an UI. When a new endpoint is added, we want the backend’s OpenAPI document to automatically update.&lt;/p&gt; &lt;h4&gt;Source Code&lt;/h4&gt; &lt;p&gt;The source code for this blog post is available from GitHub: &lt;a title="https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime" href="https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime"&gt;https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;The Starting Point&lt;/h4&gt; &lt;p&gt;We use ASP.NET Core 3.1 Razor Page application as a starting point. The template has been modified so that we can use Blazor components inside the Razor Pages. Blazor documentation provides a good &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration?view=aspnetcore-3.1&amp;amp;pivots=server" target="_blank"&gt;step-by-step tutorial for this&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;1. Adding API Framework&lt;/h3&gt; &lt;p&gt;&lt;a href="https://weik.io/apiframework/" target="_blank"&gt;API Framework&lt;/a&gt; (AF) is the tool which allows us to add and remove endpoints runtime. API Framework is available as a Nuget package and there is a &lt;a href="https://www.nuget.org/packages/Weikio.ApiFramework.AspNetCore.StarterKit/" target="_blank"&gt;specific package&lt;/a&gt; which works as a good starting point for ASP.NET Core Web API projects in 3.1 apps but as we want to include Razor Pages, Blazor components and controllers inside a single ASP.NET Core app, it’s better to use the Weikio.ApiFramework.AspNetCore package. &lt;/p&gt; &lt;p&gt;The package which we want to add is &lt;a href="https://www.nuget.org/packages/Weikio.ApiFramework.AspNetCore/" target="_blank"&gt;Weikio.ApiFramework.AspNetCore&lt;/a&gt;. The current version is 1.1.0 so let’s add that to the application in addition to NSwag: &lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;PackageReference Include="Weikio.ApiFramework.AspNetCore" Version="1.1.0"/&amp;gt;
    &amp;lt;PackageReference Include="NSwag.AspNetCore" Version="13.8.2" /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then Startup.ConfigureServices is changed to include controllers, AF and OpenAPI documentation (provided by NSwag):&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            
            services.AddControllers();
            services.AddApiFramework();
            services.AddOpenApiDocument();
        }&lt;/pre&gt;
&lt;p&gt;And finally Startup.Configure is configured to include Controllers and Blazor &amp;amp; OpenAPI. AF uses the default controller mappings:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseOpenApi();
            app.UseSwaggerUi3();

            app.UseEndpoints(endpoints =&amp;gt;
            {
                endpoints.MapControllers();
                endpoints.MapRazorPages();
                endpoints.MapBlazorHub();
            });
        }&lt;/pre&gt;
&lt;p&gt;Now when we run the app, we shouldn’t see any obvious changes:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/13affae2-b0dc-4edf-b760-699b586f8024.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/4dffef86-c6c5-4328-8beb-7b876bc6d8f8.png" width="357" height="92"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But if we navigate to /swagger, we should see all the endpoints provided by our app, which is none at this moment:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/a62835a8-c24c-467d-9e92-13c9a55a16a5.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/f7ed21e8-4940-4871-911d-c352432dbb1e.png" width="321" height="186"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now that we have the AF running, it’s time to build API.&lt;/p&gt;
&lt;h3&gt;2. Building an API&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;API&lt;/strong&gt; in API Framework is a reusable component with a name, a version and the specific functionality the API provides. APIs can be build using plain C# or using tools like delegates, Roslyn scripts and more. The APIs are often redistributed as Nuget packages. &lt;/p&gt;
&lt;p&gt;Let’s build the simplest API: The classic Hello World. We can use C# to build the API and the API is just a POCO, there’s no need to add routes or HTTP methods:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;    public class HelloWorldApi
    {
        public string SayHello()
        {
            return "Hello from AF!";
        }
    }&lt;/pre&gt;
&lt;p&gt;And that’s it. Now, in AF an API itself is not accessible using HTTP. Instead, we can create 1 or many &lt;strong&gt;endpoints &lt;/strong&gt;from the API. These endpoints can then be accessed using HTTP. In this blog we want to create an UI which can be used to create these endpoints runtime. &lt;/p&gt;
&lt;p&gt;If we now run the application, nothing has changed as we haven’t created any endpoints.&lt;/p&gt;
&lt;p&gt;API Framework keeps a catalog of available APIs. This means that we have to either register the APIs manually (using code or configuration) or we can let AF to auto register the APIs based on conventions. In this tutorial we can let AF to auto register the APIs and this can be turned on using the options:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;            services.AddApiFramework(options =&amp;gt;
            {
                options.AutoResolveApis = true;
            });&lt;/pre&gt;
&lt;p&gt;Now we are in a good position. We have an API and we have registered it into AF’s API Catalog (or rather, we have let AF register it automatically). As we still haven’t created any endpoints, running the app doesn’t provide any new functionality. &lt;/p&gt;
&lt;p&gt;The next step is to build the Blazor component for creating endpoints runtime.&lt;/p&gt;
&lt;h3&gt;3. Creating the UI&lt;/h3&gt;
&lt;p&gt;We have the AF configured and the first API ready and waiting so it’s time to build the UI which can be used to add endpoints runtime. &lt;/p&gt;
&lt;p&gt;We start by creating an UI which lists all the APIs in AF’s API catalog. For this we need a new Blazor-component which we call EndpointManagement.razor:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;&amp;lt;h3&amp;gt;API Catalog&amp;lt;/h3&amp;gt;

@code {
    
}&lt;/pre&gt;
&lt;p&gt;API Catalog is browsable using the IApiProvider-interface. Here’s a component which gets all the APIs and creates a HTML table of them:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;@using Weikio.ApiFramework.Abstractions

&amp;lt;h3&amp;gt;API Catalog&amp;lt;/h3&amp;gt;

&amp;lt;table class="table table-responsive table-striped"&amp;gt;
    &amp;lt;thead&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Version&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
    @foreach (var api in ApiProvider.List())
    {
        &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;@api.Name&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;@api.Version&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    }
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;

@code {

    [Inject]
    IApiProvider ApiProvider { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();
    }

}&lt;/pre&gt;
&lt;p&gt;And now we can add the component to Index.cshtml:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

&amp;lt;div class="text-center"&amp;gt;
    &amp;lt;h1 class="display-4"&amp;gt;Welcome&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Learn about &amp;lt;a href="https://docs.microsoft.com/aspnet/core"&amp;gt;building Web apps with ASP.NET Core&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;component type="typeof(EndpointManagement)" render-mode="ServerPrerendered" /&amp;gt;&lt;/pre&gt;
&lt;p&gt;And finally we have something new visible to show. Run the app and… the API Catalog table is empty:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/8b167d65-8f01-48cf-8e7e-8945820ee841.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/953b3766-9494-40e4-ba53-51652923b669.png" width="396" height="162"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The reason for this is that the API Catalog is initialized in a background thread. AF supports dynamically created APIs and it sometimes can take minutes to create these so by default, AF does things on background. &lt;/p&gt;
&lt;p&gt;F5 should fix the situation:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/7ffb2a8d-9e46-4b75-b994-8c3e7497bfd3.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/c5021f2b-a88c-4a98-8d0f-9fc4a3096d2c.png" width="391" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there we have it, a catalog of APIs. If we at this point navigate to /swagger we can see that the list is still empty as we haven’t created any endpoints from the API:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/01dc6e4f-17cd-4e81-8a74-1677dfe7e507.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/577ef6c5-81e0-42a6-a23d-53a13194b4f1.png" width="282" height="214"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s fix that and add the required UI for listing and creating the endpoints. For that we need IEndpointManager:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;    [Inject]
    IEndpointManager EndpointManager { get; set; }&lt;/pre&gt;
&lt;p&gt;UI should be simple: user can select the API by clicking the row and then she can enter the route to the endpoint &amp;amp; click Create. &lt;/p&gt;
&lt;p&gt;For this we add couple new properties to the component:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;    ApiDefinition SelectedApi { get; set; }
    string EndpointRoute { get; set; }&lt;/pre&gt;
&lt;p&gt;And then a really simple UI which can be used to create the endpoint:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;&amp;lt;h3&amp;gt;Create Endpoint&amp;lt;/h3&amp;gt;
&amp;lt;strong&amp;gt;Selected API: &amp;lt;/strong&amp;gt; @SelectedApi &amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Route: &amp;lt;/strong&amp;gt;&amp;lt;input @bind="EndpointRoute"/&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;div class="mt-3"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;button class="btn btn-primary" @onclick="Create"&amp;gt;Create&amp;lt;/button&amp;gt;&lt;/pre&gt;
&lt;p&gt;Finally, all that is left is the implementation of the Create-method. Creating an endpoint in runtime takes couple of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First we need to define the endpoint. The endpoint always contains the route and the API but it also can contain configuration. This means that we could create a configurable API and then create multiple endpoints from that single API, each having a different configuration.&lt;/li&gt;
&lt;li&gt;Then we need to provide the new endpoint definition to the IEndpointManager.&lt;/li&gt;
&lt;li&gt;Finally we tell IEndpointManager to Update. This makes the new endpoint accessible. This way it is possible to first add multiple endpoints and then with a single Update call make them all visible at the same time.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Here’s how we can define the endpoint:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;var endpoint = new EndpointDefinition(EndpointRoute, SelectedApi);&lt;/pre&gt;
&lt;p&gt;Then we can use CreateAndAdd method to actually the create the endpoint using the definition and to add it into the system with a single call:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        EndpointManager.CreateAndAdd(endpoint);&lt;/pre&gt;
&lt;p&gt;And now we just ask EndpointManager to update itself. At this point it goes through all the endpoints and initializes the new ones and updates the changed ones:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;EndpointManager.Update();&lt;/pre&gt;
&lt;p&gt;Here’s the full Create-method:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;    private void Create()
    {
        var endpoint = new EndpointDefinition(EndpointRoute, SelectedApi);
        
        EndpointManager.CreateAndAdd(endpoint);
        
        EndpointManager.Update();
    }&lt;/pre&gt;
&lt;p&gt;And here’s what we see when we run the app:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/71623a50-1a46-4924-971e-e88ad472f06d.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/b3e4d387-1b41-4281-913f-a46430cf3aea.png" width="357" height="267"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now we can actually test if our setup works. Click the API from API Catalog, then provide route (for example /test) and finally click Create.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/fa08d7ec-2d7f-4fd5-bc76-2d333f70c88a.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/b6454ec5-efea-4221-b818-6872f189368b.png" width="341" height="274"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe something happened, even though our UI doesn’t give any feedback. Navigating to /api/test should tell us more… And there it is!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/e544d9a7-1410-47ae-a158-5f6234f9b6ae.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/c40a629e-d458-47f2-9780-f84142a53a00.png" width="386" height="95"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Now if we check /swagger we should see the new endpoint:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/e5159686-d5ae-49d5-b58b-afdaa2b37e88.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/74e6bfce-c2a4-4343-b173-63af7d68930e.png" width="311" height="344"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Excellent. Try adding couple more endpoints, like /hello and /world and make sure things work as expected:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/0127f989-cf7d-48f7-afb4-9cf900c1051d.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/db46f130-3bdf-46fa-a974-444e9ffd2f27.png" width="311" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it. We now have an ASP.NET Core backend which can be modified runtime. &lt;/p&gt;
&lt;p&gt;If you wonder why the endpoint is available form /api/test and not from /test, it is because the AF by default uses the /api prefix for all the endpoints. This can be configured using options.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In this blog we modified an ASP.NET Core 3.1 based application so that it supports runtime changes. Through these runtime changes we can add new endpoints without having to rebuild or to restart the app. The code is available from &lt;a title="https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime" href="https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime"&gt;https://github.com/weikio/ApiFramework.Samples/tree/main/misc/RunTime&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog works more as an introduction to the subject as we used only one API and that was the simplest possible, the Hello World. But we will expand from this and here’s some ideas of things to explore, all supported by API Framework:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removing an endpoint runtime&lt;/li&gt;
&lt;li&gt;Creating endpoints from an API which requires configuration&lt;/li&gt;
&lt;li&gt;Listing endpoints&lt;/li&gt;
&lt;li&gt;Viewing endpoint’s status&lt;/li&gt;
&lt;li&gt;Creating the APIs (not endpoints) runtime using C#&lt;/li&gt;
&lt;li&gt;Creating an endpoint runtime from an API distributed as a Nuget package.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;To read more about API Framework, please visit the project’s home pages at &lt;a title="https://weik.io/apiframework" href="https://weik.io/apiframework"&gt;https://weik.io/apiframework&lt;/a&gt;. The AF’s source code is available from &lt;a href="https://github.com/weikio/apiframework" target="_blank"&gt;GitHub&lt;/a&gt; and documentation can be found from &lt;a title="https://docs.weik.io/apiframework/" href="https://docs.weik.io/apiframework/"&gt;https://docs.weik.io/apiframework/&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/introducing-api-framework-aspnet-core-openapi-runtime-plugins</id>
    <title type="text">“Everything is an OpenAPI” in ASP.NET Core: Introducing API Framework – Add Runtime Changes &amp; Reusability &amp; Plugins into Web Apps</title>
    <summary type="text">API 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 resources become the OpenAPI endpoints. </summary>
    <published>2021-09-23T15:04:19Z</published>
    <updated>2021-09-23T15:04:19Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/introducing-api-framework-aspnet-core-openapi-runtime-plugins" />
    <content type="text">&lt;p&gt;&lt;img style="float: right; display: inline" alt="Logo" src="https://docs.weik.io/apiframework/logo_alternative_2_small.png" align="right"&gt;API 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 &lt;strong&gt;ASP.NET Core based OpenAPI backends&lt;/strong&gt;. With API Framework &lt;strong&gt;your code and your resources &lt;/strong&gt;become the OpenAPI endpoints. &lt;/p&gt; &lt;p&gt;With API Framework the endpoints can be build using &lt;strong&gt;POCOs, Roslyn Script and Delegates&lt;/strong&gt; and the reusable APIs can be distributed as &lt;strong&gt;plugins using Nuget.&lt;/strong&gt; The APIs can be added &lt;strong&gt;runtime&lt;/strong&gt;, 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 &lt;strong&gt;generate OpenAPI endpoints from databases, file systems, Azure blob storage, and more&lt;/strong&gt;. &lt;/p&gt; &lt;p&gt;API Framework version 1.0.0 is now available from Nuget: &lt;a title="https://www.nuget.org/packages/weikio.apiframework.aspnetcore" href="https://www.nuget.org/packages/weikio.apiframework.aspnetcore"&gt;https://www.nuget.org/packages/weikio.apiframework.aspnetcore&lt;/a&gt;. The project’s home pages is available from &lt;a href="https://weik.io/apiframework"&gt;https://weik.io/apiframework&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Main Features&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;“Everything is an OpenAPI”&lt;/strong&gt; 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.&lt;/p&gt; &lt;p&gt;You can also integrate API Framework with your existing Controller &amp;amp; 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. &lt;/p&gt; &lt;p&gt;Here’s a short summary of the major features of API Framework:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Everything is an OpenAPI: &lt;/strong&gt;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.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Runtime Changes&lt;/strong&gt;: APIs and endpoints can be configured runtime, when the application is running. No need to restart the system to add a new endpoint.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Plugin Support: &lt;/strong&gt;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.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;There’s many more features, including support for health checks and async JSON streams. More information is available from the &lt;a href="https://weik.io/apiframework/" target="_blank"&gt;project’s home pages&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Terminology &amp;amp; Main Concepts&lt;/h3&gt; &lt;p&gt;With API Framework there’s two main concepts: &lt;/p&gt; &lt;h5&gt;&lt;font style="font-weight: normal"&gt;API&lt;/font&gt;&lt;/h5&gt; &lt;p&gt;In API Framework each &lt;strong&gt;API&lt;/strong&gt; has two properties: Name and Version. And the actual functionality they provide.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;h5&gt;Endpoint&lt;/h5&gt; &lt;p&gt;An API itself is not accessible through a web request. That's the work of an &lt;strong&gt;Endpoint&lt;/strong&gt;. Endpoint gives your API a route (for example '/helloworld') and a configuration (if needed).&lt;/p&gt; &lt;p&gt;You can create multiple endpoints from each API and every endpoint can have different configuration.&lt;/p&gt; &lt;h3&gt;Quick Start&lt;/h3&gt; &lt;p&gt;Here’s a quick start, adapted from the documentation at &lt;a title="https://docs.weik.io/apiframework/quickstart.html" href="https://docs.weik.io/apiframework/quickstart.html"&gt;https://docs.weik.io/apiframework/quickstart.html&lt;/a&gt;. The starting point is a blank &lt;strong&gt;ASP.NET Core 3.1 web api app&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;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). &lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;1. Add the required package for API Framework:&lt;/strong&gt;&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        &amp;lt;PackageReference Include="Weikio.ApiFramework.AspNetCore.StarterKit" Version="1.0.0"/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. Add the SQL Server and OpenAPI plugins:&lt;/strong&gt;&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        &amp;lt;PackageReference Include="Weikio.ApiFramework.Plugins.SqlServer" Version="2.0.0" /&amp;gt;
        &amp;lt;PackageReference Include="Weikio.ApiFramework.Plugins.OpenApi" Version="1.0.0" /&amp;gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Modify Startup.Configure by adding API Framework &amp;amp; required APIs and Endpoints:&lt;/strong&gt;&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        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;"
                    });
        }&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. Run the application, wait a few second (the endpoints are generated on the background) and navigate to &lt;/strong&gt;&lt;a href="https://localhost:5001/swagger"&gt;&lt;strong&gt;https://localhost:5001/swagger&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/80ea42a5-ea12-430d-a3ae-44fdb28154f4.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/2bef6820-4342-4e87-945f-6be36ef59663.png" width="505" height="396"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The SQL Server database can be queried and filtered and the OpenAPI specs contains the schema for the database:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/eaaa1dd3-e082-4c0b-94f2-e011a0fe1783.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://mikaelkoskinen.net/posts/files/e2067be1-726f-4a2b-84bb-18e8bb6b8501.png" width="414" height="570"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Getting Started&lt;/h3&gt;
&lt;p&gt;The quick start above show one approach for using API Framework. Best way to learn more about API Framework is through the following resources: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project’s home page at &lt;a href="https://weik.io/ApiFramework"&gt;https://weik.io/ApiFramework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Project’s documentation at &lt;a title="https://docs.weik.io/apiframework/" href="https://docs.weik.io/apiframework/"&gt;https://docs.weik.io/apiframework/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Project’s issue tracker and source code at &lt;a title="https://github.com/weikio/ApiFramework" href="https://github.com/weikio/ApiFramework"&gt;https://github.com/weikio/ApiFramework&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;Use Cases&lt;/h3&gt;
&lt;p&gt;As API Framework adds more flexibility into building and running ASP.NET Core backends, there’s different use cases where it can be helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;24/7 Backends: &lt;/strong&gt;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration Layers: &lt;/strong&gt;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More options for building APIs: &lt;/strong&gt;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.&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;Current Status&lt;/h3&gt;
&lt;p&gt;Today is the day of the &lt;a href="https://www.nuget.org/packages/weikio.apiframework.aspnetcore" target="_blank"&gt;1.0.0 release&lt;/a&gt;. The work continues, especially with the &lt;a href="https://github.com/weikio/ApiFramework.Samples" target="_blank"&gt;samples&lt;/a&gt; and with &lt;a href="https://docs.weik.io/apiframework/" target="_blank"&gt;documentation&lt;/a&gt;. Currently there’s about 12 samples available, showcasing many of the features but there’s more to add. The documentation is little farther behind.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Project Home&lt;/h3&gt;
&lt;p&gt;API Framework can be found from &lt;a href="https://github.com/weikio/ApiFramework" target="_blank"&gt;Github&lt;/a&gt; and from &lt;a href="https://weik.io/ApiFramework"&gt;https://weik.io/ApiFramework&lt;/a&gt;. &lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/blazor-animate-blazorise</id>
    <title type="text">Blazor.Animate moves into Blazorise</title>
    <summary type="text">Blazor.Animate is now part of Blazorise.</summary>
    <published>2020-12-07T12:18:00Z</published>
    <updated>2020-12-05T09:18:40Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/blazor-animate-blazorise" />
    <content type="text">&lt;p&gt;&lt;img style="float: right; display: inline" src="https://raw.githubusercontent.com/mikoskinen/Blazor.Animate/master/blazoranimate.gif" width="329" align="right" height="256"&gt;Starting from this week, Blazor.Animate is proud to be part of the &lt;a href="https://github.com/stsrki/Blazorise" target="_blank"&gt;Blazorise&lt;/a&gt;. All the updates and future work for Blazor.Animate will continue through Blazorise. For those not familiar with Blazor.Animate, it is an animation component for Blazor. With Blazor.Animate you can animate how other components are brought to the view. You can easily add fade, slide and zoom-effects and even add easing to the animations.&lt;/p&gt; &lt;p&gt;All the updates and future work for Blazor.Animate will continue through Blazorise.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/plugin-framework-aspnet-core-appsettings-111-release</id>
    <title type="text">Plugin Framework 1.1.0 for .NET released with support for appsettings.json &amp; improved Plugin Tagging</title>
    <summary type="text">New version of Plugin Framework for .NET adds support for reading catalog configuration from appsettings.json and improved plugin tagging</summary>
    <published>2020-10-14T15:31:48Z</published>
    <updated>2020-10-14T15:31:48Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/plugin-framework-aspnet-core-appsettings-111-release" />
    <content type="text">&lt;p&gt;&lt;img style="float: right; display: inline" alt="Plugin Framework Logo" src="https://github.com/weikio/PluginFramework/raw/master/docs/logo_transparent_color_256.png" align="right"&gt;&lt;/p&gt; &lt;p&gt;New version of &lt;a href="https://github.com/weikio/PluginFramework" target="_blank"&gt;Plugin Framework for .NET&lt;/a&gt; adds support for reading plugin catalog configuration from appsettings.json and improves plugin tagging. The release is now available through Nuget: &lt;a title="https://www.nuget.org/packages/Weikio.PluginFramework/" href="https://www.nuget.org/packages/Weikio.PluginFramework/"&gt;https://www.nuget.org/packages/Weikio.PluginFramework/&lt;/a&gt;&lt;/p&gt; &lt;p&gt;For those who are not familiar with Plugin Framework, it is a plugin platform for .NET applications, including ASP.NET Core, Blazor, WPF, Windows Forms and Console apps. It is light-weight and easy to integrate and supports multiple different plugin catalogs, including .NET assemblies, Nuget packages and Roslyn scripts. &lt;/p&gt; &lt;p&gt;&lt;a href="https://mikaelkoskinen.net/post/plugin-framework-dotnet-core-blazor-nuget-roslyn" target="_blank"&gt;Here’s an introduction post&lt;/a&gt; about Plugin Framework. InfoQ did a an article about the framework, &lt;a href="https://www.infoq.com/articles/Plugin-Framework-DotNet/" target="_blank"&gt;it’s available from their site&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;The 1.1.0 release&lt;/h3&gt; &lt;p&gt;I’m especially happy with the support for &lt;strong&gt;appsettings.json&lt;/strong&gt; as it’s the first community contribution (thanks &lt;a href="https://github.com/panoukos41"&gt;@panoukos41 (github.com)&lt;/a&gt;!) and as it also enables new scenarios for the framework. Folder and assembly catalogs can be configured with the following syntax (support for more catalog types is coming in the upcoming versions):&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;  "PluginFramework": {
    "Catalogs": [
      {
        "Type": "Folder",
        "Path": "..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1"
      },
      {
        "Type": "Assembly",
        "Path": ".\\bin\\Debug\\netcoreapp3.1\\WebAppPluginsLibrary.dll"
      }
    ]
  }&lt;/pre&gt;
&lt;p&gt;Sample for this specific feature is available from &lt;a title="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithAppSettings" href="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithAppSettings"&gt;https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithAppSettings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;New version also improves the &lt;strong&gt;plugin tagging&lt;/strong&gt;. The idea behind plugin tagging is that Plugin Framework can for example scan a folder of dlls and tag the found plugins based on the given criteria. The developer can then use the plugins based on their tags. This is useful in situations where the application supports multiple types of plugins. &lt;/p&gt;
&lt;p&gt;Here’s an example where all the found plugins are tagged as “operator”:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;            var folderPluginCatalog = new FolderPluginCatalog(@"..\..\..\..\Shared\Weikio.PluginFramework.Samples.SharedPlugins\bin\debug\netcoreapp3.1",
                type =&amp;gt; { type.Implements&amp;lt;IOperator&amp;gt;().Tag("operator"); });&lt;/pre&gt;
&lt;p&gt;And another part of the same app tags plugins as “dialog”:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;            var folderCatalog = new FolderPluginCatalog(@"..\..\..\..\WinFormsPluginsLibrary\bin\debug\netcoreapp3.1",
                type =&amp;gt;
                {
                    type.Implements&amp;lt;IDialog&amp;gt;()
                        .Tag("dialog");
                });&lt;/pre&gt;
&lt;p&gt;Now when these plugins are used in the application, they can be fetched using the tags. Here’s an example where the “operator” and “dialog” tags are used:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;        private void AddCalculationOperators()
        {
            var allPlugins = _allPlugins.GetByTag("operator");
            foreach (var plugin in allPlugins)
            {
                listBox1.Items.Add(plugin);
            }
        }

        private void AddDialogs()
        {
            var dialogPlugins = _allPlugins.GetByTag("dialog");
            
            foreach (var dialogPlugin in dialogPlugins)
            {
                var menuItem = new ToolStripButton(dialogPlugin.Name, null, (o, args) =&amp;gt;
                {
                    var instance = (IDialog) Activator.CreateInstance(dialogPlugin);
                    instance.Show();
                });

                dialogPluginsToolStripMenuItem.DropDownItems.Add(menuItem);
            }
        }&lt;/pre&gt;
&lt;p&gt;Sample for plugin tagging is available from &lt;a title="https://github.com/weikio/PluginFramework/tree/master/samples/WinFormsApp" href="https://github.com/weikio/PluginFramework/tree/master/samples/WinFormsApp"&gt;https://github.com/weikio/PluginFramework/tree/master/samples/WinFormsApp&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;What’s next?&lt;/h3&gt;
&lt;p&gt;Work will continue on improving (and adding new) plugin catalogs but the main thing for the next release is the &lt;strong&gt;support for .NET 5&lt;/strong&gt;. This will enable one scenario which hasn’t been that well supported: Using Plugin Framework in WebAssembly version of Blazor. &lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/blazor-animate-animations-manual-onclick</id>
    <title type="text">Blazor.Animate adds support for running animations manually</title>
    <summary type="text">New version of Blazor.Animate adds support for manually running animations</summary>
    <published>2020-09-10T16:17:55Z</published>
    <updated>2020-09-10T16:17:55Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/blazor-animate-animations-manual-onclick" />
    <content type="text">&lt;p&gt;There’s now a new version of &lt;a href="https://github.com/mikoskinen/Blazor.Animate" target="_blank"&gt;Blazor.Animate&lt;/a&gt; available which adds support for &lt;strong&gt;running animations manually&lt;/strong&gt;. The animated component stays hidden until the animation which bring the component into the view is manually executed. &lt;/p&gt; &lt;p&gt;Here’s an example where &lt;strong&gt;OnClick-event of a button&lt;/strong&gt; is used to bring Counter-component into view:&lt;/p&gt; &lt;p&gt;&lt;a href="https://mikaelkoskinen.net/posts/files/3c385536-1e3f-4fcb-bdc1-f0511341de4d.gif"&gt;&lt;img title="onclickanimation" style="display: inline" alt="onclickanimation" src="https://mikaelkoskinen.net/posts/files/1ff18182-27bb-44ae-9b57-a4fd8b88a67e.gif" width="515" height="288"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="https://www.nuget.org/packages/BlazorAnimate/3.0.0" target="_blank"&gt;The new 3.0.0 version is available from NuGet.&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;Usage&lt;/h3&gt; &lt;p&gt;In order to manually run the animation, the following is needed:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Use the IsManual-property&lt;/li&gt; &lt;li&gt;Capture reference to the component using ref &lt;/li&gt; &lt;li&gt;Manually run the animation using Run()-method for example when a button is clicked&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Here is a full example of all the steps:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;&amp;lt;button class="btn btn-primary" @onclick="RunAnimation"&amp;gt;Animate&amp;lt;/button&amp;gt;

&amp;lt;Animate Animation="Animations.ZoomIn" Duration="TimeSpan.FromSeconds(0.5)" @ref="myAnim" IsManual="true"&amp;gt;
    &amp;lt;Counter&amp;gt;&amp;lt;/Counter&amp;gt;
&amp;lt;/Animate&amp;gt;

@code {

    private Animate myAnim;

    private void RunAnimation()
    {
        myAnim.Run();
    }
}&lt;/pre&gt;
&lt;h3&gt;Sample&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/mikoskinen/Blazor.Animate/tree/master/samples/BlazorAnimate.Sample" target="_blank"&gt;Blazor.Animate’s sample&lt;/a&gt; has been updated to contain a new &lt;a href="https://github.com/mikoskinen/Blazor.Animate/blob/master/samples/BlazorAnimate.Sample/Pages/Manual.razor" target="_blank"&gt;“Manual”&lt;/a&gt; page which shows how to use the new functionality.&lt;/p&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;For those not familiar with Blazor.Animate, it’s a Blazor components which allows you to animate how other components are brought into the view. All the animations are powered by &lt;a href="https://michalsnik.github.io/aos/" target="_blank"&gt;AOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a simple example of using the component:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;&amp;lt;Animate Animation="Animations.ZoomIn" Duration="TimeSpan.FromSeconds(0.5)" &amp;gt;
    &amp;lt;Counter&amp;gt;&amp;lt;/Counter&amp;gt;
&amp;lt;/Animate&amp;gt;&lt;/pre&gt;
&lt;p&gt;For a more throughout introduction, I recommend you to check out the &lt;a href="https://mikaelkoskinen.net/post/blazor-animate-animation-component-for-blazor" target="_blank"&gt;introduction post&lt;/a&gt; or the project home site on &lt;a href="https://github.com/mikoskinen/Blazor.Animate" target="_blank"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/plugin-framework-dotnet-core-blazor-nuget-roslyn</id>
    <title type="text">Introducing Plugin Framework 1.0.0 – Plugins for .NET apps including Blazor and ASP.NET Core with built-in support for Nuget</title>
    <summary type="text">Plugin Framework is a new MIT-licensed plugin platform for .NET Core applications. It supports ASP.NET Core, Blazor and more and has a built-in support for Nuget packages and feeds.</summary>
    <published>2020-08-03T12:28:38Z</published>
    <updated>2020-08-03T12:28:38Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/plugin-framework-dotnet-core-blazor-nuget-roslyn" />
    <content type="text">&lt;p&gt;&lt;img alt="Plugin Framework Logo" src="https://github.com/weikio/PluginFramework/raw/master/docs/logo_transparent_color_256.png"&gt;&lt;/p&gt; &lt;p&gt;Plugin Framework is a new MIT-licensed &lt;strong&gt;plugin platform for .NET Core applications&lt;/strong&gt;. It is light-weight and easy way to add a plugin-support into your application. It supports all the major types of .NET Core applications, including &lt;strong&gt;ASP.NET Core, Blazor, Console Apps and WPF &amp;amp; WinForms. &lt;/strong&gt;Plugin Framework has a built-in support for &lt;strong&gt;Nuget packages and feeds&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;The Plugin Framework version 1.0.0 is now available from Nuget: &lt;a title="https://www.nuget.org/packages/Weikio.PluginFramework/" href="https://www.nuget.org/packages/Weikio.PluginFramework/"&gt;https://www.nuget.org/packages/Weikio.PluginFramework/&lt;/a&gt;. For Blazor and ASP.NET Core applications the recommended package is &lt;a title="https://www.nuget.org/packages/Weikio.PluginFramework.AspNetCore" href="https://www.nuget.org/packages/Weikio.PluginFramework.AspNetCore"&gt;https://www.nuget.org/packages/Weikio.PluginFramework.AspNetCore&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;Main features&lt;/h3&gt; &lt;p&gt;Plugin Framework follows an "Everything is a plugin" -mentality. It provides out of the box support for sharing plugins using &lt;strong&gt;Nuget packages, Roslyn scripts and delegates&lt;/strong&gt;, in addition to the more common ones like .NET assemblies and folders.&lt;/p&gt; &lt;p&gt;Here’s a short summary of the major features provided by Plugin Framework:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Deliver plugins as Nuget-packages, .NET assemblies, Roslyn scripts and more.  &lt;li&gt;Easy integration into a new or an existing .NET Core application.  &lt;li&gt;Automatic dependency management.  &lt;li&gt;MIT-licensed, commercial support available.&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Quick start: ASP.NET Core&lt;/h3&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;Install-Package Weikio.PluginFramework.AspNetCore&lt;/pre&gt;
&lt;p&gt;Using Plugin Framework can be as easy as adding a single new line into ConfigureServices. The following code finds all the plugins (types that implement the custom IOperator-interface) from the myplugins-folder. &lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;services.AddPluginFramework&amp;lt;IOperator&amp;gt;(@".\myplugins");&lt;/pre&gt;
&lt;p&gt;The plugins can be used in a controller using constructor injection:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;public CalculatorController(IEnumerable&amp;lt;IOperator&amp;gt; operator)
{
	_operators = operators;
}&lt;/pre&gt;
&lt;h3&gt;Getting started&lt;/h3&gt;
&lt;p&gt;Best way to learn more about Plugin Framework is through the project's home page at Github: &lt;a href="https://github.com/weikio/PluginFramework"&gt;https://github.com/weikio/PluginFramework&lt;/a&gt;. The repository contains multiple different samples at the time of writing this. Here's a list:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/ConsoleApp" target="_blank"&gt;Plugin Framework &amp;amp; .NET Console Application&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/WebApp" target="_blank"&gt;Plugin Framework &amp;amp; ASP.NET Core&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/BlazorApp" target="_blank"&gt;Plugin Framework &amp;amp; Blazor&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithDelegate" target="_blank"&gt;Plugin Framework &amp;amp; WPF App&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithNuget" target="_blank"&gt;Nuget &amp;amp; Plugin Framework &amp;amp; ASP.NET Core&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithRoslyn" target="_blank"&gt;Roslyn &amp;amp; Plugin Framework &amp;amp; ASP.NET Core&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithDelegate" target="_blank"&gt;Delegates &amp;amp; Plugin Framework &amp;amp; ASP.NET Core&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;How does this work?&lt;/h4&gt;
&lt;p&gt;When you create your application and add support for Plugin Framework, you usually define two things:&lt;/p&gt;
&lt;p&gt;1. The specifications for the plugins. In some applications a plugin can add new functionality into the UI. In other apps, plugins are used to distribute logs into multiple different systems. The application defines what kind of extensions it supports.&lt;/p&gt;
&lt;p&gt;2. The locations where the application can find the plugins. Many applications use a specific “plugins”-folder to indicate the location where plugins should exist in the hard drive. In some situations plugins are installed in runtime from Nuget. These plugin locations are called &lt;strong&gt;catalogs&lt;/strong&gt;. As a developer you define what catalogs your application uses.&lt;/p&gt;
&lt;h4&gt;What makes a plugin?&lt;/h4&gt;
&lt;p&gt;In the context of the Plugin Framework, plugin is a single .NET Type. For some applications a plugin is a type which implements a specific interface. In some applications a plugin is a type which has a single public method called Run. Attributes are often used to indicate the plugins and that is also supported by Plugin Framework. From the Plugin Framework's point of view anything or everything can be a plugin.&lt;/p&gt;
&lt;h4&gt;What is a plugin catalog?&lt;/h4&gt;
&lt;p&gt;Each plugin is part of a catalog. Plugin Framework provides the following officially supported catalogs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type&lt;/li&gt;
&lt;li&gt;Assembly&lt;/li&gt;
&lt;li&gt;Folder&lt;/li&gt;
&lt;li&gt;Delegate &lt;/li&gt;
&lt;li&gt;Roslyn script &lt;/li&gt;
&lt;li&gt;Nuget package &lt;/li&gt;
&lt;li&gt;Nuget feed &lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;License &amp;amp; Source code &amp;amp; Commercial Support &amp;amp; Issue Tracking&lt;/h3&gt;
&lt;p&gt;As previously mentioned, Plugin Framework is MIT-licensed and its source code is available from GitHub: &lt;a href="https://github.com/weikio/PluginFramework"&gt;https://github.com/weikio/PluginFramework&lt;/a&gt;. GitHub also contains the issue tracking.&lt;/p&gt;
&lt;p&gt;There is also commercial support available for Plugin Framework. That is provided by Adafy &lt;a href="https://adafy.com"&gt;https://adafy.com&lt;/a&gt;. Though the website is only in Finnish, the support is available both in English and in Finnish.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>https://mikaelkoskinen.net/post/blazor-eventaggregator-2-0-0-auto-refresh</id>
    <title type="text">Event Aggregator for Blazor updated to 2.0.0</title>
    <summary type="text">There’s now a new 2.0.0 version available of Event Aggregator for Blazor. The new release makes the library easier to use.</summary>
    <published>2020-03-08T08:02:07Z</published>
    <updated>2020-03-08T08:02:07Z</updated>
    <author>
      <name />
    </author>
    <link rel="alternate" href="https://mikaelkoskinen.net/post/blazor-eventaggregator-2-0-0-auto-refresh" />
    <content type="text">&lt;p&gt;After some hiatus there’s now a &lt;a href="https://www.nuget.org/packages/EventAggregator.Blazor/2.0.0" target="_blank"&gt;new 2.0.0 version&lt;/a&gt; available of &lt;a href="https://github.com/mikoskinen/Blazor.EventAggregator" target="_blank"&gt;Event Aggregator for Blazor&lt;/a&gt;. For those who are not familiar with Event Aggregator for Blazor, Event aggregator is used for &lt;strong&gt;indirect component to component communication&lt;/strong&gt;. In the event aggregator pattern you have message/event publishers and subscribers. In the case of Blazor, a component can publish its events and other component(s) can react to those.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Project home&lt;/strong&gt;: &lt;a href="https://github.com/mikoskinen/Blazor.EventAggregator"&gt;https://github.com/mikoskinen/Blazor.EventAggregator&lt;/a&gt;&lt;/p&gt; &lt;p&gt;There’s few changes and additions in this release:&lt;/p&gt; &lt;h3&gt;Easier initialization&lt;/h3&gt; &lt;p&gt;Event Aggregator for Blazor now contains a ServiceCollectionExtension, making it easier to start using the component. From version 2.0.0 you can use the following initialization code in your ConfigureServices:&lt;/p&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;public void ConfigureServices(IServiceCollection services)
{
    services.AddEventAggregator();
}
&lt;/pre&gt;
&lt;p&gt;Note: The library has been tested only with the latest server side version of Blazor. It should work with Blazor WebAssembly, but more testing is required. In Blazor WebAssembly you register the library in application’s Main-method.&lt;/p&gt;
&lt;h3&gt;Auto refresh is disabled by default&lt;/h3&gt;
&lt;p&gt;Previously, Event Aggregator for Blazor tried always to execute subscriber’s StateHasChanged-method after it had handled a message. This made (and can still make) working with the Event Aggregator easier as it means you don’t have to manually call StateHasChanged in your Handle-method, if you want to update the UI. Unfortunately in some situations the auto refresh can cause performance issues so from version 2.0.0 onwards the auto refresh is disabled by default. &lt;/p&gt;
&lt;p&gt;You can enable auto refresh through options:&lt;br&gt;&lt;pre class="brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;"&gt;services.AddEventAggregator(options =&amp;gt; options.AutoRefresh = true);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Auto refresh is based on reflection and it assumes that the subscriber inherits from ComponentBase.&lt;/p&gt;
&lt;h3&gt;Auto refresh now understands component’s SynchronizationContext&lt;/h3&gt;
&lt;p&gt;Previously, Event Aggregator for Blazor’s auto refresh just executed component’s StateHasChanged-method. In the preview versions of Blazor this worked OK but as Blazor now uses &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.1#invoke-component-methods-externally-to-update-state" target="_blank"&gt;SynchronizationContext to enforce a single logical thread of execution&lt;/a&gt;, auto refresh had a habit of crashing the application. This is now fixed.&lt;/p&gt;</content>
  </entry>
</feed>