<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Morris Janatzek</title>
    <description>The latest articles on Forem by Morris Janatzek (@morrisjdev).</description>
    <link>https://forem.com/morrisjdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F278810%2F6f2fe494-b3f1-4cc5-9e2f-5ab7867c83e0.png</url>
      <title>Forem: Morris Janatzek</title>
      <link>https://forem.com/morrisjdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/morrisjdev"/>
    <language>en</language>
    <item>
      <title>New version of SapphireDb with NodeJs support</title>
      <dc:creator>Morris Janatzek</dc:creator>
      <pubDate>Tue, 21 Jan 2020 17:43:56 +0000</pubDate>
      <link>https://forem.com/morrisjdev/new-version-of-sapphiredb-with-nodejs-support-427l</link>
      <guid>https://forem.com/morrisjdev/new-version-of-sapphiredb-with-nodejs-support-427l</guid>
      <description>&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/sapphiredb-js"&gt;
        sapphiredb-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Client for SapphireDb, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;SapphireDb now has got a new client implementation that is compatible with any JS client and also compatible with NodeJs. The npm-package is called &lt;b&gt;sapphiredb&lt;/b&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Story behind
&lt;/h1&gt;

&lt;p&gt;A few days ago I posted an article on HackerNews to advertise a framework I created. The name of it is &lt;b&gt;SapphireDb&lt;/b&gt;, it is an extension for Asp.Net Core and EF Core and enables you to easily create self hosted applications with realtime data synchronization. It should serve as alternative to firebase realtime database/firestore.&lt;/p&gt;

&lt;p&gt;I got plenty of feedback including a few recommendations like moving the code base of the client implementation to a separate project. I totally agree to that point and decided to do so. At that moment SapphireDb only had a client implementation for Angular.&lt;/p&gt;

&lt;p&gt;The process was not that complicated but I had to change all references to Angular specific things to a more generic API. I decided to use axios instead of Angulars HttpClient and it works fine. Also using direct inject of dependency instances instead of Angulars Dependency injection was pretty easy. I only decided to keep ng-packagr as build tool for the client library.&lt;/p&gt;

&lt;h1&gt;
  
  
  NodeJs example
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install sapphiredb rxjs axios -S
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sapphiredb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sapphiredb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;sapphiredb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SapphireDb&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;serverBaseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost:5000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useSsl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webapp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pw1234&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;demo.entries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Changes for ng-sapphiredb
&lt;/h1&gt;

&lt;p&gt;Because I moved the complete code base out of the project because I don't want to maintain the same code in two places you have to install sapphiredb along with ng-sapphiredb when using it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install ng-sapphiredb sapphiredb axios -S
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check out the documentation to learn more: &lt;a href="https://sapphire-db.com/"&gt;https://sapphire-db.com/&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/sapphiredb-js"&gt;
        sapphiredb-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Client for SapphireDb, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>database</category>
      <category>csharp</category>
    </item>
    <item>
      <title>How to synchronize data in realtime with Asp.Net Core and Angular</title>
      <dc:creator>Morris Janatzek</dc:creator>
      <pubDate>Tue, 10 Dec 2019 17:02:19 +0000</pubDate>
      <link>https://forem.com/morrisjdev/how-to-synchronize-data-in-realtime-with-asp-net-core-and-angular-ap3</link>
      <guid>https://forem.com/morrisjdev/how-to-synchronize-data-in-realtime-with-asp-net-core-and-angular-ap3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;To easily create a realtime application I'm using SapphireDb. Check out the documentation to learn more: &lt;a href="https://sapphire-db.com/"&gt;https://sapphire-db.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Around one year ago I started developing a new project. The project initially consisted of an asp.net core application as a backend server and an angular client application as a UI. One of the key requirements was the data synchronization in realtime.&lt;/p&gt;

&lt;p&gt;I already knew and liked firebase and had the wish to be able to use it in the project. Sadly that was not possible because another requirement was that the application should have a asp.net core backend and can be self-hosted.&lt;/p&gt;

&lt;p&gt;I made some research and sadly did not find any other solution that would make the development easier with the required tech stack.&lt;/p&gt;

&lt;p&gt;I then decided to start developing my own realtime database called &lt;a href="https://sapphire-db.com/"&gt;SapphireDb&lt;/a&gt;. Here are the most important the features the project now has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔧 Dead simple configuration&lt;/li&gt;
&lt;li&gt;🌠 Blazing fast development&lt;/li&gt;
&lt;li&gt;📡 Modern technologies&lt;/li&gt;
&lt;li&gt;💻 Self hosted&lt;/li&gt;
&lt;li&gt;💾 Easy CRUD operations&lt;/li&gt;
&lt;li&gt;🔑 Authentication/Authorization included&lt;/li&gt;
&lt;li&gt;✔️ Database support&lt;/li&gt;
&lt;li&gt;🔌 Actions&lt;/li&gt;
&lt;li&gt;🌐 NLB support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this short article I want to explain you how to quickly create your own application with realtime data synchronization using &lt;a href="https://sapphire-db.com/"&gt;SapphireDb&lt;/a&gt; for Asp.Net Core and an Angular application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Server
&lt;/h2&gt;

&lt;p&gt;First you have to create a server application using Asp.Net Core. Using the empty project template totally does the job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;The next step is to install the package from nuget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PM&amp;gt; Install-Package SapphireDb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Create DbContext
&lt;/h3&gt;

&lt;p&gt;Now create a DbContext that contains the objects you want to store in the database. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you dont know how to work with Entity Framework Core check out this documentation for more details: &lt;a href="https://docs.microsoft.com/de-de/ef/core/"&gt;EF Core Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The context should look something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Important: Use SapphireDbContext instead of DbContext&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SapphireDbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//Add SapphireDatabaseNotifier for DI&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SapphireDatabaseNotifier&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Register services and update pipeline
&lt;/h3&gt;

&lt;p&gt;The last step is to modify your service registrations and add SapphireDb to your request pipeline. Modify your &lt;code&gt;Startup.cs&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Startup&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Register services&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSapphireDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SapphireDbOptions&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSomeDatabase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IApplicationBuilder&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Add Middleware&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSapphireDb&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Try launching the application
&lt;/h3&gt;

&lt;p&gt;The server application should now work.&lt;/p&gt;
&lt;h2&gt;
  
  
  Client
&lt;/h2&gt;

&lt;p&gt;You now can create your client application. You first have to create a Angular App or use an existing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;First install the project using:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -S ng-sapphiredb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Import SapphireDbModule
&lt;/h3&gt;

&lt;p&gt;Then you have to import the &lt;code&gt;SapphireDbModule&lt;/code&gt; in you &lt;code&gt;app.module.ts&lt;/code&gt; to make the services available in the whole application:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;SapphireDbModule&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// This part is optional and only required if you want to override some of the settings&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SAPPHIRE_DB_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;serverBaseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serverBaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pw1234&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webapp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;connectionType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;websocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Start application
&lt;/h3&gt;

&lt;p&gt;The cient application should now work. Start it and navigate to the url in your browser.&lt;/p&gt;
&lt;h1&gt;
  
  
  Query data
&lt;/h1&gt;

&lt;p&gt;You are now able to query data. You can use this code in your angular client to get the data from your database. Changes on server side are not required.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DemoComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;values$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SapphireDb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nameofdbset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To display the content of your collection as json use this in your html:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;{{ values$ | async | json }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;This project uses RxJs. If you don't know what an observable is and how to work with it check out this url: &lt;a href="https://rxjs-dev.firebaseapp.com/"&gt;RxJs Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you display the content of the array in the component you can already see the entries and if you change something it should update immediatly.&lt;/p&gt;
&lt;h1&gt;
  
  
  Update data
&lt;/h1&gt;

&lt;p&gt;To update data you have to make the class of the model you want to update updatable. The class should look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Updatable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoEntry&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can then update the content using this code on client side:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DemoComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DefaultCollection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SapphireDb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;updateValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Finish
&lt;/h1&gt;

&lt;p&gt;You are now familiar to the main features of SapphireDb. If you want to learn more check out the documentation and the project on Github.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sapphire-db.com/"&gt;Documentation&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
SapphireDb - Server for Asp.Net Core &lt;a href="https://travis-ci.org/morrisjdev/RealtimeDatabase" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/4fb43af86f71df73145d0fd29bc73f98923e9f98/68747470733a2f2f7472617669732d63692e6f72672f6d6f727269736a6465762f5265616c74696d6544617461626173652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;
  &lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;
    &lt;img src="https://camo.githubusercontent.com/a6f82fb5bd0efa7e770553d0abe2dfec89a43017/68747470733a2f2f73617070686972652d64622e636f6d2f6173736574732f62616e6e65722f5361707068697265444225323042616e6e65722e706e67" alt="SapphireDb logo"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;SapphireDb is a self-hosted, easy to use realtime database for Asp.Net Core and EF Core.&lt;/p&gt;
&lt;p&gt;It creates a generic API you can easily use with different clients to effortlessly create applications with realtime data synchronization
SapphireDb should serve as a self hosted alternative to firebase realtime database and firestore on top of .Net.&lt;/p&gt;
&lt;p&gt;Check out the documentation for more details: &lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
    &lt;a href="https://www.patreon.com/user?u=27738280" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/c11c9bdf1f6c2a1d80afb11859984a61f0fadfa6/68747470733a2f2f63352e70617472656f6e2e636f6d2f65787465726e616c2f6c6f676f2f6265636f6d655f615f706174726f6e5f627574746f6e4032782e706e67" width="160"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2&gt;
Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
🔧 Dead simple configuration&lt;/li&gt;
&lt;li&gt;
📡 Broad technology support&lt;/li&gt;
&lt;li&gt;
💻 Self hosted&lt;/li&gt;
&lt;li&gt;
📱 Offline support&lt;/li&gt;
&lt;li&gt;
💾 Easy to use CRUD operations&lt;/li&gt;
&lt;li&gt;
⚡ Model validation&lt;/li&gt;
&lt;li&gt;
✔️ Database support&lt;/li&gt;
&lt;li&gt;
📂 Supports joins/includes&lt;/li&gt;
&lt;li&gt;
➿ Complex server evaluated queries&lt;/li&gt;
&lt;li&gt;
🔌 Actions&lt;/li&gt;
&lt;li&gt;
🔑 Authorization included&lt;/li&gt;
&lt;li&gt;
✉️ Messaging&lt;/li&gt;
&lt;li&gt;
🌐 Scalable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;Learn more&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;h3&gt;
Install package&lt;/h3&gt;
&lt;p&gt;To install the package execute the following command in your package manager console&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PM&amp;gt; Install-Package SapphireDb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also install the extension using Nuget package manager. The project can be found here: &lt;a href="https://www.nuget.org/packages/SapphireDb/" rel="nofollow"&gt;https://www.nuget.org/packages/SapphireDb/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
Configure&lt;/h3&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/SapphireDb/SapphireDb"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>dotnet</category>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>SapphireDb - Development of a self-hosted alternative to firebase realtime database for asp.net core</title>
      <dc:creator>Morris Janatzek</dc:creator>
      <pubDate>Mon, 09 Dec 2019 15:12:11 +0000</pubDate>
      <link>https://forem.com/morrisjdev/i-created-a-self-hosted-alternative-to-firebase-realtime-database-for-asp-net-core-29g8</link>
      <guid>https://forem.com/morrisjdev/i-created-a-self-hosted-alternative-to-firebase-realtime-database-for-asp-net-core-29g8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;If you're interested in the final result, you can find it here: &lt;a href="https://sapphire-db.com/"&gt;https://sapphire-db.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Around one year ago I started developing a new project. The project initially consisted of an asp.net core application as a backend server and an angular client application as a UI. One of the key requirements was the data synchronization in realtime.&lt;/p&gt;

&lt;p&gt;I already knew and liked firebase and had the wish to be able to use it in the project. Sadly that was not possible because another requirement was that the application should have a asp.net core backend and can be self-hosted.&lt;/p&gt;

&lt;p&gt;I made some research and sadly did not find any other solution that would make the development easier with the required tech stack.&lt;/p&gt;

&lt;h1&gt;
  
  
  The idea
&lt;/h1&gt;

&lt;p&gt;After some days of frustration I made the decision to start developing my own realtime database. After some thinking I wrote down my most important requirements and features the database should have.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extend an existing asp.net core application that uses entity framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main idea was, that the realtime database should extend an existing application. The API should be as easy as possible and I wanted to make as few changes to an existing application as possible. That would make the migration of other existing applications much easier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work with every database supported by ef core&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second idea was to build the realtime database on top of entity framework core. This would have the advantage that it could support any database, supported by entity framework core.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No change in the usage of ef core on server side&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also did not want to make big changes in the existing code on server side. This means changes in the API for querying and managing data on server side directly, for example if you have a procedure that has no realtion to interaction with the client application. The realtime database should extend the existing code and manage synchronization in background automatically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to use CRUD-operations and API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important feature for me was, that the API should be as easy as possible. I wanted to query data from the server on client side with a single line of code, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;No SignalR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I already had some bad experiences using SignalR and decided that the project should not depend on it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actions (Alternative to methods in controllers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because I'm already going to implement a connection and a new API on client side I thought, it would also be very helpful, to have something like custom actions you can define and easily call through the already existing connection.&lt;/p&gt;
&lt;h1&gt;
  
  
  Development
&lt;/h1&gt;

&lt;p&gt;With the main features in mind I started creating first drafts and making tests.&lt;/p&gt;

&lt;p&gt;I dont want to go to much into details but want to give a short overview of the main technical points related to the synchronization of data.&lt;/p&gt;

&lt;p&gt;If you are interested I will write more articles explaining more of the concepts and technology used.&lt;/p&gt;

&lt;p&gt;You can also check out the sources to learn more:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Notification about changes
&lt;/h2&gt;

&lt;p&gt;The first thing I wanted to achieve was an easy way to get notified when something in the database changes.&lt;/p&gt;

&lt;p&gt;I thought about triggers on database level but they would not be flexible enough and would not work with some database systems like the InMemory-database.&lt;/p&gt;

&lt;p&gt;The solution I came up with, was to create a custom DbContext that hooks into the &lt;code&gt;SaveChanges&lt;/code&gt;-method and triggers a notifier. The cool thing about that is, that EF Core already comes with a &lt;code&gt;ChangeTracker&lt;/code&gt; that provides you all changes that affect the next change operation. The code I came up with looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SaveChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;acceptAllChangesOnSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChangeResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;changes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acceptAllChangesOnSuccess&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChangeResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChangeTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EntityState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Added&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EntityState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deleted&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EntityState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Modified&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChangeResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this small piece of code I was already able to achieve one of the key requirements. You dont have to change anything in the code you are already using, except from changing all DbContexts to the new DbContext with the custom SaveChanges method.&lt;/p&gt;
&lt;h2&gt;
  
  
  Communication
&lt;/h2&gt;

&lt;p&gt;The next challenge to solve was the communcation between client and server.&lt;/p&gt;

&lt;p&gt;The final communication itself consists of two simple components. A command and a response. Every action on server side has a command. The client sends a command with a unique id to the server. The server will handle this command and on completion it will respond with a response containing the same unique id as the command. The client then can handle the response and associate it with the sent command.&lt;/p&gt;

&lt;p&gt;For transfer I first implemented Websockets for they already have a Bi-Directional data transport unlike other technologies like ServerSentEvents.&lt;/p&gt;

&lt;p&gt;I then created a general object &lt;code&gt;ConnectionBase&lt;/code&gt; that includes information like the subscriptions a connection has and how to talk to the client. That made it possible to implement the support for SSE and Polling afterwards.&lt;/p&gt;

&lt;p&gt;The basic structure of the &lt;code&gt;ConnectionBase&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConnectionBase&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDisposable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Subscriptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CollectionSubscription&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CollectionSubscription&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Subscriptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Every connection implementation has to implement the &lt;code&gt;Send&lt;/code&gt;-method to send data to the client.&lt;/p&gt;

&lt;p&gt;The implementation for Websockets for exampl looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebsocketConnection&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ConnectionBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDisposable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WebsocketConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebSocket&lt;/span&gt; &lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Websocket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;WebSocket&lt;/span&gt; &lt;span class="n"&gt;Websocket&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Websocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Subscription
&lt;/h2&gt;

&lt;p&gt;Every value that a client wants to receive has to be requested from the server. If you want the client to receive changes of a collection you have to create a subscription for this collection.&lt;/p&gt;

&lt;p&gt;When a client subscribes to a collection a new &lt;code&gt;CollectionSubscription&lt;/code&gt; is created and added to the list of the connection.&lt;/p&gt;

&lt;p&gt;If something changes the notifier will iterate through all connections and look for subscriptions that are affected by the changes. The changes will then get send to the client.&lt;/p&gt;
&lt;h2&gt;
  
  
  Client implementation
&lt;/h2&gt;

&lt;p&gt;The server implementation for data synchronization already works. Now I had to create the client implementation. I decided to use RxJs for this job because the concept of data synchronization is pretty reactive and it would do the perfect job.&lt;/p&gt;

&lt;p&gt;I will skip the boring part of creating a connection etc and just concentrate on the key part of the synchronization. If you are interested in the exact implementation you can check out the sources.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The main part of the client implementation is this piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wsSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectionManagerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscribeCommand&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;QueryResponse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ChangeResponse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Find and update the value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UnloadResponse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Remove the value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LoadResponse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Insert the value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The main part of this is the &lt;code&gt;ReplaySubject&lt;/code&gt;. It holds the value of the collection.&lt;/p&gt;

&lt;p&gt;When the client requests a value it sends the &lt;code&gt;SubscribeCommand&lt;/code&gt; to the server. The server stores the id associated with this command and every time something related to the subscription changes, it sends a notification with the same id back to the client. That means that everything that is related to the subscription will appear in the &lt;code&gt;subscribe&lt;/code&gt; block of this statement.&lt;/p&gt;

&lt;p&gt;The client only has to merge the changes into one list and has its value. The cool thing about using RxJs is, that you only have to emit a new value using &lt;code&gt;.next(newValue)&lt;/code&gt; and the changes will get emitted where you need it.&lt;/p&gt;

&lt;p&gt;The final API can be used like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DemoComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;values$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SapphireDb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  CRUD
&lt;/h2&gt;

&lt;p&gt;Now it was time to implement the basic CRUD operations to make development a lot easier afterwards. This operations are basically just normal calls on the DbContext to manage the data. I just created a reusable interface to call this methods.&lt;/p&gt;

&lt;p&gt;The API for the client looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// delete&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// update&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Actions
&lt;/h2&gt;

&lt;p&gt;The last requirement I had were the actions I can define on server side and easily call them through an easy API on client side.&lt;/p&gt;

&lt;p&gt;I created an &lt;code&gt;ActionHandler&lt;/code&gt; that you can generally understand like a controller. It contains different methods that will be callable through an interface. &lt;/p&gt;

&lt;p&gt;An example of an action handler looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleActions&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ActionHandlerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ExampleDb&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ExampleActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExampleDb&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;AsyncTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;33&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can call the method by using this code on client side:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AsyncTask&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The implementation itself is not very interesting but what is definitly worth a thought is the fact, that you can also use async Methods in the action handler.&lt;br&gt;
Because the connection is Bi-Directional the call does not block the communication between client and server until the execution finished. Instead the result will get pushed to the client when ready.&lt;/p&gt;
&lt;h1&gt;
  
  
  The result
&lt;/h1&gt;

&lt;p&gt;With this results I already was pretty satisfied but I did not stop improving the features. The final project has some cool and interesting features, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💾 Easy CRUD operations&lt;/li&gt;
&lt;li&gt;🔑 Authentication/Authorization included&lt;/li&gt;
&lt;li&gt;✔️ Database support&lt;/li&gt;
&lt;li&gt;🔌 Actions&lt;/li&gt;
&lt;li&gt;🌐 NLB support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final result is called &lt;code&gt;SapphireDb&lt;/code&gt; and you can find it on Github. I am thankful for every kind of feedback.&lt;/p&gt;

&lt;p&gt;Also check out the &lt;a href="https://sapphire-db.com/"&gt;documentation&lt;/a&gt; to learn more.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt; / &lt;a href="https://github.com/SapphireDb/SapphireDb"&gt;
        SapphireDb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SapphireDb Server, a self-hosted, easy to use realtime database for Asp.Net Core and EF Core
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
SapphireDb - Server for Asp.Net Core &lt;a href="https://travis-ci.org/morrisjdev/RealtimeDatabase" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/4fb43af86f71df73145d0fd29bc73f98923e9f98/68747470733a2f2f7472617669732d63692e6f72672f6d6f727269736a6465762f5265616c74696d6544617461626173652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;
  &lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;
    &lt;img src="https://camo.githubusercontent.com/a6f82fb5bd0efa7e770553d0abe2dfec89a43017/68747470733a2f2f73617070686972652d64622e636f6d2f6173736574732f62616e6e65722f5361707068697265444225323042616e6e65722e706e67" alt="SapphireDb logo"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;SapphireDb is a self-hosted, easy to use realtime database for Asp.Net Core and EF Core.&lt;/p&gt;
&lt;p&gt;It creates a generic API you can easily use with different clients to effortlessly create applications with realtime data synchronization
SapphireDb should serve as a self hosted alternative to firebase realtime database and firestore on top of .Net.&lt;/p&gt;
&lt;p&gt;Check out the documentation for more details: &lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
    &lt;a href="https://www.patreon.com/user?u=27738280" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/c11c9bdf1f6c2a1d80afb11859984a61f0fadfa6/68747470733a2f2f63352e70617472656f6e2e636f6d2f65787465726e616c2f6c6f676f2f6265636f6d655f615f706174726f6e5f627574746f6e4032782e706e67" width="160"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2&gt;
Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
🔧 Dead simple configuration&lt;/li&gt;
&lt;li&gt;
📡 Broad technology support&lt;/li&gt;
&lt;li&gt;
💻 Self hosted&lt;/li&gt;
&lt;li&gt;
📱 Offline support&lt;/li&gt;
&lt;li&gt;
💾 Easy to use CRUD operations&lt;/li&gt;
&lt;li&gt;
⚡ Model validation&lt;/li&gt;
&lt;li&gt;
✔️ Database support&lt;/li&gt;
&lt;li&gt;
📂 Supports joins/includes&lt;/li&gt;
&lt;li&gt;
➿ Complex server evaluated queries&lt;/li&gt;
&lt;li&gt;
🔌 Actions&lt;/li&gt;
&lt;li&gt;
🔑 Authorization included&lt;/li&gt;
&lt;li&gt;
✉️ Messaging&lt;/li&gt;
&lt;li&gt;
🌐 Scalable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://sapphire-db.com/" rel="nofollow"&gt;Learn more&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;h3&gt;
Install package&lt;/h3&gt;
&lt;p&gt;To install the package execute the following command in your package manager console&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PM&amp;gt; Install-Package SapphireDb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also install the extension using Nuget package manager. The project can be found here: &lt;a href="https://www.nuget.org/packages/SapphireDb/" rel="nofollow"&gt;https://www.nuget.org/packages/SapphireDb/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
Configure&lt;/h3&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/SapphireDb/SapphireDb"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>dotnet</category>
      <category>angular</category>
      <category>database</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
