<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <title>ABP.IO Stories</title>
    <link>https://abp.io/community/articles</link>
    <description>A hub for ABP Framework, .NET, and software development. Access articles, tutorials, news, and contribute to the ABP community.</description>
    <lastBuildDate>Fri, 02 Oct 2026 18:26:19 Z</lastBuildDate>
    <generator>Community - ABP.IO</generator>
    <image>
      <url>https://abp.io/assets/favicon.ico/favicon-32x32.png</url>
      <title>ABP.IO Stories</title>
      <link>https://abp.io/community/articles</link>
    </image>
    <a10:link rel="self" type="application/rss+xml" title="self" href="https://abp.io/community/rss?member=hikalkan" />
    <a10:link rel="next" type="application/rss+xml" title="next" href="https://abp.io/community/rss?page=2&amp;author=hikalkan" />
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/multitenancy-with-separate-databases-in-.net-and-abp-framework-51nvl4u9</guid>
      <link>https://abp.io/community/posts/multitenancy-with-separate-databases-in-.net-and-abp-framework-51nvl4u9</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <title>Multi-Tenancy with Separate Databases in .NET and ABP Framework</title>
      <description>We’ll explore how to use the separate database approach for multi-tenant applications.</description>
      <pubDate>Sun, 27 Jul 2025 18:02:06 Z</pubDate>
      <a10:updated>2026-10-02T13:59:25Z</a10:updated>
      <content:encoded><![CDATA[<h1>Multi-Tenancy with Separate Databases in .NET and ABP Framework</h1>
<p><a href="https://abp.io/architecture/multi-tenancy">Multi-tenancy</a> is a common architectural concept for modern SaaS applications, enabling a single application to serve multiple customers (each known as a tenant) while maintaining data isolation, scalability, and operational efficiency. The &quot;Separate database per tenant&quot; approach offers the highest level of data isolation, making it ideal for scenarios with strict data privacy, security, and performance requirements.</p>
<p>In this article, we’ll explore how to use this advanced multi-tenancy model using the powerful capabilities of the ABP Framework and the .NET platform.</p>
<blockquote>
<p>In this article, I will use <a href="https://abp.io/studio">ABP Studio</a> for creating the application. ABP Studio allows to select &quot;separate database per tenant&quot; option only for <a href="https://abp.io/pricing">commercial licenses</a>.</p>
</blockquote>
<h2>Understanding Database Models for a Multi-Tenant Application</h2>
<p>In the next sections, I will explain various models for database models of a multi-tenant solution:</p>
<ul>
<li>Single (shared) Database Model</li>
<li>Separate Tenant Databases Model</li>
<li>Hybrid Multi-Tenant Database Model</li>
</ul>
<p>Let's start with the first one...</p>
<h3>Single (shared) Database Model</h3>
<p>In the shared database model, all the application data stored in a single physical database. In the following diagram, you see different kind of users use the application, and the application stored their data in a main database:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/single-shared-database.png" alt="single-shared-database" /></p>
<p>This is the default behavior when you <a href="https://abp.io/docs/latest/get-started">create a new ABP application</a>, because it is simple to begin with and proper for most applications.</p>
<p>In this model, a single database table may contain data of multiple tenants. Each row in these tables have a <code>TenantId</code> field which is used to distinguish the tenant data and isolate a tenant's data from other tenant users. To make your entities multi-tenant aware, all you have to do is to implement the <code>IMultiTenant</code> interface provided by the ABP Framework.</p>
<p>Here, is an example <code>Product</code> entity that should support multi-tenancy:</p>
<pre><code class="language-csharp">using System;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;

namespace MtDemoApp
{
    public class Product : AggregateRoot&lt;Guid&gt;, IMultiTenant //Implementing the interface
    {
        public Guid? TenantId { get; set; } //Defined by the IMultiTenant interface
        public string Name { get; set; }
        public float Price { get; set; }
    }
}
</code></pre>
<p>In this way, ABP Framework automatically isolates data using the <code>TenantId</code> property. You don't need to care about how to set <code>TenantId</code> or filter data when you need to query from database - all automated.</p>
<h3>Separate Tenant Databases Model</h3>
<p>In the separate tenant database model, each tenant has a dedicated physical database (with a separate connection string), as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-database-multi-tenancy.png" alt="separate-tenant-database-multi-tenancy" /></p>
<p>ABP Framework can automatically select the right database from the current user's tenant context. Again, it is completely automated. You just need to set a connection string for a tenant, as we will do later in this article.</p>
<p>Even each tenant has a separate database, we still need to a main database to store host-side data, like a table of tenants, their connection strings and some other management data for tenants. Also, tenant-independent (or tenant-shared) application data is stored in the main database.</p>
<h3>Hybrid Multi-Tenant Database Model</h3>
<p>Lastly, you may want to have a hybrid model, where some tenants shares a single database (they don't have separate databases) but some of them have dedicated databases. In the following figure, Tenant C has its own physical database, but all other tenants data stored in the main database of the application.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/hybrid-database-multi-tenancy.png" alt="hybrid-database-multi-tenancy" /></p>
<p>ABP Framework handles the complexity: If a tenant has a separate database it uses that tenant's database, otherwise it filters the tenant data by the <code>TenantId</code> field in shared tables.</p>
<h2>Understanding the Separate Tenant Schema Approach</h2>
<p>When you create a new ABP solution, it has a single <code>DbContext</code> class (for Entity Framework Core) by default. It also includes the necessary EF Core code-first database migrations to create and update the database. As a result of this approach, the main database schema (tables and their fields) will be identical with a tenant database schema. As a drawback of that, tenant databases have some tables that are not meaningful and not used. For example, Tenants table (a list of tenants) will be created in the tenant database, but will never be used (because tenant list is stored in the main database).</p>
<p>As a solution to that problem, ABP Studio provides a &quot;Use separate tenant schema&quot; option on the Multi-Tenancy step of the solution creation wizard:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-schema-option.png" alt="separate-tenant-schema-option" /></p>
<p>This option is only available for the <a href="https://abp.io/docs/latest/get-started/layered-web-application">Layered Monolith (optionally Modular) Solution Template</a>. We don't provide that option in other templates, because:</p>
<ul>
<li><a href="https://abp.io/docs/latest/get-started/single-layer-web-application">Single-Layer</a> template is recommended for more simpler applications with an easy-to-understand architecture. We don't want to add these kind of complications in that template.</li>
<li><a href="https://abp.io/docs/latest/get-started/microservice">Microservice</a> template already has a separate database for each service. Having multiple database schema (and multiple <code>DbContext</code> classes) for each service makes it over complicated without bringing much value.</li>
</ul>
<p>While you can manually convert your applications so they support separate database schema approach (ABP is flexible), it is not recommended to do it for these solution types.</p>
<blockquote>
<p>Note that &quot;Separate database per tenant&quot; approach is already supported by default for the Single-Layer template too. &quot;Separate tenant schema&quot; is something different as I explained in this section.</p>
</blockquote>
<h2>Creating a new Application</h2>
<p>Follow the <em><a href="https://abp.io/docs/latest/get-started/layered-web-application">Get Started tutorial</a></em> to create a new ABP application. Remember to select the &quot;<em>Use separate tenant schema</em>&quot; option since I want to demonstrate it in this article.</p>
<h2>Understanding the DbContext Structure</h2>
<p>When you open the solution in your IDE, you will see the following structure under the <code>.EntityFrameworkCore</code> project:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/multi-tenancy-dbcontext-structure.png" alt="multi-tenancy-dbcontext-structure" /></p>
<p>There are 3 DbContext-related classes here (MtDemoApp is your application name):</p>
<ul>
<li><code>MtDemoAppDbContext</code> class is used to map entities for the main (host + shared) database.</li>
<li><code>MtDemoAppTenantDbContext</code> class is used to map entities for tenant that have separate physical databases.</li>
<li><code>MtDemoAppDbContextBase</code> is an abstract base class for the classes explained above. In this way, you can configure common mapping logic here.</li>
</ul>
<p>Let's see these classes a bit closer...</p>
<h3>The Main <code>DbContext</code> Class</h3>
<p>Here the main <code>DbContext</code> class:</p>
<pre><code class="language-csharp">public class MtDemoAppDbContext : MtDemoAppDbContextBase&lt;MtDemoAppDbContext&gt;
{
    public MtDemoAppDbContext(DbContextOptions&lt;MtDemoAppDbContext&gt; options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.SetMultiTenancySide(MultiTenancySides.Both);

        base.OnModelCreating(builder);
    }
}
</code></pre>
<ul>
<li>It inherits from the <code>MtDemoAppDbContextBase</code> as I mentioned before. So, any configuration made in the base class is also valid here.</li>
<li><code>OnModelCreating</code> overrides the base method and sets the multi-tenancy side as <code>MultiTenancySides.Both</code>. <code>Both</code> means this database can store host data as well as tenant data. This is needed because we store data in this database for the tenants who don't have a separate database.</li>
</ul>
<h3>The Tenant <code>DbContext</code> class</h3>
<p>Here is the tenant-specific <code>DbContext</code> class:</p>
<pre><code class="language-csharp">public class MtDemoAppTenantDbContext : MtDemoAppDbContextBase&lt;MtDemoAppTenantDbContext&gt;
{
    public MtDemoAppTenantDbContext(DbContextOptions&lt;MtDemoAppTenantDbContext&gt; options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.SetMultiTenancySide(MultiTenancySides.Tenant);

        base.OnModelCreating(builder);
    }
}
</code></pre>
<p>The only difference is that we used <code>MultiTenancySides.Tenant</code> as the multi-tenancy side here, since this <code>DbContext</code> will only have entities/tables for tenants that have separate databases.</p>
<h3>The Base <code>DbContext</code> Class</h3>
<p>Here is the base <code>DbContext</code> class:</p>
<pre><code class="language-csharp">public abstract class MtDemoAppDbContextBase&lt;TDbContext&gt; : AbpDbContext&lt;TDbContext&gt;
    where TDbContext : DbContext
{
    
    public MtDemoAppDbContextBase(DbContextOptions&lt;TDbContext&gt; options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        /* Include modules to your migration db context */

        builder.ConfigurePermissionManagement();
        builder.ConfigureSettingManagement();
        builder.ConfigureBackgroundJobs();
        builder.ConfigureAuditLogging();
        builder.ConfigureIdentityPro();
        builder.ConfigureOpenIddictPro();
        builder.ConfigureFeatureManagement();
        builder.ConfigureLanguageManagement();
        builder.ConfigureSaas();
        builder.ConfigureTextTemplateManagement();
        builder.ConfigureBlobStoring();
        builder.ConfigureGdpr();

        /* Configure your own tables/entities inside here */

        //builder.Entity&lt;YourEntity&gt;(b =&gt;
        //{
        //    b.ToTable(MtDemoAppConsts.DbTablePrefix + &quot;YourEntities&quot;, MtDemoAppConsts.DbSchema);
        //    b.ConfigureByConvention(); //auto configure for the base class props
        //    //...
        //});

        //if (builder.IsHostDatabase())
        //{
        //    /* Tip: Configure mappings like that for the entities only
               * available in the host side,
        //     * but should not be in the tenant databases. */
        //}
    }
}
</code></pre>
<p>This <code>DbContext</code> class configures database mappings for all the <a href="https://abp.io/docs/latest/modules">application modules</a> used by this application by calling their extension methods, like <code>builder.ConfigureBackgroundJobs()</code>. Each of these extension methods are defined as multi-tenancy aware and care about what you've set for the multi-tenancy side.</p>
<h3>Where to Configure Your Entities?</h3>
<p>You can configure your entity mappings in the <code>OnModelCreating</code> method in any of the <code>DbContext</code> classes that was explained:</p>
<ul>
<li>If you configure in the main <code>DbContext</code> class, these configuration will be valid only for the main database. So, don't configure tenant-related configuration here, otherwise, it won't be applied for the tenants who have separate databases.</li>
<li>If you configure in the tenant <code>DbContext</code> class, it will be valid only for the tenants with separate databases. You rarely need to do that. You typically want to make same configuration in the base <code>DbContext</code> to support hybrid scenarios (some tenants use the main (shared) database and some tenants have separate databases).</li>
<li>If you configure in the base <code>DbContext</code> class, it will be valid for the main database and tenant databases. You typically define tenant-related configuration here. That means, if you have a multi-tenant <code>Product</code> entity, then you should define its EF Core database mapping configuration here, so the Products table is created in the main database as well as in the tenant databases.</li>
</ul>
<p>The recommended approach is to configure all the mapping in the base class, but add controls like <code>builder.IsHostDatabase()</code> and <code>builder.IsTenantDatabase()</code> to conditionally configure the mappings:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/builder-check-tenant-side.png" alt="builder-check-tenant-side" /></p>
<h2>Adding Database Migrations</h2>
<p>In this section, I will show how to configure your entity mappings, generate database migrations and apply to the database.</p>
<h3>Defining an Entity</h3>
<p>Let's define a <code>Product</code> entity in the <code>.Domain</code> layer of your application:</p>
<pre><code class="language-csharp">using System;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;

namespace MtDemoApp
{
    public class Product : AggregateRoot&lt;Guid&gt;, IMultiTenant
    {
        public Guid? TenantId { get; set; }
        public string Name { get; set; }
        public float Price { get; set; }
    }
}
</code></pre>
<h3>Configuring the Database Mapping</h3>
<p>Open the <code>MtDemoAppDbContextBase</code> class and add the following property to the class:</p>
<pre><code class="language-csharp">public DbSet&lt;Product&gt; Products { get; set; }
</code></pre>
<p>Then add the following mapping code inside the <code>OnModelCreating</code> method (after all other existing code):</p>
<pre><code class="language-csharp">builder.Entity&lt;Product&gt;(b =&gt;
{
    b.ToTable(MtDemoAppConsts.DbTablePrefix + &quot;Products&quot;, MtDemoAppConsts.DbSchema);
    b.ConfigureByConvention(); //auto-configure for the base class props
    b.Property(x =&gt; x.Name).IsRequired().HasMaxLength(100);
});
</code></pre>
<p>We made the configuration in the base class since the <code>Products</code> table should be created in all databases, not only in the main database.</p>
<blockquote>
<p><code>DbTablePrefix</code> and <code>DbSchema</code> are optional and configurable in your application. You can change or remove them.</p>
</blockquote>
<h3>Add a New Database Migration for the Main Database</h3>
<p>To add a new EF Core database migration, we can use ABP Studio UI or EF Core command-line commands. I will show both of these approaches here.</p>
<h4>Using the ABP Studio &quot;Add Migrations&quot; UI</h4>
<p>You can right-click the <code>.EntityFrameworkCore</code> package in the ABP Studio's <em>Solution Explorer</em> panel and select <em>EF Core CLI</em> -&gt; <em>Add Migration</em> command as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png" alt="abp-studio-add-migration" /></p>
<p>You set a migration name on the opened dialog:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png" alt="abp-studio-add-migration-set-name" /></p>
<p>If you select the <em>Update Database</em> checkbox it will apply changes to the database after generating the migration code.</p>
<p>Lastly, select the main DbContext class for this migration:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-select-dbcontext.png" alt="abp-studio-add-migration-select-dbcontext" /></p>
<p>This dialog is shown when your application has multiple <code>DbContext</code> classes. Once you click the <em>OK</em> button, a new migration class is added under the <code>Migrations</code> folder of the <code>.EntityFrameworkCore</code> project (you can see in your coding editor):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-main-context.png" alt="added-product-entity-migration-main-context" /></p>
<p>Since we selected the <em>Update Database</em> option, the database table is also created. The following screenshot shows the <code>AppProducts</code> table (<code>App</code> is the default prefix for your tables, but you can change or remove it) in Microsoft SQL Server Management Studio:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/product-database-table.png" alt="product-database-table" /></p>
<h4>Using a Command-Line Terminal</h4>
<p>If you prefer to use the command-line terminal (instead of ABP Studio UI), open a command-line terminal in the directory of the <code>.EntityFrameworkCore</code> project. As a shortcut, you can right-click the <code>.EntityFrameworkCore</code> project in ABP Studio, then select <em>Open with</em> -&gt; <em>Terminal</em> command as shown in the following figure:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-open-with-terminal.png" alt="abp-studio-open-with-terminal" /></p>
<p>Then you can use the <a href="https://learn.microsoft.com/en-us/ef/core/cli/dotnet">EF Core command-line tool</a> to add a new database migration:</p>
<pre><code class="language-bash">dotnet ef migrations add &quot;Added_Product_Entity&quot; --context MtDemoAppDbContext
</code></pre>
<p>It is important to set the <code>--context</code> parameter since we have two DbContext classes in the same project.</p>
<p>After adding the migration, you can update the database:</p>
<pre><code class="language-bash">dotnet ef database update &quot;Added_Product_Entity&quot; --context MtDemoAppDbContext
</code></pre>
<blockquote>
<p>If you are using Visual Studio, you can also use the <a href="https://learn.microsoft.com/en-us/ef/core/cli/powershell">Package Manager Console</a> inside your IDE to add migrations and update the database.</p>
</blockquote>
<h3>Add a New Database Migration for the Tenant Database</h3>
<p>We added a database migration for the main (shared) database. We also need to add a new database migration for tenants who have separate databases.</p>
<p>This time, no need to configure the DbContext since we did it in the base DbContext class, so it is valid for both of the DbContext classes. Just right-click the <code>.EntityFrameworkCore</code> package in the ABP Studio's <em>Solution Explorer</em> panel and select <em>EF Core CLI</em> -&gt; <em>Add Migration</em> command as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png" alt="abp-studio-add-migration" /></p>
<p>You can set the same or a different migration name here:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png" alt="abp-studio-add-migration-set-name" /></p>
<p>The important part is to select the Tenant DbContext in the next dialog, because we want to change the tenant database this time:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-context-selection.png" alt="abp-studio-context-selection" /></p>
<p>After clicking the <em>OK</em> button, it will add a new database migration class, but this time to the <code>TenantMigrations</code> folder:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-tenant-context.png" alt="added-product-entity-migration-tenant-context" /></p>
<p>ABP Studio is smart enough to select the right folder name for the new migration by mapping with the DbContext name. However, you could manually type <code>TenantMigrations</code> in the <em>Output directory</em> textbox.</p>
<p>Since we selected the <em>Update Database</em> option, it also applied changes to the database. But, which database? Interestingly, it automatically creates a second database for tenants with the project name + <code>_Tenant</code> suffix:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-database.png" alt="tenant-database" /></p>
<blockquote>
<p>This new database is never used on runtime or production. It is only created to allow you to see the schema (tables and their fields) on development time to be sure that everything is as expected. As you see, some tables (like <code>Saas*</code> and <code>OpenIddict*</code>) are not available in that database, since they are used on the host side and only necessary to be in the main database.</p>
<p>So, where is the real tenant database? If a tenant's database is dedicated (separate), it is created on runtime as I will explain in the <em>Managing Tenant Databases and Connection Strings</em> section later.</p>
</blockquote>
<p>You can see that database's connection string in the <code>appsettings.development.json</code> file of the <code>.DbMigrator</code> project in the solution. If you want to understand how it works, you can check source code of the <code>DbContextFactory</code> classes in the <code>.EntityFrameworkCore</code> project:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbcontext-factories.png" alt="dbcontext-factories" /></p>
<p>These factory classes are used to create <code>DbContext</code> instances when you execute <em>Add Migration</em> and <em>Update Database</em> commands.</p>
<h2>Managing Tenant Databases and Connection Strings</h2>
<p>Until now, we even didn't run the application. It is the time to do it.</p>
<h3>Running the Application with ABP Studio</h3>
<p>You can run the <code>.Web</code> project in your IDE. But I prefer to use ABP Studio's <em><a href="https://abp.io/docs/latest/studio/running-applications">Solution Runner</a></em> feature here. You can open the <em>Solution Runner</em> panel in <em>ABP Studio</em> and click the play icon near to the solution root (<code>MyDemoApp</code>):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-solution-runner.png" alt="abp-studio-solution-runner" /></p>
<p>Once the application runs (and you see the blue link icon near to it), right click and select the <em>Browse</em> command:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-browse.png" alt="abp-studio-browse" /></p>
<p>It will open the application's UI in the built-in browser of ABP Studio. You can Login the application (with <code>admin</code> as user name and <code>1q2w3E*</code> as the default password) and navigate to the <em>Saas</em> -&gt; <em>Tenants</em> page.</p>
<h3>Creating a New Tenant with the Shared Database</h3>
<p>The <em>Tenants</em> page of the <a href="https://abp.io/modules/Volo.SaaS">SaaS module</a> is shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-saas-tenants-page.png" alt="abp-saas-tenants-page" /></p>
<p>As you see, there is no tenant at the beginning. I can click the <em>+ New tenant</em> button to create the first tenant:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-1.png" alt="new-tenant-dialog-1" /></p>
<p>On this screen, we can set the base tenant information. If you click the <em>Database connection strings</em> tab, you can see the following UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-1.png" alt="new-tenant-dialog-conn-string-1" /></p>
<p>For this first tenant, I will keep it as default and use the shared (main) database for this tenant's data. After clicking the <em>Save</em> button, the tenant is created and an initial <a href="https://abp.io/docs/latest/framework/infrastructure/data-seeding">data seed</a> operation is automatically performed for us. To see an example, you can open the database, show rows of the <code>AbpUsers</code> table:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/users-table-new-tenant.png" alt="users-table-new-tenant" /></p>
<p>As you see, a new <code>admin</code> user has been created with a <code>TenantId</code>. The first row is the <code>admin</code> user of the host side. So, ABP allows to define same user name in different tenants, because their data (users in this example) are completely isolated from each other.</p>
<h3>Sign in with the new Tenant</h3>
<p>We created a new tenant. In this step, we will sign in with the new tenant's <code>admin</code> user to see the application UI by that new tenant. To do that, we should logout from the host admin user first. Click the user name (<code>admin</code>) on the top right area of the application and select the <em>Log out</em> command:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-logout.png" alt="user-logout" /></p>
<p>Click the <em>Login</em> button again, which redirects you to the <em>Login</em> page:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-login.png" alt="user-login" /></p>
<p>In this page, click the <em>switch</em> button near to the <em>TENANT</em> selection area and type <code>acme</code> as <em>Name</em>:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-tenant-dialog.png" alt="switch-tenant-dialog" /></p>
<p>Once you click the <em>Save</em> button, you are now in the acme tenant's context. You can see it on the <em>TENANT</em> selection area:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-acme-name.png" alt="tenant-acme-name" /></p>
<blockquote>
<p>This kind of tenant switch feature is very useful in development to quickly change tenants to test your application. However, in production, you typically want to use subdomain/domain names or another mechanism to determine tenants automatically. When you configure domain based resolution, the tenant selection area is automatically disappears from the login page. You can check the <a href="https://abp.io/docs/latest/framework/architecture/multi-tenancy">multi-tenant document</a> to learn how to configure it.</p>
</blockquote>
<p>After switching to the <code>acme</code> tenant, we can use <code>admin</code> as user name and the password you set during the tenant creation (I had set it as <code>1q2w3E*</code>) to login to the application.</p>
<p>Here a screenshot from the <em>Roles</em> page after signing in as the <code>acme</code> tenant's <code>admin</code> user:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/acme-tenant-screen.png" alt="acme-tenant-screen" /></p>
<blockquote>
<p>Notice that each tenant has its own roles, users, permissions, and other data. If you change roles here, it doesn't affect other tenants or the host side.</p>
<p>Also, you can see that there are less menu items compared to host side. For example, tenant management page is not available for tenants as you can expect.</p>
</blockquote>
<h3>Switch Back to the Host Side</h3>
<p>To switch back to the host side to add a new tenant, logout from the application, click the <em>Login</em> button again to open the login page and then again click the <em>switch</em> button to change the current tenant context:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-host-side.png" alt="switch-host-side" /></p>
<p>In this dialog, clear the <em>Name</em> field and then <em>Save</em> the dialog to switch back to the host side. Then you can use the standard <code>admin</code> user name with <code>1q2w3E*</code> password to login to the application as the host administrator.</p>
<h3>Creating a New Tenant with a Separate Database</h3>
<p>Finally, we came to the point that we will create a new tenant with a separate, dedicated database. Open the <em>Tenants</em> page of the SaaS module and click the <em>+ New tenant</em> button:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-2.png" alt="new-tenant-dialog-2" /></p>
<p>Just fill these information as you wish, then open the <em>Database connection strings</em> tab:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-2.png" alt="new-tenant-dialog-conn-string-2" /></p>
<p>Uncheck the <em>Use the shared database</em> option and set a connection string to the <em>Default connection string</em> for this tenant. I used <code>Server=(LocalDb)\MSSQLLocalDB;Database=MtDemoApp_Volosoft;Trusted_Connection=True;TrustServerCertificate=true</code> as the connection string value. The database name is <code>MtDemoApp_Volosoft</code>. You can Test the connection string to be sure that it is a valid connection string.</p>
<p>Once you click the <em>Save</em> button, the new tenant is created, a new database is created on the fly, all the database migrations are applied and the initial data seed is performed. You can open the SQL Server Management Studio to see the new database:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-database.png" alt="separate-database" /></p>
<p>You can check the tables (e.g. <code>AbpUsers</code>) to see that only this new tenant's data is stored in this database. To test the application, switch to the Volosoft tenant (as like explained in the <em>Sign in with the new Tenant</em> section before), create a new role or user and check the database.</p>
<h2>Migrating Existing Tenant Databases</h2>
<p>In the previous section, we've seen that a tenant database is automatically created on runtime if you set a connection string for that tenant. Also, all the current migrations are automatically applied to the database, so it becomes up to date.</p>
<p>But what about existing tenant databases when a new migration is added to the application? Maybe you have a few tenants with their separate databases, or you may have thousands of tenants with separate databases. How will you apply database schema changes to all of these databases?</p>
<p>The startup template comes with a solution to this problem. There is a <code>.DbMigrator</code> console application in the solution that is responsible to apply schema (table and their fields) changes to all of the databases in the system (the main database and all the separate tenant databases). It also executes the data seeding if seed data is available. All you need to do is to execute this application on your production environment while deploying a new version of your application (of course, it is also very useful in the development environment). It checks and upgrades all the databases before the new version of your application is deployed.</p>
<p>Here is the console log screen when I run the <code>.DbMigrator</code> application on my development environment:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbmigrator-logs.png" alt="dbmigrator-logs" /></p>
<p>As you can see in the logs, it first migrates for the main (host) database, then migrates the tenant databases one by one. It doesn't make schema migration for the <code>acme</code> tenant since it has not a separate database, but uses the main database.</p>
<p>In brief, when you make changes on your entity classes;</p>
<ol>
<li>Add a new migration for the main DbContext class as I explained in this article.</li>
<li>Add a new migration for the tenant DbContext class as I explained in this article.</li>
<li>Run the <code>.DbMigrator</code> application in your development environment to ensure all the databases are up to date.</li>
<li>When you deploy your application to production or test environments, remember to run the <code>.DbMigrator</code> application first, then update your application. Or better, setup a CI/CD pipeline that automates this process. You can run the <code>.DbMigrator</code> every time while deploying the application, regardless of whether there is a schema change or not.</li>
</ol>
<blockquote>
<p>If you have too many tenants with separate database, then the migration process may take too much time. <code>.DbMigrator</code> provides the fundamental solution. But for more advanced scenarios or bigger systems, you can always develop your own solution. Just check the <code>.DbMigrator</code> application to understand how it was implemented. All the necessary code located in your solution, so you can easily understand and freely customize.</p>
</blockquote>
<h2>Conclusion</h2>
<p>In this article, I covered two important aspects of multi-tenant application development:</p>
<ul>
<li>How ABP startup templates provide a multi-tenant application setup, so some tenants may store their data in a single (main, shared) database while some others may have their own dedicated database.</li>
<li>Demonstrate how it can manage database migration process on the fly for multiple databases.</li>
</ul>
<p>I started by defining different database models for multi-tenant applications (Single database, separate databases, and hybrid), showed how to create an ABP application that supports hybrid model, explained the DbContext structure that is coming with the solution template, demonstrated how to define entities, create and apply database migrations in such an application.</p>
<p>I hope this article gives you a good understanding the problem and the solution provided by the ABP Framework. Please write your questions or comments under this article.</p>
<p>Enjoy coding! :)</p>
<h2>Further Reading</h2>
<ul>
<li><a href="https://abp.io/docs/latest/framework/architecture/multi-tenancy">ABP Multi-Tenancy document</a></li>
<li><a href="https://abp.io/architecture/multi-tenancy">Multi-Tenancy Architecture with .NET</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1b5f39-6af4-1677-b7c6-a5be0673def0" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1b5f39-6af4-1677-b7c6-a5be0673def0" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/abp-framework-ve-.net-ile-canli-modular-monolith-uygulama-gelistiriyoruz-p6n5qo2i</guid>
      <link>https://abp.io/community/videos/abp-framework-ve-.net-ile-canli-modular-monolith-uygulama-gelistiriyoruz-p6n5qo2i</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <title>ABP Framework ve .NET ile Canlı Modular Monolith Uygulama Geliştiriyoruz</title>
      <description>Bu videoda, canlı kodlama ile örnek bir modüler monolith çözüm geliştirmek için ABP Framework ve .NET'i kullanacağız.
</description>
      <pubDate>Thu, 03 Jul 2025 19:43:36 Z</pubDate>
      <a10:updated>2026-04-25T00:41:01Z</a10:updated>
      <content:encoded><![CDATA[Bu videoda, canlı kodlama ile örnek bir modüler monolith çözüm geliştirmek için ABP Framework ve .NET'i kullanacağız.
 <br \> <a href="https://www.youtube.com/watch?v=2DHTjRwt-SU" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1ae3fd-b78b-67c8-add9-b0a20a049d35" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1ae3fd-b78b-67c8-add9-b0a20a049d35" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/using-microsoft-ai-extensions-library-and-openai-to-summarize-user-comments-gj1lusg7</guid>
      <link>https://abp.io/community/posts/using-microsoft-ai-extensions-library-and-openai-to-summarize-user-comments-gj1lusg7</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>cms-kit</category>
      <category>ai</category>
      <title>Using Microsoft AI Extensions Library and OpenAI to Summarize User Comments</title>
      <description>In this tutorial, we’ll walk through a real-life implementation of using AI to summarize multiple user comments in an application.</description>
      <pubDate>Thu, 24 Apr 2025 12:13:20 Z</pubDate>
      <a10:updated>2026-10-02T16:17:30Z</a10:updated>
      <content:encoded><![CDATA[<h1>Using Microsoft AI Extensions Library and OpenAI to Summarize User Comments</h1>
<p>Either you are building an e-commerce application or a simple blog, <strong>user comments</strong> (about your products or blog posts) <strong>can grow rapidly</strong>, making it harder for users to get the gist of discussions at a glance. AI is a pretty good tool to solve the problem. By using AI, you can <strong>summarize all the user comments</strong> and show a single paragraph to your users, so they can easily understand the overall thought of users about the product or the blog post.</p>
<p>In this tutorial, we’ll walk through a real-life implementation of using AI to summarize multiple user comments in an application. I will implement the solution based on ABP's <strong><a href="https://abp.io/docs/latest/modules/cms-kit">CMS Kit</a></strong> library, as it already features a <strong><a href="https://abp.io/docs/latest/modules/cms-kit/comments">commenting system</a></strong> and a <a href="https://cms-kit-demo.abpdemo.com/">demo application</a> that displays user comments on <strong><a href="https://cms-kit-demo.abpdemo.com/image-gallery">gallery images</a></strong> (it has not a comment summary feature yet, we will implement it in this tutorial).</p>
<h2>A Screenshot</h2>
<p>Here, an example screenshot from the application with the comment summary feature:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/comment-example.png" alt="comment-example" /></p>
<h2>Cloning the Repository</h2>
<p>If you want to follow the development, you can clone the <a href="https://github.com/abpframework/cms-kit-demo">CMS Kit Demo repository</a> to your computer and make it running by following the instructions on the <a href="https://github.com/abpframework/cms-kit-demo?tab=readme-ov-file#cms-kit-demo">README file</a>.</p>
<p>I suggest to you to play a little with <a href="https://cms-kit-demo.abpdemo.com/">the application</a> (create a new user for yourself, add some comments to the images in the gallery), so you understand how it works.</p>
<h2>Preparing the Solution for AI</h2>
<p>I will use <a href="https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions">Microsoft AI Extensions Library</a> to use the AI features. It is an abstraction library that can work with multiple AI models and tools. I will use an OpenAI model in the demo.</p>
<p>The first step is to add the <a href="http://nuget.org/packages/Microsoft.Extensions.AI.OpenAI">Microsoft.Extensions.AI.OpenAI</a> NuGet package to the project:</p>
<pre><code class="language-bash">dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
</code></pre>
<blockquote>
<p>The Microsoft AI Extensions Library was in preview at the time when I wrote this article. If it has a stable release now, you can remove the <code>--prerelease</code> parameter for the preceding command.</p>
</blockquote>
<p>We will store the OpenAI key and model name in user secrets. So, locate the root path of the CMS Kit project (<code>src\CmsKitDemo</code> folder) and execute the following commands in order in a command-line terminal:</p>
<pre><code class="language-bash">dotnet user-secrets init
dotnet user-secrets set OpenAIKey &lt;your-openai-key&gt;
dotnet user-secrets set ModelName &lt;your-openai-model-name&gt;
</code></pre>
<p>For this example, you need to have an <a href="https://platform.openai.com/">OpenAI API Key</a>. That's all. Now, we are ready to use the AI.</p>
<h2>Implementing the AI Summarization</h2>
<p>Let's start from the most important point of this article: Comment summarization. I will create a class named <code>AiCommentSummarizer</code> to implement the summarization work. Here, the full content of that class:</p>
<pre><code class="language-csharp">using System.Text;
using Microsoft.Extensions.AI;
using OpenAI;
using Volo.Abp.DependencyInjection;

namespace CmsKitDemo.Utils;

public class AiCommentSummarizer : ITransientDependency
{
    private readonly IConfiguration _configuration;

    public AiCommentSummarizer(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    
    public async Task&lt;string&gt; SummarizeAsync(string[] commentTexts)
    {
        // Get the model and key from the configuration
        var aiModel = _configuration[&quot;ModelName&quot;];
        var apiKey = _configuration[&quot;OpenAIKey&quot;];

        if (aiModel.IsNullOrEmpty() || apiKey.IsNullOrEmpty())
        {
            return &quot;&quot;;
        }

        // Create the IChatClient
        var client = new OpenAIClient(apiKey)
            .GetChatClient(aiModel)
            .AsIChatClient();

        // Create a prompt (input for AI)
        var promptBuilder = new StringBuilder();

        promptBuilder.AppendLine(
            @&quot;There are comments from different users of our website about an image.
We want to summarize the comments into a single comment.
Return a single comment with a maximum of 512 characters. Comments are separated by a newline character and given below.&quot;
        );
        promptBuilder.AppendLine();
        
        foreach (var commentText in commentTexts)
        {
            promptBuilder.AppendLine(&quot;User comment:&quot;);
            promptBuilder.AppendLine(commentText);
            promptBuilder.AppendLine();
        }
        
        // Submit the prompt and get the response
        var response = await client.GetResponseAsync(
            promptBuilder.ToString(),
            new ChatOptions { MaxOutputTokens = 1024 }
        );

        return response.Text;
    }
}
</code></pre>
<p>That class is pretty simple and already decorated with comments:</p>
<ul>
<li>First, we are getting the API Key and an OpenAI model name from user secrets. I used <code>gpt-4.1</code> as the model name, but you can use another available model.</li>
<li>Then we are obtaining an <code>IChatClient</code> reference for OpenAI. <code>IChatClient</code> interface is an abstraction that is provided by the <a href="https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions">Microsoft AI Extensions Library</a> library, so we can implement rest of the code independently from OpenAI.</li>
<li>Then we continue by building a proper prompt (input) for the AI operation.</li>
<li>And finally we are using the AI to generate a response (the summary).</li>
</ul>
<p>At this point, all the AI-related work has already been done. The rest of this article explains how to integrate that summarization feature with the <a href="https://cms-kit-demo.abpdemo.com/">CMS Kit Demo application</a>.</p>
<h2>Adding a CommentsSummary Property to the GalleryImage Entity</h2>
<p>The <code>GalleryImage</code> entity is used to represent an image on <a href="https://cms-kit-demo.abpdemo.com/image-gallery">the image gallery</a>. I add a <code>CommentsSummary</code> property to that entity:</p>
<pre><code class="language-csharp">public class GalleryImage : CreationAuditedAggregateRoot&lt;Guid&gt;
{
    public string Description { get; set; }

    public Guid CoverImageMediaId { get; set; }
    
    public string CommentsSummary { get; set; } // The new property is here

    //...
}
</code></pre>
<p>Since the CMS Kit Demo application uses Entity Framework Core, I need to add a new database schema migration and update the database:</p>
<pre><code class="language-bash">dotnet ef migrations add Added_Summary_To_GalleryImage
dotnet ef database update
</code></pre>
<h2>Updating the Summary</h2>
<p>Great, we have a <code>GalleryImage.CommentsSummary</code> property now. But, how will it be updated when a users adds or removes a comment for an image? To implement that;</p>
<ul>
<li>We will listen all the change events for user comments (when a user adds, removes or updates a comment).</li>
<li>Whenever a comment is changed, we will find the related gallery image, retrieve all the user comments for this image, use the <code>AiCommentSummarizer</code> class to summarize all the comments.</li>
<li>Finally, we wil set the <code>GalleryImage.CommentsSummary</code> property with the generated summary text.</li>
</ul>
<p>Here, the implementation:</p>
<pre><code class="language-csharp">using CmsKitDemo.Entities;
using CmsKitDemo.Utils;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus;
using Volo.CmsKit.Comments;

namespace CmsKitDemo.EventHandlers;

public class GalleryImageCommentListener : 
             ILocalEventHandler&lt;EntityChangedEventData&lt;Comment&gt;&gt;,
             ITransientDependency
{
    private readonly IRepository&lt;GalleryImage, Guid&gt; _galleryImageRepository;
    private readonly IRepository&lt;Comment, Guid&gt; _commentRepository;
    private readonly AiCommentSummarizer _aiCommentSummarizer;

    public GalleryImageCommentListener(
        IRepository&lt;GalleryImage, Guid&gt; galleryImageRepository,
        IRepository&lt;Comment, Guid&gt; commentRepository,
        AiCommentSummarizer aiCommentSummarizer)
    {
        _galleryImageRepository = galleryImageRepository;
        _commentRepository = commentRepository;
        _aiCommentSummarizer = aiCommentSummarizer;
    }
    
    public async Task HandleEventAsync(EntityChangedEventData&lt;Comment&gt; eventData)
    {
        var comment = eventData.Entity;
        
        //Here, we only interest in comments related to image gallery items
        if (comment.EntityType != CmsKitDemoConsts.ImageGalleryEntityType)
        {
            return;
        }

        if (!Guid.TryParse(comment.EntityId, out var galleryImageId))
        {
            return;
        }
        
        // Get the related image from database
        var galleryImage = await _galleryImageRepository.FindAsync(galleryImageId);
        if (galleryImage == null)
        {
            return;
        }
        
        // Get all the comments related to the image
        var queryable = await _commentRepository.GetQueryableAsync();
        var allCommentTexts = await queryable
            .Where(c =&gt; c.EntityType == CmsKitDemoConsts.ImageGalleryEntityType &amp;&amp;
                        c.EntityId == comment.EntityId)
            .Select(c =&gt; c.Text)
            .ToArrayAsync();

        // Update the summary of comments related to the image
        if (allCommentTexts.Length &lt;= 0)
        {
            galleryImage.CommentsSummary = &quot;&quot;;
        }
        else
        {
            galleryImage.CommentsSummary =
                await _aiCommentSummarizer.SummarizeAsync(allCommentTexts);
        }

        // Update the image in database
        await _galleryImageRepository.UpdateAsync(galleryImage);
    }
}
</code></pre>
<p>Let's explain that class:</p>
<ul>
<li><code>GalleryImageCommentListener</code> implements the <code>ILocalEventHandler&lt;EntityChangedEventData&lt;Comment&gt;&gt;</code> interface. In this way, it can handle an event whenever a <code>Comment</code> <a href="https://abp.io/docs/latest/framework/architecture/domain-driven-design/entities">entity</a> is changed (created, updated or deleted). We are using ABP's <a href="https://abp.io/docs/latest/framework/infrastructure/event-bus/local">local event bus</a> and its <a href="https://abp.io/docs/latest/framework/infrastructure/event-bus/local#pre-built-events">pre-defined events</a>.</li>
<li><code>HandleEventAsync</code> is called by the ABP Framework whenever a new <code>Comment</code> is created, or an existing <code>Comment</code> is deleted or updated.</li>
<li>ABP's <code>Comment</code> entity is reusable and it can be associated with any kind of objects (blog posts, images, etc). So, first we are checking if this comment is related to an image gallery item.</li>
<li>Then we are getting the related <code>GalleryImage</code> entity from the database.</li>
<li>And getting all comments (including the new one) from the database for this image.</li>
<li>Finally, using the <code>AiCommentSummarizer</code> class to generate the summary and set the <code>CommentsSummary</code> property.</li>
</ul>
<h2>Show the Summary Card on the UI</h2>
<p>Everything is ready on the backend. Now, we can show the summary text on the user interface. To do, that, I added <code>CommentsSummary</code> property also to the <code>GalleryImageDto</code> class and used it on the <code>/Pages/Gallery/Detail.cshtml</code> view:</p>
<pre><code class="language-csharp">@if (!Model.Image.CommentsSummary.IsNullOrEmpty())
{
    &lt;div class=&quot;card mt-3&quot;&gt;
        &lt;div class=&quot;card-body&quot;&gt;
            &lt;h6 class=&quot;card-title&quot;&gt;Summary of the User Comments&lt;/h6&gt;
            &lt;p class=&quot;mb-auto&quot;&gt;@Model.Image.CommentsSummary&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
}
</code></pre>
<p>That section renders the following card on the user interface:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/summary-card.png" alt="summary-card" /></p>
<h2>Conclusion</h2>
<p>In this article, I demonstrated how to use <a href="https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions">Microsoft AI Extensions Library</a> to work with OpenAI for summarization of multiple user comments. I reused the <a href="https://github.com/abpframework/cms-kit-demo">ABP's CMS Kit Demo application</a> to show it in a more real world example.</p>
<h2>Source Code</h2>
<ul>
<li><a href="https://github.com/abpframework/cms-kit-demo">Source code of the CMS Kit Demo application</a></li>
<li><a href="https://github.com/abpframework/cms-kit-demo/pull/18">All the changes made for this article (as a pull request)</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1979e4-561b-9715-7969-3f2df9314687" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1979e4-561b-9715-7969-3f2df9314687" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/building-modular-monolith-applications-with-asp.net-core-abp-studio-66znukvf</guid>
      <link>https://abp.io/community/videos/building-modular-monolith-applications-with-asp.net-core-abp-studio-66znukvf</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <title>Building Modular Monolith Applications with ASP.NET Core &amp; ABP Studio</title>
      <description>ABP is an open source application development framework for .NET Developers. One of its main goals is to enable you to create modular applications. With the new ABP Studio tool, it is now easier to create fully modular systems with ASP.NET Core. In this talk, I will show how to do it in practical and explain the benefits of that approach.</description>
      <pubDate>Tue, 19 Nov 2024 13:05:20 Z</pubDate>
      <a10:updated>2026-04-26T07:42:27Z</a10:updated>
      <content:encoded><![CDATA[ABP is an open source application development framework for .NET Developers. One of its main goals is to enable you to create modular applications. With the new ABP Studio tool, it is now easier to create fully modular systems with ASP.NET Core. In this talk, I will show how to do it in practical and explain the benefits of that approach. <br \> <a href="https://www.youtube.com/watch?v=Bn7ybLRfQdg" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1656b3-e19c-4484-712b-61ce0753e859" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1656b3-e19c-4484-712b-61ce0753e859" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l</guid>
      <link>https://abp.io/community/posts/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp-studio</category>
      <category>aspire</category>
      <title>.NET Aspire vs ABP Studio: Side by Side</title>
      <description>In this article, I compare .NET Aspire and ABP Studio by explaining their similarities and differences.</description>
      <pubDate>Sun, 13 Oct 2024 13:24:20 Z</pubDate>
      <a10:updated>2026-10-02T14:00:35Z</a10:updated>
      <content:encoded><![CDATA[<h1>Aspire vs ABP Studio: Side by Side</h1>
<p>In this article, I will compare <a href="https://aspire.dev/">Aspire</a> by <a href="https://abp.io/docs/latest/studio">ABP Studio</a> by explaining their similarities and differences.</p>
<h2>Introduction</h2>
<p>While Aspire and ABP Studio are tools for different purpose with different scope and they have different approaches to solve the problems, many developers still may confuse since they also have some similar functionalities and solves some common problems.</p>
<p>In this article, I will clarify all, and you will have a clear understanding of what are the similarities and differences of them. Let's start by briefly define what are Aspire and ABP Studio.</p>
<h3>What is Aspire?</h3>
<p><strong><a href="https://aspire.dev/">Aspire</a></strong> is a <strong>cloud-ready framework</strong> designed to simplify building distributed, observable, and production-ready applications. It provides a set of opinionated tools and NuGet packages tailored for cloud-native concerns like <strong>orchestration</strong>, <strong>service integration</strong> (e.g., Redis, PostgreSQL), and <strong>telemetry</strong>. Aspire focuses on the <strong>local development experience</strong>, making it easier to manage complex, multi-service apps by <strong>abstracting away configuration details</strong>.</p>
<p>Here, a screenshot from <a href="https://aspire.dev/dashboard/overview/">Aspire dashboard</a> that is used for application monitoring and inspection:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png" alt="dotnet-aspire-dashboard" /></p>
<h3>What is ABP Studio?</h3>
<p><strong><a href="https://abp.io/docs/latest/studio">ABP Studio</a></strong> is a cross-platform <strong>desktop application</strong> designed to <strong>simplify development</strong> on the ABP Framework by <strong>automating various tasks</strong> and offering a streamlined, <strong>integrated development environment</strong>. It allows developers to <strong>build</strong>, <strong>run</strong>, <strong>test</strong>, <strong>monitor</strong>, and <strong>deploy applications</strong> more efficiently. With features like Kubernetes integration and support for complex multi-application systems, ABP Studio <strong>enhances productivity</strong>, especially in <strong>microservice or modular monolith architectures</strong>.</p>
<p>Here, a screenshot from the ABP Studio <a href="https://abp.io/docs/latest/studio/running-applications">Solution Runner panel</a> that is used to run, browse, monitor and inspect applications:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png" alt="abp-studio-solution-runner" /></p>
<h2>A Brief Comparison</h2>
<p>Before deep diving details, I want to show a <strong>table of features</strong> to compare ABP Studio and Aspire side by side:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png" alt="abp-studio-vs-net-aspire-comparison-table" /></p>
<h2>Comparing the Features</h2>
<p>In the next sections, I will go through each feature and explain differences and similarities.</p>
<h3>Integration Packages</h3>
<p>ABP Framework has tens of integration packages to 3rd-party libraries and services. Aspire also has some library integrations. But these integrations have different purposes:</p>
<ul>
<li><strong>ABP Framework</strong>'s integrations (like <a href="https://abp.io/docs/latest/framework/data/mongodb">MongoDB</a>, <a href="https://abp.io/docs/latest/framework/infrastructure/background-jobs/rabbitmq">RabbitMQ</a>, <a href="https://abp.io/docs/latest/framework/dapr">Dapr</a>, etc) are integrations for its abstractions and aimed to be <strong>used directly by your application code</strong>. They are complete and sophisticated integrations with the ABP Framework and your codebase.</li>
<li><strong>Aspire</strong>'s integrations (like <a href="https://aspire.dev/integrations/databases/mongodb/">MongoDB</a>, <a href="https://aspire.dev/integrations/messaging/rabbitmq/">RabbitMQ</a>, <a href="https://aspire.dev/integrations/frameworks/dapr/">Dapr</a>, etc), on the other hand, for simplifying configuration, service discovery, orchestration and monitoring of these tools within Aspire host. Basically, these are mostly for <strong>integrating to Aspire</strong>, not for integrating to your application.</li>
</ul>
<p>For example, ABP's <a href="https://abp.io/docs/latest/framework/data/mongodb">MongoDB</a> integration allows you to use MongoDB over <a href="https://abp.io/docs/latest/framework/architecture/domain-driven-design/repositories">repository services</a>, automatically handles database transactions, <a href="https://abp.io/docs/latest/framework/infrastructure/audit-logging">audit logs</a>, <a href="https://abp.io/docs/latest/framework/infrastructure/event-bus/distributed">event publishing</a> on data saves, dynamic <a href="https://abp.io/docs/latest/framework/fundamentals/connection-strings">connection string</a> management, <a href="https://abp.io/docs/latest/framework/architecture/multi-tenancy">multi-tenancy</a> integration and so on.</p>
<p>On the other hand, Aspire's <a href="https://aspire.dev/integrations/databases/mongodb/">MongoDB</a> integration basically adds <a href="https://www.nuget.org/packages/MongoDB.Driver/">MongoDB driver library</a> to your Aspire host application and configures it so you can discover MongoDB server on runtime, use a MongoDB Docker container and see its health status, logs and traces on Aspire dashboard.</p>
<h3>Starter Templates</h3>
<p>Both of ABP Studio and Aspire provide <strong>startup solution templates for new applications</strong>. However, there are huge differences between these startup solution templates and their purpose are completely different.</p>
<ul>
<li>ABP Studio provides <strong>production-ready</strong> and <a href="https://abp.io/docs/latest/solution-templates">advanced solution templates</a> for <strong>layered</strong>, <strong>modular</strong> or <strong>microservice</strong> solution development. They are well configured for <strong>local development</strong> and deploying to <strong>Kubernetes</strong> and other <strong>production environments</strong>. They provide different <strong>UI and database options</strong>, many optional modules and configuration. For example, you can check the <a href="https://abp.io/docs/latest/solution-templates/microservice/overview">microservice solution template</a> to see how <strong>sophisticated</strong> it is.</li>
<li>Aspire's <a href="https://aspire.dev/get-started/aspire-sdk-templates/">project templates</a>' main purpose is to provide a minimal application structure that is <strong>pre-integrated to Aspire</strong> libraries and configured for <strong>local development</strong> environment.</li>
</ul>
<p>So, when you start with Aspire project template, you will need to deal with a lot of work to make your solution production and enterprise ready. On the other hand, ABP Studio's solution templates are ready to launch your system from the first day and they provide you a perfect starting point for your new business idea.</p>
<h3>Monitoring &amp; Application Running</h3>
<p>Monitoring applications and services is an important requirement for building <strong>complex distributed systems</strong>. Both of ABP Studio and Aspire provide <strong>excellent tools</strong> for that purpose.</p>
<ul>
<li>ABP Studio's <a href="https://abp.io/docs/latest/studio/running-applications">Solution Runner panel</a> provides a powerful UI to run and monitor applications and services. You can see all HTTP requests, distributed events, exceptions and detailed application logs, trace and find problems in your system. You can use its fully functional built-in browser to navigate application UIs easily. You can also create multiple profiles to group and configure the applications for different teams.</li>
<li>Aspire's <a href="https://aspire.dev/dashboard/overview/">dashboard</a> can be used to see the states of the running applications and containers, explore their console output, logs, traces and metrics to understand what is happing in your distributed system.</li>
</ul>
<p>Both tools are pretty useful for monitoring. In addition to monitoring, <strong>ABP Studio offers an advanced UI to control the running applications</strong>, build, start and stop individually or by a group of applications.</p>
<h3>Architecting / Building Solutions</h3>
<p>One of the unique features of <strong>ABP Studio</strong> is that it <strong>is an architectural tool</strong> that helps you create the structure and architecture of your solution. You can create any kind of application, from <strong>single-layer</strong> simple web applications to <strong>layered multi-application</strong> solutions, from <strong>monolith modular</strong> to <strong>microservice</strong> systems. In the next section, I will briefly explains these architectural features.</p>
<h4>Building Modular Monolith Solutions</h4>
<p>With ABP Studio, you can create a new solution, <strong>create modules and establish relations</strong> (dependencies) between modules to architect your overall <strong>modular monolith system</strong> easily.</p>
<p>Here, a screenshot where we are adding an existing package reference to the Products module of a modular CRM solution:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png" alt="abp-studio-add-existing-package" /></p>
<p>You can see the <a href="https://abp.io/docs/latest/tutorials/modular-crm">Modular Application Development tutorial</a> to learn how to build such an application step by step.</p>
<h4>Building Microservice Solutions</h4>
<p>ABP Studio provides a full featured <a href="https://abp.io/docs/latest/solution-templates/microservice">microservice startup solution template</a> and the fundamental tooling to build <strong>large-scale microservice systems</strong>.</p>
<p>Here a screenshot that shows how to add new microservices, API gateways or web applications to a microservice solution:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png" alt="abp-studio-add-new-microservice" /></p>
<p>Aspire has no such a feature and has no such a plan to provide that kind of architectural solution building experience.</p>
<h3>Kubernetes Integration</h3>
<p>Another great ABP Studio feature is <a href="https://abp.io/docs/latest/studio/kubernetes">Kubernetes Integration</a>. It allows you to develop your distributed / microservice solutions as integrated to <a href="https://kubernetes.io/">Kubernetes</a>.</p>
<p>Here, a few tasks you can accomplish using ABP Studio's Kubernetes integration:</p>
<ul>
<li><strong>Build docker images</strong> of your applications and services</li>
<li><strong>Install and uninstall Helm charts</strong> to your Kubernetes cluster</li>
<li><strong>Connect to internal services</strong> of your Kubernetes cluster</li>
<li><strong>Monitor</strong> services and applications that are running in your Kubernetes cluster</li>
<li><strong>Intercept traffic</strong> of a service and redirect requests to your local machine. In that way, you can develop, test and run individual services or applications in your local computer that is <strong>fully integrated</strong> to other services and applications running in Kubernetes.</li>
</ul>
<p>ABP Studio's Kubernetes Integration makes microservice development so easy and comfortable. On the other hand, Aspire has no such a Kubernetes integrated development experience.</p>
<h2>The ABP Platform</h2>
<p>Until now, I directly compared ABP Studio and Aspire features. Aspire is directly built on .NET and ASP.NET Core. However, ABP Studio is not a standalone tool that is built on .NET and ASP.NET Core. It is built on the <a href="https://abp.io/">ABP Platform</a> (which is built on .NET and ASP.NET Core).</p>
<p>The following diagram shows ABP Platform components at a glance:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-overall-diagram.png" alt="abp-overall-diagram" /></p>
<p>So, when you use ABP Studio, you also take full power of the <a href="https://github.com/abpframework/abp">open source ABP Framework</a> and other ABP Platform features.</p>
<h2>ABP and Aspire Integration</h2>
<p>I have a good news to you. It is actually possible and pretty easy to make ABP Platform and Aspire working together.</p>
<p>You can check <a href="https://abp.io/community/members/berkansasmaz">@berkansasmaz</a>'s great article: <strong><a href="https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk">How to use Aspire with ABP framework</a></strong>.</p>
<h2>Licensing</h2>
<p>ABP Studio has a Community Edition which is completely free and available to everyone. It includes many of the features I mentioned here. There is also a commercial edition that is included in <a href="https://abp.io/pricing">commercial ABP licenses</a>. You can <a href="https://abp.io/blog/announcing-abp-studio-general-availability">check that blog post</a> which clearly explains the license differences and introduces the fundamental ABP Studio features.</p>
<p>On the other hand, Aspire is a free tool developed and published by Microsoft. It has no commercial version.</p>
<h2>Conclusion</h2>
<p>Both Aspire and ABP Studio serve distinct purposes, catering to different types of development environments. While Aspire excels in simplifying cloud-native application setups and observability, ABP Studio provides a comprehensive framework for modular monoliths and microservice architectures with full-fledged enterprise level production-ready startup solution templates and integrated tools.</p>
<p>In the previous section, it was mentioned that it is possible to <a href="https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk">use them together</a>. You don't have to select one of them. However, in my opinion, when you use ABP Studio, you won't need Aspire since ABP Studio can do everything and much more. If you have budget, I suggest to purchase a commercial ABP Studio <a href="https://abp.io/pricing">license</a> so you can fully unlock its power.</p>
<h2>Resources / Further Reading</h2>
<ul>
<li><a href="https://abp.io/docs/latest/studio">ABP Studio documentation</a></li>
<li><a href="https://aspire.dev/">Aspire documentation</a></li>
<li><a href="https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk">How to use Aspire with ABP framework</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a159839-f7d3-3cd0-28f6-16e6efdeb78b" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a159839-f7d3-3cd0-28f6-16e6efdeb78b" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/announcing-abp-studio-beta-general-availability-kcfec59b</guid>
      <link>https://abp.io/community/posts/announcing-abp-studio-beta-general-availability-kcfec59b</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>abp-studio</category>
      <title>Announcing ABP Studio (beta) General Availability</title>
      <description>ABP Studio (beta) is generally available to everyone and ready for download.</description>
      <pubDate>Tue, 30 Jul 2024 08:23:29 Z</pubDate>
      <a10:updated>2026-10-02T13:20:23Z</a10:updated>
      <content:encoded><![CDATA[<p>ABP Framework makes your daily coding activities much easier, more convenient, and even more enjoyable. However, building a software product is not just about coding. We know that you need to build, run, test, debug and deploy your software, and trace errors on a failure. You also should to design architecture of your overall solution and perform many common operations on your solutions in addition to the coding activity.</p>
<p>We'd already provided tools like <a href="https://abp.io/cli">ABP CLI</a> and <a href="https://abp.io/suite">ABP Suite</a> for these kind of purposes before. <a href="https://abp.io/studio">ABP Studio</a> takes this one long step further and offers a tool that you can use continuously throughout your coding activities, help you for non-coding activities to make you focus on your software development.</p>
<p>I am very excited to announce that the ABP Studio (beta) is generally available to everyone. It is now downloadable on the <a href="https://abp.io/get-started">get started page</a> of the <a href="https://abp.io/blog/new-abp-platform-is-live">new ABP Platform website</a>.</p>
<h2>What is ABP Studio?</h2>
<p><a href="https://abp.io/docs/latest/studio">ABP Studio</a> is a cross-platform desktop application for ABP and .NET developers. It aims to provide a comfortable development environment for you by automating things, providing insights about your solution, making develop, run, browse, monitor, trace and deploy your solutions much easier.</p>
<p><strong>From now on, ABP Studio is the default way to start with the ABP Platform</strong>;</p>
<ul>
<li><p>The <a href="https://abp.io/get-started">get started page</a> has updated so it offers to download ABP Studio to create a new ABP based solution.</p>
</li>
<li><p>The ABP CLI (<a href="https://nuget.org/packages/Volo.Abp.Cli">Volo.Abp.Cli</a>) is replaced by the ABP Studio CLI (<a href="https://www.nuget.org/packages/Volo.Abp.Studio.Cli">Volo.Abp.Studio.Cli</a>). <a href="https://abp.io/docs/latest/cli">The new ABP Studio CLI</a> is compatible with the old one, and extends it by introducing new commands.</p>
</li>
<li><p><a href="https://abp.io/docs/latest/solution-templates">Startup solution templates</a> are completely renewed. The solution structures are similar to the old ones, but they are totally new templates built with the new templating engine.</p>
</li>
<li><p>All the documentation and tutorials now uses ABP Studio and ABP Studio CLI.</p>
</li>
</ul>
<blockquote>
<p><strong>ABP Studio is in beta stage now.</strong> It is also in rapid development and release cycle. We frequently release new feature and patch versions. Please <a href="https://github.com/abpframework/abp/issues/new/choose">file an issue</a> if you have any problem.</p>
</blockquote>
<blockquote>
</blockquote>
<blockquote>
<p>If you want to continue to use the old CLI and old startup templates, please <a href="https://abp.io/docs/latest/cli/differences-between-old-and-new-cli">refer that document</a>.</p>
</blockquote>
<h2>The Easiest Way to Start with ABP</h2>
<p>As mentioned before, the <a href="https://abp.io/docs/latest/solution-templates">startup solution templates</a> are completely renewed with ABP Studio. They provide much more options compared to the old startup templates. The following screenshot is taken from the New Solution wizard of ABP Studio, which provides an comfortable and easy way to create new solutions:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e81208c50f7a7c2c5f2463ee95.png" alt="abp-studio-new-layered-solution-template-wizard.png" /></p>
<p>For example, you can now select most of the non-fundamental modules as optional while creating a new solution:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e82f626e06b4022b7fe077d68b.png" alt="abp-studio-new-layered-solution-template-wizard-options.png" /></p>
<h3>Developing Microservices Solutions is Now Much Easier</h3>
<p>The most important change is made on the <a href="https://abp.io/docs/latest/solution-templates/microservice">microservice startup template</a> (which is available only for Business or higher license holders). We've designed the solution structure, integrations, Kubernetes/Helm configuration, database migrations and all others from scratch and well documented all the decisions we've applied. Developing microservice solutions with ABP is now easier and more understandable than ever.</p>
<h2>Architecting Your Complex Solutions</h2>
<p>One of the main purposes to build ABP Studio was to simplify to create multi-modular and distributed systems. Either you create a modular monolith application or a microservice solution, <a href="https://abp.io/docs/latest/studio/solution-explorer">ABP Studio's solution explorer</a> provides a convenient way to design your high-level solution structure.</p>
<p>You see a microservice solution in the following screenshot:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e8580fc750ee048c9a14f7c064.png" alt="solution-explorer.png" /></p>
<p>That ABP Studio solution contains multiple separate .NET solutions (<code>.sln</code>) each has multiple .NET projects (<code>.csproj</code>). ABP Studio allows you to easily manage such a multi-solution system on a single view. You can create new packages and modules, import existing packages and modules, manage their dependencies and so on.</p>
<h2>Run and Test Your Multi-Application Solutions with a Single Click</h2>
<p>One of the biggest shortcomings we face when developing distributed or complex solutions is being able to easily run all components of the solutions so that we can test and debug a single service or application without caring about all the runtime dependencies.</p>
<p>Here a screenshot from the ABP Studio's <a href="https://abp.io/docs/latest/studio/running-applications">Solution Runner</a> view:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e87779052078513905ac904886.png" alt="abp-studio-solution-runner-overall.png" /></p>
<p>When you use ABP Studio, it is dramatically easier to run, monitor, test, debug and develop your applications and services. You can browse your web UI applications, monitor all the HTTP requests, distributed events, exceptions and logs in real time on a single screen. In this way, you can easily run all the systems and trace the problems when you have.</p>
<p>All you need to click the <em>Play</em> button or right-click and select the <em>Run</em> -&gt; <em>Start All</em> command:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e8936010694a2402ab1e771296.png" alt="abp-studio-solution-runner-start-apps.png" /></p>
<p>The nice thing is that you can create multiple profiles for each of your teams so that they can run only the applications they need to develop the application they are working on.</p>
<h2>Seamlessly Develop Your Service as Integrated to Kubernetes</h2>
<p>Kubernetes is the de-facto tool to deploy, run and scale complex systems. However, it can also be a great tool to develop such solutions in a local environment.</p>
<p>With ABP Studio's <a href="https://abp.io/docs/latest/studio/kubernetes">Kubernetes Integration</a> system, it is now possible to deploy and run a complex system in a Kubernetes cluster. Then you can establish a bridge between your local development environment and the Kubernetes cluster. In this way, you can develop, run, test and debug an application or service in your local development environment as it is running in the Kubernetes cluster. All incoming and outgoing traffic is properly routed and managed by ABP Studio. You just focus on the service you are responsible to develop and let the Kubernetes run rest of the system for you.</p>
<p>You can see all the Helm charts in a solution in the Kubernetes panel of ABP Studio:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e8bcfc8e9ce9dfdcb779fe7d74.png" alt="abp-studio-helm-charts.png" /></p>
<p>Here, you can easily build, install and uninstall the Helm charts to your Kubernetes cluster. In the Kubernetes tab, you can connect to the Kubernetes cluster and intercept a service to develop it locally. See <a href="https://abp.io/docs/latest/studio/kubernetes">the documentation</a> for more information.</p>
<p>The good news is that all the monitoring data (HTTP Requests, Events, Exceptions, Logs,...) is still visible in real time with the Kubernetes integration too.</p>
<h2>Use the ABP Suite as Integrated to ABP Studio</h2>
<p><a href="https://abp.io/suite">ABP Suite</a> is a tool that is basically used to generate code for ABP Solutions. It has started by creating simple CRUD pages, and now it does much more. It can establish relations with existing entities, create complex user interfaces like parent/child tables and so on...</p>
<p>ABP Suite can be used directly inside ABP Studio by clicking the <em>ABP Suite</em> -&gt; <em>Open</em> command:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e8eee5a21b45744cedf6e688f3.png" alt="abp-suite-open-in-abp-studio.png" /></p>
<p>This will open ABP Suite  in a new tab for the current solution and focus on the CRUD page generation:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e908e6740ea8f1a74a72a8a7e6.png" alt="abp-suite-in-abp-studio.png" /></p>
<p>The new ABP Studio solution templates and ABP Suite code generation are compatible with each other. Here a screenshot from the generated CRUD UI for a very simple Book entity:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e927e9ce87f76be80eb2946060.png" alt="suite-generated-entity.png" /></p>
<h2>The Community Edition vs Commercial Licenses</h2>
<p>ABP Studio has a Community Edition which is completely free and available to everyone. As you can guess, there are come differences between the community edition and commercial editions. ABP Platform has 4 fundamental license types;</p>
<ul>
<li><p>Open source (free)</p>
</li>
<li><p>Team</p>
</li>
<li><p>Business</p>
</li>
<li><p>Enterprise</p>
</li>
</ul>
<p>Here, the comparison table for ABP Studio features for these license types:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-07-30-announcing-abp-studio-beta-general-availability/3a1414e947cec9e65339c4faf917a656.png" alt="abp-studio-license-comparison-table.png" /></p>
<p>Microservice startup template and Kubernetes integration features are available only for commercial licenses since these are considered more enterprise requirements. Also, the solution size is limited with the ABP Community edition. If you are building a large or distributed solution, consider to <a href="https://abp.io/pricing">purchase a commercial license</a>.</p>
<h2>Conclusion</h2>
<p>I've introduced the ABP Studio General Availability with this post. It is still in the beta stage. You can expect frequent releases during the beta phase. We will add new features and fix issues quickly. Please <a href="https://abp.io/studio">download</a> and use it now. If you find any problem, do not hesitate to open an <a href="https://github.com/abpframework/abp/issues/new/choose">issue on GitHub</a>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1414e9-955b-fc83-44a5-05ec5fa4992a" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1414e9-955b-fc83-44a5-05ec5fa4992a" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/abp-framework-uctan-uca-.net-uygulama-gelistirme-altyapisi-t5odzblf</guid>
      <link>https://abp.io/community/videos/abp-framework-uctan-uca-.net-uygulama-gelistirme-altyapisi-t5odzblf</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <title>ABP FRAMEWORK: Uçtan Uca .NET Uygulama Geliştirme Altyapısı</title>
      <description>* ABP Framework nedir?
* ABP Framework'ü neden kullanmalıyız?
* Canlı demo - kodlama
* ABP Framework'ün öne çıkan özellikleri
* ABP Studio Demosu
* ABP Platform tanıtımı
* Canlı Soru &amp; Cevap</description>
      <pubDate>Wed, 24 Jul 2024 08:41:53 Z</pubDate>
      <a10:updated>2026-04-19T12:23:50Z</a10:updated>
      <content:encoded><![CDATA[* ABP Framework nedir?
* ABP Framework'ü neden kullanmalıyız?
* Canlı demo - kodlama
* ABP Framework'ün öne çıkan özellikleri
* ABP Studio Demosu
* ABP Platform tanıtımı
* Canlı Soru & Cevap <br \> <a href="https://www.youtube.com/watch?v=RTl67Rm_yYQ" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-video-cover-image-344_196.png" />
      <media:content url="https://abp.io/images/others/blank-video-cover-image-344_196.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/unifying-the-abp-platform-pq4eujes</guid>
      <link>https://abp.io/community/posts/unifying-the-abp-platform-pq4eujes</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>platform</category>
      <title>Unifying the ABP Platform</title>
      <description>Some big changes and improvements are coming to the ABP.IO Platform soon</description>
      <pubDate>Fri, 26 Apr 2024 08:46:23 Z</pubDate>
      <a10:updated>2026-10-02T17:07:05Z</a10:updated>
      <content:encoded><![CDATA[<p>I am very excited to announce that some big changes and improvements are coming to the ABP.IO Platform soon. In this post, I will explain the changes we are currently working on. Here, a brief list of these changes:</p>
<ul>
<li><p>We are merging the subdomains of the ABP.IO Platform websites: Community.abp.io, commercial.abp.io, blog.abp.io, docs.abp.io websites and their contents are being merged into the main domain, abp.io.</p>
</li>
<li><p>ABP (open source) and ABP Commercial documents are being merged into a single documentation.</p>
</li>
<li><p>Introducing ABP Studio Community Edition.</p>
</li>
</ul>
<p>These changes won't effect the license conditions. The open source part will remain the same and the commercial license contents will also be the same. The aim of the changes is to make the platform more consistent, holistic, understandable and easy to start.</p>
<p>Let's dive deep...</p>
<h2>Merging the ABP.IO Websites</h2>
<p>ABP.IO website has many subdomains currently:</p>
<ul>
<li><p><strong>abp.io</strong>: Home page of the open source ABP Framework project.</p>
</li>
<li><p><strong>community.abp.io</strong>: A website that community can share contents and we organize events.</p>
</li>
<li><p><strong>commercial.abp.io</strong>: A website to promote and sell commercial ABP licenses which have pre-built modules, themes, tooling and support on top of the ABP Framework.</p>
</li>
<li><p><strong>docs.abp.io</strong>: The technical documentation of the ABP Framework and ABP Commercial.</p>
</li>
<li><p><strong>blog.abp.io</strong>: A blog website to announce the news on the platform.</p>
</li>
<li><p><strong>support.abp.io</strong>: Premium support for the ABP Commercial customers.</p>
</li>
</ul>
<p>All these subdomains (except the support website for now) are being merged to the abp.io domain. All their contents and UI designs are being revised and enriched.</p>
<p>Some fundamental purposes of that change are;</p>
<ul>
<li><p>Making content more coherent and holistic,</p>
</li>
<li><p>Making the design more harmonious,</p>
</li>
<li><p>Making the contents of the old subdomains more visible and reachable,</p>
</li>
<li><p>Allow you to navigate through the web pages much easier,</p>
</li>
<li><p>Reducing duplications between different websites,</p>
</li>
</ul>
<p>I will highlight a few important changes in the next sections.</p>
<h3>The New Mega Menu</h3>
<p>As I said above, the abp.io UI design is also being revised. One of the big revisions is the main menu. We are replacing the current main navigation by a mega menu as shown in the following figure:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc1039888d362b74f377ad5d7a8.png" alt="new-mega-menu.png" /></p>
<p>We believe that new mega menu will allow you to navigate through the web pages much easier.</p>
<h3>The New Get Started Page</h3>
<p>We are constantly working to improve ABP's onboarding experience. With the new platform changes, we now offer ABP Studio as the starting point for the ABP Platform. You can still use the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> to created new ABP solutions, but the new ABP Studio makes it much easier and understandable. It also provides features to easily run and monitor your applications, even in the Community edition.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc13e410e85f86a8cada595c4ba.png" alt="new-get-started.png" /></p>
<p>You can easily download and install ABP Studio, login with your abp.io account and create your first ABP solution.</p>
<h3>The New Pricing Page</h3>
<p>Since the <a href="https://commercial.abp.io/">ABP Commercial website</a> has merged with the main website, you will see the <em>Pricing</em> page located on the main menu of the abp.io website. We have completely revised the design and content of this page to better reflect which features are open source and free, and what is included in the paid licenses.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc16be482de862d5cdef1ff74a3.png" alt="new-pricing.png" /></p>
<p>As mentioned above, all the free &amp; open source features are still free &amp; open source. In addition, we included the ABP Studio Community edition (will be explained below) to the free license.</p>
<h2>Merging the ABP Platform Documentation</h2>
<p>Currently, ABP Framework (open source) and ABP Commercial <a href="https://docs.abp.io/">documents</a> are completely separated. You can switch between them on the left side:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc196f7f658dad6eded9fb78ad0.png" alt="docs-project-selection.png" /></p>
<p>Based on our and customers' experiences, there are some problems with that approach:</p>
<ul>
<li><p>Getting started, development tutorials, release notes, road map and some other documents are duplicated (or very similar) among ABP Framework and ABP Commercial documents.</p>
</li>
<li><p>For ABP Commercial users, it is not clear if they also need to read the ABP Framework (open source) documentation or not. Also, when they read the framework document, some parts are different for ABP Commercial users, and it is also not clear in some cases.</p>
</li>
</ul>
<p>We are currently working to completely merge the ABP Framework (open source) and ABP Commercial documentation, remove duplications and revisit the contents. We will clearly indicate if a part of a document requires a paid license.</p>
<p>The left navigation panel tree is also completely revisited and simplified:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc1b7ca559908f2d1b149d2a6c8.png" alt="docs-new-navigation.png" /></p>
<h2>The ABP Studio Community Edition</h2>
<p><a href="https://docs.abp.io/en/commercial/latest/studio/index">ABP Studio</a> is a cross-platform desktop application designed for ABP and .NET developers. It aims to provide a comfortable development environment by automating tasks, providing insights about your solution, and simplifying the processes of creation, development, execution, browsing, monitoring, tracing, and deploying your solutions.</p>
<p>Here, a screenshot from the <em>Solution Runner</em> screen of ABP Studio:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2024-04-26-unifying-the-abp-platform/3a122bc1f4879a000ebb2a81da3cf8b8.png" alt="abp-studio-solution-runner.png" /></p>
<p>ABP Studio has been started as a commercial product, as a part of <a href="https://commercial.abp.io/">ABP Commercial</a>. We are very excited to announce that the <em>Community Edition</em> will be available soon for free. It will have some missing features and limitations compared to the full edition, but will be enough to create, explore and run ABP solutions easily.</p>
<p>We will be offering ABP Studio as a starting point to the ABP platform. The <a href="https://docs.abp.io/en/abp/latest/Getting-Started-Overall">Getting Started</a> and other documents will use ABP Studio to create new solutions and perform ABP-related operations.</p>
<h2>Other News</h2>
<p>We are also working on some other topics related to these changes. Some of them are;</p>
<ul>
<li><p>Completely renewing the <a href="https://docs.abp.io/en/abp/latest/Startup-Templates/Index">startup templates</a> (with ABP Studio), so they will be more flexible and will provide more options.</p>
</li>
<li><p>Providing a tool to automatically convert ABP solutions created with open source startup templates into ABP commercial.</p>
</li>
</ul>
<h2>Questions</h2>
<p>I tried to explain all the important changes in this post. However, you may have some questions in your mind.</p>
<h3>What should open source users expect?</h3>
<p>Since the <a href="https://commercial.abp.io/">ABP Commercial</a> website content is merged with the main <a href="https://abp.io/">abp.io</a> website, you will see paid features being introduced on the main website. The pricing page will also be available on the same website. This may lead you to wonder whether the ABP Platform is a fully paid product. The simple answer to this question is &quot;No&quot;. Actually, nothing has changed on the open source side. Everything will be the same. Additionally, open source users will now have ABP Studio Community Edition for free. So open source has more for its users than before.</p>
<h3>What should ABP Commercial customers expect?</h3>
<p>ABP Commercial license holders may wonder if any license change happens. The answer is &quot;No&quot;. All the license types, rules, restrictions and features are the same. With the changes explained in this post, you will follow the documentation easier (since you won't need to go to another website for the framework documentation) and you will better understand what special features are available to you.</p>
<h2>Last Words</h2>
<p>With this post, we wanted to announce the changes to be made on the ABP platform to the ABP community, so don't be surprised or curious about what happened. If you have any questions or suggestions, feel free to write a comment for this blog post or send an email to info@abp.io.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a122bc2-699f-390e-cc85-5bdd81c70feb" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a122bc2-699f-390e-cc85-5bdd81c70feb" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/using-complex-types-as-value-objects-with-entity-framework-core-8.0-fs0ynz6e</guid>
      <link>https://abp.io/community/posts/using-complex-types-as-value-objects-with-entity-framework-core-8.0-fs0ynz6e</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>entity-framework-core</category>
      <category>net8</category>
      <category>efcore8</category>
      <title>Using Complex Types as Value Objects with Entity Framework Core 8.0</title>
      <description>I introduce the new Complex Types feature of Entity Framework Core 8.0 and show some examples of how you can use it in your projects built with ABP Framework.</description>
      <pubDate>Tue, 07 Nov 2023 06:37:04 Z</pubDate>
      <a10:updated>2026-10-02T14:58:24Z</a10:updated>
      <content:encoded><![CDATA[<h1>Using Complex Types as Value Objects with Entity Framework Core 8.0</h1>
<p>Entity Framework Core 8.0 is being shipped in a week as a part of .NET 8.0. In this article, I will introduce the new <strong><a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#value-objects-using-complex-types">Complex Types</a></strong> feature of EF Core 8 and show some examples of how you can use it in your projects built with ABP Framework.</p>
<h2>What is a Value Object?</h2>
<p>A <a href="https://docs.abp.io/en/abp/latest/Value-Objects">Value Object</a> is a simple object that has no conceptual identity (Id). Instead, a Value Object is identified by its properties.</p>
<p>A Value Object is typically owned by a parent <a href="https://docs.abp.io/en/abp/latest/Entities">Entity</a> object. Using <a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#value-objects-using-complex-types">Complex Types</a> with EF Core 8 is the best way to create Value Objects that are stored as a part of your main entity.</p>
<h2>Creating an ABP Project</h2>
<blockquote>
<p><strong>WARNING</strong>: ABP Framework has not a .NET 8.0 compatible version yet. It is planned to be released on November 15, 2023. I created this project with ABP 7.4.1 (based on .NET 7.0), then manually changed the <code>TargetFramework</code> (in the <code>csproj</code>) to <code>net8.0</code> and added the <code>Microsoft.EntityFrameworkCore.SqlServer</code> package with version <code>8.0.0-rc.2.23480.1</code>. After that, the project is being compiled, but some parts of this article may not work as expected until ABP Framework 8.0-RC.1 is released.</p>
<p><strong>I will update the article once ABP Framework 8.0-RC.1 is released.</strong></p>
</blockquote>
<p>I will show code examples, so I am creating a new ABP project using the following <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> command:</p>
<pre><code class="language-bash">abp new ComplexTypeDemo -t app-nolayers
</code></pre>
<blockquote>
<p>I prefer a non-layered project to keep the things simple. If you are new to ABP Framework, follow the <a href="https://docs.abp.io/en/abp/latest/Getting-Started-Overall">Getting Started</a> tutorial to learn how to create a new project from scratch.</p>
</blockquote>
<p>Once I created the solution, I am running the following command to execute the database migrations in order to create the initial database:</p>
<pre><code class="language-bash">dotnet run --project ComplexTypeDemo --migrate-database
</code></pre>
<blockquote>
<p>We could also execute the <code>migrate-database.ps1</code> (that is coming as a part of the solution) as a shortcut.</p>
</blockquote>
<h2>Creating a Complex Type</h2>
<p>Assume that we have a <code>Customer</code> <a href="https://docs.abp.io/en/abp/latest/Entities">entity</a> as shown below:</p>
<pre><code class="language-csharp">public class Customer : BasicAggregateRoot&lt;Guid&gt;
{
    public string Name { get; set; }
    public Address HomeAddress { get; set; }
    public Address BusinessAddress { get; set; }
}
</code></pre>
<p>Here, we have two address properties, one for home and the other one for business. Since an address is a multi-values property, we can define it as a separate object:</p>
<pre><code class="language-csharp">public class Address
{
    public string City { get; set; }
    public string Line1 { get; set; }
    public string? Line2 { get; set; }
    public string PostCode { get; set; }
}
</code></pre>
<p><code>Address</code> is a typical complex object. It is actually a part of the <code>Customer</code> object, but we wanted to collect its parts into a dedicated class to make it a domain concept and easily manage its properties together.</p>
<h2>Configure EF Core Mappings</h2>
<p>We should set the <code>Address</code> class as a Complex Type in our EF Core mapping configuration. There are two ways of it.</p>
<p>As the first way, we can add the <code>ComplexType</code> attribute on top of the <code>Address</code> class:</p>
<pre><code class="language-csharp">[ComplexType] // Added this line
public class Address
{
    ...
}
</code></pre>
<p>As an alternative, we can configure the mapping using the fluent mapping API. You can write the following code into the <code>OnModelCreating</code> method of your <code>DbContext</code> class:</p>
<pre><code class="language-csharp">builder.Entity&lt;Customer&gt;(b =&gt;
{
    b.ToTable(&quot;Customers&quot;);
    b.ComplexProperty(x =&gt; x.HomeAddress);     // Mapping a Complex Type
    b.ComplexProperty(x =&gt; x.BusinessAddress); // Mapping another Complex Type
    //... configure other properties
});

</code></pre>
<p>You can further configure the properties of the <code>Address</code> class:</p>
<pre><code class="language-csharp">b.ComplexProperty(x =&gt; x.HomeAddress, a =&gt;
{
    a.Property(x =&gt; x.City).HasMaxLength(50).IsRequired();
});
</code></pre>
<p>Once you configure the mappings, you can use the <a href="https://learn.microsoft.com/en-us/ef/core/cli/dotnet">EF Core command-line tool</a> to create a database migration:</p>
<pre><code class="language-bash">dotnet ef migrations add &quot;Added_Customer_And_Address&quot;
</code></pre>
<p>And update the database:</p>
<pre><code class="language-bash">dotnet ef database update
</code></pre>
<p>If you check the fields of the <code>Customers</code> table in your database, you will see the following fields:</p>
<ul>
<li><code>Id</code></li>
<li><code>Name</code></li>
<li><code>HomeAddress_City</code></li>
<li><code>HomeAddress_Line1</code></li>
<li><code>HomeAddress_Line2</code></li>
<li><code>HomeAddress_PostCode</code></li>
<li><code>BusinessAddress_City</code></li>
<li><code>BusinessAddress_Line1</code></li>
<li><code>BusinessAddress_Line2</code></li>
<li><code>BusinessAddress_PostCode</code></li>
</ul>
<p>As you see, EF Core stores the <code>Address</code> properties as a part of your main entity.</p>
<h2>Querying Objects</h2>
<p>You can query entities from database using the properties of a complex type as same as you query by the properties of the main entity.</p>
<p><strong>Example: Find customers by <code>BusinessAddress.PostCode</code>:</strong></p>
<pre><code class="language-csharp">public class MyService : ITransientDependency
{
    private readonly IRepository&lt;Customer, Guid&gt; _customerRepository;

    public MyService(IRepository&lt;Customer, Guid&gt; customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public async Task DemoAsync()
    {
        var customers = await _customerRepository.GetListAsync(
            c =&gt; c.BusinessAddress.PostCode == &quot;12345&quot;
        );
        
        //...
    }
}
</code></pre>
<h2>Mutable vs Immutable</h2>
<p>Entity Framework Core Complex Types can work with mutable and immutable types. In the <code>Address</code> example above, I've shown a simple mutable class - that means you can change an individual property of an <code>Address</code> object after creating it (or after querying from database). However, designing Value Objects as immutable is a highly common approach.</p>
<p>For example, you can use C#'s <code>struct</code> type to define an immutable <code>Address</code> type:</p>
<pre><code class="language-csharp">public readonly struct Address(string line1, string? line2, string city, string postCode)
{
    public string City { get; } = city;
    public string Line1 { get; } = line1;
    public string? Line2 { get; } = line2;
    public string PostCode { get; } = postCode;
}
</code></pre>
<p>See the <a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#mutability">Microsoft's documentation</a> for more examples and different usages.</p>
<h2>Final Notes</h2>
<p>There are more details about using Complex Types in your applications. I want to mention some of them here:</p>
<ul>
<li>You can have nested complex types. For example, <code>Address</code> may have one or more <code>PhoneNumber</code> objects as its properties. Everything will work seamlessly.</li>
<li>A single instance of a Complex Type can be set to multiple properties (of the same or different entities). In that case, changing the Complex object's properties will affect all of the properties. However, try to avoid that since it may create unnecessary complexities in your code that is hard to understand.</li>
<li>You can manipulate mutable complex object properties just as another property in your entity. EF Core change tracking system will track them as you expect.</li>
<li>Currently, EF Core doesn't support to have a collection of complex objects in an entity. It works only for properties.</li>
</ul>
<p>For more details and examples, see the Microsoft's document in the <em>References</em> section.</p>
<h2>Source Code</h2>
<p>You can find the sample project here:</p>
<p><a href="https://github.com/hikalkan/samples/tree/master/EfCoreComplexTypeDemo">https://github.com/hikalkan/samples/tree/master/EfCoreComplexTypeDemo</a></p>
<h2>References</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#value-objects-using-complex-types">Value objects using Complex Types</a> in <a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew">What's new with EF Core 8.0</a> document by Microsoft.</li>
<li><a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core">ABP Entity Framework Core integration document</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/reflecting-on-devnot-dotnet-conference-2023-a0y9oayc</guid>
      <link>https://abp.io/community/posts/reflecting-on-devnot-dotnet-conference-2023-a0y9oayc</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>dotnet</category>
      <category>abp</category>
      <category>conference</category>
      <category>platform</category>
      <category>volosoft</category>
      <category>devnot</category>
      <title>Reflecting on Devnot Dotnet Conference 2023</title>
      <description>Revisit the memorable moments and discover the vibrant .NET community that made Devnot Dotnet Conference 2023 truly unforgettable.</description>
      <pubDate>Tue, 06 Jun 2023 14:10:34 Z</pubDate>
      <content:encoded><![CDATA[<p>On June 1st, we attended to <a href="https://dotnet.devnot.com/"> Devnot Dotnet Conference 2023</a> that took place in Istanbul, Dedeman Hotel &amp; Convention Centre. As one of the gold sponsors, we wanted to take a moment to express our deepest gratitude to Devnot Team for organizing such an exceptional event. The conference was a great success and we are honored to have participated.</p>
<p>Throughout the day, the conference provided an excellent platform for networking, learning, and knowledge sharing within the .NET community. The quality and depth of the specialist presentations by the 20 specialist speakers were truly remarkable. From discussions of cutting-edge .NET Core features to software architecture, cloud-based software, and DevOps, each session inspired and informed attendees. Volosoft’s Co-Founder and lead architect of ABP Framework, <a href="https://github.com/hikalkan">Halil Ibrahim Kalkan</a> was one of those talented speakers within the agenda. His captivating talk on &quot;<strong>Dealing with Concurrency and Multi - Threading in .NET</strong> &quot; was well received by the audience.</p>
<blockquote>
<p><a href="https://www.instagram.com/reel/Cs8hIt1sy5h/?utm_source=ig_embed&amp;utm_campaign=loading"> View this post on Instagram </a></p>
<p><a href="https://www.instagram.com/reel/Cs8hIt1sy5h/?utm_source=ig_embed&amp;utm_campaign=loading">A post shared by Volosoft (@volosoftcompany)</a></p>
</blockquote>
<p>Our booth in the main hall was full of excitement as we had the chance to meet and chat with the community face-to-face. We were excited to present ABP Platform to the attendees with live demos and interactive visual demonstrations, showcase new features, and share updated documentations. It is always brilliant to meet with the community and get to know them better in person. For this event, the commitment and enthusiasm of the conference participants made the experience even more rewarding for us.</p>
<p>We also want to give a special thank you to everyone who visited our booth and engaged in meaningful conversations. Your curiosity and passion for .NET was truly inspiring. We hope that our interactions during the event created new contacts and opened doors to exciting collaborations and opportunities. Finally, we would like to express our appreciation for the gifts and raffles that we had the privilege of providing. The surprise gifts and fun items were a small token of our gratitude and appreciation for your support and participation. We hope you enjoy your treats and that they remind us of the wonderful times we all had at the conference.</p>
<blockquote>
<p>We draw the raffle ‼️ And the winner is <a href="https://twitter.com/umitgnr?ref_src=twsrc%5Etfw">@umitgnr</a> 🎁 <a href="https://twitter.com/hashtag/dotnetkonf23?src=hash&amp;ref_src=twsrc%5Etfw">#dotnetkonf23</a><br />
<a href="https://t.co/PEuXwjhL6Q">pic.twitter.com/PEuXwjhL6Q</a></p>
<p>— Volosoft (@volosoftcompany) <a href="https://twitter.com/volosoftcompany/status/1664254694984761344?ref_src=twsrc%5Etfw">June 1, 2023</a></p>
</blockquote>
<p>We would like to invite everyone to revisit some memorable moments from the Devnot Dotnet 2023 conference by exploring images:</p>
<p><img src="https://i.ibb.co/6s4YjF1/IMG-1974.jpg" alt="" /></p>
<p><img src="https://i.ibb.co/tHQ3zJs/IMG-1938.jpg" alt="" /></p>
<p><img src="https://i.ibb.co/wWTLN6C/IMG-2244.jpg" alt="" /></p>
<p><img src="https://i.ibb.co/R2YFtkt/IMG-1955.jpg" alt="" /></p>
<p><img src="https://i.ibb.co/hHnccVr/IMG-2052.jpg" alt="" /></p>
<p>We would like to once again express our sincere thanks to the entire Devnot Team for organizing such a great conference. Your dedication, attention to detail, and commitment to driving growth and innovation within the .NET community is truly commendable.</p>
<p>To all attendees, speakers and sponsors, thank you for making the Devnot Dotnet Conference 2023 a truly unforgettable experience. We are honored to be a part of this vibrant community and look forward to future events that will no doubt continue to push the boundaries of .NET development.</p>
<p>Until we meet again!</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/9ea3daf4-f596-1f3a-eb8d-3a0ba3386985" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/9ea3daf4-f596-1f3a-eb8d-3a0ba3386985" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/kubernetes-integrated-microservice-development-with-.net-and-abp-studio-h11utnq8</guid>
      <link>https://abp.io/community/posts/kubernetes-integrated-microservice-development-with-.net-and-abp-studio-h11utnq8</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>microservices</category>
      <category>abp</category>
      <category>kubernetes</category>
      <category>abp-studio</category>
      <category>project-tye</category>
      <title>Kubernetes Integrated Microservice Development with .NET and ABP Studio</title>
      <description>I introduce an efficient way of creating a development environment that is well integrated to Kubernetes. In this way, you can just run the microservice you are building and let Kubernetes run all your dependencies in your local machine or a remote server.</description>
      <pubDate>Mon, 05 Jun 2023 08:59:35 Z</pubDate>
      <a10:updated>2026-10-02T15:58:35Z</a10:updated>
      <content:encoded><![CDATA[<h1>Kubernetes Integrated Microservice Development with .NET and ABP Studio</h1>
<h2>Abstract</h2>
<p><strong>Microservice architecture</strong> is a quite common approach to build <strong>highly scalable</strong> solutions with a large development team. While there are standard tools, like <strong>Kubernetes</strong>, to deploy, run and scale your microservices, the <strong>development side</strong> is not as mature as that. It is not easy to develop, run and test a single microservice that <strong>depends on</strong> other microservices and services. <strong>Running</strong> a copy of the entire system in the developer's machine is impractical.</p>
<p>In this article, I will introduce an <strong>efficient</strong> way of creating a <strong>development environment</strong> that is well <strong>integrated to Kubernetes</strong>. In this way, you can just run the microservice you are building and let Kubernetes run all your dependencies in your local machine or a remote server.</p>
<p>I will demonstrate the solution by introducing and using a brand new tool for ABP Developers: <strong>ABP Studio</strong>!</p>
<blockquote>
<p><strong>This article is based on my <em><a href="https://www.youtube.com/watch?v=XiPRcIHJ3NE">Kubernetes Integrated Microservice Development with ABP Studio</a></em> talk performed in <a href="https://abp.io/conference">ABP Dotnet Conf'23</a>. You can watch that talk if you would like watching rather than reading.</strong></p>
</blockquote>
<h2>Topics</h2>
<p>Let’s start by introducing the main topics I will cover in this article:</p>
<ul>
<li>I will begin by defining the <strong>problem</strong>: Why it is hard to prepare a development environment for a microservice development.</li>
<li>I will mention and demonstrate how <strong>Microsoft’s Tye project</strong> tries to solve the problem and why it falls short.</li>
<li>Then I will introduce the <strong>ABP Studio</strong>, a brand new product for .NET developers, which has an efficient solution for <strong>running multi-application solutions</strong> locally.</li>
<li>Finally, I will offer an efficient way of developing such complex solutions locally by <strong>integrating Kubernetes into our development environment</strong>, and demonstrate how ABP Studio automates it for us.</li>
</ul>
<h2>Difficulties of a Microservice Development Environment</h2>
<p>It is important to understand what is the essential problem when we try to set up a development environment for a microservice solution. To understand the main difficulty, let’s see what a microservice solution looks like:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/01-microservice-solution.png" alt="example-microservice-solution" /></p>
<p>A typical microservice solution consists of many components communicating to each other. In this example;</p>
<ul>
<li>We have <strong>two applications</strong> for users. One for back-office admin users and one for the end-users of the system, a public website.</li>
<li>These applications use dedicated <strong>API Gateways</strong> since we are using the Backend For Frontend pattern here.</li>
<li>There is a separate <strong>authentication service</strong> application to login and manage user accounts.</li>
<li>Behind the API gateways, we typically have many API applications, called <strong>microservices</strong>. Here, I show only three microservices, but there will be tens of microservices even in a medium-size system. Each of these microservices may have their own databases.</li>
<li>The microservices typically <strong>interact</strong> with each other using REST API calls or asynchronous messaging through an event bus service, like RabbitMQ here.</li>
</ul>
<p>There will be much more <strong>supporting services</strong>, like Redis, Elasticsearch and so on. As you see, we have a lot of independent services and applications interacting with each other in a typical microservice solution.</p>
<h3>How to run a single service locally?</h3>
<p>Generally, your responsibility is developing <strong>one or a few of these microservices</strong> or applications, not all of them. For example, you may be responsible for developing or testing the Product microservice:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/02-run-single-service.png" alt="run-single-service-in-a-microservice-solution" /></p>
<p>All you want to do is to write your code, then run and test your service if it is correctly working. However, to be able to <strong>develop</strong>, <strong>run</strong>, <strong>test</strong> or <strong>debug</strong> the product microservice, all of the service and infrastructure dependencies need to be running and communicating to each other.</p>
<p>Okay, maybe not all, but most of them are needed. Otherwise, you can not open the application UI, login to the system, add products to basket and place an order to see if it is working properly, or you can not <strong>live debug</strong> your service code in case of trouble.</p>
<p>So, how to make the whole system up and running easily to be able to <strong>focus on developing</strong>, testing and debugging the Product microservice?</p>
<h2>The Project Tye</h2>
<p>You are not the only one getting trouble to develop, run, test and debug a microservice solution. Microsoft also thought of it and introduced a tool called the <a href="https://github.com/dotnet/tye">Project Tye</a>. With its own words in their GitHub repository:</p>
<blockquote>
<p>Tye is a tool that makes developing, testing, and deploying microservices and distributed applications easier.</p>
</blockquote>
<p>Tye can <strong>simplify microservices development</strong> by making it easy to run many services with one command, use dependencies in containers, discover addresses of other services using simple conventions. It can also deploy .NET applications to Kubernetes by automatically creating containers for .NET applications and generating Kubernetes manifests with minimal knowledge or configuration.</p>
<p>The deployment part is not mature and they have to do a lot of work. However, the solution runner part works very well.</p>
<p>Tye project consists of three major components:</p>
<ul>
<li>A <strong>YAML file</strong> to configure your services</li>
<li>A <strong>CLI tool</strong> to run and deploy the solution</li>
<li>And a <strong>dashboard</strong> to visualize the running services.</li>
</ul>
<h3>The tye.yaml file</h3>
<p>Tye uses a YAML file to configure your solution. It typically contains many service definitions. There are three type of services can be defined in this YAML file:</p>
<ul>
<li>You can add a <strong>.NET Project</strong>, so Tye runs it locally with <strong>dotnet run</strong></li>
<li>You can add a <strong>container definition</strong>, and Tye runs it using <strong>Docker</strong></li>
<li>And an arbitrary <strong>executable application</strong> that can be run using a terminal command</li>
</ul>
<p>Here, an example content of a <code>tye.yaml</code> file:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/03-tye-yaml-file.png" alt="tye-yaml-file" /></p>
<h3>The Tye CLI</h3>
<p>Once you define your YAML file, Tye can run all the services with a single terminal command: <strong>tye run</strong>. It builds all .NET applications before running them. If you specify the <strong>watch parameter</strong>, it watches the changes in your .NET projects, re-builds and runs them when a change happens. There are also <a href="https://github.com/dotnet/tye/blob/main/docs/reference/commandline/README.md">other commands</a> to build and deploy your solution.</p>
<h3>The Tye Dashboard</h3>
<p>The final major component is the Tye Dashboard. With this dashboard, you can see the <strong>list of the services</strong> with their statuses. You can also view their <strong>logs</strong> and open their <strong>UI</strong> with a single click.</p>
<p>A screenshot from the Tye Dashboard:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/04-tye-dashboard.png" alt="project-tye-dashboard" /></p>
<h3>The Example Microservice Solution</h3>
<p>I’ve prepared a microservice solution for demos in this article and I will use the same solution in all demos. Here, an overall diagram of the example solution:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/05-example-microservice-solution.png" alt="example-microservice-solution" /></p>
<p>We have two web applications, two API Gateways, 5 microservices. 3 of them are shown here: Product, Ordering and Identity microservices. Every microservice has its independent SQL Server database. They communicate through REST API calls and distributed events via RabbitMQ.</p>
<h3>The Project Tye Demo</h3>
<p>You can watch my 6-minutes demo to see the Project Tye in action:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/S0-z29lMokA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<p><a href="https://www.youtube.com/watch?v=S0-z29lMokA">Click here to watch the demo on YouTube</a></p>
<h3>Tye: Shortcomings</h3>
<p>The demo shows how the Tye project is useful. However, there are many missing points and problems with the current project state. Let’s talk about them;</p>
<ul>
<li>The first problem is that it <strong>starts very slow</strong>, because every time you run it, it builds all the services. It takes more than 1 minute for a solution with only ten services.</li>
<li>It currently can run everything in your <strong>local computer</strong>. Even if you want to develop a single service, running tens of services locally consumes your system resources. You need a lot of RAM and CPU if you want to work a large solution locally.</li>
<li>The <strong>UI part</strong> is currently very simple. For example, if you want to debug one of your services by running it in Visual Studio, you need to stop all the services, change the YAML file to exclude that service from Tye, then run all the services again. Only after that you can run your service in Visual Studio to debug it as integrated to other services. Obviously this process is not easy and comfortable.</li>
<li>We can only see the application logs in the UI. <strong>More insights</strong> about the internals of services would be very helpful.</li>
<li>Tye currently has some <strong>partial documents</strong> in its GitHub repository. However, the documentation is far away from being complete.</li>
<li>Finally, and most importantly, there is <strong>no active development</strong> on the Tye project on GitHub. It was already an experimental project with its early state, as declared in its GitHub repository.</li>
</ul>
<p>So, basically, it seems Microsoft has no further interest in this project and you can expect it will be retired in the near future.</p>
<h2>ABP Studio</h2>
<p>Okay, now we came to the ABP Studio part. At <a href="https://www.volosoft.com/">Volosoft</a>, we were silently working on the ABP Studio project for more than one year.</p>
<p>ABP Studio is a <strong>cross-platform desktop application</strong> for ABP developers. It is <strong>well integrated</strong> to the ABP Framework and aims to provide a comfortable development environment for you by <strong>automating things</strong>, <strong>providing insights</strong> about your solution, making <strong>develop</strong>, <strong>run</strong> and <strong>deploy</strong> your solutions much easier.</p>
<p>We are planning to release a <strong>beta version</strong> in <strong>Q3 of 2023</strong>. You can expect the following features shipping with the initial release:</p>
<ul>
<li>You can <strong>create new ABP solutions</strong> and modules easily with a lot of options.</li>
<li>You can easily <strong>install or uninstall modules</strong> to your solution.</li>
<li>You can <strong>explore</strong> the fundamental <strong>structures</strong> of your solution or used modules, like entities, repositories, application services, UI pages, HTTP APIs, database tables and much more.</li>
<li>You can build <strong>multi-module monolith applications</strong> or distributed microservice solutions by easily adding modules and services into your solution.</li>
<li>You can easily <strong>run multiple applications</strong> and services with a single click, just like I demonstrated with the Project Tye. However, it has much more features.</li>
<li>You can run your service by <strong>integrating</strong> it into a <strong>Kubernetes</strong> cluster, so you don’t need to run all your dependencies and all other services in your local development environment. This is the essential topic of this talk and I will later demonstrate how it works.</li>
</ul>
<h2>ABP Studio Solution Runner</h2>
<p>I've prepared a demo of the ABP Studio Solution Runner, but first I want to mention the main features of the solution runner:</p>
<ul>
<li>First of all, it can run one, <strong>multiple</strong> or <strong>all services</strong> with a single click. In this way, it is very easy to stop a service, run it in Visual Studio to <strong>test</strong> or <strong>debug</strong>.</li>
<li>All the services are <strong>connected to ABP Studio</strong> and send their internal data to <strong>visualize</strong> on the ABP Studio UI.</li>
<li>In the <strong>overall view</strong>, you can see a list of services, view <strong>real-time</strong> HTTP Request and exception counts for each service.</li>
<li>You can see all details of all <strong>HTTP requests</strong> coming to any service.</li>
<li>You can see <strong>exception details</strong> as real-time in any service, easily filter and search.</li>
<li>Just like Tye, you can see the <strong>application logs</strong>. But as more, you can filter logs by log level or search in the log texts.</li>
<li>Last but not least, ABP Studio has an <strong>integrated Chrome browser</strong> inside it. You can browse the UI of your application without leaving the solution runner.</li>
</ul>
<h3>ABP Studio Solution Runner Demo</h3>
<p>You can watch my 9-minutes demo to see ABP Studio Solution Runner in action:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/sSCxyccoHqE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<p><a href="https://www.youtube.com/watch?v=sSCxyccoHqE">Click here to watch the demo on YouTube</a></p>
<h2>ABP Studio Kubernetes Tunnel</h2>
<p>Finally, we came to the essential topic I want to talk about. Until that point, we had a good understanding of the problem and possible solutions. In this part, we will make a final touch to the solution to have <strong>a great development environment for a microservice solution</strong>.</p>
<p>ABP Studio Kubernetes Tunnel System allows you to <strong>connect your local development environment to a local or remote Kubernetes cluster</strong>, where that cluster already runs your microservice solution. In this way, you can access any service in Kubernetes with their service name as DNS, just like they are running in your local computer. This is established with a secure VPN connection.</p>
<p>Secondly, you can <strong>intercept any service</strong> in that cluster, so all the <strong>traffic to the intercepted service is automatically redirected to your service</strong> that is running in your local machine. When your service needs to use any service in Kubernetes, the traffic is redirected back to the cluster, just like your local service is running inside the Kubernetes. In this way, you don’t need to care about how all other services are configured and running. You just focus on the service you are responsible for developing, testing or debugging. You can use your favorite IDE since you are running your service in your local machine as you always do.</p>
<p>The solution runner is a great way of running multiple services locally. However, if your solution consists of hundreds of services, running all them in your local machine will consume your system resources and slow down your development speed. The best news is that: You can use the <strong>Kubernetes Tunnelling combined with all the solution runner features</strong> to have a perfect local microservice development environment.</p>
<h3>How ABP Studio Kubernetes Tunnel works</h3>
<p>I am sure that you want to see it in action, but before that, let me explain how the solution works.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-06-05-Kubernetes-Integration-Abp-Studio/06-abp-studio-kubernetes-tunnel-how-it-works.png" alt="abp-studio-kubernetes-tunnel-how-it-works" /></p>
<ul>
<li><strong>Kubernetes cluster</strong> is shown on the right side and your <strong>local development machine</strong> is shown on the left side.</li>
<li>As you know, when a <strong>user requests a web page</strong> from your web application, the request is accepted by an <strong>Ingress Controller</strong> inside your Kubernetes cluster.</li>
<li>The Ingress controller forwards the request to your <strong>web application</strong>, which then uses an <strong>API gateway</strong> to consume your microservices.</li>
<li>Assume that we have the <strong>Product</strong>, <strong>Ordering</strong> and <strong>Identity</strong> microservices.</li>
<li>These microservices have their own SQL Server <strong>database</strong> and they are also using <strong>RabbitMQ</strong>, <strong>Redis</strong> and some other <strong>infrastructure services</strong>.</li>
<li>On the other hand, we want to develop, run or test our <strong>Product microservice</strong> in our <strong>own laptop</strong> using our favorite IDE, let’s say using Visual Studio.</li>
<li>If we don’t make anything special, the <strong>product microservice in the Kubernetes cluster</strong> will be used by the users, as you can expect. Even if you can somehow run the product microservice in your local computer, the Kubernetes system won’t have any knowledge about it. They are in different systems.</li>
<li>At this point, ABP Studio comes into play. When you <strong>connect</strong> to the Kubernetes cluster with ABP Studio, it first installs a <strong>VPN server</strong> into your cluster and a <strong>VPN client</strong> into your local machine.</li>
<li>Then it establishes a secure <strong>VPN tunnel</strong> between your computer and the target Kubernetes cluster. In this way, you can access all services in Kubernetes with their internal cluster IP addresses.</li>
<li>ABP Studio also installs the <strong>ABP Studio Client Proxy Server</strong> pod into the Kubernetes cluster, and the <strong>ABP Studio Proxy Client</strong> into the developer machine. It is used to collect data from the services and show them in the ABP Studio UI, like HTTP Requests, exceptions, or logs as we’ve seen in the solution runner before.</li>
<li>Finally, ABP Studio also adds <strong>DNS records to your hosts file</strong>, so you can access to internal Kubernetes services directly with their service names, in addition to their IP addresses.</li>
</ul>
<p>All of these happen when you click the Connect button on the ABP Studio. Now, your computer can use the <strong>internals of the Kubernetes cluster</strong>. But, how the HTTP Requests coming to the Product service in the Kubernetes cluster are <strong>redirected to your local machine</strong>?</p>
<ul>
<li>When you want to run and test a service locally, you <strong>intercept the matched service</strong> in the Kubernetes cluster. When you Intercept a service, ABP Studio makes some more changes in your local computer and in your Kubernetes cluster.</li>
<li>As first, it installs a <strong>pod</strong> and a <strong>service</strong> into the Kubernetes cluster to intercept the requests coming to the Product microservice and <strong>proxies the requests to</strong> a client application in <strong>your local computer</strong>.</li>
<li>The local client application then <strong>forwards requests</strong> to the Product microservice instance you are running in your local machine. In this way, whenever the Product service is used in Kubernetes, your local product service is executed. You can easily run, test or debug your service as you normally do with your standard IDE, for example with Visual Studio.</li>
<li>What happens when your local product service needs to <strong>access</strong> the SQL Server database or RabbitMQ, or another microservice in the Kubernetes cluster? It can <strong>directly use</strong> them just like local services, through the <strong>VPN tunnel</strong> we have already created.</li>
<li>ABP Studio makes a final change in your local product microservice project: It overrides all the <strong>environment variables</strong> with the ones obtained from the product service in the Kubernetes pod. In this way, your local product service instance feels itself in the Kubernetes cluster. Database connection strings and all other settings will be the same with the Kubernetes environment.</li>
</ul>
<p>Don’t worry, ABP Studio <strong>doesn’t change your local environment variables</strong>. The change only affects the live product service instance, and it is <strong>reverted</strong> when you disable the interception in ABP Studio. Also, when you click the <strong>Disconnect</strong> button in ABP Studio, all the changes made to your cluster and your local computer will be cleared. It won’t leave any sign in your systems.</p>
<h3>ABP Studio Kubernetes Tunnel Demo</h3>
<p>So, now we have a fully Kubernetes integrated development environment. Let’s see how it is used in ABP Studio in the following 9-minutes demo:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/CeUq2ysz-mQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<p><a href="https://www.youtube.com/watch?v=CeUq2ysz-mQ">Click here to watch the demo on YouTube</a></p>
<h2>ABP Studio Roadmap</h2>
<p>In the next months, the team will be working on the following items:</p>
<ul>
<li>Our first goal is to <strong>finalize and stabilize</strong> the current features. We will also <strong>document</strong> how to use them. Only after that, we will open it to customers as a beta version.</li>
<li>We’ve focused on the development part until now. We also want to add some <strong>deployment</strong> capabilities to ABP Studio in the future.</li>
<li>Another goal is to make <strong>module customizations</strong> much easier than current by the help of ABP Studio. With ABP Studio, we have completely re-though how to discover and install modules. Based on that, we will also work on a common place to publish and consume application modules for the ABP Framework.</li>
</ul>
<p>We have other great plans for that product. However, I can not declare them yet as they are secrets for now :) We’ve planned to release the first beta version in <strong>Q3 of 2023</strong>.</p>
<p>I want to notice that ABP Studio is not a new version or replacement of <strong>ABP Suite</strong>. We built the ABP Studio from scratch. Both products will be developed and shipped in parallel. ABP Suite will continue to focus on code generation. ABP Studio doesn’t have any code generation capabilities yet. So, you will use both of them together.</p>
<h2>Summary</h2>
<p>Okay let’s summarize what I’ve explained in this article:</p>
<ul>
<li>First, I explained <strong>why it is hard to set up a microservice development environment</strong>. We’ve talked about the hardness of developing, running and testing a single microservice that depends on infrastructure services and other microservices.</li>
<li>I’ve introduced <strong>Project Tye</strong>, a project developed by Microsoft to allow you to easily run multi-application solutions. We made a demo, then discussed its missing points.</li>
<li>Then I <strong>introduced ABP Studio</strong>, a new product by Volosoft for ABP developers.
As the first important feature, I explained the ABP Studio <strong>Solution Runner</strong> and demonstrated how it works and how you can develop and debug your services.</li>
<li>Finally, I introduced ABP Studio’s <strong>Kubernetes Tunneling</strong> feature. First, I explained how it works with a complicated diagram. Then I made a short demo to see it in action.</li>
</ul>
<p>With that final part, we had a <strong>great and easy to use microservice development environment</strong>. It is great, because we can focus on only a single service, while we don’t care about all other parts of the solution. Also, we can save our local development machine system resources by delegating running the dependencies to a remote Kubernetes server.</p>
<h2>See Also</h2>
<ul>
<li>ABP Dotnet Conf'23 Talk on YouTube: <a href="https://www.youtube.com/watch?v=XiPRcIHJ3NE">Kubernetes Integrated Microservice Development with ABP Studio</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a0b9cf5-589f-5255-7562-6b80a74eb310" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a0b9cf5-589f-5255-7562-6b80a74eb310" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/kubernetes-integrated-microservice-development-with-abp-studio-oix9zkp8</guid>
      <link>https://abp.io/community/videos/kubernetes-integrated-microservice-development-with-abp-studio-oix9zkp8</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp-commercial</category>
      <category>microservices</category>
      <category>kubernetes</category>
      <category>abp-studio</category>
      <title>Kubernetes Integrated Microservice Development with ABP Studio</title>
      <description>In this talk, Halil Ibrahim Kalkan will introduce an efficient way of creating a development environment that is well integrated to Kubernetes. In this way, you can just run the microservice you are building and let Kubernetes run all your dependencies in your local machine or a remote server. This talk took place in ABP .NET Conference 2023.</description>
      <pubDate>Mon, 29 May 2023 11:59:27 Z</pubDate>
      <a10:updated>2026-04-25T09:23:35Z</a10:updated>
      <content:encoded><![CDATA[In this talk, Halil Ibrahim Kalkan will introduce an efficient way of creating a development environment that is well integrated to Kubernetes. In this way, you can just run the microservice you are building and let Kubernetes run all your dependencies in your local machine or a remote server. This talk took place in ABP .NET Conference 2023. <br \> <a href="https://www.youtube.com/watch?v=XiPRcIHJ3NE" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a0b798d-7f2f-f677-15d5-72292e86cfa7" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a0b798d-7f2f-f677-15d5-72292e86cfa7" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/using-dapper-with-the-abp-framework-shp74p2l</guid>
      <link>https://abp.io/community/posts/using-dapper-with-the-abp-framework-shp74p2l</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>dapper</category>
      <category>entity-framework</category>
      <category>abp</category>
      <title>Using Dapper with the ABP Framework</title>
      <description>Dapper is a simple and lightweight object mapper for .NET. In this article, I will show how to use it in your ABP projects.</description>
      <pubDate>Fri, 31 Mar 2023 22:04:45 Z</pubDate>
      <a10:updated>2026-10-02T17:14:58Z</a10:updated>
      <content:encoded><![CDATA[<h1>Using Dapper with the ABP Framework</h1>
<p><a href="https://github.com/DapperLib/Dapper">Dapper</a> is a simple and lightweight object mapper for .NET. A key feature of Dapper is its <a href="https://github.com/DapperLib/Dapper#performance">high performance</a> compared to other ORMs. In this article, I will show how to use it in your ABP projects. But, we'll see when to use it first.</p>
<h3>Source Code</h3>
<p>You can find the <a href="https://github.com/abpframework/abp-samples/tree/master/Dapper">full source code of the demo application here</a>.</p>
<h2>When to Use Dapper?</h2>
<p>In the ABP Framework, we suggest to use Dapper in combination with Entity Framework Core (EF Core) for the following reasons:</p>
<ul>
<li>EF Core is much easier to use (you don't need to manually write SQL queries and work with low level database objects).</li>
<li>EF Core abstracts different DBMS dialects, so it will be easier to change your DBMS later.</li>
<li>The EF Core's change tracking system automatically updates the changes in the database.</li>
<li>EF Core is better compatible with Object Oriented Programming (OOP) practices and is more type safe to work with. So, the EF Core code is more understandable and maintainable.</li>
</ul>
<p>In most of your use cases, you typically work with one or a few entities and a maintainable codebase can be chosen instead of a slight performance difference. However, there may be certain places in your application where it matters:</p>
<ul>
<li>You may work with a lot of entities, so you'd like to query faster (Indeed, EF Core's <a href="https://learn.microsoft.com/en-us/ef/core/querying/tracking">AsNoTracking()</a> extension can help in most cases).</li>
<li>You may be performing too many database operations in a single request.</li>
<li>EF Core may not create an optimized SQL query and you may want to manually write it for better performance.</li>
</ul>
<p>For such cases, Dapper can be a good choice. You can easily write SQL queries and bind the result to your objects.</p>
<h2>Creating a new ABP Solution</h2>
<p>To demonstrate the useage of Dapper, I've created an ABP solution. You can find the <a href="https://github.com/abpframework/abp-samples/tree/master/Dapper">full source code of the demo application here</a>. If you want to create the same solution from scratch, follow the steps below:</p>
<p>Install the ABP CLI if you haven't installed it before:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>Create a new solution with the ABP Framework's non-layered startup template with MVC UI and EF Core database:</p>
<pre><code class="language-bash">abp new DapperDemo -t app-nolayers
</code></pre>
<blockquote>
<p>The startup template and UI selection don't matter for this article. I selected these options to keep the demo solution simple.</p>
</blockquote>
<p>After creating the solution, run the following command to migrate the database (run the command in the folder of the <code>.csproj</code> file:</p>
<pre><code class="language-csharp">dotnet run --migrate-database
</code></pre>
<blockquote>
<p>If you've created a layered solution, then run the <code>DbMigrator</code> application inside the solution. If you have trouble by creating the solution, please refer to the <a href="https://docs.abp.io/en/abp/latest/Tutorials/Todo/Single-Layer/Index">Quick Start</a> document.</p>
</blockquote>
<h2>Setting Up the Entity Framework Core Part</h2>
<p>We will use EF Core with Dapper, so we need to configure EF Core first. I will use the following <code>Book</code> entity as an example:</p>
<pre><code class="language-csharp">public class Book : AuditedAggregateRoot&lt;Guid&gt;
{
    public string Name { get; set; }
    public DateTime PublishDate { get; set; }
    public float Price { get; set; }
}
</code></pre>
<p>If you are using a layered solution, entities are located in the <code>Domain</code> project. For my demo solution, I just placed it in the <code>Entities</code> folder of the single-layer project:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-20-Dapper/book-class-in-rider.png" alt="book-class-in-rider" /></p>
<p>Once I created the <code>Book</code> entity, I should add it to my <code>DbContext</code> class:</p>
<pre><code class="language-csharp">public class DapperDemoDbContext : AbpDbContext&lt;DapperDemoDbContext&gt;
{
    // 1: ADD A DBSET PROPERTY
    public DbSet&lt;Book&gt; Books { get; set; }

    public DapperDemoDbContext(DbContextOptions&lt;DapperDemoDbContext&gt; options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        //...other code parts
        
        // 2: MAP YOUR ENTITY TO A DATABASE TABLE
        builder.Entity&lt;Book&gt;(b =&gt;
        {
            b.ToTable(&quot;Books&quot;);
            b.Property(x =&gt; x.Name).IsRequired().HasMaxLength(128);
        });
    }
}

</code></pre>
<p>Now, we can add a new database migration:</p>
<pre><code class="language-bash">dotnet ef migrations add Added_Book
</code></pre>
<p>And apply the changes to the database:</p>
<pre><code class="language-bash">dotnet ef database update
</code></pre>
<p>At this point, you should be able to see the Books table if you check your database:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-20-Dapper/book-database-table.png" alt="book-database-table" /></p>
<blockquote>
<p>As you see, the <code>Books</code> table contains more fields than the <code>Book</code> entity's property count. Other properties are inherited from the <code>AuditedAggregateRoot</code> table. You could inherit from the <code>BasicAggregateRoot</code> class if you don't want these properties.</p>
</blockquote>
<h2>Seeding the Database</h2>
<p>ABP's <a href="https://docs.abp.io/en/abp/latest/Data-Seeding">data seeding</a> system is a great way to add some test data to the database. The following class inserts two books to the <code>Books</code> table when I migrate the database:</p>
<pre><code class="language-csharp">public class DapperDemoDataSeederContributor : IDataSeedContributor, ITransientDependency
{
    private readonly IRepository&lt;Book, Guid&gt; _bookRepository;

    public DapperDemoDataSeederContributor(IRepository&lt;Book, Guid&gt; bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public async Task SeedAsync(DataSeedContext context)
    {
        if (await _bookRepository.GetCountAsync() &gt; 0)
        {
            return;
        }

        await _bookRepository.InsertAsync(
            new Book
            {
                Name = &quot;1984&quot;,
                PublishDate = new DateTime(1949, 6, 8),
                Price = 19.84f
            }
        );

        await _bookRepository.InsertAsync(
            new Book
            {
                Name = &quot;The Hitchhiker's Guide to the Galaxy&quot;,
                PublishDate = new DateTime(1995, 9, 27),
                Price = 42.0f
            }
        );
    }
}
</code></pre>
<p>After creating the <code>DapperDemoDataSeederContributor</code> class, I can re-run the following command:</p>
<pre><code class="language-bash">dotnet run --migrate-database
</code></pre>
<p>Now, I can see the records in the database:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-20-Dapper/book-table-data.png" alt="book-table-data" /></p>
<p>Now, everything is ready to try querying from the <code>Books</code> table with Dapper.</p>
<h2>Using Dapper Without the Integration Package</h2>
<p>ABP provides an integration package for Dapper. However, I first want to demonstrate using Dapper without the integration package.</p>
<h3>Installing the Dapper Package</h3>
<p>First, install the <a href="https://www.nuget.org/packages/Dapper">Dapper</a> package to your project. You can use a command-line terminal, locate the root path of your project (<code>.csproj</code> file that you want to install it in) and run the following command:</p>
<pre><code class="language-bash">dotnet add package Dapper
</code></pre>
<blockquote>
<p>If your application is layered, then we suggest to add the <code>Dapper</code> package to your <code>EntityFrameworkCore</code> integration project in your solution.</p>
</blockquote>
<h3>Executing a Dapper Query</h3>
<p>I will query from the <code>Books</code> table, but I don't want to use the <code>Book</code> entity to map the result (because I don't need all the properties). So, I am creating a new class for the query result:</p>
<pre><code class="language-csharp">public class BookDataView
{
    public Guid Id { get; set; }    
    public string Name { get; set; }
    public float Price { get; set; }
}
</code></pre>
<p>Now, we can use Dapper's <code>QueryAsync</code> extension method as shown below:</p>
<pre><code class="language-csharp">public class DemoService : ITransientDependency
{
    private readonly IRepository&lt;Book, Guid&gt; _bookRepository;

    public DemoService(IRepository&lt;Book, Guid&gt; bookRepository)
    {
        _bookRepository = bookRepository;
    }
    
    [UnitOfWork]
    public virtual async Task&lt;List&lt;BookDataView&gt;&gt; GetListAsync()
    {
        var database = (await _bookRepository.GetDbContextAsync()).Database;
        var dbConnection = database.GetDbConnection();
        var dbTransaction = database.CurrentTransaction?.GetDbTransaction();
        
        var queryResult = await dbConnection.QueryAsync&lt;BookDataView&gt;(
            &quot;SELECT Id, Name, Price FROM Books&quot;,
            transaction: dbTransaction
        );
        
        return queryResult.ToList();
    }
}
</code></pre>
<p>Let's examine this class:</p>
<ul>
<li>I've injected the ABP's standard <a href="https://docs.abp.io/en/abp/latest/Repositories">generic repository</a> service into the <code>DemoService</code> constructor.</li>
<li><code>_bookRepository.GetDbContextAsync()</code> returns the underlying <code>DbContext</code> object of EF Core. We need to have the <a href="https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore">Volo.Abp.EntityFrameworkCore</a> package reference to be able to access that method. If you have created a single-layer solution, the reference will already have existed. If you have created a layered solution you may need to manually add this package to the project that contains the <code>DemoService</code> class. Because the layered solution isolates the EF Core dependency from the rest of the solution.</li>
<li>Dapper needs a <code>DbConnection</code> and a <code>DbTransaction</code> object (as optional) to execute a query. We are getting them over the <code>database</code> object obtained from the <code>DbContext</code>. We suggest to always pass the current <code>DbTransaction</code> object while working with Dapper. Because, if there is a database transaction on the same database connection that you execute queries on, and you don't pass the transaction object, you'll get an exception.</li>
<li>Finally, we can use Dapper's <code>QueryAsync</code> extension method to execute the database query.</li>
<li>Notice that the <code>GetListAsync</code> method is made as <code>virtual</code> and marked with the <code>UnitOfWork</code> attribute to enable the <a href="https://docs.abp.io/en/abp/latest/Unit-Of-Work">Unit Of Work</a> for that method. It ensures the database connection is available in the body of the <code>GetListAsync</code> method.</li>
</ul>
<p>That's all. You can execute any Dapper operation using the <code>DbConnection</code> and <code>DbTransaction</code> objects obtained from the <code>_bookRepository</code> object. Please refer to Dapper's documentation for other operations.</p>
<blockquote>
<p>We've obtained the <code>DbContext</code> object from a repository. However, a repository is not required to obtain a <code>DbContext</code>. Instead, you could inject the <code>IDbContextProvider&lt;T&gt;</code> service (<code>IDbContextProvider&lt;DapperDemoDbContext&gt;</code> for this demo) and call its <code>GetDbContextAsync</code> method.</p>
</blockquote>
<h2>Using the Volo.Abp.Dapper Package</h2>
<p>In the previous section, you saw that you don't need an ABP integration package to be able to use Dapper in your ABP applications. However, there is an integration package here: <a href="https://www.nuget.org/packages/Volo.Abp.Dapper">Volo.Abp.Dapper</a>. In fact, that package doesn't contain much services. It just provides a convenient base class to create Dapper based repository classes.</p>
<h3>Installing the Volo.Abp.Dapper Package</h3>
<p>You can use the <a href="https://docs.abp.io/en/abp/latest/CLI#add-package">ABP CLI</a> to easily install ABP packages to your projects. Execute the following command in the folder of the <code>.csproj</code> file that you want to install the package on:</p>
<pre><code class="language-bash">abp add-package Volo.Abp.Dapper
</code></pre>
<blockquote>
<p>You can check the <a href="https://docs.abp.io/en/abp/latest/Dapper">ABP Dapper document</a> for alternative installation options.</p>
</blockquote>
<h3>Creating a Repository Class</h3>
<p>In the <code>DemoService</code> example, we used database objects out of a <a href="https://docs.abp.io/en/abp/latest/Repositories">repository</a> class. If you want to implement layering to your solution and abstracting database operations, it can be better to create a repository class to execute the Dapper operations.</p>
<p>Here's a repository class that executes the same database query:</p>
<pre><code class="language-csharp">public class BookRepository : DapperRepository&lt;DapperDemoDbContext&gt;, ITransientDependency
{
    public BookRepository(IDbContextProvider&lt;DapperDemoDbContext&gt; dbContextProvider) 
        : base(dbContextProvider)
    {
    }
    
    public virtual async Task&lt;List&lt;BookDataView&gt;&gt; GetListAsync()
    {
        var connection = await GetDbConnectionAsync();
        var queryResult = await connection.QueryAsync&lt;BookDataView&gt;(
            &quot;SELECT Id, Name, Price FROM Books&quot;,
            transaction: await GetDbTransactionAsync()
        );
        return queryResult.ToList();
    }
}
</code></pre>
<p>Let's examine this class:</p>
<ul>
<li>It inherits from the <code>DapperRepository</code> class, which provides useful methods and properties for database operations. It also implements the <code>IUnitOfWorkEnabled</code> interface, so ABP makes the database connection (and transaction if requested) available in the method body by implementing dynamic proxies (a.k.a. interception).</li>
<li>The <code>GetListAsync</code> method's been made <code>virtual</code>.  That's needed to make the interception process working. It wouldn't be needed if we introduce <code>IBookRepository</code> to that class and always use it by injecting the <code>BookRepository</code> class (in this case, it will use interface proxying - however, this is too much details for the purpose of this article).</li>
<li>We've used the <code>GetDbConnectionAsync</code> and <code>GetDbTransactionAsync</code> methods to obtain the current database connection and transaction (that is managed by ABP's <a href="https://docs.abp.io/en/abp/latest/Unit-Of-Work">unit of work</a> system).</li>
</ul>
<p>You can then inject the <code>BookRepository</code> class when you want to get a list of <code>BookDataView</code> whenever it is needed. In the demo project, I used it inside the <code>IndexModel.cshtml.cs</code> to show a list of books on the page:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-20-Dapper/list-of-books.png" alt="list-of-books" /></p>
<h2>Conclusion</h2>
<p>In this article, I've explained ABP's Dapper integration and demonstrated how you can execute Dapper operations in your applications. I suggest to use Dapper when it is really needed and adds any significant value (generally a performance gain) to your application. Otherwise, EF Core is much more convenient for most of the database operations and you will have a more maintainable codebase using EF Core.</p>
<h2>Source Code</h2>
<p>You can find the <a href="https://github.com/abpframework/abp-samples/tree/master/Dapper">full source code of the demo application here</a>.</p>
<h2>See Also</h2>
<ul>
<li><a href="https://docs.abp.io/en/abp/latest/Dapper">ABP Dapper documentation</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a0a4be0-76bb-b24b-2b28-339a2be41fe7" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a0a4be0-76bb-b24b-2b28-339a2be41fe7" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-7.1-final-has-been-released-5ofg7w92</guid>
      <link>https://abp.io/community/posts/abp.io-platform-7.1-final-has-been-released-5ofg7w92</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 7.1 Final Has Been Released</title>
      <description>Introducing the ABP.IO Platform version 7.1!</description>
      <pubDate>Thu, 23 Mar 2023 12:15:36 Z</pubDate>
      <a10:updated>2026-10-02T18:22:41Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 7.1 versions have been released today.</p>
<h2>What's New With Version 7.1?</h2>
<p>All the new features were already explained in detail in the <a href="https://blog.abp.io/abp/ABP.IO-Platform-7.1-RC-Has-Been-Published">7.1 RC Announcement Post</a>, so no need to go over them again. Check it out for more details.</p>
<h2>Getting Started with 7.1</h2>
<h3>Creating New Solutions</h3>
<p>You can create a new solution with the ABP Framework version 7.1 by either using the <code>abp new</code> command or generating the CLI command on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for more.</p>
</blockquote>
<h3>How to Upgrade an Existing Solution</h3>
<h4>Install/Update the ABP CLI</h4>
<p>First of all, install the ABP CLI or upgrade it to the latest version.</p>
<p>If you haven't installed it yet:</p>
<pre><code class="language-bash">
dotnet tool install -g Volo.Abp.Cli

</code></pre>
<p>To update the existing CLI:</p>
<pre><code class="language-bash">
dotnet tool update -g Volo.Abp.Cli

</code></pre>
<h4>Upgrading Existing Solutions with the ABP Update Command</h4>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">
abp update

</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>Migration Guides</h2>
<p>This version includes a very minor breaking change and it doesn't affect most of the applications. Check <a href="https://docs.abp.io/en/abp/7.1/Migration-Guides/Abp-7_1">the migration guide</a> for the details.</p>
<h2>Community News</h2>
<h2>ABP Community Talks 2023.2</h2>
<p>The next ABP Community Talks will take place on March 30, at 18:00 (UTC).</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-23-abpio-platform-71-final-has-been-released/3a0a20886e5c7ab36bd0475a9674495e.png" alt="abp-comm-talks-2023-2.png" /></p>
<p>In this episode, core ABP Framework developers will discuss the benefits of using the ABP Framework as a .NET developer instead of creating your own solution from scratch. They will answer most of the common doubts about using ABP and application frameworks in general. You will better understand how ABP makes a developer’s life easier and more enjoyable while cutting production costs. We will also have a question - answer session after the talk, as always. I think this talk will be useful for every .NET developer whether they use ABP or not.</p>
<p><strong><a href="https://kommunity.com/volosoft/events/abp-community-talks-20232-why-use-abp-framework-as-a-net-developer-e3254183">CLICK HERE to register for the event and join us</a></strong>.</p>
<h2>Introducing the first ABP .NET Conference!</h2>
<p>As the ABP team, we've executed more than 10 <a href="https://community.abp.io/events">online events</a> and gained a good experience of software talks. In May, we are organizing a full-featured software conference, named <strong>ABP Dotnet Conference 2023</strong>!</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2023-03-23-abpio-platform-71-final-has-been-released/3a0a208890e0a0bd9a8348c07e9ca0d1.png" alt="abp-conf-2023.png" /></p>
<p>We are still organizing the speakers, talks and schedule. There will be 12 sessions about software development and .NET. These will also include a few ABP-related talks. You can <strong>follow https://abp.io/conference website</strong> and buy early bird tickets from now.</p>
<h3>New ABP Community Posts</h3>
<p>There are exciting articles contributed by the ABP community as always. I will highlight some of them here:</p>
<ul>
<li><p><a href="https://community.abp.io/posts/creating-dockerfile-for-abp-applications-caj4fkxa">Creating Dockerfile for ABP Applications</a> by <a href="https://community.abp.io/members/antosubash">Anto Subash</a></p>
</li>
<li><p><a href="https://community.abp.io/posts/identityuser-relationship-and-extending-it-xtv79mpx">IdentityUser Relationship and Extending it</a> by <a href="https://community.abp.io/members/onurpicakci">Onur Pıçakçı</a></p>
</li>
<li><p><a href="https://community.abp.io/posts/streamline-localization-in-your-abp-project-1t12rmjc">Streamline Localization in Your ABP Project</a> by <a href="https://community.abp.io/members/salih">Salih Özkara</a></p>
</li>
<li><p><a href="https://community.abp.io/posts/.net-microservice-template-with-abp-53r52ryy">.Net Microservice template with ABP</a> by <a href="https://community.abp.io/members/antosubash">Anto Subash</a></p>
</li>
</ul>
<p>Thanks to the ABP Community for all the content they have published. You can also <a href="https://community.abp.io/articles/submit">post your ABP related (text or video) content</a> to the ABP Community.</p>
<h2>About the Next Version</h2>
<p>The next feature version will be 7.2. You can follow the <a href="https://github.com/abpframework/abp/milestones">release planning here</a>. Please <a href="https://github.com/abpframework/abp/issues/new">submit an issue</a> if you have any problems with this version.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a0a2092-3475-a40b-9604-7a937c52477a" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a0a2092-3475-a40b-9604-7a937c52477a" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/authorization-in-a-microservice-distributed-system-02eguc3e</guid>
      <link>https://abp.io/community/videos/authorization-in-a-microservice-distributed-system-02eguc3e</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>authorization</category>
      <category>microservices</category>
      <category>authentication</category>
      <category>architecture</category>
      <category>security</category>
      <title>Authorization in a Microservice / Distributed System</title>
      <description>In this session at Dotnet Conf 2022, I've talked about the requirements and challenges of performing authorization in microservice / distributed systems, and how to overcome these difficulties and how we've done it with the ABP Framework.</description>
      <pubDate>Mon, 05 Dec 2022 06:08:44 Z</pubDate>
      <a10:updated>2026-04-23T02:51:52Z</a10:updated>
      <content:encoded><![CDATA[In this session at Dotnet Conf 2022, I've talked about the requirements and challenges of performing authorization in microservice / distributed systems, and how to overcome these difficulties and how we've done it with the ABP Framework. <br \> <a href="https://www.youtube.com/watch?v=DVqvRZ0w-7g" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/6c323fb5-6a98-43c4-585f-3a07f31381f7" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/6c323fb5-6a98-43c4-585f-3a07f31381f7" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/highlights-for-asp.net-core-entity-framework-core-features-shipped-with-.net-7.0-s43fp24e</guid>
      <link>https://abp.io/community/posts/highlights-for-asp.net-core-entity-framework-core-features-shipped-with-.net-7.0-s43fp24e</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>entity-framework</category>
      <category>aspnetcore</category>
      <title>Highlights for ASP.NET Core &amp; Entity Framework Core features shipped with .NET 7.0</title>
      <description>The Volosoft Team has created 13 great articles to highlight the important features coming with ASP.NET Core 7.0 and Entity Framework Core 7.0.</description>
      <pubDate>Wed, 30 Nov 2022 11:49:54 Z</pubDate>
      <content:encoded><![CDATA[<p>As Volosoft, we are passionate about technology and tools we work on. Since our open source and commercial developer platforms are based on Microsoft's .NET technology, we are closely following the .NET team for new releases, features and improvements made in each release.</p>
<p>In November 2022, exciting things happened in the .NET world.</p>
<h2>.NET Conf 2022</h2>
<p>Microsoft has organized the <a href="https://www.dotnetconf.net/">.NET Conf 2022</a> between November 08 and 10 as an online event. There were many <a href="https://www.dotnetconf.net/speakers">speakers</a> talked in that conference from all around the World. If you've missed, you can watch <a href="https://www.youtube.com/watch?v=8V_BUGFKdaI&amp;list=PLdo4fOcmZ0oVlqu_V8EXUDDnPsYwemxjn">all the sessions on YouTube</a>.</p>
<p>Halil İbrahim Kalkan (co-founder of Volosoft) has also talked in the .NET Conf 2022 about &quot;Authorization in a Distributed / Microservice System&quot;.</p>
<p><img src="/api/posts/migrated-images/e9df46a2b3ff09326a303a07da8bb1b9.jpg" alt="halil-talk.jpg" /></p>
<p>You can <a href="https://www.youtube.com/watch?v=DVqvRZ0w-7g&amp;list=PLdo4fOcmZ0oVlqu_V8EXUDDnPsYwemxjn&amp;index=55">watch Halil's talk here</a>.</p>
<h2>What's new with ASP.NET &amp; Entity Framework Core 7.0</h2>
<p>Microsoft has released the .NET 7.0 in the .NET Conf 2022, with ASP.NET Core 7.0 and Entity Framework Core 7.0.</p>
<p>Our team has closely followed the ASP.NET Core and Entity Framework Core 7.0 releases, read Microsoft's guides and documentation and adapt the changes to our <a href="https://abp.io/">ABP.IO Platform</a>. We are proud to say that <a href="https://blog.abp.io/abp/ABP.IO-Platform-7.0-RC-Has-Been-Published">we've shipped</a> the ABP 7.0 RC.1 based on .NET 7.0 just after Microsoft's .NET 7.0 release.</p>
<p>In addition to the ABP's .NET 7.0 upgrade, the team has created 13 great articles to highlight the important features coming with ASP.NET Core 7.0 and Entity Framework Core 7.0. Here, a list of all the articles:</p>
<h3>ASP.NET Core 7.0</h3>
<ul>
<li><strong><a href="https://community.abp.io/posts/whats-new-with-.net-7-tlq2g43w">What's new with .NET 7.0</a></strong> by <a href="https://community.abp.io/members/EngincanV">Engincan Veske</a></li>
<li><strong><a href="https://community.abp.io/posts/grpc-json-transcoding-with-asp.net-core-7.0-16eai2zw">gRPC JSON Transcoding with ASP.NET Core 7.0</a></strong> by <a href="https://community.abp.io/members/EngincanV">Engincan Veske</a></li>
<li><strong><a href="https://community.abp.io/posts/grpc-health-checks-with-asp.net-core-7.0-kwnjkun1">gRPC Health Checks with ASP.NET Core 7.0</a></strong> by <a href="https://community.abp.io/members/m_aliozkaya@hotmail.com">Muhammet Ali Özkaya</a></li>
<li><strong><a href="https://community.abp.io/posts/signalr-client-results-in-asp.net-core-7.0-83msge7d">Signalr Client Results in ASP.NET Core 7.0</a></strong> by <a href="https://community.abp.io/members/liangshiwei">Liang Shiwei</a></li>
<li><strong><a href="https://community.abp.io/posts/rate-limiting-with-asp.net-core-7.0-co55vem3">Rate Limiting with ASP.NET Core 7.0</a></strong> by <a href="https://community.abp.io/members/berkansasmaz">Berkan Şaşmaz</a></li>
<li><strong><a href="https://community.abp.io/posts/asp.net-core-7.0-output-caching-middleware-4ffg29la">ASP.NET Core Output Caching Middleware</a></strong> by <a href="https://community.abp.io/members/malik.masis">Malik Masis</a></li>
</ul>
<h3>Entity Framework 7.0</h3>
<ul>
<li><strong><a href="https://community.abp.io/posts/injecting-service-dependencies-to-entities-with-entity-framework-core-7.0-db6vdh4s">Injecting Service Dependencies to Entities with Entity Framework Core 7.0</a></strong> by <a href="https://community.abp.io/members/hikalkan">Halil İbrahim Kalkan</a></li>
<li><strong><a href="https://community.abp.io/posts/the-new-ef-core-interceptors-in-entity-framework-core-7.0-gzpm29hp">The new EF Core interceptors in Entity Framework Core 7.0</a></strong> by <a href="https://community.abp.io/members/maliming">Liming Ma</a></li>
<li><strong><a href="https://community.abp.io/posts/inheritance-strategies-in-entity-framework-core-7-hg82tp4h">Inheritance Strategies in Entity Framework Core 7</a></strong> by <a href="https://community.abp.io/members/alper">Alper Ebiçoğlu</a></li>
<li><strong><a href="https://community.abp.io/posts/json-columns-in-entity-framework-core-7-cjaom76j">JSON Columns in Entity Framework Core 7</a></strong> by <a href="https://community.abp.io/members/salih">Salih Özkara</a></li>
<li><strong><a href="https://community.abp.io/posts/model-building-conventions-in-entity-framework-core-7.0-vo0hk68e">Model building conventions in Entity Framework Core 7.0</a></strong> by <a href="https://community.abp.io/members/ismcagdas">İsmail Çağdaş</a></li>
<li><strong><a href="https://community.abp.io/posts/value-generation-for-ddd-guarded-types-with-entity-framework-core-7.0-ll9qg37b">Value generation for DDD guarded types with Entity Framework Core 7.0</a></strong> by <a href="https://community.abp.io/members/gterdem">Galip Erdem</a></li>
<li><strong><a href="https://community.abp.io/posts/bulk-operations-with-entity-framework-core-7.0-zvr01mtn">Bulk Operations with Entity Framework Core 7.0</a></strong> by <a href="https://community.abp.io/members/enisn">Enis Necipoğlu</a></li>
</ul>
<p>We enjoyed while writing these, we hope you also enjoy and like while reading. Happy coding!</p>
<p>-- The Volosoft Team</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/ffa2410a-440c-1e33-1880-3a07da8c1131" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/ffa2410a-440c-1e33-1880-3a07da8c1131" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/injecting-service-dependencies-to-entities-with-entity-framework-core-7.0-db6vdh4s</guid>
      <link>https://abp.io/community/posts/injecting-service-dependencies-to-entities-with-entity-framework-core-7.0-db6vdh4s</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>dependency-injection</category>
      <category>entity-framework-core</category>
      <category>ddd</category>
      <category>dotnet7</category>
      <title>Injecting Service Dependencies to Entities with Entity Framework Core 7.0</title>
      <description>Why we may need to have references to other services in an entity class and how we can implement Entity Framework Core's new IMaterializationInterceptor interface.</description>
      <pubDate>Mon, 28 Nov 2022 10:29:37 Z</pubDate>
      <a10:updated>2026-10-02T16:18:22Z</a10:updated>
      <content:encoded><![CDATA[<h1>Injecting Service Dependencies to Entities with Entity Framework Core 7.0</h1>
<p><a href="https://docs.abp.io/en/abp/latest/Dependency-Injection">Dependency injection</a> is a widely-used pattern of obtaining references to other services from our classes. It is a built-in feature when you develop ASP.NET Core applications. In this article, I will explain why we may need to have references to other services in an entity class and how we can implement Entity Framework Core's new <code>IMaterializationInterceptor</code> interface to provide these services to the entities using the standard dependency injection system.</p>
<blockquote>
<p>You can find the source code of the example application <a href="https://github.com/abpframework/abp-samples/tree/master/EfCoreEntityDependencyInjectionDemo">here</a>.</p>
</blockquote>
<h2>The Problem</h2>
<p>While developing applications based on <a href="https://docs.abp.io/en/abp/latest/Domain-Driven-Design">Domain-Driven Design</a> (DDD) patterns, we typically write our business code inside <a href="https://docs.abp.io/en/abp/latest/Application-Services">application services</a>, <a href="https://docs.abp.io/en/abp/latest/Domain-Services">domain services</a> and <a href="https://docs.abp.io/en/abp/latest/Entities">entities</a>. Since the application and domain service instances are created by the dependency injection system, they can inject services into their constructors.</p>
<p>Here, an example domain service that injects a repository into its constructor:</p>
<pre><code class="language-csharp">public class ProductManager : DomainService
{
    private readonly IRepository&lt;Product, Guid&gt; _productRepository;

    public ProductManager(IRepository&lt;Product, Guid&gt; productRepository)
    {
        _productRepository = productRepository;
    }

    //...
}
</code></pre>
<p><code>ProductManager</code> can then use the <code>_productRepository</code> object in its methods to perform its business logic. In the following example, <code>ChangeCodeAsync</code> method is used to change a product's code (the <code>ProductCode</code> property) by ensuring uniqueness of product codes in the system:</p>
<pre><code class="language-csharp">public class ProductManager : DomainService
{
    private readonly IRepository&lt;Product, Guid&gt; _productRepository;

    public ProductManager(IRepository&lt;Product, Guid&gt; productRepository)
    {
        _productRepository = productRepository;
    }

    public async Task ChangeCodeAsync(Product product, string newProductCode)
    {
        Check.NotNull(product, nameof(product));
        Check.NotNullOrWhiteSpace(newProductCode, nameof(newProductCode));

        if (product.ProductCode == newProductCode)
        {
            return;
        }
        
        if (await _productRepository.AnyAsync(x =&gt; x.ProductCode == newProductCode))
        {
            throw new ApplicationException(
                &quot;Product code is already used: &quot; + newProductCode);
        }

        product.ProductCode = newProductCode;
    }
}
</code></pre>
<p>Here, the <code>ProductManager</code> forces the rule &quot;product code must be unique&quot;. Let's see the <code>Product</code> entity class too:</p>
<pre><code class="language-csharp">public class Product : AuditedAggregateRoot&lt;Guid&gt;
{
    public string ProductCode { get; internal set; }
    
    public string Name { get; private set; }
    
    private Product()
    {
        /* This constructor is used by EF Core while
           getting the Product from database */
    }
    
    /* Primary constructor that should be used in the application code */
    public Product(string productCode, string name)
    {
        ProductCode = Check.NotNullOrWhiteSpace(productCode, nameof(productCode));
        Name = Check.NotNullOrWhiteSpace(name, nameof(name));
    }
}
</code></pre>
<p>You see that the <code>ProductCode</code> property's setter is <code>internal</code>, which makes possible to set it from the <code>ProductManager</code> class as shown before.</p>
<p>This design has a problem: We had to make the <code>ProductCode</code> setter <code>internal</code>. Now, any developer may forget to use the <code>ProductManager.ChangeCodeAsync</code> method, and can directly set the <code>ProductCode</code> on the entity. So, we can't completely force the &quot;product code must be unique&quot; rule.</p>
<p>It would be better to move the <code>ChangeCodeAsync</code> method into the <code>Product</code> class and make the <code>ProductCode</code> property's setter <code>private</code>:</p>
<pre><code class="language-csharp">public class Product : AuditedAggregateRoot&lt;Guid&gt;
{
    public string ProductCode { get; private set; }
    
    public string Name { get; private set; }
    
    // ...
    
    public async Task ChangeCodeAsync(string newProductCode)
    {
        Check.NotNullOrWhiteSpace(newProductCode, nameof(newProductCode));

        if (newProductCode == ProductCode)
        {
            return;
        }
        
        /* ??? HOW TO INJECT THE PRODUCT REPOSITORY HERE ??? */        
        if (await _productRepository.AnyAsync(x =&gt; x.ProductCode == newProductCode))
        {
            throw new ApplicationException(&quot;Product code is already used: &quot; + newProductCode);
        }
        
        ProductCode = newProductCode;
    }
}
</code></pre>
<p>With that design, there is no way to set the <code>ProductCode</code> without applying the rule &quot;product code must be unique&quot;. Great! But we have a problem: An entity class can not inject dependencies into its constructor, because an entity is not created using the dependency injection system. There are two common points of creating an entity:</p>
<ul>
<li>We can create an entity in our application code, using the standard <code>new</code> keyword, like <code>var product = new Product(...);</code>.</li>
<li>Entity Framework (and any other ORM / database provider) creates entities after getting them from the database. They typically use the empty (default) constructor of the entity to create it, then sets the properties coming from the database query.</li>
</ul>
<p>So, how we can use the product repository in the <code>Product.ChangeCodeAsync</code> method? If we forget the dependency injection system, we would think to add the repository as a parameter to the <code>ChangeCodeAsync</code> method and delegate the responsibility of obtaining the service reference to the caller of that method:</p>
<pre><code class="language-csharp">public async Task ChangeCodeAsync(
    IRepository&lt;Product, Guid&gt; productRepository, string newProductCode)
{
    Check.NotNull(productRepository, nameof(productRepository));
    Check.NotNullOrWhiteSpace(newProductCode, nameof(newProductCode));

    if (newProductCode == ProductCode)
    {
        return;
    }

    if (await productRepository.AnyAsync(x =&gt; x.ProductCode == newProductCode))
    {
        throw new ApplicationException(
            &quot;Product code is already used: &quot; + newProductCode);
    }
    
    ProductCode = newProductCode;
}
</code></pre>
<p>However, that design would make hard to use the <code>ChangeCodeAsync</code> method, and also exposes its internal dependencies to outside. If we need another dependency in the <code>ChangeCodeAsync</code> method later, we should add another parameter, which will effect all the application code that uses the <code>ChangeCodeAsync</code> method. I think that's not reasonable. The next section offers a better and a more generic solution to the problem.</p>
<h2>The Solution</h2>
<p>First of all, we can introduce an interface that should be implemented by the entity classes which needs to use services in their methods:</p>
<pre><code class="language-csharp">public interface IInjectServiceProvider
{
     ICachedServiceProvider ServiceProvider { get; set; }
}
</code></pre>
<p><code>ICachedServiceProvider</code> is a service that is provided by the ABP Framework. It extends the standard <code>IServiceProvider</code>, but caches the resolved services. Basically, it internally resolves a service only a single time, even if you resolve the service from it multiple times. The <code>ICachedServiceProvider</code> service itself is a scoped service, means it is created only once in a scope. We can use it to optimize the service resolution, however, the standard <code>IServiceProvider</code> would work as expected.</p>
<p>Next, we can implement the <code>IInjectServiceProvider</code> for our <code>Product</code> entity:</p>
<pre><code class="language-csharp">public class Product : AuditedAggregateRoot&lt;Guid&gt;, IInjectServiceProvider
{
    public ICachedServiceProvider ServiceProvider { get; set; }

    //...
}
</code></pre>
<p>I will explain how to set the <code>ServiceProvider</code> property later, but first see how to use it in our <code>Product.ChangeCodeAsync</code> method. Here, the final <code>Product</code> class:</p>
<pre><code class="language-csharp">public class Product : AuditedAggregateRoot&lt;Guid&gt;, IInjectServiceProvider
{
    public string ProductCode { get; internal set; }
    
    public string Name { get; private set; }
    
    public ICachedServiceProvider ServiceProvider { get; set; }

    private Product()
    {
        /* This constructor is used by EF Core while
           getting the Product from database */
    }
    
    /* Primary constructor that should be used in the application code */
    public Product(string productCode, string name)
    {
        ProductCode = Check.NotNullOrWhiteSpace(productCode, nameof(productCode));
        Name = Check.NotNullOrWhiteSpace(name, nameof(name));
    }
    
    public async Task ChangeCodeAsync(string newProductCode)
    {
        Check.NotNullOrWhiteSpace(newProductCode, nameof(newProductCode));

        if (newProductCode == ProductCode)
        {
            return;
        }

        var productRepository = ServiceProvider
            .GetRequiredService&lt;IRepository&lt;Product, Guid&gt;&gt;();
        
        if (await productRepository.AnyAsync(x =&gt; x.ProductCode == newProductCode))
        {
            throw new ApplicationException(&quot;Product code is already used: &quot; + newProductCode);
        }
        
        ProductCode = newProductCode;
    }
}
</code></pre>
<p>The <code>ChangeCodeAsync</code> method gets the product repository from the <code>ServiceProvider</code> and uses it to check if there is another product with the given <code>newProductCode</code> value.</p>
<p>Now, let's explain how to set the <code>ServiceProvider</code> value...</p>
<h3>Entity Framework Core Configuration</h3>
<p>Entity Framework 7.0 introduces the <code>IMaterializationInterceptor</code> interceptor that allows us to manipulate an entity object just after the entity object is created as a result of database query.</p>
<p>We can write the following interceptor that sets the <code>ServiceProvider</code> property of an entity, if it implements the <code>IInjectServiceProvider</code> interface:</p>
<pre><code class="language-csharp">public class ServiceProviderInterceptor : IMaterializationInterceptor
{
    public object InitializedInstance(
        MaterializationInterceptionData materializationData, 
        object instance)
    {
        if (instance is IInjectServiceProvider entity)
        {
            entity.ServiceProvider = materializationData
                .Context
                .GetService&lt;ICachedServiceProvider&gt;();
        }

        return instance;
    }
}
</code></pre>
<blockquote>
<p>Lifetime of the resolved services are tied to the lifetime of the related <code>DbContext</code> instance. So, you don't need to care if the resolved dependencies are disposed. ABP's <a href="https://docs.abp.io/en/abp/latest/Unit-Of-Work">unit of work</a> system already disposes the <code>DbContext</code> instance when the unit of work is completed.</p>
</blockquote>
<p>Once we defined such an interceptor, we should configure our <code>DbContext</code> class to use it. You can do it by overriding the <code>OnConfiguring</code> method in your <code>DbContext</code> class:</p>
<pre><code class="language-csharp">protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.AddInterceptors(new ServiceProviderInterceptor());
}
</code></pre>
<p>Finally, you should ignore the <code>ServiceProvider</code> property in your entity mapping configuration in your <code>DbContext</code> (because we don't want to map it to a database table field):</p>
<pre><code class="language-csharp">protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    // ...
    builder.Entity&lt;Product&gt;(b =&gt;
    {
        // ...
        /* We should ignore the ServiceProvider on mapping! */
        b.Ignore(x =&gt; x.ServiceProvider);
    });
}
</code></pre>
<p>That's all. From now, EF Core will set the <code>ServiceProvider</code> property for you.</p>
<h3>Manually Creating Entities</h3>
<p>While EF Core seamlessly set the <code>ServiceProvider</code> property while getting entities from database, you should still set it manually while creating new entities yourself.</p>
<p><strong>Example: Set <code>ServiceProvider</code> property while creating a new Product entity:</strong></p>
<pre><code class="language-csharp">public async Task CreateAsync(CreateProductDto input)
{
    var product = new Product(input.ProductCode, input.Name)
    {
        ServiceProvider = _cachedServiceProvider
    };
    
    await _productRepository.InsertAsync(product);
}
</code></pre>
<p>Here, you may think that it is not necessary to set the <code>ServiceProvider</code>, because we haven't used the <code>ChangeCodeAsync</code> method. You are definitely right; It is not needed in this example, because it is clear to see the entity object is not used between the entity creation and saving it to the database. However, if you call a method of the entity, or pass it to another service before inserting into the database, you may not know if the <code>ServiceProvider</code> will be needed. So, you should carefully use it.</p>
<p>Basically, I've introduced the problem and the solution. In the next section, I will explain some limitations of that design and some of my other thoughts.</p>
<h2>Discussions</h2>
<p>In this section, I will first discuss a slightly different way of obtaining services. Then I will explain limitations and problems of injecting services into entities.</p>
<h3>Why injected a service provider, but not the services?</h3>
<p>As an obvious question, you may ask why we've property-injected a service provider object, then resolved the services manually. Can't we directly property-inject our dependencies?</p>
<p><strong>Example: Property-inject the <code>IRepository&lt;Product, Guid&gt;</code> service:</strong></p>
<pre><code class="language-csharp">public class Product : AuditedAggregateRoot&lt;Guid&gt;
{
    // ...
    
    public IRepository&lt;Product, Guid&gt; ProductRepository { get; set; }
    
    public async Task ChangeCodeAsync(string newProductCode)
    {
        Check.NotNullOrWhiteSpace(newProductCode, nameof(newProductCode));

        if (newProductCode == ProductCode)
        {
            return;
        }

        if (await ProductRepository.AnyAsync(x =&gt; x.ProductCode == newProductCode))
        {
            throw new ApplicationException(&quot;Product code is already used: &quot; + newProductCode);
        }
        
        ProductCode = newProductCode;
    }
}
</code></pre>
<p>Now, we don't need to implement the <code>IInjectServiceProvider</code> interface and manually resolve the <code>IRepository&lt;Product, Guid&gt;</code> object from the <code>ServiceProvider</code>. You see that the <code>ChangeCodeAsync</code> method is much simpler now.</p>
<p>So, how to set <code>ProductRepository</code>? For the EF Core interceptor part, you can somehow get all public properties of the entity via reflection. Then, for each property, check if such a service does exist, and set it from the dependency injection system if available. Surely, that will be less performant, but will work if you can truly implement. On the other hand, it would be extra hard to set all the dependencies of the entity while manually creating it using the <code>new</code> keyword. So, personally I wouldn't recommend that approach.</p>
<h3>Limitations</h3>
<p>One important limitation is that you can not use the services inside your entity's constructor code. Ideally, the constructor of the <code>Product</code> class should check if the product code is already used before. See the following constructor:</p>
<pre><code class="language-csharp">public Product(string productCode, string name)
{
    ProductCode = Check.NotNullOrWhiteSpace(productCode, nameof(productCode));
    Name = Check.NotNullOrWhiteSpace(name, nameof(name));
    
    /* Can not check if product code is already used by another product? */
}
</code></pre>
<p>It is not possible to use the product repository here, because;</p>
<ol>
<li>The services are property-injected. That means they will be set after the object creation has completed.</li>
<li>Even if the service is available, it won't be truly possible to call async code in a constructor. You know constructors can not be async in C#, but the repository and other service methods are generally designed as async.</li>
</ol>
<p>So, if you want to force the &quot;product code must be unique&quot; rule, you should create an async domain service method (like <code>ProductManager.CreateAsync(...)</code>) and always use it to create products (you can make the <code>Product</code> class constructor <code>internal</code> to not allow to use it in the application layer).</p>
<h3>Design Problems</h3>
<p>Beside the technical limitations, coupling your entities to external services is generally considered as a bad design. It makes your entities over-complicated, hard to test, and generally leads to take too much responsibility over the time.</p>
<h2>Conclusion</h2>
<p>In this article, I tried to investigate all aspects of injecting services into entity classes. I explained how to use Entity Framework 7.0 <code>IMaterializationInterceptor</code> to implement property-injection pattern while getting entities from database.</p>
<p>Injecting services into entities seems a certain way of forcing some business rules in your entities. However, because of the current technical limitations, design issues and usage difficulties, I don't suggest to depend on services in your entities. Instead, create domain services when you need to implement a business rule that depends on external services and entities.</p>
<h2>The Source Code</h2>
<ul>
<li>You can find the full source code of the example application <a href="https://github.com/abpframework/abp-samples/tree/master/EfCoreEntityDependencyInjectionDemo">here</a>.</li>
<li>You can see <a href="https://github.com/abpframework/abp-samples/pull/207/files">this pull request</a> for the changes I've done after creating the application.</li>
</ul>
<h2>See Also</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew">What's new in EF Core 7.0</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Dependency-Injection">ABP Framework: Dependency Injection</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Domain-Driven-Design">ABP Framework: Domain Driven Design</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/consuming-grpc-services-from-blazor-webassembly-application-using-grpcweb-dqjry3rv</guid>
      <link>https://abp.io/community/posts/consuming-grpc-services-from-blazor-webassembly-application-using-grpcweb-dqjry3rv</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>gRPC</category>
      <title>Consuming gRPC Services from Blazor WebAssembly Application Using gRPC-Web</title>
      <description>In this second part, I will show how to consume the gRPC service from the Blazor WebAssembly application, using the gRPC-Web technology.</description>
      <pubDate>Sun, 18 Sep 2022 17:41:22 Z</pubDate>
      <a10:updated>2026-10-02T15:42:58Z</a10:updated>
      <content:encoded><![CDATA[<h1>Consuming gRPC Services from Blazor WebAssembly Application Using gRPC-Web</h1>
<blockquote>
<p><strong>WARNING: I've demonstrated <a href="https://community.abp.io/posts/using-grpc-with-the-abp-framework-2dgaxzw3">Using gRPC with the ABP Framework</a> in my latest post. If you haven't seen it, you should read it before this article, since this is a continuation of that article.</strong></p>
</blockquote>
<p>In this second part, I will show how to consume the gRPC service from the Blazor WebAssembly application, using the gRPC-Web technology.</p>
<p>This will be a short article, based on Microsoft's <a href="https://learn.microsoft.com/en-us/aspnet/core/grpc/grpcweb">gRPC-Web in ASP.NET Core gRPC apps</a> and <a href="https://learn.microsoft.com/en-us/aspnet/core/grpc/code-first">Code-first gRPC services and clients with .NET</a> documents. For more information, I suggest to check these documents. Let's get started...</p>
<h2>Configuring the Server Side</h2>
<p>First of all, the server-side should support gRPC-Web. Follow the steps below to enable it:</p>
<h3>Add Grpc.AspNetCore.Web Package</h3>
<p>Add <a href="https://www.nuget.org/packages/Grpc.AspNetCore.Web">Grpc.AspNetCore.Web</a> NuGet package to the <code>ProductManagement.HttpApi.Host</code> project.</p>
<h3>Add GrpcWeb Middleware</h3>
<p>Add the following line just before the <code>app.UseConfiguredEndpoints(...)</code> line to add the GrpcWeb middleware to your ASP.NET Core request pipeline:</p>
<pre><code class="language-csharp">app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
</code></pre>
<h3>Configure Cors</h3>
<p>ABP's startup template already configures Cors when you create a new solution. However, we need to allow some extra headers in our Cors configuration.</p>
<p>Add the following line just after the <code>.WithAbpExposedHeaders()</code> line in the <code>OnApplicationInitialization</code> method of the <code>ProductManagementHttpApiHostModule</code> class:</p>
<pre><code class="language-csharp">.WithExposedHeaders(&quot;Grpc-Status&quot;, &quot;Grpc-Message&quot;, &quot;Grpc-Encoding&quot;, &quot;Grpc-Accept-Encoding&quot;)
</code></pre>
<p>Finally, call <code>RequireCors</code> extension method just after the <code>MapGrpcService</code> calls:</p>
<pre><code class="language-csharp">app.UseConfiguredEndpoints(endpoints =&gt;
{
    endpoints
        .MapGrpcService&lt;IProductAppService&gt;()
        .RequireCors(&quot;__DefaultCorsPolicy&quot;); // Configure Cors for the product service
});
</code></pre>
<p><code>__DefaultCorsPolicy</code> may seem a magic string here. Let me explain it: ABP startup template configures the default Cors policy with the <code>context.Services.AddCors(...)</code> method (you can see it in the source code). If we define a named policy, we should use the same name here. However, when we don't specify, ASP.NET Core uses <code>__DefaultCorsPolicy</code> as the policy name by default. If you don't want to use the magic string, you can resolve the <code>IOptions&lt;CorsOptions&gt;</code> service and get the <code>DefaultPolicyName</code> from the <code>CorsOption</code> object.</p>
<p>Anyway, that's all on the server-side. We can work on he client now.</p>
<h2>Configuring the Client Side</h2>
<p><code>ProductManagement.Blazor</code> is the Blazor WebAssembly application in the solution I'd created in the <a href="https://community.abp.io/posts/using-grpc-with-the-abp-framework-2dgaxzw3">first article</a>. We will configure that project to be able to consume the server-side gRPC services from our Blazor application.</p>
<h3>Add Client-side Nuget Packages</h3>
<p>Add <a href="https://www.nuget.org/packages/Grpc.Net.Client">Grpc.Net.Client</a>, <a href="https://www.nuget.org/packages/Grpc.Net.Client.Web">Grpc.Net.Client.Web</a> and <a href="https://www.nuget.org/packages/protobuf-net.Grpc">protobuf-net.Grpc</a> NuGet packages to the <code>ProductManagement.Blazor</code> project. We are ready to consume the gRPC services.</p>
<h3>Consume the Product Service</h3>
<p>Change the <code>Pages/Index.razor.cs</code> file's content with the following code block:</p>
<pre><code class="language-csharp">using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using ProductManagement.Products;
using ProtoBuf.Grpc.Client;

namespace ProductManagement.Blazor.Pages;

public partial class Index
{
    private List&lt;ProductDto&gt; Products { get; set; } = new();

    protected override async Task OnInitializedAsync()
    {
        var channel = GrpcChannel.ForAddress(&quot;https://localhost:10042&quot;, new GrpcChannelOptions
        {
            HttpHandler = new GrpcWebHandler(new HttpClientHandler())
        });

        var productAppService = channel.CreateGrpcService&lt;IProductAppService&gt;();
        Products = await productAppService.GetListAsync();
    }
}
</code></pre>
<ul>
<li>We've created a gRPC channel for the server-side endpoint (surely, you get the address from a configuration) with channel options by specifying that we will use the <code>GrpcWebHandler</code>.</li>
<li>We've created a service proxy object using the <code>CreateGrpcService</code> extension method that is defined by the <a href="https://www.nuget.org/packages/protobuf-net.Grpc">protobuf-net.Grpc</a> NuGet package.</li>
<li>We've used the service proxy object, <code>productAppService</code>, to consume remote endpoint just like a local service.</li>
</ul>
<p>That's all. If we want to show the products on the page, we can add the following markup into the <code>Pages/Index.razor</code> view:</p>
<pre><code class="language-xml">&lt;h2&gt;A list of products:&lt;/h2&gt;

&lt;ul class=&quot;list-group&quot;&gt;
    @foreach(var product in Products)
    {
        &lt;li class=&quot;list-group-item&quot;&gt;
            @product.Name &lt;br/&gt;
            &lt;small&gt;@product.Id.ToString()&lt;/small&gt;
        &lt;/li&gt;
    }
&lt;/ul&gt;
</code></pre>
<p>Run the applications (first run the <code>ProductManagement.HttpApi.Host</code> project, then run the <code>ProductManagement.Blazor</code> project in the solution) to see it in action:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-18-Grpc-Demo-Part-2/blazor-product-list.png" alt="blazor-product-list" /></p>
<h2>Conclusion</h2>
<p>In the first part of this article, I'd demonstrated how to implement a gRPC service and consume it in a client application, using the <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/code-first">code-first approach</a>. In this article, I've demonstrated how to consume the same gRPC service from a Blazor WebAssembly application, using the <a href="https://learn.microsoft.com/en-us/aspnet/core/grpc/grpcweb">gRPC-Web</a> technology. As you see in these two articles, using gRPC with the ABP Framework is straightforward.</p>
<h2>The Source Code</h2>
<ul>
<li>You can find the completed source code here: https://github.com/abpframework/abp-samples/tree/master/GrpcDemo2</li>
<li>You can also see all the changes I've done in this article here: https://github.com/abpframework/abp-samples/pull/201/files</li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/using-grpc-with-the-abp-framework-2dgaxzw3</guid>
      <link>https://abp.io/community/posts/using-grpc-with-the-abp-framework-2dgaxzw3</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>gRPC</category>
      <title>Using gRPC with the ABP Framework</title>
      <description>I will show you how to create a gRPC service and consume it from a console application with the ABP Framework.</description>
      <pubDate>Thu, 15 Sep 2022 16:32:36 Z</pubDate>
      <a10:updated>2026-10-02T14:55:24Z</a10:updated>
      <content:encoded><![CDATA[<h1>Using gRPC with the ABP Framework</h1>
<p><a href="https://grpc.io/">gRPC</a> defines itself as an open source, language agnostic, universal, high-performance <strong>Remote Procedure Call (RPC)</strong> framework.</p>
<p>In this article, I will show you how to create a gRPC service and consume it from a console application with the ABP Framework. While the client application is console in this article, it can easily be a service consuming another service in a microservice system.</p>
<blockquote>
<p><strong>This article will be a step by step tutorial.</strong> I wrote the article based on Microsoft's <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/code-first">Code-first gRPC services and clients with .NET</a> document. You can read that document for more details about gRPC and the code-first approach.</p>
</blockquote>
<h2>Creating the Application</h2>
<p>Install the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> if you haven't installed it yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>or update to the latest version if you've already installed an old version:</p>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g
</code></pre>
<p>Create an empty folder, open a command-line terminal and type the following command in the terminal window to create a new ABP solution using the ABP CLI:</p>
<pre><code class="language-bash">abp new ProductManagement -u blazor -t app --preview
</code></pre>
<p>I've created an application with the Blazor UI, but the UI is not important for this tutorial, you can select your favorite UI option.</p>
<h2>Open the Solution</h2>
<p>Open the solution in your favorite IDE. I like <a href="https://www.jetbrains.com/rider/">Rider</a>, but Visual Studio, VS Code or any other IDE perfectly works. The following figure shows the solution structure in Rider:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-15-Grpc-Demo/solution.png" alt="solution" /></p>
<p>Run the <code>ProductManagement.DbMigrator</code> project (a console application) to create the database and seed the initial data.</p>
<h2>Defining the Service Contract</h2>
<p>We are starting by defining the service contract and DTO classes that will be shared between the server and the client applications.</p>
<p>Create a <code>Products</code> folder in the <code>ProductManagement.Application.Contracts</code> project and add a new interface named <code>IProductAppService</code>:</p>
<pre><code class="language-csharp">using System.Collections.Generic;
using System.ServiceModel;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace ProductManagement.Products;

[ServiceContract]
public interface IProductAppService : IApplicationService
{
    Task&lt;List&lt;ProductDto&gt;&gt; GetListAsync();
}
</code></pre>
<p>Your IDE will complain about the <code>[ServiceContract]</code> attribute, but it is necessary for the contract-first gRPC library we will be using later. So, add the <a href="https://www.nuget.org/packages/System.ServiceModel.Primitives">System.ServiceModel.Primitives</a> NuGet package to the <code>ProductManagement.Application.Contracts</code> project, and it should be fixed. You can simply edit the <code>ProductManagement.Application.Contracts.csproj</code> file and add the following line in an <code>ItemGroup</code> tag:</p>
<pre><code class="language-xml">&lt;PackageReference Include=&quot;System.ServiceModel.Primitives&quot; Version=&quot;4.7.0&quot; /&gt;
</code></pre>
<p>Or you can use your IDE to find and add that NuGet package, it is up to you.</p>
<p>I've also used the <code>ProductDto</code> class, but haven't defined it yet. Create a new class in the same folder with the <code>IProductAppService</code> file:</p>
<pre><code class="language-csharp">using System;
using System.Runtime.Serialization;

namespace ProductManagement.Products;

[DataContract]
public class ProductDto
{
    [DataMember(Order = 1)]
    public Guid Id { get; set; }

    [DataMember(Order = 2)]
    public string Name { get; set; }
}
</code></pre>
<p>The <code>[DataContract]</code> and <code>[DataMember]</code> properties are needed for serialization. In gRPC, property serialization orders are important, because property names are not transferred to the target application, to keep the serialized data small.</p>
<p>After adding these classes, the <code>ProductManagement.Application.Contracts</code> project should look as in the following figure:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-15-Grpc-Demo/contracts.png" alt="contracts" /></p>
<p>The contracts part is over. We actually didn't have any dependency to gRPC at that point. Our service and DTOs are pretty plain classes, except a few standard attributes, which are already defined in the .NET Core framework. Now, we can implement the <code>IProductAppService</code>.</p>
<h2>Implementing the Service</h2>
<p>We are implementing the application services in the <code>ProductManagement.Application</code> project. So, add a new <code>Products</code> folder to that project and define a <code>ProductAppService</code> class inside it:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ProductManagement.Products;

public class ProductAppService : ProductManagementAppService, IProductAppService
{
    public async Task&lt;List&lt;ProductDto&gt;&gt; GetListAsync()
    {
        return new List&lt;ProductDto&gt;
        {
            new ProductDto { Id = Guid.NewGuid(), Name = &quot;Product 1&quot; },
            new ProductDto { Id = Guid.NewGuid(), Name = &quot;Product 2&quot; },
        };
    }
}
</code></pre>
<p>This is a pretty standard, plain <a href="https://docs.abp.io/en/abp/latest/Application-Services">application service </a>class. All the ABP application service features (validation, audit logging, unit of work, etc.) are available. You can inject <a href="https://docs.abp.io/en/abp/latest/Repositories">repositories</a> and perform database queries. To keep this article simple, I am returning hard-coded data from here.</p>
<blockquote>
<p><code>ProductManagementAppService</code> is a base class coming in the ABP startup template. While you don't have to inherit from it, it provides useful base properties and methods you typically need in an application service.</p>
</blockquote>
<p>The application service part is over. Again, we didn't write any gRPC specific code. Don't worry, we will write in the next section.</p>
<h2>Configuring the gRPC Server</h2>
<p>In this solution, <code>ProductManagement.HttpApi.Host</code> is the project that configures and runs the server-side application. So, we will make changes in that project.</p>
<p>First, add the <a href="https://www.nuget.org/packages/protobuf-net.Grpc.AspNetCore">protobuf-net.Grpc.AspNetCore</a> NuGet package to the <code>ProductManagement.HttpApi.Host</code> project:</p>
<pre><code class="language-xml">&lt;PackageReference Include=&quot;protobuf-net.Grpc.AspNetCore&quot; Version=&quot;1.0.177&quot; /&gt;
</code></pre>
<p>Then open the <code>ProductManagementHttpApiHostModule.cs</code> file, find the <code>ConfigureServices</code> method and add the following line into this method:</p>
<pre><code class="language-csharp">context.Services.AddCodeFirstGrpc();
</code></pre>
<p>This will register code-first gRPC services to the <a href="https://docs.abp.io/en/abp/latest/Dependency-Injection">dependency injection</a> system. Then find the <code>app.UseConfiguredEndpoints()</code> line in the <code>OnApplicationInitialization</code> method and change it as shown below:</p>
<pre><code class="language-csharp">app.UseConfiguredEndpoints(endpoints =&gt;
{
    endpoints.MapGrpcService&lt;IProductAppService&gt;();
});
</code></pre>
<p>We've configured the <code>IProductAppService</code> to handle gRPC requests to that service. The following figure shows the whole change done in the <code>ProductManagementHttpApiHostModule</code> class:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-15-Grpc-Demo/host-changes-1.png" alt="host-changes-1" /></p>
<p>gRPC handles requests with the HTTP/2 protocol and should listen an endpoint other than the default HTTP endpoint used by the application. We can easily configure the Kestrel server to listen two endpoints, one for our HTTP APIs, the other one for gRPC services. Add the following configuration inside the <code>appsettings.json</code> file of the <code>ProductManagement.HttpApi.Host</code> project:</p>
<pre><code class="language-json">&quot;Kestrel&quot;: {
  &quot;Endpoints&quot;: {
    &quot;Https&quot;: {
      &quot;Url&quot;: &quot;https://localhost:44388&quot;,
      &quot;Protocols&quot;: &quot;Http1AndHttp2&quot;
    },
    &quot;gRPC&quot;: {
      &quot;Url&quot;: &quot;https://localhost:10042&quot;,
      &quot;Protocols&quot;: &quot;Http2&quot;
    }
  }
}
</code></pre>
<p>Note that <code>https://localhost:44388</code> may be different for your case, since ABP CLI assignes a random port while you're creating a new solution. You can check your port by running the <code>ProductManagement.HttpApi.Host</code> project and looking at the address bar on your browser.</p>
<p>The server-side configuration is done. It is ready to receive gRPC requests. Now, we can change the client to consume the gRPC service we've created.</p>
<h2>Implementing the Client Side</h2>
<p>The ABP startup solution template comes with a console application to test consuming your HTTP APIs. For this example, the project is named as <code>ProductManagement.HttpApi.Client.ConsoleTestApp</code> and located under the <code>test</code> folder in the solution.</p>
<p>First, add the <a href="https://www.nuget.org/packages/Grpc.Net.Client">Grpc.Net.Client</a> and the <a href="https://www.nuget.org/packages/protobuf-net.Grpc">protobuf-net.Grpc</a> NuGet packages to the <code>ProductManagement.HttpApi.Client.ConsoleTestApp</code> project.</p>
<pre><code class="language-xml">&lt;PackageReference Include=&quot;Grpc.Net.Client&quot; Version=&quot;2.49.0-pre1&quot; /&gt;
&lt;PackageReference Include=&quot;protobuf-net.Grpc&quot; Version=&quot;1.0.177&quot; /&gt;
</code></pre>
<p>Now, open the <code>ClientDemoService.cs</code> file under the <code>ProductManagement.HttpApi.Client.ConsoleTestApp</code> project and change its contents with the following code block:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Grpc.Net.Client;
using ProductManagement.Products;
using ProtoBuf.Grpc.Client;
using Volo.Abp.DependencyInjection;

namespace ProductManagement.HttpApi.Client.ConsoleTestApp;

public class ClientDemoService : ITransientDependency
{
    public async Task RunAsync()
    {
        using (var channel = GrpcChannel.ForAddress(&quot;https://localhost:10042&quot;))
        {
            var productAppService = channel.CreateGrpcService&lt;IProductAppService&gt;();
            var productDtos = await productAppService.GetListAsync();

            foreach (var productDto in productDtos)
            {
                Console.WriteLine($&quot;[Product] Id = {productDto.Id}, Name = {productDto.Name}&quot;);
            }
        }
    }
}
</code></pre>
<p>We are simply creating a gRPC channel, then creating a client proxy for the <code>IProductAppService</code> service. Then we can call its method just like local method calls. You can run the applications to test it.</p>
<h2>Run the Applications</h2>
<p>First run the <code>ProductManagement.HttpApi.Host</code> application. It should show a Swagger UI as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-15-Grpc-Demo/swagger.png" alt="swagger" /></p>
<p>If you see that page, it means your server-side is up and running. Now, you can run the <code>ProductManagement.HttpApi.Client.ConsoleTestApp</code> console application to call the gRPC service defined on the server.</p>
<p>The test console application should produce an output as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-09-15-Grpc-Demo/client-application.png" alt="client-application" /></p>
<p>As you see, products are returned from the server. That's all, you've done it!</p>
<h2>Conclusion</h2>
<p>In this article, I've used the <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/code-first">code-first approach</a> to implement a gRPC server and consume it in a client application. Code-first approach is very practical if both of your client and server applications are built with .NET. By the help of ABP's layered solution structure, we even didn't add any gRPC dependency into our server-side and contracts. We've just configured gRPC in the hosting side, with a small amount of code.</p>
<p>gRPC on .NET has different approaches, features, configurations and more details. I suggest you to read <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc">Microsoft's documentation</a> to learn more about it. All the approaches can work with the ABP Framework. Enjoy coding!</p>
<h2>The Source Code</h2>
<ul>
<li><p>You can find the completed source code here: https://github.com/abpframework/abp-samples/tree/master/GrpcDemo2</p>
</li>
<li><p>You can also see all the changes I've done in this article here: https://github.com/abpframework/abp-samples/pull/200/files</p>
</li>
</ul>
<h2>See Also</h2>
<ul>
<li><a href="https://abp.io/community/articles/consuming-grpc-services-from-blazor-webassembly-application-using-grpcweb-dqjry3rv">Consuming gRPC Services from Blazor WebAssembly Application Using gRPC-Web</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/dealing-with-multiple-implementations-of-a-service-in-asp.net-core-abp-dependency-injection-ysfp4ho2</guid>
      <link>https://abp.io/community/posts/dealing-with-multiple-implementations-of-a-service-in-asp.net-core-abp-dependency-injection-ysfp4ho2</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>dependency-injection</category>
      <title>Dealing with Multiple Implementations of a Service in ASP.NET Core &amp; ABP Dependency Injection</title>
      <description>I will explain how you can register multiple implementations of the same service interface and inject/resolve all these implementations when you need them</description>
      <pubDate>Thu, 14 Apr 2022 08:34:04 Z</pubDate>
      <a10:updated>2026-10-02T16:10:12Z</a10:updated>
      <content:encoded><![CDATA[<h1>Dealing with Multiple Implementations of a Service in ASP.NET Core &amp; ABP Dependency Injection</h1>
<p>ASP.NET Core provides a built-in <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection">dependency injection system</a> to register your services to the dependency injection container and inject/resolve them whenever you need. ABP's <a href="https://docs.abp.io/en/abp/latest/Dependency-Injection">dependency injection infrastructure</a> is built on ASP.NET Core's DI system, automates service registration by conventions and provides some additional features.</p>
<p>In this tutorial, I will explain how you can register multiple implementations of the same service interface and inject/resolve all these implementations when you need them.</p>
<h2>Defining Services</h2>
<p>Assume that you have an <code>IExternalLogger</code> interface with two implementations:</p>
<pre><code class="language-csharp">public interface IExternalLogger
{
    Task LogAsync(string logText);
}

public class ElasticsearchExternalLogger : IExternalLogger
{
    public async Task LogAsync(string logText)
    {
        // TODO...
    }
}

public class AzureExternalLogger : IExternalLogger
{
    public async Task LogAsync(string logText)
    {
        // TODO...
    }
}
</code></pre>
<p>An example service injecting the <code>IExternalLogger</code> interface:</p>
<pre><code class="language-csharp">public class MyService : ITransientDependency
{
    private readonly IExternalLogger _externalLogger;

    public MyService(IExternalLogger externalLogger)
    {
        _externalLogger = externalLogger;
    }

    public async Task DemoAsync()
    {
        await _externalLogger.LogAsync(&quot;Example log message...&quot;);
    }
}
</code></pre>
<p>In this example, we haven't registered any of the implementation classes to the dependency injection system yet. So, if we try to use the <code>MyService</code> class, we get an error indicating that no implementation found for the <code>IExternalLogger</code> service. We should register at least one implementation for the <code>IExternalLogger</code> interface.</p>
<h2>Registering Services</h2>
<p>If we register both of the <code>ElasticsearchExternalLogger</code> and <code>AzureExternalLogger</code> services for the <code>IExternalLogger</code> interface, and then try to inject the <code>IExternalLogger</code> interface, the last registered implementation will be used. However, how to determine the last registered implementation?</p>
<p>If we implement one of the <a href="https://docs.abp.io/en/abp/latest/Dependency-Injection#dependency-interfaces">dependency interfaces</a> (e.g. <code>ITransientDependency</code>), then the registration order will be uncertain (it may depend on the namespaces of the classes). The <em>last registered implementation</em> can be different than you expect. So, it is not suggested to use the dependency interfaces to register multiple implementations.</p>
<p>You can register your services in the <code>ConfigureServices</code> method of your module:</p>
<pre><code class="language-csharp">public override void ConfigureServices(ServiceConfigurationContext context)
{
    context.Services.AddTransient&lt;IExternalLogger, ElasticsearchExternalLogger&gt;();
    context.Services.AddTransient&lt;IExternalLogger, AzureExternalLogger&gt;();
}
</code></pre>
<p>In this case, you get an <code>AzureExternalLogger</code> instance when you inject the <code>IExternalLogger</code> interface, because the last registered implementation is the <code>AzureExternalLogger</code> class.</p>
<h2>Injecting Multiple Implementations</h2>
<p>When you have multiple implementation of an interface, you may want to work with all these implementations. For this example, you may want to write log to all the external loggers. We can change the <code>MyService</code> implementation as the following:</p>
<pre><code class="language-csharp">public class MyService : ITransientDependency
{
    private readonly IEnumerable&lt;IExternalLogger&gt; _externalLoggers;

    public MyService(IEnumerable&lt;IExternalLogger&gt; externalLoggers)
    {
        _externalLoggers = externalLoggers;
    }

    public async Task DemoAsync()
    {
        foreach (var externalLogger in _externalLoggers)
        {
            await externalLogger.LogAsync(&quot;Example log message...&quot;);
        }
    }
}
</code></pre>
<p>In this example, we are injecting <code>IEnumerable&lt;IExternalLogger&gt;</code> instead of <code>IExternalLogger</code>, so we have a collection of the <code>IExternalLogger</code> implementations. Then we are using a <code>foreach</code> loop to write the same log text to all the <code>IExternalLogger</code> implementations.</p>
<p>If you are using <code>IServiceProvider</code> to resolve dependencies, then use its <code>GetServices</code> method to obtain a collection of the service implementations:</p>
<pre><code class="language-csharp">IEnumerable&lt;IExternalLogger&gt; services = _serviceProvider.GetServices&lt;IExternalLogger&gt;();
</code></pre>
<h2>Further Reading</h2>
<p>In this small tutorial, I explained how you can register multiple implementations of the same interface to the dependency injection system and inject/resolve all of them when you need.</p>
<p>If you want to get more information about ABP's and ASP.NET Core's dependency injection systems, you can read the following documents:</p>
<ul>
<li><a href="https://docs.abp.io/en/abp/latest/Dependency-Injection">ABP's Dependency Injection documentation</a></li>
<li><a href="https://medium.com/volosoft/asp-net-core-dependency-injection-best-practices-tips-tricks-c6e9c67f9d96">ASP.NET Core Dependency Injection best practices, tips &amp; tricks</a></li>
<li><a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection">ASP.NET Core's Dependency Injection documentation</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-5.2-final-has-been-released-1xb0upor</guid>
      <link>https://abp.io/community/posts/abp.io-platform-5.2-final-has-been-released-1xb0upor</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 5.2 Final Has Been Released</title>
      <description>Introducing the ABP.IO Platform version 5.2.0!</description>
      <pubDate>Tue, 05 Apr 2022 18:32:50 Z</pubDate>
      <a10:updated>2026-10-02T13:20:17Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 5.2 versions have been released today.</p>
<h2>What's New With 5.2?</h2>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP.IO-Platform-5-2-RC-Has-Been-Published">5.2 RC Announcement Post</a>, I will not repeat all the details again. See the <a href="https://blog.abp.io/abp/ABP.IO-Platform-5-2-RC-Has-Been-Published">RC Blog Post</a> for all the features and enhancements.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 5.2 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for more.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>Migration Guide</h2>
<p>Check <a href="https://docs.abp.io/en/abp/5.2/Migration-Guides/Abp-5_2">the migration guide</a> for the applications with the version 5.x upgrading to the version 5.2.</p>
<h2>About the Next Version</h2>
<p>The next feature version will be 5.3. It is planned to release the 5.3 RC (Release Candidate) on May 03 and the final version on May 31, 2022. You can follow the <a href="https://github.com/abpframework/abp/milestones">release planning here</a>.</p>
<p>Please <a href="https://github.com/abpframework/abp/issues/new">submit an issue</a> if you have any problem with this version.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/9abae68f-e781-aef6-4da4-3a030d2d1098" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/9abae68f-e781-aef6-4da4-3a030d2d1098" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-5.2-rc-has-been-published-2phv3hbz</guid>
      <link>https://abp.io/community/posts/abp.io-platform-5.2-rc-has-been-published-2phv3hbz</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 5.2 RC Has Been Published</title>
      <description>Introducing the new features and changes coming with ABP Framework and ABP Commercial version 5.2.</description>
      <pubDate>Wed, 09 Mar 2022 15:10:05 Z</pubDate>
      <a10:updated>2026-10-02T09:38:42Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we are happy to release the <a href="https://abp.io/">ABP Framework</a> and  <a href="https://commercial.abp.io/">ABP Commercial</a> version <strong>5.2 RC</strong> (Release Candidate). This blog post introduces the new features and important changes in this new version.</p>
<blockquote>
<p><strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/66">5.2.0 Stable</a> version is April 05, 2022</strong>.</p>
</blockquote>
<p>Please try this version and provide feedback for a more stable ABP version 5.2! Thank you all.</p>
<h2>Get Started with the 5.2 RC</h2>
<p>Follow the steps below to try the version 5.2.0 RC today:</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to version <code>5.2.0-rc.1</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 5.2.0-rc.1
</code></pre>
<p>​	<strong>or install</strong> it if you haven't before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 5.2.0-rc.1
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<p>You can use any IDE that supports .NET 6.x, like <strong><a href="https://visualstudio.microsoft.com/downloads/">Visual Studio 2022</a></strong>.</p>
<h2>Migration Guides</h2>
<p>Please see the migration guides if you are upgrading from 5.x versions:</p>
<ul>
<li><a href="https://docs.abp.io/en/abp/5.2/Migration-Guides/Abp-5_2">ABP Framework 5.x to 5.2 migration guide</a></li>
<li><a href="https://docs.abp.io/en/commercial/5.2/migration-guides/index">ABP Commercial 5.x to 5.2 migration guide</a></li>
</ul>
<h2>What's New with ABP Framework 5.2?</h2>
<p>In this section, I will introduce some major features released with this version. Here, a brief list of titles explained in the next sections:</p>
<ul>
<li>Single-layer Solution Template</li>
<li>API Versioning</li>
<li>libs Folder Has been Removed from Source Control</li>
<li>Hiding the Default ABP Endpoints from Swagger UI</li>
<li>Custom Global CSS and JavaScript for the CMS Kit module</li>
<li>Other news</li>
</ul>
<p>Let's begin with the first item.</p>
<h3>Single-layer Solution Template</h3>
<p>ABP's <a href="https://docs.abp.io/en/abp/latest/Startup-Templates/Application">application startup template</a> is a well-organized and layered solution to create maintainable business applications. However, some developers find it a little bit complex for simple and short-term applications. For such applications, we've created a new startup template that has no layering and built as simple as possible. It has the same functionality, features and modules on runtime, but the development model is minimal and everything is in the single project (<code>csproj</code>), as shown in the following figure:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/a4df6d07407c698f36a53a02814594e7.png" alt="single-layer-solution.png" /></p>
<p>Use the <code>app-nolayers</code> as the template name while creating your solution:</p>
<pre><code class="language-bash">abp new BookStore -t app-nolayers --preview
</code></pre>
<p><a href="https://commercial.abp.io/">ABP Commercial</a> developers can use the <code>app-nolayers-pro</code> as the startup template:</p>
<pre><code class="language-csharp">abp new BookStore -t app-nolayers-pro --preview
</code></pre>
<blockquote>
<p>There is a bug for the <code>app-nolayers-pro</code> related to the licensing system, which will be fixed with 5.2.0-rc.2: <code>appsettings.secrets.json</code> is missing in the project folder (should be near to <code>appsettings.json</code> and contains the license code normally). As a workaround, create a new solution with the layered startup template, find and copy that file to the single-layer solution.</p>
</blockquote>
<p>One note about the single-layer project is it doesn't have Blazor WebAssembly UI, because it requires 3 projects at least (one server-side, one UI and one shared library project between these two). We will consider to add Blazor UI support based on your feedback. You can continue to develop Blazor WASM projects using the standard layered solution template.</p>
<h4>Database Migrations for EF Core</h4>
<p>After creating your solution, you need to create the database before running the application. We've added a parameter to the application that can be specified to migrate the database and seed the initial data. Open the project's directory (that contains the <code>csproj</code> file) in a command-line terminal and type the following command:</p>
<pre><code class="language-bash">dotnet run --migrate-database
</code></pre>
<p>It will run, migrate the database and exit. You can then run the application as normal.</p>
<p>You could use the standard <code>dotnet ef database update</code> command (or <code>Update-Database</code> command in Visual Studio's Package Manager Console). It can successfully create the database tables. However, it doesn't seed the initial data that is necessary to run the application.</p>
<p>To keep the solution simple, we haven't added an external application (like the <code>DbMigrator</code> in the layered application startup template) to migrate the database.</p>
<p>Using the same application to migrate the database is simple and useful for development environment, and it can also be used in production environment. However, there are other ways of migrating a database. Please read more on <a href="https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations">Microsoft's documentation</a>.</p>
<h4>Other UI and Database Options</h4>
<p>The new single-layer solution template also supports Angular and Blazor UI, and MongoDB for the database side. For the UI, you can use <code>mvc</code> (default), <code>angular</code> or <code>blazor-server</code> with the <code>-u</code> (or <code>--ui</code>) parameter. For the database provider, you can use <code>ef</code> (default) or <code>mongodb</code> with the <code>-d</code> (or <code>--database-provider</code>) parameter. Example:</p>
<pre><code class="language-bash">abp new BookStore -t app-nolayers -u angular -d mongodb --preview
</code></pre>
<p>This will create a single layer template with Angular as the UI framework and MongoDB as the database provider.</p>
<h4>Single-Layer Tutorial</h4>
<p><a href="https://twitter.com/st_braim">Hamza Albreem</a> has created a video tutorial to explain how to develop a simple application with this startup template.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/9168547a7e70ca84f1a53a028145fc71.png" alt="video-single-layer-tutorial.png" /></p>
<p>You can <a href="https://community.abp.io/posts/developing-a-minimalist-application-with-the-abp-framework-mvad01ca">watch it here</a>.</p>
<h3>API Versioning</h3>
<p>API versioning has always been possible with the ABP Framework, but we haven't had a documentation for it. With version 5.2, we've created a document to explain how to implement API versioning for your applications and add versioning support to your standard application service classes. See the <a href="https://docs.abp.io/en/abp/5.2/API/API-Versioning">documentation here</a>.</p>
<h3>libs Folder Has been Removed from Source Control</h3>
<blockquote>
<p><strong>NOTICE: This can be a breaking change for your development environment and CI/CD pipelines. So, please read it carefully and take the necessary actions.</strong></p>
</blockquote>
<p>When you create solutions with MVC (Razor Pages) or Blazor Server UI, your application will have a <code>wwwroot/libs</code> folder in the UI project as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/59e40287b10caca3a7b33a0281462c37.png" alt="libs-folder.png" /></p>
<p>The <code>libs</code> folder contains all the client-side (mostly JavaScript and CSS) library dependencies. For example, in the figure above, the <code>bootstap</code> folder contains the necessary files for the Bootstrap library. The folder's content is copied from the <code>node_modules</code> folder (it only copies the minimum files to make the library work, not the whole folder) with ABP CLI's <code>abp install-libs</code> command.</p>
<p>Before version 5.2, the <code>libs</code> folder was coming with the startup template and committed into your source control system (e.g. Git). With version 5.2, this folder is excluded from the source control by default, so every developer getting the solution must run <code>abp install-libs</code> in the UI project's root directory to install these libraries. This approach saves a huge amount of size of the solution. For example, the initial size of an MVC UI application reduces from <code>9.83MB</code>  to <code>0.23MB</code> (you read it right!).</p>
<p>When you create a new solution with ABP CLI, <code>abp install-libs</code> command is automatically executed, so your application directly works. However, if your teammates (or CI/CD system) get the solution from the source control, they should run the <code>abp install-libs</code> before running the solution. If you don't want that, you can simply remove the <code>**/wwwroot/libs/*</code> line from the <code>.gitignore</code> file in the root folder of your solution, then the <code>libs</code> folder is added to your source control again (if you are using a source control system other than Git, you should apply your system's rules to include/exclude that folder).</p>
<h3>Hiding the Default ABP Endpoints from Swagger UI</h3>
<p><a href="https://twitter.com/EngincanVeske">Engincan Veske</a> had written <a href="https://community.abp.io/posts/how-to-hide-abp-related-endpoints-on-swagger-ui-mb2w01fe">an article</a> to explain how to hide ABP's default endpoints from Swagger UI. Then We thought that could be a good built-in option in the ABP Framework and added a <code>HideAbpEndpoints</code> method to the <code>AddAbpSwaggerGen</code> method, which can be used as in the following code example:</p>
<pre><code class="language-csharp">services.AddAbpSwaggerGen(
    options =&gt; 
    {
        //... other options
        
        //Hides ABP Related endpoints on Swagger UI
        options.HideAbpEndpoints();
    }
)
</code></pre>
<p>After that, ABP's default endpoints will still be functional, but will be hidden in Swagger UI.</p>
<h3>Custom Global CSS and JavaScript for the CMS Kit module</h3>
<p>We are improving the <a href="https://docs.abp.io/en/abp/5.2/Modules/Cms-Kit/Index">CMS Kit module</a> and adding new features constantly. A new feature with version 5.2 is a global resources system, where you can write custom JavaScript or CSS code on the application's UI (added a new page for it), which will be immediately available in all your application pages:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/1c453b5c819a46c9e8583a028146680e.png" alt="cms-kit-global-resources.png" /></p>
<p>In this way, you can customize your application's look and behavior on runtime. See <a href="https://docs.abp.io/en/abp/5.2/Modules/Cms-Kit/Global-Resources">the documentation</a> for more information.</p>
<blockquote>
<p>Note that the <a href="https://docs.abp.io/en/abp/5.2/Modules/Cms-Kit/Pages">pages</a> feature already have a page-basis script/style editor. But this new feature allows you to write script/style that is applied to all pages of your application.</p>
</blockquote>
<h3>Other news</h3>
<ul>
<li>Upgraded the <a href="https://blazorise.com/">Blazorise</a> library to v1.0 for Blazor UI. After the upgrade, ensure that all Blazorise-related packages are using v1.0 in your application.</li>
</ul>
<p>If you want to see more details, you can check <a href="https://github.com/abpframework/abp/releases/tag/5.2.0-rc.1">the release on GitHub</a>, that contains a list of all issues and pull requests closed with this version.</p>
<h2>What's New with ABP Commercial 5.2?</h2>
<p>We've also made many enhancements for <a href="https://commercial.abp.io/">ABP Commercial</a>, and also made the necessary changes and improvements to align with the v5.2 release of the ABP Framework. For example, the <strong>single-layer solution template</strong> is also available for ABP Commercial as explained above.</p>
<h3>Many to Many Relations on Code Generation</h3>
<p>One exciting new feature with ABP Commercial v5.2 is supporting many-to-many entity relations while generating CRUD code with <a href="https://commercial.abp.io/tools/suite">ABP Suite</a>.</p>
<p>When you open ABP Suite v5.2, you will see an &quot;Add navigation collection&quot; button in the Navigation tab. Here, you can click that button, select the target entity and other options:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/48b7bb8717413c1f78323a028146a77b.png" alt="suite-many-to-many-entity-relation.png" /></p>
<p>With this new feature, you can automatically generate advanced user interfaces without touching the code, then customize the generated code to implement your business logic.</p>
<h2>Community News</h2>
<p>We organized the 3rd live <a href="https://community.abp.io/events">ABP Community Talks</a> event on February 23rd. ABP community has a good interest in these events and we will continue to organize such a live event in every month. March's event will be announced in a few days. <a href="https://twitter.com/abpframework">Follow us on twitter</a>.</p>
<p><a href="https://community.abp.io/">ABP Community</a> website is being a huge resource of articles and video tutorials on the ABP Framework and .NET. There have been 93 articles/tutorials submitted so far. Here's a list of a few contents posted in the last weeks:</p>
<ul>
<li><a href="https://twitter.com/YellowDraqon">Ahmet Urel</a> submitted a series of articles to demonstrate the usage of <a href="https://www.mudblazor.com/">MudBlazor</a> library with the ABP Framework Blazor UI: <a href="https://community.abp.io/posts/mudblazor-theme-in-abp-blazor-webassembly-ae23zz17">Part 1</a>, <a href="https://community.abp.io/posts/mudblazor-theme-in-abp-blazor-webassembly-part-2-tkvrvyvm">Part 2</a> and <a href="https://community.abp.io/posts/mudblazor-theme-in-abp-blazor-webassembly-part-3-c8hwx00l">Part 3</a>.</li>
<li><a href="https://twitter.com/EnisNecipoglu">Enis Necipoğlu</a> has created two articles for ABP &amp; <strong>.NET MAUI</strong> integration: See <a href="https://community.abp.io/posts/integrating-maui-client-via-using-openid-connect-aqjjwsdf">Part 1</a> and <a href="https://community.abp.io/posts/using-abp-client-proxies-in-maui-with-openid-connect-em7x1s8k">Part 2</a>. <a href="https://twitter.com/bartvanhoey">Bart Van Hoey</a> also created <a href="https://community.abp.io/posts/abp-framework-consumed-by-a-.net-maui-app-e74fmblw">an article</a> for .NET MAUI and the ABP Framework.</li>
<li><a href="https://twitter.com/EnisNecipoglu">Enis Necipoğlu</a> has also created <a href="https://community.abp.io/posts/using-autofilterer-with-abp-framework-uuqv81jm">an article</a> to demonstrate how to use his own open source <a href="https://github.com/enisn/AutoFilterer">AutoFilterer</a> library with the ABP Framework.</li>
<li><a href="https://github.com/jonathanpotts">Jonathan Potts</a> has created his first ABP Community article that shows how to use Bootswatch themes with the ABP Framework. <a href="https://community.abp.io/posts/customizing-the-abp-basic-theme-with-bootswatch-4luoqzr0">See it here</a>.</li>
</ul>
<p>Thanks to all the contributors. It is appreciated if you want to submit your post and share your knowledge with the ABP community: https://community.abp.io/posts/create</p>
<h2>Conclusion</h2>
<p>This version was mostly about minor features and enhancements for existing features, and getting the framework, architecture and solution structure more mature. Currently, we are working on middle and long term features, changes and goals. You can find most of them on the <a href="https://docs.abp.io/en/abp/5.2/Road-Map">road map here</a>.</p>
<p>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/66">5.2.0 Stable</a> version is April 05, 2022. Please try the ABP v5.2 RC and provide feedback to have a more stable release.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/138d2a41-e8fd-3331-9a0c-3a028167bcd9" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/138d2a41-e8fd-3331-9a0c-3a028167bcd9" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v5.1-has-been-released-k7sx6vsx</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v5.1-has-been-released-k7sx6vsx</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform v5.1 Has Been Released</title>
      <description>Introducing the new features and changes coming with ABP Framework and ABP Commercial version 5.1.</description>
      <pubDate>Thu, 13 Jan 2022 14:28:35 Z</pubDate>
      <a10:updated>2026-10-02T12:11:45Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we are releasing the <a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> version 5.1 (with a version number <code>5.1.1</code>). This blog post introduces the new features and important changes in this new version.</p>
<h2>Get Started with 5.1</h2>
<p>Follow the steps below to try the 5.1 version today:</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the latest version using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g
</code></pre>
<p><strong>or install</strong> if you haven't installed it before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong>:</li>
</ol>
<pre><code class="language-bash">abp new BookStore
</code></pre>
<p>Check out the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page.</p>
</blockquote>
<p>You can use any IDE that supports .NET 6.x development (e.g. <a href="https://visualstudio.microsoft.com/downloads/">Visual Studio 2022</a>).</p>
<h3>Migration Notes &amp; Breaking Changes</h3>
<p>This is a minor feature release, mostly with enhancements and improvements based on <a href="https://blog.abp.io/abp/ABP-IO-Platform-5-0-Final-Has-Been-Released">version 5.0</a>. There aren't any breaking changes except for the Angular UI upgrade. ABP 5.1 startup templates use <strong>Angular 13</strong>.</p>
<h3>Angular UI</h3>
<p><strong>If you want to upgrade the ABP Framework but want to continue with Angular 12</strong>, add the following section to the <code>package.json</code> file of the Angular project:</p>
<pre><code class="language-json">&quot;resolutions&quot;: {
    &quot;ng-zorro-antd&quot;: &quot;^12.1.1&quot;,
    &quot;@ng-bootstrap/ng-bootstrap&quot;: &quot;11.0.0-beta.2&quot;
  }
</code></pre>
<h2>What's New with the ABP Framework 5.1?</h2>
<p>In this section, I will introduce some major features released with this version.</p>
<h3>The New Hosting Model</h3>
<p>The ABP startup application template now uses the new ASP.NET Core hosting APIs (<a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0">check out the Microsoft's minimal APIs document</a>) on application startup (<a href="https://github.com/abpframework/abp/blob/46cdfbe7b06c93690181633be4e96bf62e7f34e2/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Program.cs#L33-L40">check out the exact place in the ABP startup template</a>). So, the <code>Startup.cs</code> file has been removed.</p>
<p>Old-style hosting logic will continue to work as long as ASP.NET Core supports it. It is recommended to switch to the new model if it's possible for your solution. Check out <a href="https://docs.abp.io/en/abp/latest/Migration-Guides/Upgrading-Startup-Template">this guide</a> if you need to know how to do that.</p>
<h3>Asynchronous Startup Lifecycle Methods</h3>
<p>The new hosting model allows us to execute asynchronous code on application initialization in the <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">ABP module</a> classes. If you are using the new hosting model (which is default with 5.1 startup templates), you can override the <code>Async</code> versions of the module lifecycle methods.</p>
<p>For example, you can now override the <code>ConfigureServicesAsync</code> (instead of <code>ConfigureServices</code>) or <code>OnApplicationInitializationAsync</code> (instead of <code>OnApplicationInitialization</code>) as shown in the following code block:</p>
<pre><code class="language-csharp">public class MyModule : AbpModule
{
    public override async Task ConfigureServicesAsync(ServiceConfigurationContext context)
    {
        /* You can use await here and safely execute other async methods */
    }

    public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
    {
        /* You can use await here and safely execute other async methods */
    }
}
</code></pre>
<p>If you override both the asynchronous and synchronous versions of the same method, only the asynchronous one will be executed. So, override only one of them based on your needs.</p>
<h3>eShopOnABP Is Getting More Stable</h3>
<p>Our team is working to finalize the <a href="https://github.com/abpframework/eShopOnAbp">eShopOnAbp</a> example solution, which is a reference <strong>microservice solution</strong> built with the ABP Framework. They will explain the project status and show what's done in the next <strong>ABP Community Talks</strong> meeting (Check out the <em>ABP Community Talks 2021.1</em> section at the bottom of this post).</p>
<h3>The New ABP.IO Design!</h3>
<p>We've been working on a new design for the <a href="https://abp.io/">abp.io</a> websites for a while. We are adding the final touches; the new design will be live very soon. Here's a screenshot from the design work:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-01-13-abpio-platform-v51-has-been-released/04c9be6a819f74d7d7003a0165ff0d88.png" alt="new-abp-io-design.png" /></p>
<p>The <a href="https://commercial.abp.io/">ABP Commercial</a> and <a href="https://community.abp.io/">ABP Community</a> websites will also have new designs as part of this update.</p>
<h3>Other Changes</h3>
<p>Here are some other notable changes that come with this release:</p>
<ul>
<li>Support markdown in <a href="https://docs.abp.io/en/abp/latest/Modules/Cms-Kit/Comments">CMS-Kit comments </a>feature (<a href="https://github.com/abpframework/abp/pull/10792">#10792</a>)</li>
<li>Used file scoped namespaces for all the ABP Framework source code :) (<a href="https://github.com/abpframework/abp/pull/10696">#10552</a>)</li>
</ul>
<p>All issues &amp; PRs in <a href="https://github.com/abpframework/abp/milestone/60?closed=1">5.1 milesone</a>.</p>
<h3>About  ABP Commercial</h3>
<p>The core team is also working on ABP Commercial (which provides pre-built modules, themes, tooling and support on top of the ABP Framework). We've done a lot of minor improvements and fixes to the modules and tooling.</p>
<p>There's some exciting news about the <strong>LeptonX theme</strong>; We are working on making it available in the <strong>MVC (Razor Pages)</strong> and <strong>Blazor</strong> UI options too (in addition to Angular UI). We are also adding more components, layout options, demo pages, etc... We are planning to release a beta version in the next weeks. Here's an animated GIF from the dashboard we've prepared as a demonstration:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-01-13-abpio-platform-v51-has-been-released/1b50e6d6317b84f963ab3a016602cca7.png" alt="leptonx-dash-2.png" /></p>
<p>If you are wondering what is the LeptonX project, please check out this <a href="https://blog.abp.io/abp/LeptonX-Theme-for-ABP-Framework-Alpha-Release">blog post</a>.</p>
<p>As another visible functionality, we've added a new feature to the <a href="https://docs.abp.io/en/commercial/latest/modules/cms-kit/index">CMS Kit Pro</a> module that is used to forward a URL to another URL. This is a screenshot from the management UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-01-13-abpio-platform-v51-has-been-released/3104802a0898db35a15c3a0166002a3f.png" alt="url-forward.png" /></p>
<p>This feature can be used to create short URLs in your application (like URL shortening services providers) or forward old pages to their new URLs.</p>
<p>In addition to the new features shipped in every minor version, we are working on long-term projects for ABP.IO Platform and ABP Commercial (a little secret for now :). We will have announcements once these projects get more stable.</p>
<h2>Community News</h2>
<h3>ABP Community Talks 2021.1</h3>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2022-01-13-abpio-platform-v51-has-been-released/79374b567169e34b283f3a016603708f.png" alt="abp-community-talks-2022-1.png" /></p>
<p>This is the second episode of the ABP Community Talks and we are talking about microservice development with the ABP Framework, based on the <a href="https://github.com/abpframework/eShopOnAbp">eShopOnAbp</a> reference solution. We will also briefly talk about the changes that come with ABP version 5.1. This <strong>live meeting</strong> will be on <strong>January 20, 2022, 17:00 (UTC)</strong> on YouTube.</p>
<p><strong>Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-20221-microservice-development-acd0f44b</strong></p>
<p>You can also <a href="https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ">subscribe to Volosoft YouTube channel</a> for reminders of further ABP events and videos.</p>
<h3>New ABP Community Posts</h3>
<p>Here are some of the recent posts added to the <a href="https://community.abp.io/">ABP community</a>:</p>
<ul>
<li><a href="https://community.abp.io/articles/minimal-api-with-abp-hello-world-part-1-sg5i44p8">Minimal API development with the ABP Framework</a> by <a href="https://github.com/antosubash">@antosubash</a> (three parts, video tutorial).</li>
<li><a href="https://community.abp.io/articles/integrating-the-syncfusion-mvc-components-to-the-abp-mvc-ui-0gpkr1if">Integrating the Syncfusion MVC Components to the ABP MVC UI</a> by <a href="https://github.com/EngincanV">@EngincanV</a>.</li>
<li><a href="https://community.abp.io/articles/add-tailwindcss-to-your-abp-blazor-ui-vidiwzcy">Add Tailwind CSS to your ABP Blazor UI</a> by <a href="https://github.com/antosubash">@antosubash</a> (video tutorial).</li>
<li><a href="https://community.abp.io/articles/import-external-users-into-the-users-table-from-an-abp-framework-application-7lnyw415">Import external users into the users Table from an ABP Framework application</a> by <a href="https://github.com/bartvanhoey">@bartvanhoey</a>.</li>
</ul>
<p>Thanks to the ABP Community for all the contents they have published. You can also <a href="https://community.abp.io/articles/submit">post your ABP and .NET related (text or video) contents</a> to the ABP Community.</p>
<h2>Conclusion</h2>
<p>In this blog post, I summarized the news about the new version and the ABP Community. Please try it and provide feedback by opening issues on the <a href="https://github.com/abpframework/abp">GitHub repository</a>. Thank you all!</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/da282497-9776-d607-0b38-3a016603fd8c" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/da282497-9776-d607-0b38-3a016603fd8c" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/intermicroservice-communication-with-the-abp-framework-r5f0jaw9</guid>
      <link>https://abp.io/community/videos/intermicroservice-communication-with-the-abp-framework-r5f0jaw9</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>microservices</category>
      <category>inter-microservice-communication</category>
      <title>Inter-microservice communication with the ABP Framework</title>
      <description>ABP Framework ile microservice'ler arası ve gerçek zamanlı iletişimi anlatan bir sunum ve demo.</description>
      <pubDate>Thu, 23 Dec 2021 13:17:33 Z</pubDate>
      <a10:updated>2026-03-21T18:14:36Z</a10:updated>
      <content:encoded><![CDATA[ABP Framework ile microservice'ler arası ve gerçek zamanlı iletişimi anlatan bir sunum ve demo. <br \> <a href="https://www.youtube.com/watch?v=_GiZAK3m5kA" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/fcc9c29c-a55e-ba23-243a-3a00f99d6870" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/fcc9c29c-a55e-ba23-243a-3a00f99d6870" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-5.0-final-has-been-released-f4ktq0g7</guid>
      <link>https://abp.io/community/posts/abp.io-platform-5.0-final-has-been-released-f4ktq0g7</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 5.0 Final Has Been Released!</title>
      <description>Introducing the ABP 5.0 release.</description>
      <pubDate>Wed, 15 Dec 2021 11:19:00 Z</pubDate>
      <a10:updated>2026-10-02T15:16:29Z</a10:updated>
      <content:encoded><![CDATA[<p>We are very excited to release the <a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 5.0 versions today. It was a big development cycle, and finally it is available!</p>
<h2>What's new with 5.0?</h2>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released">5.0 RC.1 Announcement Post</a>, I will not repeat all the details again. See the <a href="https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released">RC Blog Post</a> for all the features and enhancements.</p>
<h2>Getting started with 5.0</h2>
<h3>Creating new solutions</h3>
<p>You can create a new solution with the ABP Framework version 5.0 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<p>Type the following command in a command-line terminal to install the ABP CLI version 5.0:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli --version 5.0.0
</code></pre>
<p>To upgrade your existing ABP CLI installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli --version 5.0.0
</code></pre>
<p>Then you can create a new solution using the <code>abp new</code> command:</p>
<pre><code class="language-bash">abp new Acme.BookStore
</code></pre>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h3>Upgrading existing solutions</h3>
<p>Check <a href="https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-5_0">the migration guide</a> for the applications with the version 4.x upgrading to the version 5.0. Also see <a href="https://docs.abp.io/en/abp/latest/Upgrading">the upgrading guide</a> to understand how to update existing solutions.</p>
<h2>ABP Community Talks 2021.12</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-12-15-abpio-platform-50-final-has-been-released/36c5e78b69024dd6792a3a00cff9e1ea.png" alt="community-talks.png" /></p>
<p>As the core ABP development team, we've decided to organize monthly live meetings with the ABP community. The first live meeting will be at <strong>December 16, 2021, 17:00 (UTC)</strong> on YouTube. ABP core team members will present some of the new features coming with ABP 5.0.</p>
<p><strong>Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-4afca9c9</strong></p>
<p>See you in the event!</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/e4f01fcb-baa7-2ca3-d334-3a00cffdffff" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/e4f01fcb-baa7-2ca3-d334-3a00cffdffff" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-5.0-rc.1-has-been-released-ax1lgvxf</guid>
      <link>https://abp.io/community/posts/abp.io-platform-5.0-rc.1-has-been-released-ax1lgvxf</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 5.0 RC.1 Has Been Released</title>
      <description>Introducing the ABP v5.0 RC and the new features coming with this version.</description>
      <pubDate>Thu, 18 Nov 2021 06:29:49 Z</pubDate>
      <a10:updated>2026-10-02T09:04:02Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we are excited to release the <a href="https://abp.io/">ABP Framework</a> and the <a href="https://commercial.abp.io/">ABP Commercial</a> version <strong>5.0 RC</strong> (Release Candidate). This blog post introduces the new features and important changes in this new version.</p>
<blockquote>
<p><strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/57">5.0.0 Stable</a> version is December 14, 2021</strong>.</p>
</blockquote>
<p>Please try this version and provide feedback for a more stable ABP version 5.0! Thank you all.</p>
<h2>Get Started with the 5.0 RC</h2>
<p>follow the steps below to try the version 5.0.0 RC today;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>5.0.0-rc.1</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 5.0.0-rc.1
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 5.0.0-rc.1
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<p>You can use any IDE that supports .NET 6.0, like <strong><a href="https://visualstudio.microsoft.com/downloads/">Visual Studio 2022</a></strong>.</p>
<h3>Migration Notes &amp; Breaking Changes</h3>
<p>This is a major version and there are some breaking changes and upgrade steps. Here, a list of important breaking changes in this version:</p>
<ul>
<li>Upgraded to .NET 6.0, so you need to move your solution to .NET 6.0 if you want to use the ABP 5.0.</li>
<li>Upgraded to Bootstrap 5. This is the most important breaking change in ABP 5.0 and you should take care of it.</li>
<li><code>IRepository</code> doesn't inherit from <code>IQueryable</code> anymore. It was already made obsolete in 4.2.</li>
<li>Removed NGXS and states from the Angular UI.</li>
<li>Removed gulp dependency from the MVC / Razor Pages UI in favor of <code>abp install-libs</code> command of the ABP CLI.</li>
<li>Deprecated <code>EntityCreatingEventData</code>, <code>EntityUpdatingEventData</code>, <code>EntityDeletingEventData</code> and <code>EntityChangingEventData</code> classes. See <a href="https://github.com/abpframework/abp/issues/9897">#9897</a>.</li>
</ul>
<p>Please see the <a href="https://docs.abp.io/en/abp/5.0/Migration-Guides/Abp-5_0">migration document</a> for all the details. You can also see all <a href="https://github.com/abpframework/abp/milestone/51">the closed issues and pull requests</a>.</p>
<h2>What's new with 5.0?</h2>
<p>In this section, I will introduce some major features released with this version.</p>
<h3>Static (Generated) Client Proxies for C# and JavaScript</h3>
<p>Dynamic C# (<a href="https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients">see</a>) and JavaScript (<a href="https://docs.abp.io/en/abp/latest/UI/AspNetCore/Dynamic-JavaScript-Proxies">see</a>) client proxy system is one of the most loved features of the ABP Framework. It generates the proxy code on runtime and makes client-to-server calls a breeze. With ABP 5.0, we are providing an alternative approach: You can generate the client proxy code on development-time.</p>
<p>Development-time client proxy generation has a performance advantage since it doesn't need to obtain the HTTP API definition on runtime. It also makes it easier to consume a (micro)service behind an API Gateway. With dynamic proxies, we should return a combined HTTP API definition from the API Gateway and need to add HTTP API layers of the microservices to the gateway. Static proxies removes this requirement. One disadvantage is that you should re-generate the client proxy code whenever you change your API endpoint definition. Yes, software development always has tradeoffs :)</p>
<p>Working with static client proxy generation is simple with the ABP CLI. You first need to run the server application, open a command-line terminal, locate to the root folder of your client application, then run the <code>generate-proxy</code> command of the ABP CLI.</p>
<h4>Creating C# client proxies</h4>
<p>C# client proxies are useful to consume APIs from Blazor WebAssembly applications. It is also useful for microservice to microservice HTTP API calls. Notice that the client application need to have a reference to the application service contracts (typically, the <code>.Application.Contracts</code> project in your solution) in order to consume the services.</p>
<p><strong>Example usage:</strong></p>
<pre><code class="language-bash">abp generate-proxy -t csharp -u https://localhost:44305
</code></pre>
<p><code>-t</code> indicates the client type, C# here. <code>-u</code> is the URL of the server application. It creates the proxies for the application (the app module) by default. You can specify the module name as <code>-m &lt;module-name&gt;</code> if you are building a modular system. The following figure shows the generated files:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/df5319bd5c6ea32035ce3a0043e5b8d8.png" alt="csharp-proxies.png" /></p>
<p>The next step is to enable the static proxy system for your application (or module) using the <code>AddStaticHttpClientProxies</code> extension method:</p>
<pre><code class="language-csharp">context.Services.AddStaticHttpClientProxies(
    typeof(MyApplicationContractsModule).Assembly
);
</code></pre>
<p>You can then inject and use the application service interfaces of these proxies. The usage is same of the <a href="https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients">dynamic C# client proxies</a>.</p>
<p>When you use static proxies for a module / application, you don't need to dynamic proxies. Find and remove the <code>context.Services.AddHttpClientProxies(...)</code> in your solution (typically in the <code>*.HttpApi.Client</code> project).</p>
<h4>Creating JavaScript client proxies</h4>
<p>JavaScript proxies are useful to consume APIs from MVC / Razor Pages UI. It works on JQuery AJAX API, just like the <a href="https://docs.abp.io/en/abp/latest/UI/AspNetCore/Dynamic-JavaScript-Proxies">dynamic JavaScript proxies</a>.</p>
<p><strong>Example usage:</strong></p>
<pre><code class="language-bash">abp generate-proxy -t js -u https://localhost:44305
</code></pre>
<p>The following figure shows the generated file:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/1b985b5f5bed9358713a3a0043e61af2.png" alt="js-proxies.png" /></p>
<p>Then you can consume the server-side APIs from your JavaScript code just like the <a href="https://docs.abp.io/en/abp/latest/UI/AspNetCore/Dynamic-JavaScript-Proxies">dynamic JavaScript proxies</a>.</p>
<h4>Creating Angular client proxies</h4>
<p>Angular developers knows that the generate-proxy command was already available in ABP's previous versions to create client-side proxy services in the Angular UI. The same functionality continues to be available and already <a href="https://docs.abp.io/en/abp/latest/UI/Angular/Service-Proxies">documented here</a>.</p>
<p><strong>Example usage:</strong></p>
<pre><code class="language-bash">abp generate-proxy -t ng -u https://localhost:44305
</code></pre>
<h3>Transactional Outbox &amp; Inbox for the Distributed Event Bus</h3>
<p>This was one of the most awaited features by distributed software developers.</p>
<p>The <a href="https://microservices.io/patterns/data/transactional-outbox.html">transactional outbox pattern</a> is used to publishing distributed events within the same transaction that manipulates the application database. Distributed events are saved into the database inside the same transaction with your data changes, then sent to the message broker (like RabbitMQ or Kafka) by a separate background worker with a re-try system. In this way, it ensures the consistency between your database state and the published events.</p>
<p>The transactional inbox pattern, on the other hand, saves incoming events into database first, then executes the event handler in a transactional manner and removes the event from the inbox queue in the same transaction. It also ensures that the event is only executed one time by keeping the processed messages for a while and discarding the duplicate events received from the message broker.</p>
<p>Enabling the inbox and outbox patterns requires a few manual steps for your application. We've created a simple <a href="https://github.com/abpframework/abp/tree/dev/test/DistEvents">console application example</a>, but I will also explain all the steps here.</p>
<h4>Pre-requirements</h4>
<p>First of all, you need to have EF Core or MongoDB installed into your solution. It should be already installed if you'd created a solution from the ABP startup template.</p>
<h4>Install the packages</h4>
<p>For the outbox &amp; inbox functionality, ABP depends on <a href="https://www.nuget.org/packages/DistributedLock.Core">DistributedLock.Core</a> library which provides a distributed locking system for concurrency control in a distributed environment. There are <a href="https://github.com/madelson/DistributedLock#implementations">many distributed lock providers</a>, including Redis, SqlServer and ZooKeeper. You can use the one you like. Here, I will show the Redis provider.</p>
<p>Add <a href="https://www.nuget.org/packages/DistributedLock.Redis">DistributedLock.Redis</a> NuGet package to your project, then add the following code into the ConfigureService method of your ABP module class:</p>
<pre><code class="language-csharp">context.Services.AddSingleton&lt;IDistributedLockProvider&gt;(sp =&gt;
{
    var connection = ConnectionMultiplexer.Connect(configuration[&quot;Redis:Configuration&quot;]);
    return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
});
</code></pre>
<p>We are getting the Redis configuration from the <code>appsettings.json</code> file, so add the following lines to your <code>appsettings.json</code> file:</p>
<pre><code class="language-json">&quot;Redis&quot;: {
    &quot;Configuration&quot;: &quot;127.0.0.1&quot;
}
</code></pre>
<p>You can change the IP or customize the configuration based on your environment.</p>
<h4>Configure the DbContext</h4>
<p>Open your <code>DbContext</code> class, implement the <code>IHasEventInbox</code> and the <code>IHasEventOutbox</code> interfaces. You should end up by adding two <code>DbSet</code> properties into your <code>DbContext</code> class:</p>
<pre><code class="language-csharp">public DbSet&lt;IncomingEventRecord&gt; IncomingEvents { get; set; }
public DbSet&lt;OutgoingEventRecord&gt; OutgoingEvents { get; set; }
</code></pre>
<p>Add the following lines inside the <code>OnModelCreating</code> method of your <code>DbContext</code> class:</p>
<pre><code class="language-csharp">builder.ConfigureEventInbox();
builder.ConfigureEventOutbox();
</code></pre>
<p>It is similar for MongoDB; implement the <code>IHasEventInbox</code> and the <code>IHasEventOutbox</code> interfaces. There is no <code>Configure...</code> method for MongoDB.</p>
<p>Now, we've added inbox/outbox related tables to our database schema. Now, for EF Core, use the standard <code>Add-Migration</code> and <code>Update-Database</code> commands to apply changes into your database (you can skip this step for MongoDB). If you want to use the command-line terminal, run the following commands in the root directory of the database integration project:</p>
<pre><code class="language-bash">dotnet ef migrations add &quot;Added_Event_Boxes&quot;
dotnet ef database update
</code></pre>
<h4>Configure the distributed event bus options</h4>
<p>As the last step, write the following configuration code inside the <code>ConfigureServices</code> method of your module class:</p>
<pre><code class="language-csharp">Configure&lt;AbpDistributedEventBusOptions&gt;(options =&gt;
{
    options.Outboxes.Configure(config =&gt;
    {
        config.UseDbContext&lt;YourDbContext&gt;();
    });
    
    options.Inboxes.Configure(config =&gt;
    {
        config.UseDbContext&lt;YourDbContext&gt;();
    });
});
</code></pre>
<p>Replace <code>YourDbContext</code> with your <code>DbContext</code> class.</p>
<p>That's all. You can continue to publishing and consuming events just as before. See the <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus">distributed event bus documentation</a> if you don't know how to use it.</p>
<h3>Publishing events in transaction</h3>
<p>The previous feature (outbox &amp; inbox) solves the transactional event publishing problem for distributed systems. This feature, publishing events in transaction, solves the problem of executing event handlers in the same transaction that the events are published in for non-distributed applications. With 5.0, all events (local or distributed) are handled in the same transaction. If any handler fails, the transaction is rolled back. If you don't want that, you should use try/catch and ignore the exception inside your event handler.</p>
<p>Remember that if you don't install a real distributed event provider (like <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus-RabbitMQ-Integration">RabbitMQ</a> or <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus-Kafka-Integration">Kafka</a>), the <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus">distributed events</a> are actually executed in-process, just like the <a href="https://docs.abp.io/en/abp/latest/Local-Event-Bus">local events</a>. So, with this development, all the events become transactional, even if your system is distributed or not.</p>
<p>No action needed to take. It will just work by default. There is a <a href="https://github.com/abpframework/abp/issues/9897">deprecation note</a> related to this change (some pre-defined events <a href="https://github.com/abpframework/abp/issues/9908">will be removed</a> in the next major version since they are not needed anymore)</p>
<h3>Inactivating a user</h3>
<p>The <a href="https://docs.abp.io/en/abp/latest/Modules/Identity">Identity module</a> has a new feature to make a user active or inactive. Inactive users can not login to the system. In this way, you can disable a user account without deleting it. An <em>Active</em> checkbox is added to the user create/edit dialog to control it on the UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/d95519a64013bdf417ad3a0043e67091.png" alt="user-active.png" /></p>
<p>EF Core developers should add a new database migration since this brings a new field to the <code>AbpUsers</code> table.</p>
<h3>Overriding email settings per tenant</h3>
<p>If you're building a multi-tenant application, it is now possible to override email sending settings per tenant. To make this possible, you should first enable that <a href="https://docs.abp.io/en/abp/latest/Features">feature</a> to the tenant you want, by clicking the <em>Actions -&gt; Features</em> for the tenant.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/a7dca2286734d7639df73a0043e69a5b.png" alt="tenant-features.png" /></p>
<p>Enable the feature using the checkbox as shown in the following modal:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/44948ada62c17e46b2473a0043e6bf7b.png" alt="enable-email-tenant.png" /></p>
<p>Then the tenant admin can open the email settings page under the Administration -&gt; Settings menu (on development environment, logout, switch to the tenant and re-login with the tenant admin):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/e34b85f434a8e361bce13a0043e6e920.png" alt="email-settings.png" /></p>
<h3>Hangfire dashboard permission</h3>
<p>ABP allows to use Hangfire as the background job manager when you install the integration package <a href="https://docs.abp.io/en/abp/5.0/Background-Jobs-Hangfire">as documented</a>. Hangfire's dashboard is used to monitor and control the background job queues. Here, a screenshot from the dashboard:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/97e5fd88057afaea6bbb3a0043e70c00.png" alt="hangfire-dashboard.png" /></p>
<p>Hangfire's dashboard is not authorized by default, so any user can navigate to the <code>/hangfire</code> URL and see/control the jobs. With the ABP version 5.0, we've added a built-in authorization implementation for the Hangfire dashboard. Instead of <code>app.UseHangfireDashboard();</code>, you can use the following middleware configuration:</p>
<pre><code class="language-csharp">app.UseHangfireDashboard(&quot;/hangfire&quot;, new DashboardOptions
{
    AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }
});
</code></pre>
<p>In this way, only the authenticated users can see the dashboard. However, we suggest to set a permission name, so only the users with that permission can see the dashboard:</p>
<pre><code class="language-csharp">app.UseHangfireDashboard(&quot;/hangfire&quot;, new DashboardOptions
{
    AsyncAuthorization = new[] {
        new AbpHangfireAuthorizationFilter(&quot;MyPermissionName&quot;)
    }
});     
</code></pre>
<p>You can define the permission (<code>MyPermissionName</code> in this example) using the standard <a href="https://docs.abp.io/en/abp/5.0/Authorization#permission-system">permission system</a>.</p>
<h3>Introducing AbpControllerBase</h3>
<p>ABP provides an <code>AbpController</code> class that you can inherit your MVC controllers from. It provides some pre-injected services to simplify your controllers. With v5.0, we are adding a second base controller class, <code>AbpControllerBase</code>, which is more proper to create API controllers (without view features). It is suggested to inherit from the <code>AbpControllerBase</code> class to create API controllers, instead of the <code>AbpController</code> class.</p>
<p><strong>Example:</strong></p>
<pre><code class="language-csharp">[Route(&quot;api/products&quot;)]
public class ProductController : AbpControllerBase
{
    // TODO: ...
}
</code></pre>
<h3>Automatically setting the TenantId for new entities</h3>
<p>Beginning from the version 5.0, ABP automatically sets the <code>TenantId</code> for you when you create a new entity object (that implements the <code>IMultiTenant</code> interface). It is done in the constructor of the base <code>Entity</code> class (all other base entity and aggregate root classes are derived from the <code>Entity</code> class). The <code>TenantId</code> is set from the current value of the <code>ICurrentTenant.Id</code> property.</p>
<p>Previously, it was a responsibility of the developer to set <code>TenantId</code> for new entities. Now, ABP takes care of it. You only may need to set it if you want to set id of a tenant other than the current tenant.</p>
<p>This can be a breaking change in rare cases (for example, if you create host side entities from a tenant context and do not explicitly set host entity's <code>TenantId</code> to <code>null</code>).</p>
<h2>Community News</h2>
<h3>ABP Community Talks 2021.12</h3>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/518c1127f772c4cc26e53a004436c1ba.png" alt="community-talks.png" /></p>
<p>As the core ABP development team, we've decided to organize monthly live meetings with the ABP community. The first live meeting will be at <strong>December 16, 2021, 17:00 (UTC)</strong> on YouTube. ABP core team members will present some of the new features coming with ABP 5.0.</p>
<p><strong>Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-4afca9c9</strong></p>
<p>You can also <a href="https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ">subscribe to the Volosoft channel</a> for reminders for further ABP events and videos.</p>
<h3>ASP.NET Community Startup!</h3>
<p>It was great for us to be invited to Microsoft's <a href="https://dotnet.microsoft.com/live/community-standup">ASP.NET Community Weekly Standup</a> show, at September 28. There was a very high attention and that made us very happy. Thanks to the ABP Community and all the watchers :) If you've missed the talk, <a href="https://www.youtube.com/watch?v=vMWM-_ihjwM">you can watch it here</a>.</p>
<h3>Upcoming ABP Book!</h3>
<p>I am currently authoring the first official book for the ABP Framework and it is on <a href="https://www.amazon.com/Mastering-ABP-Framework-maintainable-implementing-dp-1801079242/dp/1801079242">pre-sale on Amazon</a> now.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-11-18-abpio-platform-50-rc1-has-been-released/bad6fa7e5605c270f0ca3a0043e7534a.png" alt="abp-book-cover.png" /></p>
<p>This books is a complete guide to start working with the ABP Framework, explore the ABP features and concepts. It also contains chapters for DDD, modular application development and multi-tenancy to learn and practically work with the ABP architecture to build maintainable software solutions and create SaaS applications. The book will be based on ABP 5.0 and published in the beginning of 2022. You can <a href="https://www.amazon.com/Mastering-ABP-Framework-maintainable-implementing-dp-1801079242/dp/1801079242">pre-order now</a>!</p>
<h3>New ABP Community posts</h3>
<p>Here, some of the latest posts added to the <a href="https://community.abp.io/">ABP community</a>:</p>
<ul>
<li><a href="https://community.abp.io/articles/many-to-many-relationship-with-abp-and-ef-core-g7rm2qut">Many to many relationship with ABP and EF Core</a></li>
<li><a href="https://community.abp.io/articles/abp-framework-add-a-new-module-to-your-abp-application-eogrfm88">Add a new module to your ABP application</a></li>
<li><a href="https://community.abp.io/articles/changing-ui-theme-for-abp-mvc-razor-pages-ui-ravx6a0o">Changing UI Theme for ABP MVC / Razor Pages UI</a></li>
<li><a href="https://community.abp.io/articles/create-a-windows-service-with-abp-framework-hop4dtra">Create a Windows Service with the ABP Framework</a></li>
<li><a href="https://community.abp.io/articles/deploy-abp-framework-dotnet-core-tiered-app-to-docker-swarm-kcrjbjec">Deploy ABP Framework .NET Core tiered application to docker swarm</a></li>
<li><a href="https://community.abp.io/articles/centralized-logging-for-.net-core-abp-microservices-app-using-seq-g1xe7e7y">Centralized logging for .NET Core ABP microservices application using Seq</a></li>
</ul>
<p>Thanks to the ABP Community for all the contents they have published. You can also post your ABP and .NET related (text or video) contents to the ABP Community.</p>
<h2>Conclusion</h2>
<p>The ABP version 5.0 is coming with important changes (like .NET 6 and Bootstrap 5) and features. In this blog post, I summarized the news about that new version. Please try it and provide feedback by opening issues on <a href="https://github.com/abpframework/abp">the GitHub repository</a>. Thank you all!</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/a5125df3-0bf7-d685-1d12-3a0043e98ad7" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/a5125df3-0bf7-d685-1d12-3a0043e98ad7" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/asp.net-community-standup-exploring-the-abp-framework-17egi3mw</guid>
      <link>https://abp.io/community/videos/asp.net-community-standup-exploring-the-abp-framework-17egi3mw</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>exploring-abp</category>
      <category>community-standup</category>
      <title>ASP.NET Community Standup: Exploring the ABP Framework</title>
      <description>ABP team member Halil ibrahim Kalkan is presenting the ABP Framework on the .NET Community Standup. He is also explaining some coming features with ABP 5.0!</description>
      <pubDate>Wed, 29 Sep 2021 06:45:32 Z</pubDate>
      <a10:updated>2026-04-24T06:41:27Z</a10:updated>
      <content:encoded><![CDATA[ABP team member Halil ibrahim Kalkan is presenting the ABP Framework on the .NET Community Standup. He is also explaining some coming features with ABP 5.0! <br \> <a href="https://www.youtube.com/watch?v=vMWM-_ihjwM" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/26fba04c-d008-de20-feeb-39ff4279f1e3" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/26fba04c-d008-de20-feeb-39ff4279f1e3" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-4.4-final-has-been-released-sg9gkf3h</guid>
      <link>https://abp.io/community/posts/abp.io-platform-4.4-final-has-been-released-sg9gkf3h</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform 4.4 Final Has Been Released!</title>
      <description>ABP Framework and ABP Commercial 4.4 versions have been released.</description>
      <pubDate>Wed, 04 Aug 2021 07:59:52 Z</pubDate>
      <a10:updated>2026-10-02T17:08:15Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 4.4 versions have been released today.</p>
<h2>What's New With 4.4?</h2>
<p>Since all the new features are already explained in details with the 4.4 RC announcement posts, I will not repeat all the details again. See <a href="https://blog.abp.io/abp/ABP-Platform-4-4-RC-Has-Been-Released">the related blog post</a> for all the features and enhancements.</p>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>The Road Map</h2>
<p>The next feature version will be 5.0. It is planned to release the 5.0 RC (Release Candidate) in November 2021. See the updated road maps;</p>
<ul>
<li><a href="https://docs.abp.io/en/abp/latest/Road-Map">ABP Framework Road Map</a></li>
<li><a href="https://docs.abp.io/en/commercial/latest/road-map">ABP Commercial Road Map</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/8796f527-c651-7ad3-518d-39fe2259e417" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/8796f527-c651-7ad3-518d-39fe2259e417" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-platform-4.4-rc-has-been-released-5l7govbx</guid>
      <link>https://abp.io/community/posts/abp-platform-4.4-rc-has-been-released-5l7govbx</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP Platform 4.4 RC Has Been Released</title>
      <description>This post covers the new features and changes coming with the ABP.IO platform version 4.4.</description>
      <pubDate>Wed, 30 Jun 2021 07:28:44 Z</pubDate>
      <a10:updated>2026-10-02T14:11:57Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we have released the <a href="https://abp.io/">ABP Framework</a> and the <a href="https://commercial.abp.io/">ABP Commercial</a> version 4.4 RC (Release Candidate). This blog post introduces the new features and important changes in this new version.</p>
<blockquote>
<p><strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/53">4.4.0 final</a> version is July 27, 2021</strong>.</p>
</blockquote>
<h2>Get Started with the 4.4 RC</h2>
<p>If you want to try the version 4.4.0 today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>4.4.0-rc.2</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 4.4.0-rc.2
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 4.4.0-rc.2
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<h3>Migration Notes</h3>
<p>There is <strong>no breaking change</strong> with this version. However, if you are using Entity Framework Core, you will need to run the <code>Add-Migration</code> command to add a new <strong>database migration</strong> since some changes done in the module database mappings.</p>
<h2>What's new with the ABP Framework 4.4</h2>
<h3>Removed EntityFrameworkCore.DbMigrations Project</h3>
<p>With this version, we are doing an important change in the application startup solution template. The startup solution was containing an <code>EntityFrameworkCore.DbMigrations</code> project that contains a separate <code>DbContext</code> class which was responsible to unify the module database mappings and maintain the code-first database migrations. With the v4.4, we've removed that project from the solution. In the new structure, the <code>EntityFrameworkCore</code> integration project will be used for database migrations as well as on runtime.</p>
<p>We'd published <a href="https://community.abp.io/articles/unifying-dbcontexts-for-ef-core-removing-the-ef-core-migrations-project-nsyhrtna">a community article</a> about that change. Please see the article to understand the motivation behind the change.</p>
<p>Beside the <code>DbContext</code> unification, we've also used the new <code>ReplaceDbContext</code> attribute and <a href="https://github.com/abpframework/abp/blob/ea2205f0855f52015152ae066a5c239af4b8511f/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs#L18-L19">replaced</a> the <code>IIdentityDbContext</code> and <code>ITenantManagementDbContext</code> interfaces to make it possible to perform join queries over repositories for these modules easily. In the next days, we will publish another community article to explain the problem and the solution. However, most of times, you don't need to know these details.</p>
<h3>Dynamic Menu Management for the CMS Kit Module</h3>
<p>CMS Kit is a set of reusable <em>Content Management System</em> features packaged as an ABP application module. We had published the first usable version with the previous release. With this release, we are adding another feature to the CMS Kit module: You can now dynamically arrange the main menu on the UI, which is an essential feature for any kind of content management system. In this way, you can add pages or any kind of arbitrary URLs to the main menu from the UI.</p>
<p>A screenshot from the menu management page (from the CMS Kit admin side):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/7a3cf29d2aba7b2ba2da39fd6de861a4.png" alt="image.png" /></p>
<p>And the items rendered in a public website:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/ff130f8587690cfec96a39fd6de8a340.png" alt="image.png" /></p>
<p>Note that this feature is also available with the open source <a href="https://docs.abp.io/en/abp/4.4/Modules/Cms-Kit/Index">CMS Kit module</a> (while the screenshots have been taken from the ABP Commercial).</p>
<h3>Razor Engine Support for Text Templating</h3>
<p><a href="https://docs.abp.io/en/abp/4.4/Text-Templating">Text Templating</a> is a system to generate content on runtime by using a model (data) and a template. It was running on the <a href="https://github.com/scriban/scriban">Scriban</a> templating engine. Beginning from this version, we have a second option: We can use the familiar <strong>razor syntax</strong> to build and render the templates. See the text templating <a href="https://docs.abp.io/en/abp/4.4/Text-Templating-Razor">razor integration document</a> to get started with the new engine!</p>
<h3>New Customization Points for DbContext/Entities</h3>
<p>Two new extension methods are added to <code>ObjectExtensionManager.Instance</code> to override EF Core mappings of <a href="https://docs.abp.io/en/abp/latest/Modules/Index">pre-built application modules</a>.</p>
<p><strong>Example: Change mappings for the <code>IdentityDbContext</code> to override mappings for the <code>IdentityUser</code> entity</strong></p>
<pre><code class="language-csharp">ObjectExtensionManager.Instance.MapEfCoreDbContext&lt;IdentityDbContext&gt;(modelBuilder =&gt;
{
    modelBuilder.Entity&lt;IdentityUser&gt;(b =&gt;
    {
        b.ToTable(&quot;MyUsers&quot;);
        b.Property(x =&gt; x.Email).HasMaxLength(300);
    });
});
</code></pre>
<p>The startup template contains a class, like <code>YourProjectNameEfCoreEntityExtensionMappings</code>, that can be used to place that code.</p>
<h3>New ABP CLI Commands</h3>
<p>There are new <a href="https://docs.abp.io/en/abp/4.4/CLI">ABP CLI</a> commands introduced with the v4.4:</p>
<ul>
<li><code>abp install-libs</code> command is used for MVC / Razor Pages and Blazor Server applications to restore the <code>wwwroot/libs</code> folder. Previously we were running the <code>yarn</code> and <code>gulp</code> commands to restore that folder. While the <code>install-libs</code> command still uses yarn (if available), it is no longer needed to use <code>gulp</code>.</li>
<li><code>abp prompt</code> command can be used to open a prompt for the ABP CLI and run multiple commands without needing to specify the <code>abp</code> command every time. For example, if you run <code>abp prompt</code>, then you can directly run <code>install-libs</code> instead of <code>abp install-libs</code>. Use <code>exit</code> to quit from the ABP prompt.</li>
<li><code>abp batch</code> command can be used to run multiple ABP commands with one command. Prepare a text file, write each command as a line (without the <code>abp</code> command prefix), then execute <code>abp batch &lt;batch-file&gt;</code> (ex: <code>abp batch your_commands.txt</code>) command to execute all the commands in that file.</li>
</ul>
<h3>appsettings.secrets.json</h3>
<p>Added <code>appsettings.secrets.json</code> to the startup template that can be used to set your sensitive/secret configuration values. You can ignore this file from source control (by adding to <code>.gitignore</code> if you're using git) and keep it only in developer/production machines.</p>
<h3>Other ABP Framework Improvements</h3>
<ul>
<li><a href="https://github.com/abpframework/abp/pull/9350">#9350</a> Extracted <code>IRemoteServiceConfigurationProvider</code> to get remote service configurations. You can replace this service to get the configuration from any source.</li>
<li><a href="https://github.com/abpframework/abp/pull/8829">#8829</a> Implemented error handler and retry for distributed event bus.</li>
<li><a href="https://github.com/abpframework/abp/issues/9288">#9288</a> Use default CORS policy instead of a named one in the startup template. It is suggested to update your own solutions to make it simpler.</li>
<li>Translated the framework and module localization strings to Hindi, Italian (thanks to Emanuele Filardo), Finnish, French and Slovak (thanks to <a href="https://www.m2ms.sk/">Michal Čadecký</a>) languages.</li>
</ul>
<p>Beside these, there are a lot of enhancements and bug fixes. See the <a href="https://github.com/abpframework/abp/milestone/52?closed=1">4.4-preview milestone</a> for all issues and pull requests closed with this version.</p>
<h2>What's new with the ABP Commercial 4.4</h2>
<h3>New Features for the SaaS Module</h3>
<p>We've implemented some important features to the <a href="https://commercial.abp.io/modules/Volo.Saas">SaaS module</a>:</p>
<ul>
<li>Integrated to the <a href="https://commercial.abp.io/modules/Volo.Payment">Payment module</a> and implemented <strong>subscription system</strong> for the SaaS module.</li>
<li>Allow to make a <strong>tenant active/passive</strong>. In this way, you can take a tenant to passive to prevent the users of that tenant from using the system. In addition, you can set a date to automatically make a tenant passive when the date comes.</li>
<li>Allow to <strong>limit user count</strong> for a tenant.</li>
<li>Allow to set <strong>different connection strings</strong> for a tenant for each database/module, which makes possible to create different databases for a tenant for each microservice in a microservice solution.</li>
</ul>
<h3>New ABP Suite Code Generation Features</h3>
<p>There are many improvements done for for <a href="https://commercial.abp.io/tools/suite">ABP Suite</a>, including CRUD page generation for the <strong><a href="https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index">microservice solution</a> template</strong>.</p>
<h3>Angular UI: Two Factor Authentication for the Resource Owner Password Flow</h3>
<p>In the previous version, we had implemented the resource owner password authentication flow for the Angular UI, which makes the login process easier for simpler applications. With this release, we've implemented two-factor authentication for that flow. Authorization code flow already supports 2FA.</p>
<h3>Other ABP Commercial Improvements</h3>
<ul>
<li>Added web layers to microservices in the microservice solution. You can use them to create modular UI or override existing pages/components of pre-built modules (e.g. Identity and SaaS).</li>
<li>ABP Commercial license code has been moved to <code>appsettings.secrets.json</code> in the new startup templates.</li>
</ul>
<p>Beside these, there are many minor improvements and fixes done in the modules and themes.</p>
<h2>Other News</h2>
<p>In this section, I will share some news that you may be interested in.</p>
<h3>New Article: Using Elsa Workflow with ABP Framework</h3>
<p>We have been frequently asked how to use <a href="https://elsa-workflows.github.io/elsa-core/">Elsa Workflows</a> with the ABP Framework. Finally, we have <a href="https://community.abp.io/articles/using-elsa-workflow-with-the-abp-framework-773siqi9">created an article</a> to demonstrate it.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/78af8114d6a067fdad1739fd6de94488.gif" alt="elsa-overview.gif" /></p>
<p>You can <a href="https://community.abp.io/articles/using-elsa-workflow-with-the-abp-framework-773siqi9">check it</a> to see how to integrate Elsa into an ABP based solution easily.</p>
<h3>Free E-Book: Implementing Domain Driven Design</h3>
<p>We've published a free e-book for the ABP Community in the beginning of June. This is a practical guide for implementing Domain Driven Design (DDD). While the implementation details are based on the ABP Framework infrastructure, the basic concepts, principles and models can be applied to any solution, even if it is not a .NET solution.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/efb3af37378b58e9960839fd6de992e2.png" alt="ddd-book.png" /></p>
<p>Thousands of copies are already downloaded. If you haven't seen it yet, <a href="https://abp.io/books/implementing-domain-driven-design">click here to get a free copy of that e-book</a>.</p>
<h3>The LeptonX Theme</h3>
<p>We have been working on a new ABP theme, named the <em>LeptonX</em>, for a long time. The theme will be available for ABP Framework (free - lite version) and ABP Commercial (pro version). It is being finalized in the next weeks and we will release the first version in a short time.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/9b4c6bd70a839fd0781839fd6de9b717.png" alt="leptonx.png" /></p>
<p>See <a href="https://volosoft.com/blog/introducing-the-lepton-theme-next-generation">this blog post</a> to learn more about that project.</p>
<h3>Volosoft &amp; .NET Foundation</h3>
<p><a href="https://volosoft.com/">Volosoft</a>, the company leads the ABP Framework project, has been a corporate sponsor of the <a href="https://dotnetfoundation.org/">.NET Foundation</a>. We are happy by taking our place among other great sponsors!</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-06-30-abp-platform-44-rc-has-been-released/a828f0a8f5283d73020039fd6de9db2d.png" alt="dotnetfoundation-sponsor-volosoft.png" /></p>
<p>We will continue to contribute to and support open source! See this <a href="https://volosoft.com/blog/Volosoft-Announces-the-NET-Foundation-Sponsorship">blog post for the announcement</a>.</p>
<h3>Looking for Developer Advocate(s)</h3>
<p>We are actively looking for professional developer advocates for the ABP.IO platform. If you want to create content and touch to the ABP community, please check our <a href="https://github.com/volosoft/vs-home/issues/13">job post</a>.</p>
<h2>About the Next Version</h2>
<p>The next version will be a major version: 5.0, which will be based on .NET 6.0. We are planning to release it in the end of 2021, short time after the .NET 6.0 release. We will release multiple preview/beta versions before the RC version. See the <a href="https://docs.abp.io/en/abp/latest/Road-Map">road map</a> for details of the planned works for the version 5.0.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/8d5bd418-7a99-0ab5-a6a2-39fd6dfecd1b" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/8d5bd418-7a99-0ab5-a6a2-39fd6dfecd1b" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/unifying-dbcontexts-for-ef-core-removing-the-ef-core-migrations-project-nsyhrtna</guid>
      <link>https://abp.io/community/posts/unifying-dbcontexts-for-ef-core-removing-the-ef-core-migrations-project-nsyhrtna</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>entity-framework-core</category>
      <category>migrations</category>
      <category>unifying-contexts</category>
      <title>Unifying DbContexts for EF Core / Removing the EF Core Migrations Project</title>
      <description>This article shows how to remove the EntityFrameworkCore.DbMigrations project from your solution to have a single DbContext for your database mappings and code first migrations.</description>
      <pubDate>Sat, 22 May 2021 10:53:57 Z</pubDate>
      <a10:updated>2026-10-02T13:06:19Z</a10:updated>
      <content:encoded><![CDATA[<h1>Unifying DbContexts for EF Core / Removing the EF Core Migrations Project</h1>
<p>This article shows how to remove the <code>EntityFrameworkCore.DbMigrations</code> project from your solution to have a single <code>DbContext</code> for your database mappings and code first migrations.</p>
<h2>Source Code</h2>
<p>You can find source of the example solution used in this article <a href="https://github.com/abpframework/abp-samples/tree/master/UnifiedEfCoreMigrations">here</a>.</p>
<h2>Motivation</h2>
<p>If you create a new solution with <strong>Entity Framework Core</strong> as the database provider, you see two projects related to EF Core:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/default-solution.png" alt="default-solution" /></p>
<ul>
<li><code>EntityFrameworkCore</code> project contains the actual <code>DbContext</code> of your application. It includes all the database mappings and your repository implementations.</li>
<li><code>EntityFrameworkCore.DbMigrations</code> project, on the other hand, contains another <code>DbContext</code> class that is only used to create and apply the database migrations. It contains the database mappings for all the modules you are using, so have a single, unified database schema.</li>
</ul>
<p>There were two main reasons we'd created such a separation;</p>
<ol>
<li>Your actual <code>DbContext</code> remains simple and focused. It only contains your own entities and doesn't contain anything related to the modules that are used by the application.</li>
<li>You can create your own classes that map to the tables of depending modules. For example, the <code>AppUser</code> entity (that is included in the downloaded solution) is mapped to <code>AbpUsers</code> table in the database, which is actually mapped to the <code>IdentityUser</code> entity of the <a href="https://docs.abp.io/en/abp/latest/Modules/Identity">Identity Module</a>. That means they share the same database table. <code>AppUser</code> includes less properties compared to <code>IdentityServer</code>. You only add the properties you need, not more. This also allows you to add new standard (type-safe) properties to the <code>AppUser</code> for your custom requirements as long as you carefully manage the database mappings.</li>
</ol>
<p>We've <a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Migrations">documented the structure</a> in details. However, it has always been a problem for the developers since that structure makes your database mappings complicated when you re-use tables of the depended modules. Many developers are misunderstanding or making mistakes while mapping such classes, especially when they try to use these entities in relations to other entities.</p>
<p><strong>So, <a href="https://github.com/abpframework/abp/issues/8776">we've decided</a> to cancel that separation and remove the <code>EntityFrameworkCore.DbMigrations</code> project in the version 4.4. New startup solutions will come with a single <code>EntityFrameworkCore</code> project and single <code>DbContext</code> class.</strong></p>
<p>If you want to make it in your solution with today, follow the steps in this article.</p>
<h2>Warnings</h2>
<blockquote>
<p>There is one <strong>drawback</strong> with the new design (everything in software development is a trade-off). We need to remove the <code>AppUser</code> entity, because EF Core can't map two classes to single table without an inheritance relation. I will cover this later in this article and provide suggestions to deal with it.</p>
</blockquote>
<blockquote>
<p>If you are using <strong>ABP Commercial</strong>, ABP Suite code generation won't work correctly before the version 4.4. Please upgrade to v4.4 if you are using a previous version.</p>
</blockquote>
<h2>The Steps</h2>
<p>Our goal to enable database migrations in the <code>EntityFrameworkCore</code> project, remove the <code>EntityFrameworkCore.DbMigrations</code> project and revisit the code depending on that package.</p>
<blockquote>
<p>I've created a new solution with v4.3, then made all the changes in a pull request, so you can see all the changes line by line.  While this article will cover all, you may want to <a href="https://github.com/abpframework/abp-samples/pull/88">check the changes done in this PR</a> if you have problems with the implementation.</p>
</blockquote>
<h3>1) Add Microsoft.EntityFrameworkCore.Tools package to the EntityFrameworkCore project</h3>
<p>Add the following code into the <code>EntityFrameworkCore.csproj</code> file:</p>
<pre><code class="language-xml">&lt;ItemGroup&gt;
  &lt;PackageReference Include=&quot;Microsoft.EntityFrameworkCore.Tools&quot; Version=&quot;5.0.*&quot;&gt;
    &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers&lt;/IncludeAssets&gt;
    &lt;PrivateAssets&gt;compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native&lt;/PrivateAssets&gt;
  &lt;/PackageReference&gt;
&lt;/ItemGroup&gt;
</code></pre>
<h3>2) Create design time DbContext factory</h3>
<p>Create a class implementing <code>IDesignTimeDbContextFactory&lt;T&gt;</code> inside the <code>EntityFrameworkCore</code> project:</p>
<pre><code class="language-csharp">using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
    public class UnifiedContextsDemoDbContextFactory : IDesignTimeDbContextFactory&lt;UnifiedContextsDemoDbContext&gt;
    {
        public UnifiedContextsDemoDbContext CreateDbContext(string[] args)
        {
            UnifiedContextsDemoEfCoreEntityExtensionMappings.Configure();

            var configuration = BuildConfiguration();

            var builder = new DbContextOptionsBuilder&lt;UnifiedContextsDemoDbContext&gt;()
                .UseSqlServer(configuration.GetConnectionString(&quot;Default&quot;));

            return new UnifiedContextsDemoDbContext(builder.Options);
        }

        private static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), &quot;../UnifiedContextsDemo.DbMigrator/&quot;))
                .AddJsonFile(&quot;appsettings.json&quot;, optional: false);

            return builder.Build();
        }
    }
}
</code></pre>
<p>I basically copied from the <code>EntityFrameworkCore.DbMigrations</code> project, renamed and uses the actual <code>DbContext</code> of the application.</p>
<h3>3) Create DB schema migrator</h3>
<p>Copy <code>EntityFrameworkCore...DbSchemaMigrator</code> (<code>...</code> standard for your project name) class to the <code>EntityFrameworkCore</code> project and change the code in the <code>MigrateAsync</code> method to use the actual <code>DbContext</code> of the application. In my case, the final class is shown below:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using UnifiedContextsDemo.Data;
using Volo.Abp.DependencyInjection;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
    public class EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator
        : IUnifiedContextsDemoDbSchemaMigrator, ITransientDependency
    {
        private readonly IServiceProvider _serviceProvider;

        public EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator(
            IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public async Task MigrateAsync()
        {
            /* We intentionally resolving the UnifiedContextsDemoMigrationsDbContext
             * from IServiceProvider (instead of directly injecting it)
             * to properly get the connection string of the current tenant in the
             * current scope.
             */

            await _serviceProvider
                .GetRequiredService&lt;UnifiedContextsDemoDbContext&gt;()
                .Database
                .MigrateAsync();
        }
    }
}
</code></pre>
<h3>4) Move module configurations</h3>
<p>The migrations <code>DbContext</code> typically contains code lines like <code>builder.ConfigureXXX()</code> for each module you are using. We can move these lines to our actual <code>DbContext</code> in the <code>EntityFrameworkCore</code> project. Also, remove the database mappings for the <code>AppUser</code> (we will remove this entity). Optionally, you may move the database mappings code for your own entities from <code>...DbContextModelCreatingExtensions</code> class in the <code>OnModelCreating</code> method of the actual <code>DbContext</code>, and remove the static extension class.</p>
<p>For the example solution, the final <code>DbContext</code> class is shown below:</p>
<pre><code class="language-csharp">using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.Users;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
    [ConnectionStringName(&quot;Default&quot;)]
    public class UnifiedContextsDemoDbContext
        : AbpDbContext&lt;UnifiedContextsDemoDbContext&gt;
    {
        public DbSet&lt;AppUser&gt; Users { get; set; }

        /* Add DbSet properties for your Aggregate Roots / Entities here.
         * Also map them inside UnifiedContextsDemoDbContextModelCreatingExtensions.ConfigureUnifiedContextsDemo
         */

        public UnifiedContextsDemoDbContext(
            DbContextOptions&lt;UnifiedContextsDemoDbContext&gt; options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.ConfigurePermissionManagement();
            builder.ConfigureSettingManagement();
            builder.ConfigureBackgroundJobs();
            builder.ConfigureAuditLogging();
            builder.ConfigureIdentity();
            builder.ConfigureIdentityServer();
            builder.ConfigureFeatureManagement();
            builder.ConfigureTenantManagement();

            /* Configure your own tables/entities inside here */

            //builder.Entity&lt;YourEntity&gt;(b =&gt;
            //{
            //    b.ToTable(UnifiedContextsDemoConsts.DbTablePrefix + &quot;YourEntities&quot;, UnifiedContextsDemoConsts.DbSchema);
            //    b.ConfigureByConvention(); //auto configure for the base class props
            //    //...
            //});
        }
    }
}
</code></pre>
<h3>5) Remove <code>EntityFrameworkCore.DbMigrations</code> project from the solution</h3>
<p>Remove the <code>EntityFrameworkCore.DbMigrations</code> project from the solution and replace references given to that project by the <code>EntityFrameworkCore</code> project reference.</p>
<p>Also, change usages of <code>...EntityFrameworkCoreDbMigrationsModule</code> to <code>...EntityFrameworkCoreModule</code> (<code>...</code> stands for your project name).</p>
<p>In this example, I had to change references and usages in the <code>DbMigrator</code>, <code>Web</code> and <code>EntityFrameworkCore.Tests</code> projects.</p>
<h3>6) Remove AppUser Entity</h3>
<p>We need to remove the <code>AppUser</code> entity, because EF Core can't map two classes to single table without an inheritance relation. So, remove this class and all the usages. You can replace the usages with <code>IdentityUser</code> if you need to query users in your application code. See The AppUser Entity &amp; Custom Properties section for more info.</p>
<h3>7) Create or move the migrations</h3>
<p>We've removed the <code>EntityFrameworkCore.DbMigrations</code> project. What about the migrations created and applied into the database until now? If you want to keep your migrations history, copy all the migrations from the <code>EntityFrameworkCore.DbMigrations</code> project to the <code>EntityFrameworkCore</code> project and manually change the <code>DbContext</code> type in the designer classes.</p>
<p>If you want to clear the migrations history, but continue with the migrations already applied to the database, create a new database migration in the <code>EntityFrameworkCore</code> project, executing the following command in a command-line terminal in the directory of that project:</p>
<pre><code class="language-bash">dotnet ef migrations add InitialUnified
</code></pre>
<p>You can specify a different migration name, surely. This will create a migration class that contains all the database tables you already have in the database. Keep calm and delete all the content in the <code>Up</code> and <code>Down</code> methods. Then you can apply the migration to the database:</p>
<pre><code class="language-bash">dotnet ef database update
</code></pre>
<p>Your database won't have any change, because the migration is just empty and does nothing. From now, you can create new migrations as you change your entities, just like you normally do.</p>
<p>All the changes are done. The next section explains how to add custom properties to entities of depending modules with this design.</p>
<h2>The AppUser Entity &amp; Custom Properties</h2>
<p>The database mapping logic, solution structure and migrations become much simpler and easier to manage with that new setup.</p>
<p>As a drawback, we had to remove the <code>AppUser</code> entity, which was sharing the <code>AbpUsers</code> table with the <code>IdentityUser</code> entity of the Identity Module. Fortunately, ABP provides a flexible system to <a href="https://docs.abp.io/en/abp/latest/Module-Entity-Extensions">extend existing entities</a> in case of you need to define some custom properties. In this section, I will show how to add a custom property to the <code>IdentityUser</code> entity and use it in your application code and database queries.</p>
<p>I've done all the changes in this part as a single PR, so you may want to <a href="https://github.com/abpframework/abp-samples/pull/89">check the changes done in this PR</a> if you have problems with the implementation.</p>
<h3>Defining a Custom Property</h3>
<p>The application startup template provides a point to configure the custom properties for existing entities, which is located under <code>Domain.Shared</code> project, in the <code>...ModuleExtensionConfigurator.cs</code> (<code>...</code> standard for your project name) class. Open that class and add the following code into the <code>ConfigureExtraProperties</code> method:</p>
<pre><code class="language-csharp">ObjectExtensionManager.Instance.Modules()
    .ConfigureIdentity(identity =&gt;
    {
        identity.ConfigureUser(user =&gt;
        {
            user.AddOrUpdateProperty&lt;string&gt;( //property type: string
                &quot;SocialSecurityNumber&quot;, //property name
                property =&gt;
                {
                    //validation rules
                    property.Attributes.Add(new RequiredAttribute());
                    property.Attributes.Add(new StringLengthAttribute(64));
                }
            );
        });
    });
</code></pre>
<p>After that setup, just run the application to see the new property on the Users table:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/new-prop-on-table.png" alt="new-prop-on-table" /></p>
<p>The new <code>SocialSecurityNumber</code> property will also be available on the create and edit modals with the validation rules.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Module-Entity-Extensions">Module Entity Extensions</a> document to understand and control the new custom property with all the details.</p>
</blockquote>
<h3>Mapping to the Database Table</h3>
<p>By default, ABP saves all custom properties inside the <code>ExtraProperties</code> field as a single JSON object. If you prefer to create a table field for a custom property, you can configure it in the <code>...EfCoreEntityExtensionMappings.cs</code> (<code>...</code> standard for your project name) class in the <code>EntityFrameworkCore</code> project. You can write the following code inside this class (in the <code>OneTimeRunner.Run</code>):</p>
<pre><code class="language-csharp">ObjectExtensionManager.Instance
    .MapEfCoreProperty&lt;IdentityUser, string&gt;(
        &quot;SocialSecurityNumber&quot;,
        (entityBuilder, propertyBuilder) =&gt;
        {
            propertyBuilder.HasMaxLength(64).IsRequired().HasDefaultValue(&quot;&quot;);
        }
    );
</code></pre>
<p>After that, you can just run the following command in a command-line terminal to add a new database migration (in the directory of the <code>EntityFrameworkCore</code> project):</p>
<pre><code class="language-bash">dotnet ef migrations add Added_SocialSecurityNumber_To_IdentityUser
</code></pre>
<p>This will add a new migration class to your project. You can then run the following command (or run the <code>.DbMigrator</code> application) to apply changes to the database:</p>
<pre><code class="language-bash">dotnet ef database update
</code></pre>
<p>This will add a <code>SocialSecurityNumber</code> field to the <code>AbpUsers</code> table in the database.</p>
<h3>Using Custom Properties in the Application Code</h3>
<p>Now, we can use <code>GetProperty</code> and <code>SetProperty</code> methods on the <code>IdentityUser</code> entity to work with the new property. The following code demonstrates to get/set the custom property:</p>
<pre><code class="language-csharp">public class MyUserService : ITransientDependency
{
    private readonly IRepository&lt;IdentityUser, Guid&gt; _userRepository;

    public MyUserService(IRepository&lt;IdentityUser, Guid&gt; userRepository)
    {
        _userRepository = userRepository;
    }

    public async Task SetSocialSecurityNumberDemoAsync(string userName, string number)
    {
        var user = await _userRepository.GetAsync(u =&gt; u.UserName == userName);
        user.SetProperty(&quot;SocialSecurityNumber&quot;, number);
        await _userRepository.UpdateAsync(user);
    }

    public async Task&lt;string&gt; GetSocialSecurityNumberDemoAsync(string userName)
    {
        var user = await _userRepository.GetAsync(u =&gt; u.UserName == userName);
        return user.GetProperty&lt;string&gt;(&quot;SocialSecurityNumber&quot;);
    }
}
</code></pre>
<p>Tip: Using <code>SetProperty</code> and <code>GetProperty</code> with a string property name everywhere could be tedious and error-prone. I suggest you to create the following extension methods:</p>
<pre><code class="language-csharp">public static class MyUserExtensions
{
    public const string SocialSecurityNumber = &quot;SocialSecurityNumber&quot;;

    public static void SetSocialSecurityNumber(this IdentityUser user, string number)
    {
        user.SetProperty(SocialSecurityNumber, number);
    }
    
    public static string GetSocialSecurityNumber(this IdentityUser user)
    {
        return user.GetProperty&lt;string&gt;(SocialSecurityNumber);
    }
}
</code></pre>
<p>Then we can change the previous demo method as shown below:</p>
<pre><code class="language-csharp">public async Task SetSocialSecurityNumberDemoAsync(string userName, string number)
{
    var user = await _userRepository.GetAsync(u =&gt; u.UserName == userName);
    user.SetSocialSecurityNumber(number); //Using the new extension property
    await _userRepository.UpdateAsync(user);
}

public async Task&lt;string&gt; GetSocialSecurityNumberDemoAsync(string userName)
{
    var user = await _userRepository.GetAsync(u =&gt; u.UserName == userName);
    return user.GetSocialSecurityNumber(); //Using the new extension property
}
</code></pre>
<h3>Querying Based on a Custom Property</h3>
<p>You may want to query users based on <code>SocialSecurityNumber</code>. We will use Entity Framework's API to accomplish that. You have two options to use EF Core API in your application code:</p>
<ol>
<li>Reference to the <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore">Microsoft.EntityFrameworkCore</a> NuGet package from your project (domain or application layer, depending on where you want to use the EF Core API).</li>
<li>Create a <a href="https://docs.abp.io/en/abp/latest/Repositories">repository</a> interface in the domain layer and implement it in your <code>EntityFrameworkCore</code> project.</li>
</ol>
<p>I will prefer the second approach, so I am defining a new repository interface in the <code>Domain</code> project:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

namespace UnifiedContextsDemo.Users
{
    public interface IMyUserRepository : IRepository&lt;IdentityUser, Guid&gt;
    {
        Task&lt;IdentityUser&gt; FindBySocialSecurityNumber(string number);
    }
}
</code></pre>
<p>Then implementing it in the <code>EntityFrameworkCore</code> project:</p>
<pre><code class="language-csharp">using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Identity;

namespace UnifiedContextsDemo.Users
{
    public class MyUserRepository 
        : EfCoreRepository&lt;UnifiedContextsDemoDbContext, IdentityUser, Guid&gt;, 
          IMyUserRepository
    {
        public MyUserRepository(
            IDbContextProvider&lt;UnifiedContextsDemoDbContext&gt; dbContextProvider) 
            : base(dbContextProvider)
        {
        }

        public async Task&lt;IdentityUser&gt; FindBySocialSecurityNumber(string number)
        {
            var dbContext = await GetDbContextAsync();
            return await dbContext.Set&lt;IdentityUser&gt;()
                .Where(u =&gt; EF.Property&lt;string&gt;(u, &quot;SocialSecurityNumber&quot;) == number)
                .FirstOrDefaultAsync();
        }
    }
}
</code></pre>
<p>Tip: Use the constant instead of <code>SocialSecurityNumber</code> as a magic string.</p>
<p>Now, I can use that repository method in my service by injecting the <code>IMyUserRepository</code>:</p>
<pre><code class="language-csharp">public class MyUserService : ITransientDependency
{
    private readonly IMyUserRepository _userRepository;

    public MyUserService(IMyUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    //...other methods

    public async Task&lt;IdentityUser&gt; FindBySocialSecurityNumberDemoAsync(string number)
    {
        return await _userRepository.FindBySocialSecurityNumber(number);
    }
}
</code></pre>
<p>I changed <code>IRepository&lt;IdentityUser, Guid&gt;</code> dependency to <code>IMyUserRepository</code>.</p>
<h2>Conclusion</h2>
<p>With this article, I wanted to show you how to remove the <code>EntityFrameworkCore.DbMigrations</code> project from your solution to simplify your database mappings, database migrations and your application code. In the next version (4.4), this <a href="https://github.com/abpframework/abp/issues/8776">will be</a> the default approach.</p>
<h3>Source Code</h3>
<p>You can find source of the example solution used in this article <a href="https://github.com/abpframework/abp-samples/tree/master/UnifiedEfCoreMigrations">here</a>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/0ad7a05a-0e01-10e9-1900-39fca5e2aa5d" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/0ad7a05a-0e01-10e9-1900-39fca5e2aa5d" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/asp.net-coreun-abpsi-ts7xgq6h</guid>
      <link>https://abp.io/community/videos/asp.net-coreun-abpsi-ts7xgq6h</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp-framework</category>
      <title>ASP.NET Core'un ABP'si!</title>
      <description>Bu canlı etkinliğin kaydında ABP Framework'e giriş, örnek uygulama geliştirme, bazı ABP özelliklerinin gösterimi ve soru &amp; cevap kısımları bulunmaktadır.</description>
      <pubDate>Sun, 16 May 2021 18:45:41 Z</pubDate>
      <a10:updated>2026-04-03T10:45:36Z</a10:updated>
      <content:encoded><![CDATA[Bu canlı etkinliğin kaydında ABP Framework'e giriş, örnek uygulama geliştirme, bazı ABP özelliklerinin gösterimi ve soru & cevap kısımları bulunmaktadır. <br \> <a href="https://www.youtube.com/watch?v=o9X2FAcxD1Q" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/fdd02210-37f7-25b9-37d8-39fcea853b27" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/fdd02210-37f7-25b9-37d8-39fcea853b27" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v4.3-has-been-released-4jhtq1f2</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v4.3-has-been-released-4jhtq1f2</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <category>release</category>
      <title>ABP.IO Platform v4.3 Has Been Released!</title>
      <description>Introducing the ABP.IO Platform version 4.3.0!</description>
      <pubDate>Sat, 24 Apr 2021 00:21:12 Z</pubDate>
      <a10:updated>2026-10-02T12:11:52Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 4.3 versions have been released today.</p>
<h2>What's New With 4.3?</h2>
<p>Since all the new features are already explained in details with the 4.3 RC announcement posts, I will not repeat all the details again. See the related blog posts for all the features and enhancements;</p>
<ul>
<li><a href="https://blog.abp.io/abp/ABP-Framework-4.3-RC-Has-Been-Published">What's New with the ABP Framework 4.3</a></li>
<li><a href="https://blog.abp.io/abp/ABP-Commercial-4.3-RC-Has-Been-Published">What's new with the ABP Commercial 4.3</a></li>
</ul>
<h2>The Quick Start Tutorial</h2>
<p>With this version, we've created a minimalist <a href="https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index">quick start tutorial</a> for developers who are new to the ABP Framework.</p>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>Migration Guides</h2>
<p><strong>Check the migration guides (<a href="https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-4_3">for ABP Framework</a> &amp; for <a href="https://docs.abp.io/en/commercial/latest/migration-guides/v4_3">ABP Commercial</a>) for the applications with the version 4.2.x upgrading to the version 4.3.0.</strong></p>
<h2>The Road Map</h2>
<p>The next feature version will be 4.4. It is planned to release the 4.4 RC (Release Candidate) at the end of Quarter 2, 2021. See the updated road maps;</p>
<ul>
<li><a href="https://docs.abp.io/en/abp/latest/Road-Map">ABP Framework Road Map</a></li>
<li><a href="https://docs.abp.io/en/commercial/latest/road-map">ABP Commercial Road Map</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/fd5f1bec-5e2a-90c4-1b5b-39fc136d4fd1" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/fd5f1bec-5e2a-90c4-1b5b-39fc136d4fd1" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-commercial-4.3-rc-has-been-published-u6gqz1ce</guid>
      <link>https://abp.io/community/posts/abp-commercial-4.3-rc-has-been-published-u6gqz1ce</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp-commercial</category>
      <title>ABP Commercial 4.3 RC Has Been Published</title>
      <description>Introducing the ABP Commercial v4.3 RC and the new features coming with this version</description>
      <pubDate>Thu, 01 Apr 2021 12:23:20 Z</pubDate>
      <a10:updated>2026-10-02T09:04:49Z</a10:updated>
      <content:encoded><![CDATA[<p>ABP Commercial version 4.3 RC (Release Candidate) has been published alongside <a href="https://blog.abp.io/abp/ABP-Framework-4.3-RC-Has-Been-Published">ABP Framework 4.3. RC</a>. I will introduce the new features in this blog post. Here, a list of highlights for this release;</p>
<ul>
<li>The <strong>microservice starter template</strong> is getting more mature. We've also added a <strong>service template</strong> to add new microservices to the solution.</li>
<li>New option for the application starter template to have a <strong>separate database schema for tenant databases</strong>.</li>
<li>New <strong>Forms</strong> module to create surveys</li>
<li><strong>Enable/disable modules</strong> per edition/tenant.</li>
<li><strong>Lepton theme</strong> and <strong>Account module</strong>'s source codes are available with the Team License.</li>
</ul>
<p>Here, some other features already covered in the ABP Framework announcement, but worth mentioning here since they are also implemented for the ABP Commercial;</p>
<ul>
<li><strong>Blazor UI server-side</strong> support</li>
<li><strong>Email setting</strong> management UI</li>
<li><strong>Module extensibility</strong> system is now available for the <strong>Blazor UI</strong> too.</li>
</ul>
<blockquote>
<p>This post doesn't cover the features and changes done on the ABP Framework side. Please also see the <strong><a href="https://blog.abp.io/abp/ABP-Framework-4.3-RC-Has-Been-Published">ABP Framework 4.3. RC blog post</a></strong>.</p>
</blockquote>
<h2>The Migration Guide</h2>
<p><strong>This upgrade requires some manual work documented in <a href="https://docs.abp.io/en/commercial/4.3/migration-guides/v4_3">the migration guide</a>.</strong> Please read the guide carefully. Even if your application doesn't break on upgrade, you should apply the changes to avoid future release problems.</p>
<h2>Known Issues</h2>
<p>If you upgrade the ABP CLI to 4.3.0-rc.1 and try to create a new solution using the stable (4.2.x) version, it won't compile because of some missing packages. Use ABP CLI to create solutions with <code>--preview</code> option and downgrade to 4.2.2 to create 4.2.2 solutions. This will be fixed in 4.3.0-rc.2.</p>
<h2>What's New With The ABP Commercial 4.3</h2>
<h3>The Microservice Starter Template</h3>
<p>We'd introduced an initial version of the <a href="https://docs.abp.io/en/commercial/4.3/startup-templates/microservice/index">microservice starter template</a> in the <a href="https://blog.abp.io/abp/ABP-IO-Platform-v4-2-RC-Has-Been-Released">previous version</a>. It is getting more mature with this release. We've made a lot of improvements and changes, including;</p>
<ul>
<li>New <strong>&quot;service&quot; template</strong> to add new microservices for the solution. It still requires some manual work to integrate to other services and gateways; however, it makes progress very easy and straightforward.</li>
<li>Added <a href="https://github.com/dotnet/tye">Tye</a> configuration to develop and test the solution easier.</li>
<li>Added <a href="https://prometheus.io/">Prometheus</a>, <a href="https://grafana.com/">Grafana</a> integrations for monitoring the solution.</li>
<li><strong>Automatic database migrations</strong>. Every microservice automatically checks and migrates/seeds its database on startup (concurrency issues are resolved for multiple instances). For multi-tenant systems, tenant databases are also upgraded by the queue.</li>
<li>For multi-tenant systems, <strong>databases are being created on the fly</strong> for new tenants with separate connection strings.</li>
<li>Created <strong>separate solution (<code>.sln</code>) file</strong> for each microservice, gateway, and application. In this way, you can focus on what you are working on. The main (roof) solution file only includes the executable projects in these solutions.</li>
<li>All microservices are converted to the standard <strong>layered module structure</strong>, making it easier to align with ABP application development practices.</li>
</ul>
<p>After this release, <strong>we will be preparing microservice development guides</strong> based on this startup solution.</p>
<h3>Separate Tenant Schema</h3>
<p>ABP's multi-tenancy system allows to the creation of dedicated databases for tenants. However, the application startup solution comes with a single database migration path; hence it has a single database schema. As a result, tenant databases have some host-related tables. These tables are not used for tenants, and they are always empty. However, their existence may disturb us as a clean developer.</p>
<p>With this release, the application startup template provides an option to address this problem. So, if you want, you can have a separate migration path for tenant databases. Of course, this has a cost; You will have two DbContexts for migration purposes, bringing additional complexity to your solution. We've done our best to reduce this complexity and added a README file into the migration assembly. If you prefer this approach, please check that README file.</p>
<p>You can specify the new <code>--separate-tenant-schema</code> parameter while you are creating a new solution using the <a href="https://docs.abp.io/en/abp/4.3/CLI">ABP CLI</a>:</p>
<pre><code class="language-bash">abp new Acme.BookStore --separate-tenant-schema
</code></pre>
<p>If you prefer the <a href="https://docs.abp.io/en/commercial/latest/abp-suite/create-solution">ABP Suite</a> to create solutions, you can check the <em>Separated tenant schema</em> option.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/8ebd9aac852b5784ac5a39fb9f7d8545.png" alt="abp-suite-separate-tenant-schema.png" /></p>
<h3>Creating Tenant Databases On The Fly</h3>
<p>With this release, the separate tenant database feature becomes more mature. When you create a new tenant with specifying a connection string, the <strong>new database is automatically created</strong> with all the tables and the initial seed data if available. So, tenants can immediately start to use the new database. With this change, tenant connection string textboxes come in the tenant creation modal:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/704de57f75e01c54da7e39fb9f7a1a9d.png" alt="new-tenant-modal.png" /></p>
<p>Besides, we've added an &quot;<strong>Apply database migrations</strong>&quot; action to the tenant management UI to manually trigger the database creation &amp; migration in case you have a problem with automatic migration:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/e5d9e0f63668c8d8734e39fb9f7a5d44.png" alt="tenant-db-migrate.png" /></p>
<p>Automatic migration only tries one time. If it fails, it writes the exception log and discards this request. For example, this can happen if the connection string is wrong or the database server is not available. In this case, you can manually retry with this action.</p>
<blockquote>
<p>Note that this feature requires to <strong>make changes in your solution</strong>, if you upgrade from an older version. Because the tenant database creation and migration code are located in the application startup template. See the <a href="https://docs.abp.io/en/commercial/4.3/migration-guides/v4_3">version 4.3 migration guide</a> for details.</p>
</blockquote>
<h3>New Module: CMS Kit</h3>
<p>CMS Kit module initial version has been released with this version. As stated in the <a href="https://blog.abp.io/abp/ABP-Framework-4.3-RC-Has-Been-Published">ABP Framework 4.3 announcement post</a>, it should be considered premature for now.</p>
<p>For ABP Commercial application startup template, we are providing an option to include the CMS Kit into the solution while creating new solutions:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/878e889ad7aaa6c6644939fb9f7aad50.png" alt="cms-kit-selection.png" /></p>
<p>It is available only if you select the <em>Public web site</em> option. Once you include CMS Kit, a <em>Cms</em> item is shown on the menu:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/6e2a6211140d5e181b7839fb9f7af1f2.png" alt="cms-kit-menu.png" /></p>
<p>Each CMS Kit feature can be individually enabled/disabled, using the global feature system. Once you disable a feature, it becomes completely invisible; even the related tables are not included in your database.</p>
<p>CMS Kit features are separated into two categories: Open source (free) features and pro (commercial) features. For now, only newsletter and contact form features are commercial. By the time, we will add more free and commercial features.</p>
<blockquote>
<p>We will create a separate blog post for the CMS Kit module, so I keep it short.</p>
</blockquote>
<h3>New Module: Forms</h3>
<p><em>Forms</em> is a new module that is being introduced with this version. It looks like the Google Forms application; You dynamically create forms on the UI and send them to people to answer. Then you can get statistics/report and export answers to a CSV file.</p>
<p>Forms module currently supports the following question types;</p>
<ul>
<li><strong>Free text</strong></li>
<li>Selecting a <strong>single option</strong> from a <strong>dropdown</strong> list or a <strong>radio button</strong> list</li>
<li><strong>Multiple choice</strong>: Selecting multiple options from a checkbox list</li>
</ul>
<p><strong>Screenshot: editing form and questions - view responses</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/650b59e4f21de768c47039fb9f7b5658.png" alt="forms-edit-report.png" /></p>
<p><strong>Screenshot: answering to the form</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/a40402b854fdd27d446539fb9f7bbc1d.png" alt="forms-answer.png" /></p>
<h3>Team License Source Code for Modules</h3>
<p>Team License users can't access the source code of modules and themes as a license restriction. You have to buy a Business or Enterprise license to download any module/theme's full source code. However, we got a lot of feedback from the Team License owners on the source code of the account module and the lepton theme. We see that customization of these two modules is highly necessary for most of our customers.</p>
<p>With this version, we decided to allow Team License holders to download the source code of the <strong>Account Module</strong> and the <strong>Lepton Theme</strong> to freely customize them based on their requirements.</p>
<p>You can <strong>Replace these modules with their source code</strong> using the ABP Suite:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/f4984a23c9f2a6f5919639fb9f7c06a1.png" alt="account-lepton-source.png" /></p>
<p>Remember that; when you include the source code in your solution, it is your responsibility to upgrade them when we release new versions (while you don't have to upgrade them).</p>
<h3>Lepton Theme Public Website Layout</h3>
<p>We'd added a public website application in the application starter template in the previous versions. It was using the public website layout of the Lepton Theme. We realized that the layout of this application is customized or completely changed in most of the solutions. So, with this version, the layout is included inside the application in the downloaded solution. You can freely change it. Before, you had to download it separately and include it in your solution manually.</p>
<h3>Enable/Disable Modules</h3>
<p>With this release, all modules can be enabled/disabled per edition/tenant. You can allow/disallow modules when you click <em>Features</em> action for an edition or tenant:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-commercial-43-rc-has-been-published/cab3b63d4fad58a3b8c039fb9f7c4961.png" alt="enable-disable-features.png" /></p>
<h3>Other Features/Changes</h3>
<ul>
<li>ABP Suite now supports defining <em>required</em> navigation properties on code generation.</li>
<li><strong>Blazor server-side</strong> (with tiered option) is added for the application and microservice starter templates.</li>
<li>An <strong>&quot;Email&quot;</strong> tab has been added to the Settings page to configure the email settings.</li>
</ul>
<h2>Feedback</h2>
<p>Please check out the ABP Commercial 4.3 RC to help us to release a more stable version. <strong>The planned release date for the 4.3.0 final version is April 21, 2021</strong>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/e239ff2c-ed55-3b3b-50fa-39fb9f902aad" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/e239ff2c-ed55-3b3b-50fa-39fb9f902aad" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-4.3-rc-has-been-published-kb3gkwur</guid>
      <link>https://abp.io/community/posts/abp-framework-4.3-rc-has-been-published-kb3gkwur</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <title>ABP Framework 4.3 RC Has Been Published</title>
      <description>Introducing the ABP v4.3 RC and the new features coming with this version</description>
      <pubDate>Thu, 01 Apr 2021 11:47:51 Z</pubDate>
      <a10:updated>2026-10-02T14:44:28Z</a10:updated>
      <content:encoded><![CDATA[<blockquote>
<p>Notice that the <strong>version 4.3.0 stable has already been released</strong>. We've updated the version usages in this post.</p>
</blockquote>
<p>We are super excited to announce the ABP Framework 4.3 RC (Release Candidate). Here, a list of highlights of this release;</p>
<ul>
<li><strong>CMS Kit</strong> module initial release.</li>
<li><strong>Blazor UI server-side</strong> support.</li>
<li><strong>Module extensibility</strong> system for the Blazor UI.</li>
<li>Angular UI <strong>resource owner password</strong> flow comes back.</li>
<li><strong>Volo.Abp.EntityFrameworkCore.Oracle</strong> package is now compatible with .NET 5.</li>
<li>CLI support to easily add the <strong>Basic Theme</strong> into the solution.</li>
<li>New <strong>IInitLogger</strong> service to write logs before dependency injection phase completed.</li>
</ul>
<p>Besides the new features above, we've done many performance improvements, enhancements and bug fixes on the current features. See the <a href="https://github.com/abpframework/abp/milestone/49">4.3 milestone</a> on GitHub for all changes made on this version.</p>
<p>This version was a big development journey for us; <a href="https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.3-preview">~160 issues</a> resolved, <a href="https://github.com/abpframework/abp/pulls?q=is%3Aopen+is%3Apr+milestone%3A4.3-preview">~300 PRs</a> merged and <strong>~1,700 commits</strong> done only in the <a href="https://github.com/abpframework/abp">main framework repository</a>. <strong>Thanks to the ABP Framework team and all the contributors.</strong></p>
<blockquote>
<p>ABP Commercial 4.3 RC has also been published. We will write a separate blog post for it.</p>
</blockquote>
<h2>The Migration Guide</h2>
<p>We normally don't make breaking changes in feature versions. However, this version has some small <strong>breaking changes</strong> mostly related to Blazor UI WebAssembly &amp; Server separation. <strong>Please check the <a href="https://docs.abp.io/en/abp/4.3/Migration-Guides/Abp-4_3">migration guide</a> while upgrading to version 4.3</strong>.</p>
<h2>Known Issues</h2>
<p>Some minor issues will be fixed in the stable release. You can see the known issues <a href="https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.3-final">here</a>.</p>
<h2>Get Started With The 4.3</h2>
<p>If you want to try version 4.3 today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>4.3.0</code> using a command-line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 4.3.0
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 4.3.0
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/4.3/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<h3>Quick Start Tutorial</h3>
<p>If you are new to ABP Framework, we've prepared a <a href="https://docs.abp.io/en/abp/4.3/Tutorials/Todo/Index">new quick start tutorial</a> that can be pretty helpful to warm up to the ABP Framework.</p>
<h2>What's New With The ABP Framework 4.3</h2>
<h3>CMS Kit</h3>
<p>CMS (Content Management System) Kit was a module we worked on for the last couple of months. It is usable now, and we are releasing the initial version with this release. We are considering this module as pre-mature. It will be improved in the next versions. The goal to provide a flexible and extensible CMS infrastructure to .NET community. It currently has the following features;</p>
<ul>
<li><strong>Pages</strong>: Used to create UI pages with a Markdown + WYSIWYG editor. Once you create a page, it becomes available via URL like <code>/pages/my-page-url</code>.</li>
<li><strong>Blog</strong>: A built-in blog system that supports multiple blogs with blog posts.</li>
<li><strong>Comments</strong>: Allows users to write comments under contents. It is used for blog posts.</li>
<li><strong>Tags</strong>: To add tag feature to any content/entity. It is used for blog posts.</li>
<li><strong>Reactions</strong>: Allows users to react to content via emojis, like a smile, upvote, downvote, etc.</li>
<li><strong>Rating</strong>: This component is used to rate content by users.</li>
</ul>
<p>All features are separately usable. For example, you can create an image gallery and reuse the Comments and Tags features for the images. You can enable/disable features individually using the <a href="https://docs.abp.io/en/abp/4.3/global-features">Global Features System</a>.</p>
<blockquote>
<p>We will create a separate blog post for the CMS Kit module, so I keep it short.</p>
</blockquote>
<h3>Blazor Server Side</h3>
<p>We'd implemented Blazor WebAssembly before. With version 4.3, we have the Blazor Server-Side option too. All the current functionalities are available to the Blazor Server.</p>
<p>You can select Blazor Server as the UI type while creating a new solution.</p>
<p><strong>Example:</strong></p>
<pre><code class="language-bash">abp new Acme.BookStore -u blazor-server
</code></pre>
<p>If you write <code>blazor</code> as the UI type, it will create Blazor WebAssembly just as before.</p>
<blockquote>
<p>You can also select the Blazor Server on the <a href="https://abp.io/get-started">get started</a> page.</p>
</blockquote>
<p>Blazor Server applications are mixed applications; You can mix the server-side MVC / Razor Pages with the Blazor SPA. This brings an interesting opportunity: MVC / Razor Pages modules can work seamlessly in the Blazor Server applications. For example, the CMS Kit module has no Blazor UI yet, but you can use its MVC UI inside your Blazor Server application.</p>
<blockquote>
<p>Blazor Server UI has a <code>--tiered</code> option just <a href="https://docs.abp.io/en/abp/latest/Startup-Templates/Application#tiered-structure">like</a> the MVC / Razor Pages UI. This can be used to separate the HTTP API server from the UI server (UI application doesn't directly connect to the database).</p>
</blockquote>
<h3>Blazor UI Module Extensibility</h3>
<p>Module Entity Extensions and some other extensibility features was not supported by the Blazor UI. With this version, we've implemented that system for Blazor UI.</p>
<p>For anyone wondering what the module entity extensions is, please check <a href="https://docs.abp.io/en/abp/4.3/Module-Entity-Extensions">the document</a> or <a href="https://community.abp.io/articles/overview-of-abp-framework-4.1-module-extensions-part-1-n04f7bhf">this community video</a>.</p>
<h3>Email Setting Management UI</h3>
<p>With this release, a new item is added to the main menu to navigate to the setting management page. This page contains the email setting management UI, as shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-04-01-abp-framework-43-rc-has-been-published/2dbd008296ba5b04d66c39fb9f7330e2.png" alt="email-settings-page.png" /></p>
<p>The setting page is provided by the <a href="https://docs.abp.io/en/abp/4.3/Modules/Setting-Management">setting management module</a>, and it is extensible; You can add your tabs to this page for your application settings.</p>
<h3>Angular UI Resource Owner Password Flow</h3>
<p>The login page was removed from the Angular UI in previous versions because Authorization Code flow is the recommended approach for SPAs. However, it requires redirecting the user to the authentication server, logging there, and returning to the application. We got a lot of feedback because this brings overhead for simple applications.</p>
<p>With version 4.3, Angular UI can use its login page with resource owner password flow. Please refer to <a href="https://github.com/abpframework/abp/blob/dev/docs/en/UI/Angular/Account-Module.md">the documentation</a> to learn how to make it work.</p>
<h3>Volo.Abp.EntityFrameworkCore.Oracle Package</h3>
<p>We couldn't update the <a href="https://www.nuget.org/packages/Oracle.EntityFrameworkCore/">Oracle.EntityFrameworkCore</a> package on .NET 5.0 upgrade since it was not supporting .NET 5.0 at that time. Now, it supports .NET 5.0 and we've upgraded the package.</p>
<p>See <a href="https://docs.abp.io/en/abp/4.3/Entity-Framework-Core-Oracle-Official">the documentation</a> to learn how to switch to this package for the Oracle database.</p>
<h3>Add Basic Theme Into Your Solution</h3>
<p>ABP Framework provides a strong theming system. However, the default theme, named the Basic Theme, has a non-styled, base Bootstrap UI. It is expected that you override the styles and UI components of that theme in a serious application.</p>
<p>There are some articles (see for <a href="https://community.abp.io/articles/creating-a-new-ui-theme-by-copying-the-basic-theme-for-mvc-ui-yt9b18io">mvc</a> &amp; <a href="https://community.abp.io/articles/creating-a-new-ui-theme-by-copying-the-basic-theme-for-blazor-ui-qaf5ho1b">blazor</a>) to explain how to include the Basic Theme's source code into your solution to modify it fully. However, it still requires some manual work.</p>
<p>With this version, ABP CLI providing a command to add the Basic Theme's source code into your solution. Run the following command in a command-line terminal inside the root directory of your solution:</p>
<p><strong>MVC UI</strong></p>
<pre><code class="language-bash">abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic --with-source-code --add-to-solution-file
</code></pre>
<p><strong>Blazor Web Assembly UI</strong></p>
<pre><code class="language-bash">abp add-package Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme --with-source-code --add-to-solution-file
abp add-package Volo.Abp.AspNetCore.Components.Web.BasicTheme --with-source-code --add-to-solution-file
</code></pre>
<p><strong>Blazor Server UI</strong></p>
<pre><code class="language-bash">abp add-package Volo.Abp.AspNetCore.Components.Server.BasicTheme --with-source-code --add-to-solution-file
abp add-package Volo.Abp.AspNetCore.Components.Web.BasicTheme --with-source-code --add-to-solution-file
</code></pre>
<p>As you see, Blazor UI developers should add two packages. The Basic Theme consists of two packages for the Blazor UI: one for wasm/server and one shared.</p>
<p><strong>Angular UI</strong></p>
<p>Execute the following command in a terminal inside the <code>angular</code> folder of your solution:</p>
<pre><code class="language-bash">abp add-package @abp/ng.theme.basic --with-source-code
</code></pre>
<h3>IInitLogger</h3>
<p>In ASP.NET Core, logging is not possible before the dependency injection phase is completed. For example, you can't write log in <code>ConfigureServices</code> method. However, we sometimes need to write logs in this stage.</p>
<p>We are introducing the <code>IInitLogger</code> service, which allows writing logs inside the <code>ConfigureServices</code> method.</p>
<p><strong>Example:</strong></p>
<pre><code class="language-csharp">public class MyModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var logger = context.Services.GetInitLogger&lt;MyModule&gt;();
        logger.LogInformation(&quot;Some log...&quot;);
    }
}
</code></pre>
<p>Logs are written once the service registration phase is completed. It stores the written logs in memory and then writes logs to the actual <code>ILogger</code> when ready.</p>
<blockquote>
<p>Notice: Startup templates come with <a href="https://serilog.net/">Serilog</a> pre-installed. So, you can write logs everywhere by directly using its static API (ex: <code>Log.Information(&quot;...&quot;);</code>). The <code>InitLogger</code> is a way to write pre-initialization logs without depending on a particular logging library. So, it makes it very handy to write logs inside reusable modules.</p>
</blockquote>
<h3>Other Features/Changes</h3>
<ul>
<li><a href="https://github.com/abpframework/abp/issues/7423">#7423</a> MongoDB repository base aggregation API.</li>
<li><a href="https://github.com/abpframework/abp/issues/8163">#8163</a> Ignoring given files on minification for MVC UI.</li>
<li><a href="https://github.com/abpframework/abp/pull/7799">#7799</a> Added <code>RequiredPermissionName</code> to <code>ApplicationMenuItem</code> for MVC &amp; Blazor UI to easily show/hide menu items based on user permissions. Also added <code>RequiredPermissionName</code> to <code>ToolbarItem</code> for the MVC UI for the same purpose.</li>
<li><a href="https://github.com/abpframework/abp/pull/7523">#7523</a> Add more bundle methods to the distributed cache.</li>
<li><a href="https://github.com/abpframework/abp/pull/8013">#8013</a> Handle <code>JsonProperty</code> attribute on Angular proxy generation.</li>
</ul>
<p>See the <a href="https://github.com/abpframework/abp/milestone/49">4.3 milestone</a> on GitHub for all changes made on this version.</p>
<h2>Feedback</h2>
<p>Please check out the ABP Framework 4.3 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us release a more stable version. <strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/50">4.3.0 final</a> version is April 21, 2021</strong>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/23f298e3-d5a0-4e33-0633-39fb9f6fb10a" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/23f298e3-d5a0-4e33-0633-39fb9f6fb10a" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-4.2-final-has-been-released-bv0wf2e0</guid>
      <link>https://abp.io/community/posts/abp.io-platform-4.2-final-has-been-released-bv0wf2e0</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <title>ABP.IO Platform 4.2 Final Has Been Released!</title>
      <description>ABP Framework and ABP Commercial 4.2 versions have been released today.</description>
      <pubDate>Fri, 29 Jan 2021 06:32:08 Z</pubDate>
      <a10:updated>2026-10-02T12:11:34Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 4.2 versions have been released today.</p>
<h2>What's New With 4.2?</h2>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP-IO-Platform-v4-2-RC-Has-Been-Released">4.2 RC Announcement Post</a>, I will not repeat all the details again. See the <a href="https://blog.abp.io/abp/ABP-IO-Platform-v4-2-RC-Has-Been-Released">RC Blog Post</a> for all the features and enhancements.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 4.2 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>Migration Guide</h2>
<p>Check <a href="https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-4_2">the migration guide</a> for the applications with the version 4.x upgrading to the version 4.2.</p>
<blockquote>
<p>It is strongly recommended to check the migration guide for this version. Especially, the new <code>IRepository.GetQueryableAsync()</code> method is a core change should be considered after upgrading the solution.</p>
</blockquote>
<h2>About the Next Version</h2>
<p>The next feature version will be 4.3. It is planned to release the 4.3 RC (Release Candidate) on March 11 and the final version on March 25, 2021.</p>
<p>We decided to slow down the feature development for the <a href="https://github.com/abpframework/abp/milestone/49">next milestone</a>. We will continue to improve the existing features and introduce new ones, sure, but wanted to have more time for the planning, documentation, creating guides and improving the development experience.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/fe9ae537-21ec-319b-9221-39fa5f045d9d" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/fe9ae537-21ec-319b-9221-39fa5f045d9d" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v4.2-rc-has-been-released-gnp4cwji</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v4.2-rc-has-been-released-gnp4cwji</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <title>ABP.IO Platform v4.2 RC Has Been Released!</title>
      <description>This post covers the new features and changes coming with the ABP.IO platform 4.2 version.</description>
      <pubDate>Mon, 18 Jan 2021 18:50:10 Z</pubDate>
      <a10:updated>2026-10-02T09:01:38Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we have released the <a href="https://abp.io/">ABP Framework</a> and the <a href="https://commercial.abp.io/">ABP Commercial</a> 4.2.0 RC (Release Candidate). This blog post introduces the new features and important changes in this new version.</p>
<blockquote>
<p><strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/48">4.2.0 final</a> version is January 28, 2021</strong>.</p>
</blockquote>
<h2>Get Started with the 4.2 RC</h2>
<p>If you want to try the version <code>4.2.0</code> today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>4.2.0-rc.2</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 4.2.0-rc.2
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 4.2.0-rc.2
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<h2>Migration Guide</h2>
<p>Check <a href="https://docs.abp.io/en/abp/4.2/Migration-Guides/Abp-4_2">the migration guide</a> for the applications with the version 4.x upgrading to the version 4.2.</p>
<h2>What's new with the ABP Framework 4.2</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/56d7c496adc0c24c33b139fa29085a20.png" alt="104887532-78a79f00-597c-11eb-956a-2e9b77851f23.png" /></p>
<h2>IRepository.GetQueryableAsync()</h2>
<blockquote>
<p><strong>This version comes with an important change about using <code>IQueryable</code> features over the <a href="https://docs.abp.io/en/abp/4.2/Repositories">repositories</a>. It is suggested to read this section carefully and apply in your applications.</strong></p>
</blockquote>
<p><code>IRepository</code> interface inherits <code>IQueryable</code>, so you can directly use the standard LINQ extension methods, like <code>Where</code>, <code>OrderBy</code>, <code>First</code>, <code>Sum</code>... etc.</p>
<p><strong>Example: Using LINQ directly over the repository object</strong></p>
<pre><code class="language-csharp">public class BookAppService : ApplicationService, IBookAppService
{
    private readonly IRepository&lt;Book, Guid&gt; _bookRepository;

    public BookAppService(IRepository&lt;Book, Guid&gt; bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public async Task DoItInOldWayAsync()
    {
        //Apply any standard LINQ extension method
        var query = _bookRepository
            .Where(x =&gt; x.Price &gt; 10)
            .OrderBy(x =&gt; x.Name);

        //Execute the query asynchronously
        var books = await AsyncExecuter.ToListAsync(query);
    }
}
</code></pre>
<p><em>See <a href="https://docs.abp.io/en/abp/4.2/Repositories#iqueryable-async-operations">the documentation</a> if you wonder what is the <code>AsyncExecuter</code>.</em></p>
<p>Beginning from the version 4.2, the recommended way is using <code>IRepository.GetQueryableAsync()</code> to obtain an <code>IQueryable</code>, then use the LINQ extension methods over it.</p>
<p><strong>Example: Using the new GetQueryableAsync method</strong></p>
<pre><code class="language-csharp">public async Task DoItInNewWayAsync()
{
    //Use GetQueryableAsync to obtain the IQueryable&lt;Book&gt; first
    var queryable = await _bookRepository.GetQueryableAsync();

    //Then apply any standard LINQ extension method
    var query = queryable
        .Where(x =&gt; x.Price &gt; 10)
        .OrderBy(x =&gt; x.Name);

    //Finally, execute the query asynchronously
    var books = await AsyncExecuter.ToListAsync(query);
}
</code></pre>
<p>ABP may start a database transaction when you get an <code>IQueryable</code> (If current <a href="https://docs.abp.io/en/abp/latest/Unit-Of-Work">Unit Of Work</a> is transactional). In this new way, it is possible to <strong>start the database transaction in an asynchronous way</strong>. Previously, we could not get the advantage of asynchronous while starting the transactions.</p>
<blockquote>
<p><strong>The new way has a significant performance and scalability gain. The old usage (directly using LINQ over the repositories) will be removed in the next major version.</strong> You have a lot of time for the change, but we recommend to immediately take the action since the old usage has a big scalability problem.</p>
</blockquote>
<p>See <a href="https://docs.abp.io/en/abp/4.2/Migration-Guides/Abp-4_2">the migration guide</a> for the actions you may need to take while upgrading your applications.</p>
<h4>About IRepository Async Extension Methods</h4>
<p>Using IRepository Async Extension Methods has no such a problem. The examples below are pretty fine:</p>
<pre><code class="language-csharp">var countAll = await _personRepository
    .CountAsync();

var count = await _personRepository
    .CountAsync(x =&gt; x.Name.StartsWith(&quot;A&quot;));

var book1984 = await _bookRepository
    .FirstOrDefaultAsync(x =&gt; x.Name == &quot;John&quot;);   
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/4.2/Repositories#iqueryable-async-operations">repository documentation</a> to understand the relation between <code>IQueryable</code> and asynchronous operations.</p>
<h3>Repository Bulk Operations</h3>
<p>This version adds the following methods to the repositories:</p>
<ul>
<li><code>InsertManyAsync</code></li>
<li><code>UpdateManyAsync</code></li>
<li><code>DeleteManyAsync</code></li>
</ul>
<p>The purpose of these methods to insert, update or delete many entities in one call with a better performance.</p>
<p>Currently, <strong>MongoDB</strong> provider implements these methods as a single bulk operation since MongoDB API natively supports. But current <strong>Entity Framework Core</strong> implementation is not a real bulk operation. Instead, it does its best with the native API of the EF Core. If you want to implement in a more performant way, you can <a href="https://docs.abp.io/en/abp/4.2/Entity-Framework-Core#customize-bulk-operations">customize the bulk operations</a> with your own implementation or by using a library. We could find a good open source library for EF Core 5.0 to implement it.</p>
<h3>Selecting DBMS on Template Creation</h3>
<p><a href="https://docs.abp.io/en/abp/4.2/CLI#new">ABP CLI</a> now has an option to specify the DBMS when you use EF Core as the database provider.</p>
<p><strong>Example: Select MySQL as the DBMS</strong></p>
<pre><code class="language-bash">abp new BookStore -dbms mysql --preview
</code></pre>
<p>Available options: <code>SqlServer</code> (default), <code>MySQL</code>, <code>SQLite</code>, <code>Oracle-Devart</code>, <code>PostgreSQL</code>. See the <a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Other-DBMS">documentation</a> to use any other DBMS or switch the DBMS later.</p>
<p>One change related to this feature is that: Now, the startup template doesn't come with an <strong>initial migration</strong> file. This is because the database migrations are different based on your DBMS preference and should be re-created. However, when you first run the <code>.DbMigrator</code> application, it will create the initial migration and create the database just like before.</p>
<blockquote>
<p>See The Initial Migration section in the <a href="https://docs.abp.io/en/abp/4.2/Getting-Started-Running-Solution?DB=EF#database-migrations">Getting Started</a> document if you have problems on running the <code>.DbMigrator</code> application first time.</p>
</blockquote>
<h3>Swagger UI Login / Authorization</h3>
<p>Testing the swagger UI was requiring some additional work, especially your authentication server is separated from the application that hosts the Swagger UI.</p>
<p>With the version 4.2, the startup templates come with the authorization pre-configured for you. An Authorize button is available when you open the Swagger UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/7269e47595a878d6cea339fa2900c1a0.png" alt="swagger-authorize.png" /></p>
<p>When you click, it opens a modal to authorize:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/cebf90df69ed4e35791f39fa2900e3fe.png" alt="swagger-authorize-modal.png" /></p>
<p>When you click to the Authorize button here, you are redirected to the login page to login with your username and password (default username is <code>admin</code> and password is <code>1q2w3E*</code>).</p>
<blockquote>
<p>Remember to select the Scopes (typically <strong>select all</strong>) you want to use before clicking to the Authorize button.</p>
</blockquote>
<h3>Angular Unit Testing</h3>
<p>We've improved the modules and the startup template to setup and write unit tests easier with the Angular UI. See the <a href="https://docs.abp.io/en/abp/4.2/UI/Angular/Testing">Angular Unit Testing document</a> for details.</p>
<h3>Other News</h3>
<ul>
<li>Improved HTTP <strong>request-response performance</strong> by resolving dependencies in a deferred way in the action/page filters, interceptors and some other services.</li>
<li>Removed <code>MultipleActiveResultSets</code> from connection strings for new templates for SQL Server, since the new EF Core gives a warning when using it. If you want to use it, you need to change the connection string yourself.</li>
<li>Added <code>HardDeleteAsync</code> extension method that takes a predicate to delete multiple entities. This extension method is available if the entity <a href="https://docs.abp.io/en/abp/latest/Data-Filtering">Soft Delete</a>.</li>
<li>Implemented the <a href="https://docs.abp.io/en/abp/4.2/UI/Angular/Page-Alerts">Page Alerts</a> for the <strong>Angular UI</strong>.</li>
<li>Implemented <a href="https://docs.abp.io/en/abp/4.2/UI/Blazor/Page-Progress">Page Progress</a> for the <strong>Blazor UI</strong>. It automatically shows an undetermined progress bar on top of the page while performing an AJAX request. It also proves an API to you if you need to show/hide the progress bar in your code.</li>
</ul>
<h2>What's new with the ABP Commercial 4.2</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/54bb24af515fbdc810b439fa290916ff.png" alt="104887528-780f0880-597c-11eb-8da4-cf008bd37c66.png" /></p>
<h3>Microservice Startup Template</h3>
<p>The new <a href="https://docs.abp.io/en/commercial/4.2/startup-templates/microservice/index">Microservice Startup Template</a> is a generic solution to start a new microservice solution.</p>
<p>While we accept that every microservice solution will be different and every system has its own design requirements and trade-offs, we believe such a startup solution is a very useful starting point for most of the solutions, and a useful example for others.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/8b2ab5592ffa4477392339fa29011429.png" alt="microservice-template-diagram.png" /></p>
<p><em>Figure: A simplified overall diagram of the microservice solution.</em></p>
<p>You can <a href="https://docs.abp.io/en/commercial/4.2/startup-templates/microservice/index">follow the documentation</a> to get started with this startup template. <strong>This template should be considered as an early release</strong>. We will improve it and write a lot of guides.</p>
<p>If you want to use the ABP Suite to create your solution, then you need to first upgrade it:</p>
<pre><code class="language-bash">abp suite update --preview
</code></pre>
<p>If you want, you can directly create a new solution from the command line:</p>
<pre><code class="language-bash">abp new Volosoft.MyMicroserviceSystem -t microservice-pro --preview
</code></pre>
<p>Company Name is optional. Solution name could be <em>MyMicroserviceSystem</em> for this example.</p>
<h3>Public Website in the Startup Templates</h3>
<p>As mentioned in the previous release post, we've added a <em>Public Website</em> application to the startup templates. It is configured to authenticate through the IdentityServer with a single sign-on system.</p>
<p>You can use this application to create a landing page for your actual application or a corporate website for your business. An example screenshot:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/acbeb3307fc192f57ad839fa29013656.jpg" alt="public-website.jpg" /></p>
<p>It uses the same <em>Lepton Theme</em>, so you can apply <a href="https://commercial.abp.io/themes">all the styles</a>. The Public Website has a different layout and also has a different setting for the styling (that can be configured in the <em>Settings / Lepton Theme</em> page of the main web application).</p>
<blockquote>
<p><em>Public Website</em> is optional and you need to select the &quot;Public Website&quot; option while creating a new solution using the ABP Suite, or use the <code>--with-public-website</code> option while using the <code>abp new</code> CLI command.</p>
</blockquote>
<h3>Easy CRM Blazor UI</h3>
<p><a href="https://docs.abp.io/en/commercial/latest/samples/easy-crm">Easy CRM</a> is an example application built with the ABP Commercial. MVC (Razor Pages) and Angular UI implementations were already provided. With the version 4.2, we are providing the Blazor UI implementation for this application.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2021-01-18-abpio-platform-v42-rc-has-been-released/3de6a4bbfd8d8536775339fa29015efd.png" alt="easy-crm.png" /></p>
<h3>Other News</h3>
<ul>
<li>Implemented Iyzico as a payment gateway provider for the <a href="https://commercial.abp.io/modules/Volo.Payment">payment module</a> in addition to Paypal, Stripe, 2Checkout and Payu providers.</li>
<li>ABP Suite supports the new microservice template creation, public website and DBMS selection options.</li>
<li>Swagger authorization and other features mentioned in the ABP Framework section are already implemented for the ABP Commercial too.</li>
</ul>
<h2>ABP Community News</h2>
<h3>Sharing Video Contents</h3>
<p><a href="https://community.abp.io/">community.abp.io</a> is a place to share ABP related contents. It started with publishing articles. Now, it supports to publish video contents. <a href="https://community.abp.io/articles/be-a-superhero-on-day-1-with-abp.io-wvifcy9s">See this example</a>. All you need to do is to create a video and upload to YouTube. Then you can <a href="https://community.abp.io/articles/submit">submit</a> the YouTube link to the ABP Community website.</p>
<h3>Multi-language support</h3>
<p>We planned ABP Community to publish English-only contents. However, we see that people want to share contents in other languages too. Now, <strong>it is possible to submit a content in any language</strong>. Just select the Language option while submitting your content.</p>
<p><strong>When you submit a non-English content, it is not visible to all the visitors by default</strong>. Visitors can see a non-English content only if their browser language or the selected language matches to the content language (there is a language selection at the end of the website).</p>
<h3>External Contents</h3>
<p>If you want to publish your content anywhere else, but want to post a link of your content, you can select <em>External Content</em> option while submitting the post. For example, <a href="https://community.abp.io/articles/aspnet-boilerplate-to-abp-framework-xml-to-json-localization-conversion-0mxyjrzj">this article</a> is an external article and also written in Chinese language.</p>
<h2>About the Next Release</h2>
<p>The next feature version will be 4.3.0. It is planned to release the 4.3 RC (Release Candidate) on March 11 and the final version on March 25, 2021.</p>
<p>We decided to slow down the feature development for the <a href="https://github.com/abpframework/abp/milestone/49">next milestone</a>. We will continue to improve the existing features and introduce new ones, sure, but wanted to have more time for the planning, documentation, creating guides and improving the development experience.</p>
<h2>Feedback</h2>
<p>Please check out the ABP Framework 4.2.0 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us to release a more stable version. <strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/48">4.2.0 final</a> version is January 28, 2021</strong>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/a3ac7206-271a-26b6-3f99-39fa29021993" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/a3ac7206-271a-26b6-3f99-39fa29021993" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v4.1-final-has-been-released-8w37svhs</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v4.1-final-has-been-released-8w37svhs</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>abp</category>
      <title>ABP.IO Platform v4.1 Final Has Been Released!</title>
      <description>ABP Framework and ABP Commercial 4.1 versions have been released.</description>
      <pubDate>Wed, 06 Jan 2021 19:40:30 Z</pubDate>
      <a10:updated>2026-10-02T15:37:44Z</a10:updated>
      <content:encoded><![CDATA[<p><a href="https://abp.io/">ABP Framework</a> and <a href="https://commercial.abp.io/">ABP Commercial</a> 4.1 versions have been released today.</p>
<h2>What's New With 4.1?</h2>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP.IO-Platform-v4.1-RC-Has-Been-Released">4.1 RC Announcement Post</a>, I will not repeat all the details again. See the <a href="https://blog.abp.io/abp/ABP.IO-Platform-v4.1-RC-Has-Been-Released">RC Blog Post</a> for all the features and enhancements.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 4.1 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution.</p>
<h2>ABP Community</h2>
<p>We started to get more contributions by the community for the <a href="https://community.abp.io/">ABP Community</a> contents. Thank you all!</p>
<p>We will be adding <strong>Video Content</strong> sharing system in a short time. We are planning to create short video contents, especially to explore the new features in every release. Again, we will be waiting video contributions by the community :)</p>
<h2>About the Next Versions</h2>
<p>Planned preview date for the version <strong>4.2 is January 14, 2021</strong>. See the <a href="https://docs.abp.io/en/abp/latest/Road-Map">Road Map</a> document and <a href="https://github.com/abpframework/abp/milestones">GitHub Milestones</a> to learn what's planned for the next versions. We are trying to be clear about the coming features and the next release dates.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/1f18c901-3947-2bff-d2b5-39f9eb63dd2b" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/1f18c901-3947-2bff-d2b5-39f9eb63dd2b" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v4.1-rc-has-been-released-4ir9fgf9</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v4.1-rc-has-been-released-4ir9fgf9</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP.IO Platform v4.1 RC Has Been Released!</title>
      <description>Released ABP.IO Platform v4.1 RC. Some new features: Module Entity Extensions, Blazor UI Improvements, Spanish Language Translation etc. Learn more about what's new with v4.1 RC release.</description>
      <pubDate>Mon, 21 Dec 2020 06:46:41 Z</pubDate>
      <a10:updated>2026-10-02T12:11:41Z</a10:updated>
      <content:encoded><![CDATA[<p>We have released the <a href="https://abp.io/">ABP Framework</a> (and the <a href="https://commercial.abp.io/">ABP Commercial</a>) 4.1.0 RC. This blog post introduces the new features and important changes in this new version.</p>
<blockquote>
<p><strong>Notice: <a href="https://github.com/abpframework/abp/milestone/47">4.1.0 final</a> version has been released at January 6, 2021</strong>.</p>
</blockquote>
<h2>Get Started with the 4.1 RC</h2>
<p>If you want to try the version <code>4.1.0</code> today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>4.1.0-rc.2</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 4.1.0-rc.2
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 4.1.0-rc.2
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<h2>Breaking Changes</h2>
<p>This version has a minor breaking change if you'd injected a repository by class. This is not a problem for 99% of the applications. However, see <a href="https://github.com/abpframework/abp/issues/6677">#6677</a> for the solution if that's a breaking change for you.</p>
<h2>What's new with the ABP Framework 4.1</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/ed6fc66747ade597ea2b39f99634f925.png" alt="abp-fr-note-41rc.png" /></p>
<h3>Module Entity Extensions</h3>
<p>Module Entity Extension system provides a simple way of adding new properties to an existing entity defined by a module that is used by your application. This feature is now available also for the open source modules (identity and tenant-management). <a href="https://docs.abp.io/en/abp/latest/Module-Entity-Extensions">The documentation</a> has been moved into the ABP Framework's documentation.</p>
<p><strong>Example: Add &quot;SocialSecurityNumber&quot; property to the <code>IdentityUser</code> entity</strong></p>
<pre><code class="language-csharp">ObjectExtensionManager.Instance.Modules()
    .ConfigureIdentity(identity =&gt;
    {
        identity.ConfigureUser(user =&gt;
        {
            user.AddOrUpdateProperty&lt;string&gt;( //property type: string
                &quot;SocialSecurityNumber&quot;, //property name
                property =&gt;
                {
                    //validation rules
                    property.Attributes.Add(new RequiredAttribute());
                    property.Attributes.Add(
                        new StringLengthAttribute(64) {
                            MinimumLength = 4
                        }
                    );

                    //...other configurations for this property
                }
            );
        });
    });
</code></pre>
<p>The new property becomes available on the UI, API and the database. You can even define navigation properties. This provides an easy way to extend existing modules while using them as NuGet packages. See <a href="https://docs.abp.io/en/abp/latest/Module-Entity-Extensions">the document</a> for details.</p>
<h3>Blazor UI Improvements</h3>
<p>Since the Blazor UI is relatively new in the ABP Framework, we continue to add features and make enhancements to fill the gap between other supported UI types.</p>
<h4>Bundling &amp; Minification</h4>
<p>In the version 4.1, we had introduced the <code>abp bundle</code> command for the Blazor UI to add global script and style files of the depended modules into the <code>index.html</code>. It was a preparation for a real bundling &amp; minification system. With the version 4.2, this command has been completed.</p>
<p>Whenever you add a new module to your Blazor application, just type the <code>abp bundle</code> command in a command line terminal;</p>
<ul>
<li>It finds all the global script/style files in your application and the modules your application directly or indirectly depends on, ordered by the module dependencies.</li>
<li>Bundles all the scripts into a single file and minified the file (same for the styles).</li>
<li>Add the single bundle file to the <code>index.html</code> file.</li>
</ul>
<p>Added a configuration into the <code>appsettings.json</code> file in the Blazor application in the application startup template to control the bundling mode:</p>
<pre><code class="language-js">{
  &quot;AbpCli&quot;: {
    &quot;Bundle&quot;: {
      &quot;Mode&quot;: &quot;BundleAndMinify&quot;
    }
  }
}
</code></pre>
<p>Possible values are;</p>
<ul>
<li><code>BundleAndMinify</code>: Bundle all the files into a single file and minify the content.</li>
<li><code>Bundle</code>: Bundle all files into a single file, but not minify.</li>
<li><code>None</code>: Add files individually, do not bundle.</li>
</ul>
<p>See the <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Global-Scripts-Styles">Global Scripts &amp; Styles</a> document for details.</p>
<h4>SubmitButton</h4>
<p><code>SubmitButton</code> is a new component that simplifies to save a form:</p>
<pre><code class="language-html">&lt;SubmitButton Clicked=&quot;UpdateEntityAsync&quot; /&gt;
</code></pre>
<p>The main advantages of using this component instead of a standard <code>Button</code> with submit type is; It automatically blocks the submit button until the save operation has fully completed. This prevents multiple clicks by user. And it is shorter than doing all manually. See the <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/SubmitButton">document</a>.</p>
<h4>Other Blazor UI highlights</h4>
<ul>
<li>Implemented some <strong>animations</strong> (like opening/closing modals and dropdowns).</li>
<li>Automatically <strong>focus</strong> to the first input when you open a modal form.</li>
</ul>
<p>Module extensibility system (mentioned above) for the Blazor UI is under development and not available yet.</p>
<h2>What's new with the ABP Commercial 4.1</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/4dc15b8c5f46da81c68739f996354058.png" alt="abp-co-note-41rc.png" /></p>
<h3>Blazor UI Improvements</h3>
<p>We continue to complete missing modules and functionalities for the Blazor UI.</p>
<h4>Organization Unit Management</h4>
<p>Organization Management UI has been implemented for the Blazor UI. Example screenshot:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/3374c36d0142fa896bba39f99631b937.png" alt="blazor-organization-units.png" /></p>
<h4>IdentityServer UI</h4>
<p>IdentityServer Management UI is also available for the Blazor UI now:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/4f81a99cc6e49386e98d39f99632228e.png" alt="blazor-identityserver-ui.png" /></p>
<h3>Suite: Navigation Property Selection with Typeahead</h3>
<p>We had introduced auto-complete select style navigation property selection. With this release, it is fully supported by all the UI options. So, when you create an CRUD page with ABP Suite for entity that has 1 to Many relation to another entity, you can simply select the target entity with a typeahead style select component. Example screenshot:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/8bb3d261bea682dd7c4a39f996328baf.png" alt="type-ahead.png" /></p>
<h3>Spanish Language Translation</h3>
<p>We continue to add new language supports for the UI. In this version, translated the UI to <strong>Spanish</strong> language.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/d5bcdafe37bcb333a24039f9963300b5.png" alt="spanish-commercial-translation.png" /></p>
<h3>Coming: Public Website with Integrated CMS Features</h3>
<p>In the next version, the application startup template will come with a public website application option. CMS Kit module will be installed in the website by default, that means newsletter, contact form, comments and some other new features will be directly usable in your applications.</p>
<p>An early screenshot from the public website application home page:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/0c328649718826cf744439f99633728b.png" alt="abp-commercial-public-website.png" /></p>
<h2>Other News</h2>
<h3>ABP Community Contents</h3>
<p>A lot of new contents have been published in the ABP Community Web Site in the last two weeks:</p>
<ul>
<li><a href="https://community.abp.io/articles/how-to-integrate-the-telerik-blazor-components-to-the-abp-blazor-ui-q8g31abb">How to Integrate the Telerik Blazor Components to the ABP Blazor UI</a> by <a href="https://github.com/EngincanV">EngincanV</a></li>
<li><a href="https://community.abp.io/articles/using-devexpress-blazor-ui-components-with-the-abp-framework-wrpoa8rw">Using DevExpress Blazor UI Components With the ABP Framework</a> by <a href="https://github.com/berkansasmaz">@berkansasmaz</a></li>
<li><a href="https://community.abp.io/articles/creating-a-new-ui-theme-by-copying-the-basic-theme-for-mvc-ui-yt9b18io">Creating a new UI theme by copying the Basic Theme (for MVC UI)</a> by <a href="https://github.com/ebubekirdinc">@ebubekirdinc</a></li>
<li><a href="https://community.abp.io/members/muhammedaltug">Using Angular Material Components With the ABP Framework</a> by <a href="https://github.com/muhammedaltug">@muhammedaltug</a></li>
<li><a href="https://community.abp.io/articles/how-to-export-excel-files-from-the-abp-framework-wm7nnw3n">How to export Excel files from the ABP framework</a> by <a href="https://github.com/bartvanhoey">bartvanhoey</a></li>
<li><a href="https://community.abp.io/articles/creating-an-event-organizer-application-with-the-blazor-ui-wbe0sf2z">Creating an Event Organizer Application with the ABP Framework &amp; Blazor UI</a> by <a href="https://github.com/hikalkan">@hikalkan</a></li>
</ul>
<p>Thanks to all of the contributors. We are waiting for your contributions too. If you want to create content for the ABP Community, please visit <a href="https://community.abp.io/">community.abp.io</a> website and submit your article.</p>
<h4>Be a Superhero on Day 1 with ABP.IO</h4>
<p>Thanks to <a href="http://github.com/lprichar">@lprichar</a> prepared an awesome introduction video for the ABP.IO Platform: &quot;<a href="https://www.youtube.com/watch?v=ea0Zx9DLcGA">Be a Superhero on Day 1 with ABP.IO</a>&quot;.</p>
<h4>New Sample Application: Event Organizer</h4>
<p>This is a new example application developed using the ABP Framework and the Blazor UI. See <a href="https://community.abp.io/articles/creating-an-event-organizer-application-with-the-blazor-ui-wbe0sf2z">this article</a> for a step by step implementation guide.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-21-abpio-platform-v41-rc-has-been-released/3ae582c6154776fbb71039f99633f611.png" alt="event-list-ui.png" /></p>
<h3>Github Discussions</h3>
<p>We enabled the <a href="https://github.com/abpframework/abp/discussions">GitHub Discussions for the abp repository</a> as another place to discuss ideas or get help for the ABP Framework. The ABP core team is spending time participating in discussions and answering to questions as much as possible.</p>
<h2>About the Next Release(s)</h2>
<p>Beginning from the next version (4.2.0), we are starting to spend more effort on the <strong>CMS Kit module</strong>. The purpose of this module is to provide CMS primitives (e.g. <strong>comments, tags, reactions, contents</strong>...) and features (e.g. <strong>blog, pages, surveys</strong>) as pre-built and reusable components. Current blog module will be a part of the CMS Kit module.</p>
<p>We will continue to prepare documents, guides, tutorials and examples. And surely, we will continue to make enhancements and optimizations on the current features.</p>
<blockquote>
<p>The planned preview release date for the version 4.2.0 is January 14, 2021 and the final (stable) version release date is January 28, 2021.</p>
</blockquote>
<p>Follow the <a href="https://github.com/abpframework/abp/milestones">GitHub milestones</a> for all the planned ABP Framework version release dates.</p>
<h2>Feedback</h2>
<p>Please check out the ABP Framework 4.1.0 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us to release a more stable version. <strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/45">4.1.0 final</a> version is January 4, 2021</strong>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/b26909f1-c6f4-fb4f-4e91-39f99639a8fc" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/b26909f1-c6f4-fb4f-4e91-39f99639a8fc" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/creating-an-event-organizer-application-with-the-blazor-ui-wbe0sf2z</guid>
      <link>https://abp.io/community/posts/creating-an-event-organizer-application-with-the-blazor-ui-wbe0sf2z</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>blazor</category>
      <title>Creating an Event Organizer Application with the Blazor UI</title>
      <description>we will create an example application that is a simple meeting/event organizer. People create events and other people registers to the events.</description>
      <pubDate>Fri, 04 Dec 2020 11:22:08 Z</pubDate>
      <a10:updated>2026-10-02T15:23:50Z</a10:updated>
      <content:encoded><![CDATA[<h1>Creating an Event Organizer Application with the ABP Framework &amp; Blazor UI.</h1>
<h2>Introduction</h2>
<p>In this article, we will create an example application that is a simple <strong>meeting/event organizer</strong>: People create events and other people registers to the event.</p>
<p>The application has been developed with <strong>Blazor</strong> as the UI framework and <strong>MongoDB</strong> as the database provider.</p>
<blockquote>
<p>This tutorial is based on my notes that I'd created to implement this application in a workshop. It shows the necessary steps to build the application rather than detailed explanations.</p>
</blockquote>
<h3>Source Code</h3>
<p>Source code of the completed application is <a href="https://github.com/abpframework/abp-samples/tree/master/EventOrganizer">available on GitHub</a>.</p>
<h3>Screenshots</h3>
<p>Here, the pages of the final application.</p>
<p><strong>Home Page - Event List</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-list-ui.png" alt="event-list-ui" /></p>
<p><strong>Creating a new Event</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-create-ui.png" alt="event-create-ui" /></p>
<p><strong>Event Detail Page</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-detail-ui.png" alt="event-detail-ui" /></p>
<h2>Requirements</h2>
<p>The following tools are needed to be able to run the solution.</p>
<ul>
<li>.NET 5.0 SDK</li>
<li>Visual Studio 2019 16.8.0+ or another compatible IDE</li>
<li>MongoDB Server (with MongoDB Compass)</li>
</ul>
<h2>Development</h2>
<h3>Creating a new Application</h3>
<ul>
<li>Use the following ABP CLI command:</li>
</ul>
<pre><code class="language-bash">abp new EventOrganizer -u blazor -d mongodb
</code></pre>
<h3>Open &amp; Run the Application</h3>
<ul>
<li>Open the solution in Visual Studio (or your favorite IDE).</li>
<li>Run the <code>EventOrganizer.DbMigrator</code> application to seed the initial data.</li>
<li>Run the <code>EventOrganizer.HttpApi.Host</code> application that starts the server side.</li>
<li>Run the <code>EventOrganizer.Blazor</code> application to start the UI.</li>
</ul>
<h3>Apply the Custom Styles</h3>
<ul>
<li>Add styles to <code>wwwroot/main.css</code>:</li>
</ul>
<pre><code class="language-css">body.abp-application-layout {
    background-color: #222 !important;
    font-size: 18px;
}
nav#main-navbar.bg-dark {
    background-color: #222 !important;
    box-shadow: none !important;
}
.event-pic {
    width: 100%;
    border-radius: 12px;
    box-shadow: 5px 5px 0px 0px rgba(0,0,0,.5);
    margin-bottom: 10px;
}
.event-link:hover, .event-link:hover *{
    text-decoration: none;
}
.event-link:hover .event-pic {
    box-shadow: 5px 5px 0px 0px #ffd800;
}
.event-form {
    background-color: #333 !important;
    box-shadow: 5px 5px 0px 0px rgba(0,0,0,.5);
    border-radius: 12px;
}
.table {
    background: #fff;
    border-radius: 12px;
    box-shadow: 5px 5px 0px 0px rgba(0,0,0,.5);
}
.table th{
    border: 0 !important;
}
.modal {
    color: #333;
}
.page-item:first-child .page-link {
    margin-left: 0;
    border-top-left-radius: 12px;
    border-bottom-left-radius: 12px;
}
.page-item:last-child .page-link {
    border-top-right-radius: 12px;
    border-bottom-right-radius: 12px;
}
.btn {
    border-radius: 8px;
}
.att-list {
    list-style: none;
    padding: 0;
}
.att-list li {
    padding: 4px 0 0 0;
}
</code></pre>
<ul>
<li><code>wwwroot/index.html</code>: Remove <code>bg-light</code> class from the <code>body</code> tag and add <code>bg-dark text-light</code>.</li>
</ul>
<h3>Domain Layer</h3>
<ul>
<li>Add the following <code>Event</code> aggregate (with <code>EventAttendee</code>) to the solution:</li>
</ul>
<p><strong>Event</strong></p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities.Auditing;

namespace EventOrganizer.Events
{
    public class Event : FullAuditedAggregateRoot&lt;Guid&gt;
    {
        public string Title { get; set; }

        public string Description { get; set; }

        public bool IsFree { get; set; }

        public DateTime StartTime { get; set; }

        public ICollection&lt;EventAttendee&gt; Attendees { get; set; }

        public Event()
        {
            Attendees = new List&lt;EventAttendee&gt;();
        }
    }
}
</code></pre>
<p><strong>EventAttendee</strong></p>
<pre><code class="language-csharp">using System;
using Volo.Abp.Auditing;

namespace EventOrganizer.Events
{
    public class EventAttendee : IHasCreationTime
    {
        public Guid UserId { get; set; }

        public DateTime CreationTime { get; set; }
    }
}
</code></pre>
<h3>MongoDB Mapping</h3>
<ul>
<li>Add the following property to the <code>EventOrganizerMongoDbContext</code>:</li>
</ul>
<pre><code class="language-csharp">public IMongoCollection&lt;Event&gt; Events =&gt; Collection&lt;Event&gt;();
</code></pre>
<h3>Clean Index.razor &amp; Add the Header &amp; &quot;Create Event&quot; button</h3>
<ul>
<li>Clean the <code>Index.razor</code> file.</li>
<li>Replace the content with the following code:</li>
</ul>
<pre><code class="language-html">@page &quot;/&quot;
@inherits EventOrganizerComponentBase
&lt;Row Class=&quot;mb-4&quot;&gt;
    &lt;Column Class=&quot;text-left&quot;&gt;
        &lt;h1&gt;Upcoming Events&lt;/h1&gt;
    &lt;/Column&gt;
    &lt;Column Class=&quot;text-right&quot;&gt;
        @if (CurrentUser.IsAuthenticated)
        {
            &lt;a class=&quot;btn btn-primary&quot; href=&quot;/create-event&quot;&gt;
                &lt;i class=&quot;fa fa-plus&quot;&gt;&lt;/i&gt; @L[&quot;CreateEvent&quot;]
            &lt;/a&gt;
        }
    &lt;/Column&gt;
&lt;/Row&gt;
</code></pre>
<ul>
<li>Open <code>Localization/EventOrganizer/en.json</code> in the <code>EventOrganizer.Domain.Shared</code> project and add the following entry:</li>
</ul>
<pre><code class="language-json">&quot;CreateEvent&quot;: &quot;Create a new event!&quot;
</code></pre>
<p>The Result (run the <code>EventOrganizer.Blazor</code> application to see):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/index-title.png" alt="index-title" /></p>
<h3>Event Creation</h3>
<ul>
<li>Create the Initial <code>IEventAppService</code> with the <code>CreateAsync</code> method:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace EventOrganizer.Events
{
    public interface IEventAppService : IApplicationService
    {
        Task&lt;Guid&gt; CreateAsync(EventCreationDto input);
    }
}
</code></pre>
<ul>
<li>Add <code>EventCreationDto</code> class:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.ComponentModel.DataAnnotations;

namespace EventOrganizer.Events
{
    public class EventCreationDto
    {
        [Required]
        [StringLength(100)]
        public string Title { get; set; }

        [Required]
        [StringLength(2000)]
        public string Description { get; set; }

        public bool IsFree { get; set; }

        public DateTime StartTime { get; set; }
    }
}
</code></pre>
<ul>
<li>Implement the <code>EventAppService</code>:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Domain.Repositories;

namespace EventOrganizer.Events
{
    public class EventAppService : EventOrganizerAppService, IEventAppService
    {
        private readonly IRepository&lt;Event, Guid&gt; _eventRepository;

        public EventAppService(IRepository&lt;Event, Guid&gt; eventRepository)
        {
            _eventRepository = eventRepository;
        }

        [Authorize]
        public async Task&lt;Guid&gt; CreateAsync(EventCreationDto input)
        {
            var eventEntity = ObjectMapper.Map&lt;EventCreationDto, Event&gt;(input);
            await _eventRepository.InsertAsync(eventEntity);
            return eventEntity.Id;
        }
    }
}
</code></pre>
<ul>
<li>Add AutoMapper mapping to the <code>EventOrganizerApplicationAutoMapperProfile</code> class:</li>
</ul>
<pre><code class="language-csharp">using AutoMapper;
using EventOrganizer.Events;

namespace EventOrganizer
{
    public class EventOrganizerApplicationAutoMapperProfile : Profile
    {
        public EventOrganizerApplicationAutoMapperProfile()
        {
            CreateMap&lt;EventCreationDto, Event&gt;();
        }
    }
}
</code></pre>
<p>This will automatically create the HTTP (REST) API for the application service (run the <code>EventOrganizer.HttpApi.Host</code> application to see it on the Swagger UI):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/swagger-event-create.png" alt="swagger-event-create" /></p>
<ul>
<li>Create the <code>CreateEvent.razor</code> file:</li>
</ul>
<pre><code class="language-csharp">@page &quot;/create-event&quot;
@inherits EventOrganizerComponentBase
&lt;Heading Size=&quot;HeadingSize.Is3&quot; Margin=&quot;Margin.Is5.FromTop.Is4.FromBottom&quot; Class=&quot;text-center&quot;&gt;Create Event&lt;/Heading&gt;
&lt;Row&gt;
    &lt;Column ColumnSize=&quot;ColumnSize.Is6.Is3.WithOffset&quot;&gt;
        &lt;div class=&quot;p-lg-5 p-md-3 event-form&quot;&gt;
            &lt;EditForm Model=&quot;@Event&quot; OnValidSubmit=&quot;Create&quot;&gt;
                &lt;Field&gt;
                    &lt;FieldLabel&gt;@L[&quot;Title&quot;]&lt;/FieldLabel&gt;
                    &lt;TextEdit @bind-Text=&quot;@Event.Title&quot; /&gt;
                &lt;/Field&gt;
                &lt;Field&gt;
                    &lt;FieldLabel&gt;@L[&quot;Description&quot;]&lt;/FieldLabel&gt;
                    &lt;MemoEdit @bind-Text=&quot;@Event.Description&quot; /&gt;
                &lt;/Field&gt;
                &lt;Field&gt;
                    &lt;Check TValue=&quot;bool&quot; @bind-Checked=&quot;@Event.IsFree&quot;&gt;@L[&quot;Free&quot;]&lt;/Check&gt;
                &lt;/Field&gt;
                &lt;Field&gt;
                    &lt;FieldLabel&gt;@L[&quot;StartTime&quot;]&lt;/FieldLabel&gt;
                    &lt;DateEdit TValue=&quot;DateTime&quot; @bind-Date=&quot;@Event.StartTime&quot; /&gt;
                &lt;/Field&gt;
                &lt;Button Type=&quot;@ButtonType.Submit&quot; Block=&quot;true&quot; Color=&quot;@Color.Primary&quot; Size=&quot;Size.Large&quot;&gt;@L[&quot;Save&quot;]&lt;/Button&gt;
            &lt;/EditForm&gt;
        &lt;/div&gt;
    &lt;/Column&gt;
&lt;/Row&gt;
</code></pre>
<ul>
<li>Create a partial <code>CreateEvent</code> class in the same folder, with the <code>CreateEvent.razor.cs</code> as the file name:</li>
</ul>
<pre><code class="language-csharp">using System.Threading.Tasks;
using EventOrganizer.Events;
using Microsoft.AspNetCore.Components;

namespace EventOrganizer.Blazor.Pages
{
    public partial class CreateEvent
    {
        private EventCreationDto Event { get; set; } = new EventCreationDto();

        private readonly IEventAppService _eventAppService;
        private readonly NavigationManager _navigationManager;

        public CreateEvent(
            IEventAppService eventAppService,
            NavigationManager navigationManager)
        {
            _eventAppService = eventAppService;
            _navigationManager = navigationManager;
        }

        private async Task Create()
        {
            var eventId = await _eventAppService.CreateAsync(Event);
            _navigationManager.NavigateTo(&quot;/events/&quot; + eventId);
        }
    }
}
</code></pre>
<p>The final UI is (run the <code>EventOrganizer.Blazor</code> application and click to the &quot;Create Event&quot; button):</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-create-ui.png" alt="event-create-ui" /></p>
<h3>Upcoming Events (Home Page)</h3>
<ul>
<li>Open the <code>IEventAppService</code> and add a <code>GetUpcomingAsync</code> method to get the list of upcoming events:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace EventOrganizer.Events
{
    public interface IEventAppService : IApplicationService
    {
        Task&lt;Guid&gt; CreateAsync(EventCreationDto input);

        Task&lt;List&lt;EventDto&gt;&gt; GetUpcomingAsync();
    }
}
</code></pre>
<ul>
<li>Add a <code>EventDto</code> class:</li>
</ul>
<pre><code class="language-csharp">using System;
using Volo.Abp.Application.Dtos;

namespace EventOrganizer.Events
{
    public class EventDto : EntityDto&lt;Guid&gt;
    {
        public string Title { get; set; }

        public string Description { get; set; }

        public bool IsFree { get; set; }

        public DateTime StartTime { get; set; }

        public int AttendeesCount { get; set; }
    }
}
</code></pre>
<ul>
<li>Implement the <code>GetUpcomingAsync</code> in the <code>EventAppService</code> class:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Domain.Repositories;

namespace EventOrganizer.Events
{
    public class EventAppService : EventOrganizerAppService, IEventAppService
    {
        private readonly IRepository&lt;Event, Guid&gt; _eventRepository;

        public EventAppService(IRepository&lt;Event, Guid&gt; eventRepository)
        {
            _eventRepository = eventRepository;
        }

        [Authorize]
        public async Task&lt;Guid&gt; CreateAsync(EventCreationDto input)
        {
            var eventEntity = ObjectMapper.Map&lt;EventCreationDto, Event&gt;(input);
            await _eventRepository.InsertAsync(eventEntity);
            return eventEntity.Id;
        }

        public async Task&lt;List&lt;EventDto&gt;&gt; GetUpcomingAsync()
        {
            var queryable = await _eventRepository.GetQueryableAsync();
            var query = queryable
                .Where(x =&gt; x.StartTime &gt; Clock.Now)
                .OrderBy(x =&gt; x.StartTime);

            var events = await AsyncExecuter.ToListAsync(query);

            return ObjectMapper.Map&lt;List&lt;Event&gt;, List&lt;EventDto&gt;&gt;(events);
        }
    }
}
</code></pre>
<ul>
<li>Add the following line into the <code>EventOrganizerApplicationAutoMapperProfile</code> constructor:</li>
</ul>
<pre><code class="language-csharp">CreateMap&lt;Event, EventDto&gt;();
</code></pre>
<p>Run the <code>EventOrganizer.HttpApi.Host</code> application to see the new <code>upcoming</code> endpoint on the Swagger UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/swagger-event-upcoming.png" alt="swagger-event-upcoming" /></p>
<ul>
<li>Change the <code>Pages/Index.razor.cs</code> content in the <code>EventOrganizer.Blazor</code> project as shown below:</li>
</ul>
<pre><code class="language-csharp">using System.Collections.Generic;
using System.Threading.Tasks;
using EventOrganizer.Events;

namespace EventOrganizer.Blazor.Pages
{
    public partial class Index
    {
        private List&lt;EventDto&gt; UpcomingEvents { get; set; } = new List&lt;EventDto&gt;();

        private readonly IEventAppService _eventAppService;

        public Index(IEventAppService eventAppService)
        {
            _eventAppService = eventAppService;
        }

        protected override async Task OnInitializedAsync()
        {
            UpcomingEvents = await _eventAppService.GetUpcomingAsync();
        }
    }
}
</code></pre>
<ul>
<li>Change the <code>Pages/Index.razor</code> content in the <code>EventOrganizer.Blazor</code> project as shown below:</li>
</ul>
<pre><code class="language-html">@page &quot;/&quot;
@inherits EventOrganizerComponentBase
&lt;Row Class=&quot;mb-4&quot;&gt;
    &lt;Column Class=&quot;text-left&quot;&gt;
        &lt;h1&gt;Upcoming Events&lt;/h1&gt;
    &lt;/Column&gt;
    &lt;Column Class=&quot;text-right&quot;&gt;
        @if (CurrentUser.IsAuthenticated)
        {
            &lt;a class=&quot;btn btn-primary&quot; href=&quot;/create-event&quot;&gt;
                &lt;i class=&quot;fa fa-plus&quot;&gt;&lt;/i&gt; @L[&quot;CreateEvent&quot;]
            &lt;/a&gt;
        }
    &lt;/Column&gt;
&lt;/Row&gt;
&lt;Row&gt;
    @foreach (var upcomingEvent in UpcomingEvents)
    {
        &lt;Column Class=&quot;col-12 col-lg-4 col-md-6&quot;&gt;
            &lt;a class=&quot;mb-5 position-relative d-block event-link&quot; href=&quot;/events/@upcomingEvent.Id&quot;&gt;
                &lt;div class=&quot;position-absolute text-right w-100 px-3 py-2&quot; style=&quot;left: 0; top: 2px;&quot;&gt;
                    @if (upcomingEvent.IsFree)
                    {
                        &lt;Badge Color=&quot;Color.Success&quot; Class=&quot;mr-1&quot;&gt;FREE&lt;/Badge&gt;
                    }
                    &lt;span class=&quot;badge badge-warning font-weight-normal&quot;&gt;
                        &lt;i class=&quot;fas fa-user-friends&quot;&gt;&lt;/i&gt;
                        &lt;span class=&quot;font-weight-bold&quot;&gt;@upcomingEvent.AttendeesCount&lt;/span&gt;
                    &lt;/span&gt;
                &lt;/div&gt;
                &lt;img src=&quot;https://picsum.photos/seed/%40upcomingEvent.Id/400/300&quot; class=&quot;event-pic&quot;/&gt;&amp;nbsp;
                &lt;div class=&quot;px-3 py-1&quot;&gt;
                    &lt;small class=&quot;font-weight-bold text-warning my-2 d-block text-uppercase&quot;&gt;@upcomingEvent.StartTime.ToLongDateString()&lt;/small&gt;
                    &lt;p class=&quot;h4 text-light d-block mb-2&quot;&gt;@upcomingEvent.Title&lt;/p&gt;
                    &lt;p class=&quot;text-light&quot; style=&quot;opacity: .65;&quot;&gt;@upcomingEvent.Description.TruncateWithPostfix(150)&lt;/p&gt;
                &lt;/div&gt;
            &lt;/a&gt;
        &lt;/Column&gt;
    }
&lt;/Row&gt;
</code></pre>
<p>The new home page is shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-list-ui.png" alt="event-list-ui" /></p>
<h3>Event Detail Page</h3>
<ul>
<li>Add <code>GetAsync</code>, <code>RegisterAsync</code>, <code>UnregisterAsync</code> and <code>DeleteAsync</code> methods to the <code>IEventAppService</code>:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace EventOrganizer.Events
{
    public interface IEventAppService : IApplicationService
    {
        Task&lt;Guid&gt; CreateAsync(EventCreationDto input);

        Task&lt;List&lt;EventDto&gt;&gt; GetUpcomingAsync();

        Task&lt;EventDetailDto&gt; GetAsync(Guid id);

        Task RegisterAsync(Guid id);

        Task UnregisterAsync(Guid id);

        Task DeleteAsync(Guid id);
    }
}
</code></pre>
<ul>
<li>Add <code>EventDetailDto</code> class:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;

namespace EventOrganizer.Events
{
    public class EventDetailDto : CreationAuditedEntityDto&lt;Guid&gt;
    {
        public string Title { get; set; }

        public string Description { get; set; }

        public bool IsFree { get; set; }

        public DateTime StartTime { get; set; }

        public List&lt;EventAttendeeDto&gt; Attendees { get; set; }
    }
}
</code></pre>
<ul>
<li>Add <code>EventAttendeeDto</code> class:</li>
</ul>
<pre><code class="language-csharp">using System;

namespace EventOrganizer.Events
{
    public class EventAttendeeDto
    {
        public Guid UserId { get; set; }

        public string UserName { get; set; }

        public DateTime CreationTime { get; set; }
    }
}
</code></pre>
<ul>
<li>Implement the new methods in the <code>EventAppService</code>:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EventOrganizer.Users;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Users;

namespace EventOrganizer.Events
{
    public class EventAppService : EventOrganizerAppService, IEventAppService
    {
        private readonly IRepository&lt;Event, Guid&gt; _eventRepository;
        private readonly IRepository&lt;AppUser, Guid&gt; _userRepository;

        public EventAppService(IRepository&lt;Event, Guid&gt; eventRepository, IRepository&lt;AppUser, Guid&gt; userRepository)
        {
            _eventRepository = eventRepository;
            _userRepository = userRepository;
        }

        [Authorize]
        public async Task&lt;Guid&gt; CreateAsync(EventCreationDto input)
        {
            var eventEntity = ObjectMapper.Map&lt;EventCreationDto, Event&gt;(input);
            await _eventRepository.InsertAsync(eventEntity);
            return eventEntity.Id;
        }

        public async Task&lt;List&lt;EventDto&gt;&gt; GetUpcomingAsync()
        {
            var queryable = await _eventRepository.GetQueryableAsync();
            var query = queryable
                .Where(x =&gt; x.StartTime &gt; Clock.Now)
                .OrderBy(x =&gt; x.StartTime);

            var events = await AsyncExecuter.ToListAsync(query);

            return ObjectMapper.Map&lt;List&lt;Event&gt;, List&lt;EventDto&gt;&gt;(events);
        }

        public async Task&lt;EventDetailDto&gt; GetAsync(Guid id)
        {
            var @event = await _eventRepository.GetAsync(id);
            var attendeeIds = @event.Attendees.Select(a =&gt; a.UserId).ToList();

            var queryable = await _userRepository.GetQueryableAsync();
            var query = queryable
                .Where(u =&gt; attendeeIds.Contains(u.Id));

            var attendees = (await AsyncExecuter.ToListAsync(query))
                .ToDictionary(x =&gt; x.Id);

            var result = ObjectMapper.Map&lt;Event, EventDetailDto&gt;(@event);

            foreach (var attendeeDto in result.Attendees)
            {
                attendeeDto.UserName = attendees[attendeeDto.UserId].UserName;
            }

            return result;
        }

        [Authorize]
        public async Task RegisterAsync(Guid id)
        {
            var @event = await _eventRepository.GetAsync(id);
            if (@event.Attendees.Any(a =&gt; a.UserId == CurrentUser.Id))
            {
                return;
            }

            @event.Attendees.Add(new EventAttendee {UserId = CurrentUser.GetId(), CreationTime = Clock.Now});
            await _eventRepository.UpdateAsync(@event);
        }

        [Authorize]
        public async Task UnregisterAsync(Guid id)
        {
            var @event = await _eventRepository.GetAsync(id);
            var removedItems = @event.Attendees.RemoveAll(x =&gt; x.UserId == CurrentUser.Id);
            if (removedItems.Any())
            {
                await _eventRepository.UpdateAsync(@event);
            }
        }

        [Authorize]
        public async Task DeleteAsync(Guid id)
        {
            var @event = await _eventRepository.GetAsync(id);

            if (CurrentUser.Id != @event.CreatorId)
            {
                throw new UserFriendlyException(&quot;You don't have the necessary permission to delete this event!&quot;);
            }

            await _eventRepository.DeleteAsync(id);
        }
    }
}
</code></pre>
<ul>
<li>Add the following mappings into the <code>EventOrganizerApplicationAutoMapperProfile</code>:</li>
</ul>
<pre><code class="language-csharp">CreateMap&lt;Event, EventDetailDto&gt;();
CreateMap&lt;EventAttendee, EventAttendeeDto&gt;();
</code></pre>
<p>Run the <code>EventOrganizer.HttpApi.Host</code> application to see the complete Event HTTP API in the Swagger UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/swagger-event-all.png" alt="swagger-event-all" /></p>
<ul>
<li>Create <code>EventDetail.razor</code> component with the following content:</li>
</ul>
<pre><code class="language-html">@page &quot;/events/{id}&quot;
@inherits EventOrganizerComponentBase
@if (Event != null)
{
    &lt;Row Class=&quot;mb-4&quot;&gt;
        &lt;Column Class=&quot;text-left&quot;&gt;
            &lt;h1&gt;@Event.Title&lt;/h1&gt;
        &lt;/Column&gt;
        &lt;Column Class=&quot;text-right pt-2&quot;&gt;
            &lt;a href=&quot;/&quot; Class=&quot;btn btn-dark&quot;&gt;&lt;i class=&quot;fa fa-arrow-left&quot;&gt;&lt;/i&gt; Back&lt;/a&gt;
            @if (CurrentUser.IsAuthenticated &amp;&amp; CurrentUser.Id == Event.CreatorId)
            {
                &lt;Button Color=&quot;Color.Danger&quot; Clicked=&quot;Delete&quot; Class=&quot;ml-1&quot;&gt;Delete&lt;/Button&gt;
            }
        &lt;/Column&gt;
    &lt;/Row&gt;
    &lt;Row&gt;
        &lt;Column Class=&quot;col-12 col-md-8&quot;&gt;
            &lt;div class=&quot;position-relative&quot;&gt;
                &lt;div class=&quot;position-absolute text-right w-100 px-3 py-2&quot; style=&quot;left: 0; top: 2px;&quot;&gt;
                    @if (Event.IsFree)
                    {
                        &lt;Badge Color=&quot;Color.Success&quot; Class=&quot;mr-1&quot;&gt;FREE&lt;/Badge&gt;
                    }
                    &lt;span class=&quot;badge badge-warning font-weight-normal&quot;&gt;
                        &lt;i class=&quot;fas fa-user-friends&quot;&gt;&lt;/i&gt;
                        &lt;span class=&quot;font-weight-bold&quot;&gt;@Event.Attendees.Count&lt;/span&gt;
                    &lt;/span&gt;
                &lt;/div&gt;
                &lt;img src=&quot;https://picsum.photos/seed/%40Event.Id/800/600&quot; class=&quot;event-pic&quot; /&gt;&amp;nbsp;
                &lt;small class=&quot;font-weight-bold text-warning my-2 d-block text-uppercase&quot;&gt;Start time: @Event.StartTime.ToLongDateString()&lt;/small&gt;
                &lt;p style=&quot;opacity: .65;&quot;&gt;@Event.Description&lt;/p&gt;
            &lt;/div&gt;
        &lt;/Column&gt;
        &lt;Column Class=&quot;col-12 col-md-4&quot;&gt;
            &lt;div class=&quot;p-4 event-form&quot;&gt;
                @if (CurrentUser.IsAuthenticated)
                {
                    &lt;div&gt;
                        @if (!IsRegistered)
                        {
                            &lt;Button Color=&quot;Color.Primary&quot; Clicked=&quot;Register&quot; Class=&quot;btn-block btn-lg&quot;&gt;Register now!&lt;/Button&gt;
                        }
                        else
                        {
                            &lt;p&gt;You are registered in this event&lt;/p&gt;
                            &lt;Button Color=&quot;Color.Secondary&quot; Clicked=&quot;UnRegister&quot; Class=&quot;btn-block&quot;&gt;Cancel registration!&lt;/Button&gt;
                        }
                    &lt;/div&gt;
                }
                else
                {
                    &lt;a class=&quot;btn btn-primary&quot; href=&quot;/authentication/login&quot;&gt;
                        &lt;i class=&quot;fa fa-sign-in-alt&quot;&gt;&lt;/i&gt; Login to attend!
                    &lt;/a&gt;
                }
            &lt;/div&gt;
            &lt;div class=&quot;mt-4 event-form p-4&quot;&gt;
                &lt;span class=&quot;font-weight-bold&quot;&gt;&lt;i class=&quot;fas fa-user-friends&quot;&gt;&lt;/i&gt; Attendees &lt;span class=&quot;float-right font-weight-normal&quot; style=&quot;opacity:.65;&quot;&gt;(@Event.Attendees.Count)&lt;/span&gt;&lt;/span&gt;
                &lt;ul class=&quot;mt-1 mb-0 att-list&quot;&gt;
                    @foreach (var attendee in Event.Attendees)
                    {
                        &lt;li&gt;&lt;i class=&quot;fa fa-check&quot;&gt;&lt;/i&gt; @attendee.UserName&lt;/li&gt;
                    }
                &lt;/ul&gt;
            &lt;/div&gt;
        &lt;/Column&gt;
    &lt;/Row&gt;
}
</code></pre>
<ul>
<li>Create <code>EventDetail.razor.cs</code> file with the following content:</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Linq;
using System.Threading.Tasks;
using EventOrganizer.Events;
using Microsoft.AspNetCore.Components;

namespace EventOrganizer.Blazor.Pages
{
    public partial class EventDetail
    {
        [Parameter]
        public string Id { get; set; }

        private EventDetailDto Event { get; set; }
        private bool IsRegistered { get; set; }

        private readonly IEventAppService _eventAppService;
        private readonly NavigationManager _navigationManager;

        public EventDetail(
            IEventAppService eventAppService,
            NavigationManager navigationManager)
        {
            _eventAppService = eventAppService;
            _navigationManager = navigationManager;
        }

        protected override async Task OnInitializedAsync()
        {
            await GetEventAsync();
        }

        private async Task GetEventAsync()
        {
            Event = await _eventAppService.GetAsync(Guid.Parse(Id));
            if (CurrentUser.IsAuthenticated)
            {
                IsRegistered = Event.Attendees.Any(a =&gt; a.UserId == CurrentUser.Id);
            }
        }

        private async Task Register()
        {
            await _eventAppService.RegisterAsync(Guid.Parse(Id));
            await GetEventAsync();
        }

        private async Task UnRegister()
        {
            await _eventAppService.UnregisterAsync(Guid.Parse(Id));
            await GetEventAsync();
        }

        private async Task Delete()
        {
            if (!await Message.Confirm(&quot;This event will be deleted: &quot; + Event.Title))
            {
                return;
            }

            await _eventAppService.DeleteAsync(Guid.Parse(Id));
            _navigationManager.NavigateTo(&quot;/&quot;);
        }
    }
}
</code></pre>
<p>The resulting page is shown below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/images/event-detail-ui.png" alt="event-detail-ui" /></p>
<h3>Integration Tests</h3>
<p>Create an <code>EventAppService_Tests</code> class in the <code>EventOrganizer.Application.Tests</code> project:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Shouldly;
using Xunit;

namespace EventOrganizer.Events
{
    [Collection(EventOrganizerTestConsts.CollectionDefinitionName)]
    public class EventAppService_Tests : EventOrganizerApplicationTestBase
    {
        private readonly IEventAppService _eventAppService;

        public EventAppService_Tests()
        {
            _eventAppService = GetRequiredService&lt;IEventAppService&gt;();
        }

        [Fact]
        public async Task Should_Create_A_Valid_Event()
        {
            // Create an event

            var eventId = await _eventAppService.CreateAsync(
                new EventCreationDto
                {
                    Title = &quot;My test event 1&quot;,
                    Description = &quot;My test event description 1&quot;,
                    IsFree = true,
                    StartTime = DateTime.Now.AddDays(2)
                }
            );

            eventId.ShouldNotBe(Guid.Empty);

            // Get the event

            var @event = await _eventAppService.GetAsync(eventId);
            @event.Title.ShouldBe(&quot;My test event 1&quot;);

            // Get upcoming events

            var events = await _eventAppService.GetUpcomingAsync();
            events.ShouldContain(x =&gt; x.Title == &quot;My test event 1&quot;);
        }
    }
}
</code></pre>
<h2>Source Code</h2>
<p>Source code of the completed application is <a href="https://github.com/abpframework/abp-samples/tree/master/EventOrganizer">available on GitHub</a>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/fb293699-a971-1a15-ad58-39f93fa9bb49" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/fb293699-a971-1a15-ad58-39f93fa9bb49" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-4.0-with-.net-5.0-in-the-4th-year-f35diaro</guid>
      <link>https://abp.io/community/posts/abp.io-platform-4.0-with-.net-5.0-in-the-4th-year-f35diaro</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP.IO Platform 4.0 with .NET 5.0 in the 4th Year!</title>
      <description>Released ABP.IO Platform v4.0 Final. Some new features: Migrated to .NET 5.0, Stable Blazor UI, Identity Server 4 Upgrade, Moved to System.Text.Json, etc. etc. Learn more about what's new with v4.0 Final release.</description>
      <pubDate>Fri, 04 Dec 2020 07:40:07 Z</pubDate>
      <a10:updated>2026-10-02T15:58:54Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we are extremely happy to release ABP Framework 4.0 with <strong>.NET 5.0 support</strong>!</p>
<h2>4 Years of Work</h2>
<p>As a nice coincidence, today is the <strong>4th year</strong> since the first commit made in the <a href="https://github.com/abpframework/abp">abp repository</a>! So, we can say &quot;<em>Happy Birthday ABP Framework!</em>&quot;.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-abpio-platform-40-with-net-50-in-the-4th-year/461ed871392027d60be739f93edde364.png" alt="abp-contribution-graph-4-years.png" /></p>
<h3>Some Statistics</h3>
<p>ABP.IO Platform and the ABP Community is growing. Here, a summary of these 4 years.</p>
<p>From GitHub, only from the main <a href="https://github.com/abpframework/abp">abp repository</a>;</p>
<ul>
<li><strong>15,297 commits</strong> done.</li>
<li><strong>3,764 issues</strong> are closed.</li>
<li><strong>2,133 pull requests</strong> are merged.</li>
<li><strong>158 contributors</strong>.</li>
<li><strong>88 releases</strong> published.</li>
<li><strong>5.2K stars</strong> on GitHub.</li>
</ul>
<p>From NuGet &amp; NPM;</p>
<ul>
<li><strong>220 NuGet</strong> packages &amp; <strong>52 NPM</strong> packages.</li>
<li><strong>1,000,000 downloads</strong> only for the core NuGet package.</li>
</ul>
<p>From Website;</p>
<ul>
<li><strong>200,000 visitors</strong>.</li>
<li><strong>1,000,000+ sessions</strong>.</li>
</ul>
<h2>What's New With 4.0?</h2>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP.IO-Platform-v4.0-RC-Has-Been-Released-based-on-.NET-5.0">4.0 RC Announcement Post</a>, I will not repeat all the details again. Please read <a href="https://blog.abp.io/abp/ABP.IO-Platform-v4.0-RC-Has-Been-Released-based-on-.NET-5.0">the RC post</a> for <strong>new feature and changes</strong> you may need to do for your solution while upgrading to the version 4.0.</p>
<p>Here, a brief list of major features and changes;</p>
<ul>
<li>Migrated to <strong>.NET 5.0</strong>.</li>
<li>Stable <strong>Blazor</strong> UI.</li>
<li>Moved to <strong>System.Text.Json</strong>.</li>
<li>Upgraded to <strong>IdentityServer</strong> version 4.0.</li>
<li><strong>WPF</strong> startup template.</li>
</ul>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 4.0 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<p>This is a <strong>major version</strong> and requires some <strong>manual work</strong>, especially related to <strong>.NET 5.0</strong> and <strong>IdentityServer</strong> 4.0 upgrades.</p>
<ul>
<li><p>See the <a href="https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-4_0">MIGRATION GUIDE</a> that covers all the details about the upgrade progress.</p>
</li>
<li><p>You can also see the <a href="https://docs.abp.io/en/abp/latest/Upgrading">upgrading document</a>.</p>
</li>
</ul>
<h2>New Guides / Documents</h2>
<p>We are constantly improving the documentation. Our purpose is not only document the ABP Framework, but also write architectural and practical guides for developers.</p>
<h3>Implementing Domain Driven Design</h3>
<p><a href="https://docs.abp.io/en/abp/latest/Domain-Driven-Design-Implementation-Guide">Implementing Domain Driven Design</a> is a practical guide for they want to implement the DDD principles in their solutions. While the implementation details rely on the ABP Framework infrastructure, core concepts, principles and patterns are applicable in any kind of solution, even if it is not a .NET solution.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-12-04-abpio-platform-40-with-net-50-in-the-4th-year/7585eb53490fa17c62c939f93ede61d6.png" alt="ddd-implementation-guide-sample.png" /></p>
<h3>Testing</h3>
<p>The new <a href="https://docs.abp.io/en/abp/latest/Testing">Testing document</a> discusses different kind of automated tests and explains how you can write tests for your ABP based solutions.</p>
<h3>UI Documents</h3>
<p>We've created a lot of documents for the <a href="https://docs.abp.io/en/abp/latest/UI/AspNetCore/Overall">MVC</a>, <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Overall">Blazor</a> and the <a href="https://docs.abp.io/en/abp/latest/UI/Angular/Quick-Start">Angular</a> UI.</p>
<h2>About the Next Version</h2>
<p>The next versions 4.1 will mostly focus on;</p>
<ul>
<li>Improving current features.</li>
<li>Complete module features for the Blazor UI.</li>
<li>Improve developer experience and productivity.</li>
<li>More documentation and examples.</li>
</ul>
<p>Planned preview date for the version <strong>4.1 is December 17, 2020</strong>. See the <a href="https://docs.abp.io/en/abp/latest/Road-Map">Road Map</a> document and <a href="https://github.com/abpframework/abp/milestones">GitHub Milestones</a> to learn what's planned for the next versions. We are trying to be clear about the coming features and the next release dates.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/18ad7dbb-fcd8-3dfc-b1b4-39f93ede7b45" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/18ad7dbb-fcd8-3dfc-b1b4-39f93ede7b45" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-platform-v4.0-rc-has-been-released-based-on-.net-5.0-4ogtt6cz</guid>
      <link>https://abp.io/community/posts/abp.io-platform-v4.0-rc-has-been-released-based-on-.net-5.0-4ogtt6cz</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP.IO Platform v4.0 RC Has Been Released based on .NET 5.0!</title>
      <description>Released ABP.IO Platform v4.0 RC. Some new features: Migrated to .NET 5.0, Stable Blazor UI, Identity Server 4 Upgrade, Moved to System.Text.Json, etc. etc. Learn more about what's new with v4.0 RC release.</description>
      <pubDate>Tue, 17 Nov 2020 07:22:15 Z</pubDate>
      <a10:updated>2026-10-02T12:11:40Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we have released the <a href="https://abp.io/">ABP Framework</a> (and the <a href="https://commercial.abp.io/">ABP Commercial</a>) 4.0.0 RC that is based on the <strong>.NET 5.0</strong>. This blog post introduces the new features and important changes in the new version.</p>
<blockquote>
<p><strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/45">4.0.0 final</a> version is December 3, 2020</strong>.</p>
</blockquote>
<h2>Get Started with the 4.0 RC</h2>
<p>If you want to try the version <code>4.0.0</code> today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>4.0.0-rc.5</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 4.0.0-rc.5
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 4.0.0-rc.5
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/3.3/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the <strong>Preview checkbox</strong>.</p>
</blockquote>
<h2>Migrating From 3.x to 4.0</h2>
<p>The version 4.0 comes with some major changes including the <strong>migration from .NET Core 3.1 to .NET 5.0</strong>.</p>
<p>We've prepared a <strong>detailed <a href="https://docs.abp.io/en/abp/4.0/Migration-Guides/Abp-4_0">migration document</a></strong> to explain all the changes and the actions you need to take while upgrading your existing solutions.</p>
<h2>What's new with the ABP Framework 4.0</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-11-17-abpio-platform-v40-rc-has-been-released-based-on-net-50/723f7d5553da8714d3f839f8e747c95f.png" alt="abp-fr-note.png" /></p>
<h3>The Blazor UI</h3>
<p>The Blazor UI is now stable and officially supported. The <a href="https://docs.abp.io/en/abp/4.0/Tutorials/Part-1?UI=Blazor">web application development tutorial</a> has been updated based on the version 4.0.</p>
<h4>abp bundle command</h4>
<p>Introducing the <code>abp bundle</code> CLI command to manage static JavaScript &amp; CSS file dependencies of a Blazor application. This command is currently used to add the dependencies to the <code>index.html</code> file in the dependency order by respecting to modularity. In the next version it will automatically unify &amp; minify the files. The documentation is being prepared.</p>
<h4>Removed the JQuery &amp; Bootstrap JavaScript</h4>
<p>Removed JQuery &amp; Bootstrap JavaScript dependencies for the Blazor UI.</p>
<blockquote>
<p>There are some other changes in the startup template and some public APIs. Follow the <a href="https://docs.abp.io/en/abp/4.0/Migration-Guides/Abp-4_0">Migration Guide</a> to apply changes for existing solutions that you're upgrading from the version 3.3. While we will continue to make improvements add new features, we no longer make breaking changes on the existing APIs until the version 5.0.</p>
</blockquote>
<h4>Others</h4>
<p>A lot of minor and major improvements have been done for the Blazor UI. Some of them are listed below:</p>
<ul>
<li>Implemented <code>IComponentActivator</code> to resolve the component from the <code>IServiceProvider</code>. So, you can now inject dependencies into the constructor of your razor component.</li>
<li>Introduced the <code>AbpComponentBase</code> base class that you derive your components from. It has useful base properties that you can use in your pages/components.</li>
<li>Introduced <code>IUiNotificationService</code> service to show toast notifications on the UI.</li>
<li>Improved the <code>IUiMessageService</code> to show message &amp; confirmation dialogs.</li>
</ul>
<h3>System.Text.Json</h3>
<p>ABP Framework 4.0 uses the System.Text.Json by default as the JSON serialization library. It, actually, using a hybrid approach: Continues to use the Newtonsoft.Json when it needs to use the features not supported by the System.Text.Json.</p>
<p>Follow the <a href="https://docs.abp.io/en/abp/4.0/Migration-Guides/Abp-4_0">Migration Guide</a> to learn how to configure to use the Newtonsoft.Json for some specific types or switch back to the Newtonsoft.Json as the default JSON serializer.</p>
<h3>Identity Server 4 Upgrade</h3>
<p>ABP Framework upgrades the <a href="https://www.nuget.org/packages/IdentityServer4">IdentityServer4</a> library from 3.x to 4.1.1 with the ABP Framework version 4.0. IdentityServer 4.x has a lot of changes. Some of them are <strong>breaking changes in the data structure</strong>.</p>
<p>Follow the <a href="https://docs.abp.io/en/abp/4.0/Migration-Guides/Abp-4_0">Migration Guide</a> to upgrade existing solutions.</p>
<h3>Creating a New Module Inside the Application</h3>
<p>ABP CLI has now a command to create a new module and add it to an existing solution. In this way, you can create modular applications easier than before.</p>
<p>Example: Create a <em>ProductManagement</em> module into your solution.</p>
<pre><code class="language-bash">abp add-module ProductManagement --new --add-to-solution-file
</code></pre>
<p>Execute this command in a terminal in the root folder of your solution. If you don't specify the <code>--add-to-solution-file</code> option, then the module projects will not be added to the main solution, but the project references still be added. In this case, you need to open the module's solution to develop the module.</p>
<p>See the <a href="https://docs.abp.io/en/abp/4.0/CLI">CLI document</a> for other options.</p>
<h3>WPF Startup Template</h3>
<p>Introducing the WPF startup template for the ABP Framework. Use the ABP CLI new command to create a new WPF application:</p>
<pre><code class="language-bash">abp new MyWpfApp -t wpf
</code></pre>
<p>This is a minimalist, empty project template that is integrated to the ABP Framework.</p>
<h3>New Languages</h3>
<p><strong>Thanks to the contributors</strong> from the ABP Community, the framework modules and the startup template have been localized to <strong>German</strong> language by <a href="https://github.com/alexanderpilhar">Alexander Pilhar</a> &amp; <a href="https://github.com/tntwist">Nico Lachmuth</a> and to <strong>Spanish</strong> language by <a href="https://github.com/jmglezgz">Jose Manuel Gonzalez</a> and <a href="https://github.com/washyn">Washington Acero M.</a>.</p>
<h3>Other Notes</h3>
<ul>
<li>Upgraded to Angular 11.</li>
<li>Since <a href="https://github.com/Mongo2Go/Mongo2Go">Mongo2Go</a> library not supports transactions, you can use transactions in unit tests for MongoDB.</li>
</ul>
<h2>What's new with the ABP Commercial 4.0</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-11-17-abpio-platform-v40-rc-has-been-released-based-on-net-50/066daf9bcf2e9e2c6bed39f8e7480552.png" alt="abp-co-note.png" /></p>
<h3>The Blazor UI</h3>
<p>The Blazor UI for the ABP Commercial is also becomes stable and feature rich with the version 4.0;</p>
<ul>
<li><a href="https://commercial.abp.io/tools/suite">ABP Suite</a> now supports to generate CRUD pages for the Blazor UI.</li>
<li>Completed the <a href="https://commercial.abp.io/themes">Lepton Theme</a> for the Blazor UI.</li>
<li>Implemented the <a href="https://commercial.abp.io/modules/Volo.FileManagement">File Management</a> module for the Blazor UI.</li>
</ul>
<h3>The ABP Suite</h3>
<p>While creating create/edit modals with a navigation property, we had two options: A dropdown to select the target entity and a modal to select the entity by searching with a data table.</p>
<p>Dropdown option now supports <strong>lazy load, search and auto-complete</strong>. In this way, selecting a navigation property becomes much easier and supports large data sets on the dropdown.</p>
<p><strong>Example: Select an author while creating a new book</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-11-17-abpio-platform-v40-rc-has-been-released-based-on-net-50/1ad2d609148d655845ea39f8e73d0894.png" alt="abp-suite-auto-complete-dropdown.png" /></p>
<p>With the new version, you can <strong>disable backend code generation</strong> on CRUD page generation. This is especially useful if you want to regenerate the page with a different UI framework, but don't want to regenerate the server side code.</p>
<h3>Identity Server Management UI Revised</h3>
<p>Completely revised the Identity Server Management UI based on the IDS 4.x changes.</p>
<h2>About the Next Release</h2>
<p>The next feature version, <code>4.1.0</code>, will mostly focus on completing the missing documents, fixing bugs, performance optimizations and improving the Blazor UI features. The planned preview release date for the version <code>4.1.0</code> is December 10 and the final (stable) version release date is December 24.</p>
<p>Follow the <a href="https://github.com/abpframework/abp/milestones">GitHub milestones</a> for all the planned ABP Framework version release dates.</p>
<h2>Feedback</h2>
<p>Please check out the ABP Framework 4.0.0 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us to release a more stable version. <strong>The planned release date for the <a href="https://github.com/abpframework/abp/milestone/45">4.0.0 final</a> version is November 26</strong>.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/e020b90e-e62d-f7d5-45f6-39f8e742020a" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/e020b90e-e62d-f7d5-45f6-39f8e742020a" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-abp-commercial-3.3-final-have-been-released-k5efzq6d</guid>
      <link>https://abp.io/community/posts/abp-framework-abp-commercial-3.3-final-have-been-released-k5efzq6d</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework &amp; ABP Commercial 3.3 Final Have Been Released</title>
      <description>Released ABP v3.3. Some new features: New modules &amp; features for the Blazor UI, Automatic Validation for AntiForgery Token for HTTP APIs, Rebus Integration Package for the Distributed Event Bus etc. Learn more about what's new with v3.3 final release.</description>
      <pubDate>Wed, 28 Oct 2020 07:43:47 Z</pubDate>
      <a10:updated>2026-10-02T09:01:24Z</a10:updated>
      <content:encoded><![CDATA[<p>ABP Framework &amp; ABP Commercial 3.3.0 have been released today.</p>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released">3.3 RC Announcement Post</a>, I will not repeat all the details again. Please read <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released">the RC post</a> for <strong>new feature and changes</strong> you may need to do for your solution while upgrading to the version 3.3.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 3.3 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>Run this command in the root folder of your solution. After the update command, check <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released">the RC blog post</a> to learn if you need to make any changes in your solution.</p>
<blockquote>
<p>You may want to see the new <a href="https://docs.abp.io/en/abp/latest/Upgrading">upgrading document</a>.</p>
</blockquote>
<h2>About the Next Version: 4.0</h2>
<p>The next version will be 4.0 and it will be mostly related to completing the Blazor UI features and upgrading the ABP Framework &amp; ecosystem to the .NET 5.0.</p>
<p>The goal is to complete the version 4.0 with a stable Blazor UI with the fundamental features implemented and publish it just after the Microsoft lunches .NET 5 in this November. The planned 4.0 preview release date is November 11th.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/d8e6f3b9-d52a-561d-2a08-39f880568913" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/d8e6f3b9-d52a-561d-2a08-39f880568913" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-abp-commercial-v3.3-rc-have-been-released-4wvax9v2</guid>
      <link>https://abp.io/community/posts/abp-framework-abp-commercial-v3.3-rc-have-been-released-4wvax9v2</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework &amp; ABP Commercial v3.3 RC Have Been Released</title>
      <description>Released ABP v3.3 RC. Some new features: New modules &amp; features for the Blazor UI, Automatic Validation for AntiForgery Token for HTTP APIs, Rebus Integration Package for the Distributed Event Bus etc. Learn more about what's new with v3.3 RC release.</description>
      <pubDate>Fri, 16 Oct 2020 07:47:30 Z</pubDate>
      <a10:updated>2026-10-02T09:04:42Z</a10:updated>
      <content:encoded><![CDATA[<blockquote>
<p>Note that the blog post has been updated for the <code>3.3.0-rc.2</code> release.</p>
</blockquote>
<p>We have released the <a href="https://abp.io/">ABP Framework</a> (and the <a href="https://commercial.abp.io/">ABP Commercial</a>) <code>3.3.0-rc.2</code> today. This blog post introduces the new features and important changes in the new version.</p>
<h2>Get Started with the 3.3 RC.2</h2>
<p>If you want to try the version <code>3.3.0-rc.2</code> today, follow the steps below;</p>
<ol>
<li><strong>Upgrade</strong> the ABP CLI to the version <code>3.3.0-rc.2</code> using a command line terminal:</li>
</ol>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 3.3.0-rc.2
</code></pre>
<p><strong>or install</strong> if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install Volo.Abp.Cli -g --version 3.3.0-rc.2
</code></pre>
<ol start="2">
<li>Create a <strong>new application</strong> with the <code>--preview</code> option:</li>
</ol>
<pre><code class="language-bash">abp new BookStore --preview
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/3.3/CLI">ABP CLI documentation</a> for all the available options.</p>
<blockquote>
<p>You can also use the <em>Direct Download</em> tab on the <a href="https://abp.io/get-started">Get Started</a> page by selecting the Preview checkbox.</p>
</blockquote>
<h3>Entity Framework Core Migrations</h3>
<p>This release includes changes in the database tables. If you are using EF Core, then you need to <strong>add a new migration</strong> (<code>Add-Migration</code>) and <strong>apply changes</strong> (<code>Update-Database</code>) to the database after upgrading your project.</p>
<h2>What's new in the ABP Framework 3.3</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/86021f7f983fc9739cfb39f842a29644.png" alt="abp-fr-note.png" /></p>
<h3>The Blazor UI</h3>
<p>We had released an experimental early preview version of the Blazor UI with the <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI">previous version</a>. In this version, we've completed most of the fundamental infrastructure features and the application modules (like identity and tenant management).</p>
<p>It currently has almost the same functionalities as the other UI types (Angular &amp; MVC / Razor Pages).</p>
<p><strong>Example screenshot</strong>: User management page of the Blazor UI</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/41968da6c558c075cf1239f842a30e29.png" alt="abp-blazor-ui.png" /></p>
<blockquote>
<p>We've adapted the <a href="https://commercial.abp.io/themes">Lepton Theme</a> for the ABP Commercial, see the related section below.</p>
</blockquote>
<p>We are still working on the fundamentals. So, the next version may introduce breaking changes of the Blazor UI. We will work hard to keep them with the minimal effect on your application code.</p>
<h4>Blazor UI Tutorial</h4>
<p>The <a href="https://docs.abp.io/en/abp/3.3/Tutorials/Part-1?UI=Blazor">Blazor UI tutorial</a> has been updated for the version <code>3.3.0-rc.2</code>. So, you can start the development today!</p>
<h4>Breaking Changes on the Blazor UI</h4>
<p>There are some breaking changes with the Blazor UI. If you've built an application and upgrade it, your application might not properly work. See <a href="https://docs.abp.io/en/abp/3.3/Migration-Guides/BlazorUI-3_3">the migration guide</a> for the changes you need to do after upgrading your application.</p>
<h3>Automatic Validation for AntiForgery Token for HTTP APIs</h3>
<p>Starting with the version 3.3, all your HTTP API endpoints are <strong>automatically protected</strong> against CSRF attacks, unless you disable it for your application. So, no configuration needed, just upgrade the ABP Framework.</p>
<p><a href="https://docs.abp.io/en/abp/3.3/CSRF-Anti-Forgery">See the documentation</a> to if you want to understand why you need it and how ABP Framework solves the problem.</p>
<h3>Rebus Integration Package for the Distributed Event Bus</h3>
<p><a href="https://github.com/rebus-org/Rebus">Rebus</a> describes itself as &quot;Simple and lean service bus implementation for .NET&quot;. There are a lot of integration packages like RabbitMQ and Azure Service Bus for the Rebus. The new <a href="https://www.nuget.org/packages/Volo.Abp.EventBus.Rebus">Volo.Abp.EventBus.Rebus</a> package allows you to use the Rebus as the <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus">distributed event bus</a> for the ABP Framework.</p>
<p>See <a href="https://docs.abp.io/en/abp/3.3/Distributed-Event-Bus-Rebus-Integration">the documentation</a> to learn how to use Rebus with the ABP Framework.</p>
<h3>Async Repository LINQ Extension Methods</h3>
<p>You have a problem when you want to use <strong>Async LINQ Extension Methods</strong> (e.g. <code>FirstOrDefaultAsync(...)</code>) in your <strong>domain</strong> and <strong>application</strong> layers. These async methods are <strong>not included in the standard LINQ extension methods</strong>. Those are defined by the <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore">Microsoft.EntityFrameworkCore</a> NuGet package (see <a href="https://github.com/dotnet/efcore/blob/main/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs">the code</a>). To be able to use these <code>async</code> methods, you need to reference to the <code>Microsoft.EntityFrameworkCore</code> package.</p>
<p>If you don't want to depend on the EF Core in your business layer, then ABP Framework provides the <code>IAsyncQueryableExecuter</code> service to execute your queries asynchronously without depending on the EF Core package. You can see <a href="https://docs.abp.io/en/abp/latest/Repositories#option-3-iasyncqueryableexecuter">the documentation</a> to get more information about this service.</p>
<p>ABP Framework version 3.3 takes this one step further and allows you to directly execute the async LINQ extension methods on the <code>IRepository</code> interface.</p>
<p><strong>Example: Use <code>CountAsync</code> and <code>FirstOrDefaultAsync</code> methods on the repositories</strong></p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace MyCompanyName.MyProjectName
{
    public class BookAppService : ApplicationService, IBookAppService
    {
        private readonly IRepository&lt;Book, Guid&gt; _bookRepository;

        public BookAppService(IRepository&lt;Book, Guid&gt; bookRepository)
        {
            _bookRepository = bookRepository;
        }

        public async Task DemoAsync()
        {
            var countAll = await _bookRepository
                .CountAsync();

            var count = await _bookRepository
                .CountAsync(x =&gt; x.Name.Contains(&quot;A&quot;));

            var book1984 = await _bookRepository
                .FirstOrDefaultAsync(x =&gt; x.Name == &quot;1984&quot;);            
        }
    }
}
</code></pre>
<p>All the standard LINQ methods are supported: <em>AllAsync, AnyAsync, AverageAsync, ContainsAsync, CountAsync, FirstAsync, FirstOrDefaultAsync, LastAsync, LastOrDefaultAsync, LongCountAsync, MaxAsync, MinAsync, SingleAsync, SingleOrDefaultAsync, SumAsync, ToArrayAsync, ToListAsync</em>.</p>
<p>This approach still has a limitation. You need to execute the extension method directly on the repository object. For example, the below usage is <strong>not supported</strong>:</p>
<pre><code class="language-csharp">var count = await _bookRepository.Where(x =&gt; x.Name.Contains(&quot;A&quot;)).CountAsync();
</code></pre>
<p>This is because the object returned from the <code>Where</code> method is not a repository object, it is a standard <code>IQueryable</code>. In such cases, you can still use the <code>IAsyncQueryableExecuter</code>:</p>
<pre><code class="language-csharp">var count = await AsyncExecuter.CountAsync(
    _bookRepository.Where(x =&gt; x.Name.Contains(&quot;A&quot;))
);
</code></pre>
<p><code>AsyncExecuter</code> has all the standard extension methods, so you don't have any restriction here. See <a href="https://docs.abp.io/en/abp/latest/Repositories#iqueryable-async-operations">the repository documentation</a> for all the options you have.</p>
<blockquote>
<p>ABP Framework does its best to not depend on the EF Core and still be able to use the async LINQ extension methods. However, there is no problem to depend on the EF Core for your application, you can add the <code>Microsoft.EntityFrameworkCore</code> NuGet package and use the native methods.</p>
</blockquote>
<h3>Stream Support for the Application Service Methods</h3>
<p><a href="https://docs.abp.io/en/abp/latest/Application-Services">Application services</a> are consumed by clients and the parameters and return values (typically <a href="https://docs.abp.io/en/abp/latest/Data-Transfer-Objects">Data Transfer Objects</a>). In case of the client is a remote application, then these objects should be serialized &amp; deserialized.</p>
<p>Until the version 3.3, we hadn't suggest to use the <code>Stream</code> in the application service contracts, since it is not serializable/deserializable. However, with the version 3.3, ABP Framework properly supports this scenario by introducing the new <code>IRemoteStreamContent</code> interface.</p>
<p>Example: An application service that can get or return streams</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;

namespace MyProject.Test
{
    public interface ITestAppService : IApplicationService
    {
        Task Upload(Guid id, IRemoteStreamContent streamContent);
        Task&lt;IRemoteStreamContent&gt; Download(Guid id);
    }
}
</code></pre>
<p>The implementation can be as shown below:</p>
<pre><code class="language-csharp">using System;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;

namespace MyProject.Test
{
    public class TestAppService : ApplicationService, ITestAppService
    {
        public Task&lt;IRemoteStreamContent&gt; Download(Guid id)
        {
            var fs = new FileStream(&quot;C:\\Temp\\&quot; + id + &quot;.blob&quot;, FileMode.OpenOrCreate);
            return Task.FromResult(
                (IRemoteStreamContent) new RemoteStreamContent(fs) {
                    ContentType = &quot;application/octet-stream&quot; 
                }
            );
        }

        public async Task Upload(Guid id, IRemoteStreamContent streamContent)
        {
            using (var fs = new FileStream(&quot;C:\\Temp\\&quot; + id + &quot;.blob&quot;, FileMode.Create))
            {
                await streamContent.GetStream().CopyToAsync(fs);
                await fs.FlushAsync();
            }
        }
    }
}
</code></pre>
<blockquote>
<p>This is just a demo code. Do it better in your production code :)</p>
</blockquote>
<p>Thanks to <a href="https://github.com/alexandru-bagu">@alexandru-bagu</a> for the great contribution!</p>
<h3>Other Changes</h3>
<ul>
<li>Upgraded all the .NET Core / ASP.NET Core related packages to the version 3.1.8. If you have additional dependencies to the .NET Core / ASP.NET Core related packages, we suggest you to updates your packages to the version 3.1.8 to have the latest bug and security fixes published by Microsoft.</li>
<li>The blogging module now uses the <a href="https://docs.abp.io/en/abp/latest/Blob-Storing">BLOB Storing</a> system to store images &amp; files of the blog posts. If you are using this module, then you need to manually migrate the local files to the BLOB Storing system after the upgrade.</li>
<li>The Angular UI is now redirecting to the profile management page of the MVC UI instead of using its own UI, if you've configured the authorization code flow (which is default since the version 3.2.0).</li>
</ul>
<h2>What's new in the ABP Commercial 3.3</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/532b0018b486294ac3e539f842a36433.png" alt="abp-co-note.png" /></p>
<h3>The Blazor UI</h3>
<p>We have good news for the ABP Commercial Blazor UI too. We have implemented the <a href="https://commercial.abp.io/themes">Lepton Theme</a> integration, so it is now available with the Blazor UI. Also, implemented most of the fundamental <a href="https://commercial.abp.io/modules">modules</a>.</p>
<p><strong>A screenshot from the ABP Commercial startup template with the Blazor UI</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/546a89e4112ec73f45ec39f842a3b663.png" alt="abp-commercial-blazor-ui.png" /></p>
<p>There are still missing features and modules. However, we are working on it to have a more complete version in the next release.</p>
<h4>Breaking Changes on the Blazor UI</h4>
<p>There are some breaking changes with the Blazor UI. If you've built an application and upgrade it, your application might not properly work. See the <a href="https://docs.abp.io/en/commercial/3.3/migration-guides/blazor-ui-3_3">ABP Commercial Blazor UI v 3.3 Migration Guide</a> for the changes you need to do after upgrading your application.</p>
<h4>Known Issues</h4>
<p>When you create a new project, profile management doesn't work, you get an exception because it can't find the <code>/libs/cropperjs/css/cropper.min.css</code> file. To fix the issue;</p>
<ul>
<li>Add <code>&quot;@volo/account&quot;: &quot;^3.3.0-rc.2&quot;</code> to the <code>package.json</code> in the <code>.Host</code> project.</li>
<li>Run <code>yarn</code> (or <code>npm install</code>), then <code>gulp</code> on a command line terminal in the root folder of the <code>.Host</code> project.</li>
</ul>
<h3>Multi-Tenant Social Logins</h3>
<p><a href="https://commercial.abp.io/modules/Volo.Account.Pro">Account module</a> now supports to manage the social/external logins in the UI. You can <strong>enable/disable</strong> and <strong>set options</strong> in the settings page. It also supports to use <strong>different credentials for the tenants</strong> and it is also <strong>configured on the runtime</strong>.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/0f4aa548ce22a256829739f842a3ff54.png" alt="abp-commercial-setting-account-external-logins.png" /></p>
<h3>Linked Accounts</h3>
<p>Linked user system allows you to link other accounts (including account in a different tenant) with your account, so you can switch between different accounts with a single-click. It is practical since you no longer need to logout and login again with entering the credentials of the target account.</p>
<p>To manage the linked accounts, go to the profile management page from the user menu;</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-10-16-abp-framework--abp-commercial-v33-rc-have-been-released/ef376d39f6c5be0a628639f842a448d7.png" alt="abp-commercial-linked-users.png" /></p>
<h3>Paypal &amp; Stripe Integrations</h3>
<p>The <a href="https://commercial.abp.io/modules/Volo.Payment">Payment Module</a> was supporting PayU and 2Checkout providers until the version 3.3. It's now integrated to PayPal and Stripe. See the <a href="https://docs.abp.io/en/commercial/latest/modules/payment">technical documentation</a> to learn how to use it.</p>
<h3>ABP Suite Improvements</h3>
<p>We've done a lot of small improvements for the <a href="https://commercial.abp.io/tools/suite">ABP Suite</a>. Some of the enhancements are;</p>
<ul>
<li>Show the previously installed modules as <em>installed</em> on the module list.</li>
<li>Switch between the latest stable, the latest <a href="https://docs.abp.io/en/abp/latest/Previews">preview</a> and the latest <a href="https://docs.abp.io/en/abp/latest/Nightly-Builds">nightly build</a> versions of the ABP related packages.</li>
<li>Moved the file that stores the <em>previously created entities</em> into the solution folder to allow you to store it in your source control system.</li>
</ul>
<h3>Others</h3>
<ul>
<li>Added an option to the Account Module to show reCAPTCHA on the login &amp; the registration forms.</li>
</ul>
<p>Besides the new features introduced in this post, we've done a lot of small other enhancements and bug fixes to provide a better development experience and increase the developer productivity.</p>
<h2>New Articles</h2>
<p>The core ABP Framework team &amp; the community continue to publish new articles on the <a href="https://community.abp.io/">ABP Community</a> web site. The recently published articles are;</p>
<ul>
<li><a href="https://community.abp.io/articles/replacing-email-templates-and-sending-emails-jkeb8zzh">Replacing Email Templates and Sending Emails</a> (by <a href="https://community.abp.io/members/EngincanV">@EngincanV</a>)</li>
<li><a href="https://community.abp.io/articles/how-to-add-custom-property-to-the-user-entity-6ggxiddr">How to Add Custom Properties to the User Entity</a> (by <a href="https://community.abp.io/members/berkansasmaz">@berkansasmaz</a>)</li>
<li><a href="https://community.abp.io/articles/using-the-adminlte-theme-with-the-abp-framework-mvc-razor-pages-ui-gssbhb7m">Using the AdminLTE Theme with the ABP Framework MVC / Razor Pages UI</a> (by <a href="https://community.abp.io/members/mucahiddanis">@mucahiddanis</a>)</li>
<li><a href="https://community.abp.io/articles/using-devextreme-angular-components-with-the-abp-framework-x5nyvj3i">Using DevExtreme Angular Components With the ABP Framework</a> (by <a href="https://community.abp.io/members/bunyamin">@bunyamin</a>)</li>
</ul>
<p>It is appreciated if you want to <a href="https://community.abp.io/articles/submit">submit an article</a> related to the ABP Framework.</p>
<h2>About the Next Release</h2>
<p>The next version will be <code>4.0.0</code>. We are releasing a major version, since we will move the ABP Framework to .NET 5.0. We see that for most of the applications this will not be a breaking change and we hope you easily upgrade to it.</p>
<p>The planned 4.0.0-rc.1 (Release Candidate) version date is <strong>November 11</strong>, just after the Microsoft releases the .NET 5.0 final. The planned 4.0.0 final release date is <strong>November 26</strong>.</p>
<p>Follow the <a href="https://github.com/abpframework/abp/milestones">GitHub milestones</a> for all the planned ABP Framework version release dates.</p>
<h2>Feedback</h2>
<p>Please check out the ABP Framework 3.3.0 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us to release a more stable version. The planned release date for the <a href="https://github.com/abpframework/abp/milestone/44">3.3.0 final</a> version is October 27th.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/13ffa218-c16a-0f86-95b5-39f8428da1c2" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/13ffa218-c16a-0f86-95b5-39f8428da1c2" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-v3.2-final-has-been-released-37ccd61c</guid>
      <link>https://abp.io/community/posts/abp-framework-v3.2-final-has-been-released-37ccd61c</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework v3.2 Final Has Been Released</title>
      <description>Released ABP v3.2 final. Some new features: The Blazor UI, MongoDB ACID Transactions, Kafka Integration for the Distributed Event Bus etc. Learn more about what's new with v3.2 final release.</description>
      <pubDate>Fri, 02 Oct 2020 06:18:35 Z</pubDate>
      <a10:updated>2026-10-02T14:12:03Z</a10:updated>
      <content:encoded><![CDATA[<p>ABP Framework &amp; ABP Commercial 3.2 have been released today.</p>
<p>Since all the new features are already explained in detail with the <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI">3.2 RC Announcement Post</a>, I will not repeat all the details again. Please read <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI">the RC post</a> for <strong>new features and changes</strong> you may need to do for your solution while upgrading to version 3.2.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 3.2 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>After the update command, check <a href="https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI">the RC blog post</a> to learn if you need to make any changes in your solution.</p>
<blockquote>
<p>You may want to see the new <a href="https://docs.abp.io/en/abp/latest/Upgrading">upgrading document</a>.</p>
</blockquote>
<h2>About the Next Versions</h2>
<p>The next two versions (3.3 &amp; 4.0) will be mostly related to completing the Blazor UI features and upgrading the ABP Framework &amp; ecosystem to the .NET 5.0.</p>
<p>The ultimate goal is to complete the version 4.0 with a stable Blazor UI with the fundamental features implemented and publish it just after the Microsoft lunches .NET 5 in this November.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/f2001380-e851-e227-2191-39f7fa23305a" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/f2001380-e851-e227-2191-39f7fa23305a" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-abp-commercial-3.2-rc-with-the-new-blazor-ui--wn0yr5p0</guid>
      <link>https://abp.io/community/posts/abp-framework-abp-commercial-3.2-rc-with-the-new-blazor-ui--wn0yr5p0</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework &amp; ABP Commercial 3.2 RC With The New Blazor UI 🚀</title>
      <description>Released ABP v3.2 RC. Some new features: The Blazor UI, MongoDB ACID Transactions, Kafka Integration for the Distributed Event Bus etc. Learn more about what's new with v3.2 RC release.</description>
      <pubDate>Fri, 18 Sep 2020 06:59:48 Z</pubDate>
      <a10:updated>2026-10-02T15:19:09Z</a10:updated>
      <content:encoded><![CDATA[<p>We are extremely excited today to release the <a href="https://abp.io/">ABP Framework</a> Release Candidate (and the <a href="https://commercial.abp.io/">ABP Commercial</a>, as always). This release includes an early preview version of the <strong>Blazor UI</strong> for the ABP.IO Platform.</p>
<h2>The Blazor UI</h2>
<p>While the Blazor UI <strong>should be considered as experimental</strong> for now, it is possible to start to develop your application today.</p>
<h3>Fundamental Services</h3>
<p>Currently, implemented some important framework features;</p>
<ul>
<li><strong>Authentication</strong> through the MVC backend using the OpenId Connect authorization code flow. So, all the current login options (login, register, forgot password, external/social logins...) are supported.</li>
<li><strong>Authorization</strong>, using the ABP Framework <strong>permissions</strong> as well as the standard authorization system.</li>
<li><strong>Localization</strong> just works like the MVC UI.</li>
<li><strong>Basic Theme</strong> with the top main menu.</li>
<li><strong>Dynamic C# HTTP API proxies</strong>, so you can directly consume your backend API by injecting the application service interfaces.</li>
<li>Some other <strong>fundamental services</strong> like <code>ISettingProvider</code>, <code>IFeatureChecker</code>, <code>ICurrentUser</code>...</li>
</ul>
<p>Also, the standard .net services are already available, like caching, logging, validation and much more. Since the ABP Framework has layered itself, all the non-MVC UI related features are already usable for the Blazor UI.</p>
<h3>Pre-Built Modules</h3>
<p>Some modules have been implemented;</p>
<ul>
<li><strong>Identity</strong> module is pre-installed and provides <strong>user, role and permission management</strong>.</li>
<li><strong>Profile management</strong> page is implemented to allow to change the password and personal settings.</li>
</ul>
<h3>About the Blazorise Library</h3>
<p>We've selected the <a href="https://blazorise.com/">Blazorise</a> as a fundamental UI library for the Blazor UI. It already supports different HTML/CSS frameworks (like Bootstrap, Bulma, Ant Design...) and significantly increases the developer productivity.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/blazorise-github.png" alt="blazorise-github" /></p>
<p>We also have good news: <strong><a href="https://github.com/stsrki">Mladen Macanović</a></strong>, the creator of the Blazorise, is <strong>joining to the core ABP Framework team</strong> in the next weeks. We are excited to work with him to bring the power of these two successful projects together.</p>
<h3>The Tutorial</h3>
<p>We've <strong>updated</strong> the <a href="https://docs.abp.io/en/abp/3.2/Tutorials/Part-1?UI=Blazor">web application development tutorial</a> for the <strong>Blazor UI</strong>. You can start to develop applications today! The <strong>source code</strong> of the BookStore application developed with this tutorial is <a href="https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore">here</a>.</p>
<h3>Get started with the Blazor UI</h3>
<p>If you want to try the Blazor UI today, follow the instructions below.</p>
<h4>Upgrade the ABP CLI</h4>
<p>Install the latest <a href="https://docs.abp.io/en/abp/3.2/CLI">ABP CLI</a> preview version:</p>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 3.2.0-rc.2
</code></pre>
<h4>Create a new Solution</h4>
<p>Then you can create a new solution using the <em>abp new</em> command:</p>
<pre><code class="language-bash">abp new AbpBlazorDemo -u blazor --preview
</code></pre>
<p>Also, specify the <code>-t app-pro</code> parameter if you are an ABP Commercial user.</p>
<blockquote>
<p>See the ABP CLI documentation for the additional options, like MongoDB database or separated authentication server.</p>
</blockquote>
<h4>Open the Solution</h4>
<p>Open the generated solution using the latest Visual Studio 2019. You will see a solution structure like the picture below:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/visual-studio-solution-with-blazor.png" alt="visual-studio-solution-with-blazor" /></p>
<h4>Run the Application</h4>
<ul>
<li>Run the <code>DbMigrator</code> project to create the database and seed the initial data.</li>
<li>Run the <code>HttpApi.Host</code> project for the server-side.</li>
<li>Run the <code>Blazor</code> project to start the Blazor UI.</li>
</ul>
<p>Use <code>admin</code> as the username and <code>1q2w3E*</code> as the password to login to the application.</p>
<p>Here, a screenshot from the role management page of the Blazor UI:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/blazor-role-management-img.png" alt="blazor-role-management-img" /></p>
<h2>What's New with the ABP Framework 3.2</h2>
<p>Besides the Blazor UI, there are a lot of issues that have been closed with <a href="https://github.com/abpframework/abp/milestone/39?closed=1">the milestone 3.2</a>. I will highlight some of the major features and changes released with this version.</p>
<h3>MongoDB ACID Transactions</h3>
<p><a href="https://docs.abp.io/en/abp/3.2/MongoDB">MongoDB integration</a> now supports multi-document transactions that comes with the MongoDB 4.x.</p>
<p>We've <strong>disabled transactions</strong> for solutions use the MongoDB, inside the <code>YourProjectMongoDbModule.cs</code> file in the MongoDB project. If your MongoDB server <strong>supports transactions</strong>, you should manually enable it in this class:</p>
<pre><code class="language-csharp">Configure&lt;AbpUnitOfWorkDefaultOptions&gt;(options =&gt;
{
    options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto;
});
</code></pre>
<blockquote>
<p>Or you can delete this code since this is already the default behavior.</p>
</blockquote>
<h4>Upgrade Notes</h4>
<p>If you are upgrading an existing solution and your MongoDB server doesn't support transactions, please disable it:</p>
<pre><code class="language-csharp">Configure&lt;AbpUnitOfWorkDefaultOptions&gt;(options =&gt;
{
    options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/3.2/Unit-Of-Work">Unit Of Work document</a> to learn more about UOW and transactions.</p>
<p>Also, add <a href="https://github.com/abpframework/abp/blob/rel-3.2/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MongoDbMyProjectNameDbSchemaMigrator.cs">this file</a> into your MongoDB project (remember to change <code>MongoDbMyProjectNameDbSchemaMigrator</code> and <code>IMyProjectNameDbSchemaMigrator</code> with your own project name).</p>
<h4>Integration Tests</h4>
<blockquote>
<p>Transactions are also <strong>disabled for automated integration tests</strong> coming with the application startup template, since the <a href="https://github.com/Mongo2Go/Mongo2Go">Mongo2Go</a> library (we use in the test projects) has a problem with the transactions. We've sent a <a href="https://github.com/Mongo2Go/Mongo2Go/pull/101">Pull Request</a> to fix it and will enable the transactions again when they merge &amp; release it.</p>
<p>If you are upgrading an existing solution and using MongoDB, please disable transactions for the test projects just as described above.</p>
</blockquote>
<h3>Kafka Integration for the Distributed Event Bus</h3>
<p>ABP Framework's <a href="https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus">distributed event system</a> has been <a href="https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-RabbitMQ-Integration">integrated to RabbitMQ</a> before. By the version 3.2, it has a Kafka integration package, named <a href="https://www.nuget.org/packages/Volo.Abp.EventBus.Kafka">Volo.Abp.EventBus.Kafka</a>.</p>
<p>See the <a href="https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-Kafka-Integration">Kafka integration documentation</a> to learn how to install and configure it.</p>
<h3>Host Features</h3>
<p><a href="https://docs.abp.io/en/abp/3.2/Features">ABP Feature System</a> allows you to define features in your application. Then you can enable/disable a feature dynamically on the runtime. It is generally used in a <a href="https://docs.abp.io/en/abp/3.2/Multi-Tenancy">multi-tenant</a> system to restrict features for tenants, so you can charge extra money for some features in a SaaS application.</p>
<p>In some cases, you may want to use the same features in the host side (host is you as you are managing the tenants). For this case, we've added a &quot;<strong>Manage Host Features</strong>&quot; button to the Tenant Management page so you can open a modal dialog to select the features for the host side.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/host-features.png" alt="host-features" /></p>
<h3>AbpHttpClientBuilderOptions</h3>
<p>ABP Framework provides a system to dynamically create C# proxies to consume HTTP APIs from your client applications. <code>AbpHttpClientBuilderOptions</code> is a new option class to configure the <code>HttpClient</code>s used by the proxy system.</p>
<p><strong>Example: Use the <a href="https://github.com/App-vNext/Polly">Polly</a> library to retry up to 3 times for a failed HTTP request</strong></p>
<pre><code class="language-csharp">public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure&lt;AbpHttpClientBuilderOptions&gt;(options =&gt;
    {
        options.ProxyClientBuildActions.Add((remoteServiceName, clientBuilder) =&gt;
        {
            clientBuilder.AddTransientHttpErrorPolicy(policyBuilder =&gt;
                policyBuilder.WaitAndRetryAsync(
                    3,
                    i =&gt; TimeSpan.FromSeconds(Math.Pow(2, i))
                )
            );
        });
    });
}
</code></pre>
<p>See the issue <a href="https://github.com/abpframework/abp/issues/5304">#5304</a> for the details.</p>
<h3>ABP Build Command</h3>
<p>We are using <strong>mono repository</strong> approach and the <a href="https://github.com/abpframework/abp">abp repository</a> has tens of solutions and hundreds of projects (the framework, modules, tooling, templates...) with all of them are referencing to each other.</p>
<p>It gets a significant time to build the whole repository for every Git push. To <strong>optimize</strong> this process, we've created the <strong>abp build</strong> command in the <a href="https://docs.abp.io/en/abp/3.2/CLI">ABP CLI</a>:</p>
<pre><code class="language-bash">abp build
</code></pre>
<p>We will use this command to build the abp repository or a solution inside it. However, it is available to everyone in case of need.</p>
<blockquote>
<p><strong>Most of the people will not need it</strong>. If you need it, see the <a href="https://docs.abp.io/en/abp/3.2/CLI">ABP CLI</a> document to learn all the details and options.</p>
</blockquote>
<h3>Other Features, Improvements and Changes</h3>
<ul>
<li>Introduced the <code>DynamicRangeAttribute</code> that can be used to determine the range values on runtime, just like the <code>DynamicStringLengthAttribute</code> was introduced before.</li>
<li>Improved the feature management modal for multi-tenant applications to group features on the UI and show hierarchically.</li>
<li>Added <code>--skip-cli-version-check</code> option to ABP CLI to improve the performance by bypassing the online version check.</li>
<li>Angular UI now redirect to MVC UI (the authentication server-side) for profile management page, if the authorization code flow is used (which is the default).</li>
<li>Account module profile management page is now extensible. You can implement the <code>IProfileManagementPageContributor</code> interface and register it using the <code>ProfileManagementPageOptions</code> class.</li>
<li>Improvements and optimizations for the <a href="https://blog.abp.io/abp/Introducing-the-Angular-Service-Proxy-Generation">Angular service proxy generation</a>.</li>
</ul>
<p>And a lot of minor improvements and bug fixes. You can see <a href="https://github.com/abpframework/abp/milestone/39?closed=1">the milestone 3.2</a> for all issues &amp; PRs closed with this version.</p>
<h2>What's New with the ABP Commercial 3.2</h2>
<h3>Breaking Changes</h3>
<p>The new <em>profile picture management</em> feature uses the <a href="https://docs.abp.io/en/abp/3.2/Blob-Storing">BLOB storing</a> system, so it needs a Storage Provider. The new <strong>startup template comes with the <a href="https://docs.abp.io/en/abp/3.2/Blob-Storing-Database">Database BLOB Provider</a> pre-installed</strong>. You can change it if you want to use another BLOB provider (like Azure, AWS or a simple file system).</p>
<p><strong>Existing solutions must configure a BLOB provider</strong> after upgrading to the version 3.2. Follow the <a href="https://docs.abp.io/en/abp/3.2/Blob-Storing#blob-storage-providers">BLOB Storing document</a> to configure the provider yourself.</p>
<h3>The Blazor UI</h3>
<p>The <strong>experimental</strong> Blazor UI is also available for the ABP Commercial. The <a href="https://commercial.abp.io/themes">Lepton Theme</a> hasn't been implemented with this initial preview, however we are working on it with the highest priority.</p>
<p>You can use the <a href="https://docs.abp.io/en/commercial/latest/abp-suite/index">ABP Suite</a> or the following ABP CLI command to create a new solution with the Blazor UI:</p>
<pre><code class="language-bash">abp new AbpBlazorDemo -u blazor -t app-pro --preview
</code></pre>
<p>Please try it and provide feedback to us. Thanks in advance.</p>
<blockquote>
<p>See the instructions in the <em>Get started with the Blazor UI</em> section above to properly create and run your application.</p>
</blockquote>
<h3>File Management Angular UI</h3>
<p>Angular UI for the <a href="https://commercial.abp.io/modules/Volo.FileManagement">File Management</a> module is available with version 3.2. You can add it to your solution using the ABP Suite.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/file-management-module-angular.png" alt="file-management-module-angular" /></p>
<h3>Profile Picture Management</h3>
<p>We've added profile picture management for the account module, so a user can select one of the options below for her profile picture;</p>
<ul>
<li>Use the default placeholder as the avatar.</li>
<li>Use <a href="https://gravatar.com/">Gravatar</a> service to get the picture matching the email address of the user.</li>
<li>Upload a file as the profile picture.</li>
</ul>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/account-profile-picture.jpg" alt="account-profile-picture" /></p>
<h3>Two Factor Authentication Features</h3>
<p>Created <a href="https://docs.abp.io/en/abp/3.2/Features">features</a> and <a href="https://docs.abp.io/en/abp/3.2/Settings">settings</a> to disable, enable or force to use 2FA on login for the tenants and users.</p>
<h3>Upgrading the ABP Suite</h3>
<p>You can use the following command to upgrade the ABP Suite to the latest preview version:</p>
<pre><code>abp suite update --preview
</code></pre>
<h2>Other News</h2>
<h3>The ABP Community</h3>
<p><strong>ABP Community</strong> web site is constantly being improved and new articles are added. We will add &quot;<strong>commenting</strong>&quot; and &quot;<strong>rating</strong>&quot; features to the articles soon to increase the interactivity between the people.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-18-abp-framework--abp-commercial-32-rc-with-the-new-blazor-ui-/abp-community-20200917.png" alt="abp-community-20200917" /></p>
<p>If you have something to share with the ABP community or want to follow the project progress, please check the <strong><a href="https://community.abp.io/">community.abp.io</a></strong>!</p>
<h3>CMS Kit Project</h3>
<p>We are silently working on a project, named <a href="https://github.com/abpframework/abp/tree/dev/modules/cms-kit">CMS Kit</a>, for a few months. CMS Kit is a set of reusable CMS (Content Management System) components based on the ABP Framework. Some of the components currently being developed:</p>
<ul>
<li><strong>Comments</strong>; Allows users to comment under something (a blog post, a document, an image... etc).</li>
<li><strong>Reactions</strong>; Allows users to give reactions to something (a comment, a picture... etc.) using simple emoji icons.</li>
<li><strong>Rating</strong>; Allows users to rate some content from 1 to 5.</li>
<li><strong>Newsletter</strong>; Allows you to put a newsletter box to your web site to collect emails from users.</li>
<li><strong>Contact</strong>; Put a form to get a message from the web site visitors.</li>
</ul>
<p>There are more planned components like articles, tags, votes, favorites, portfolios, image galleries, FAQs... etc. We will document and deploy these components when they get matured and ready to use. Some of them will be open source &amp; free while some of them are paid (included in the <a href="https://commercial.abp.io/">ABP Commercial</a> license).</p>
<h2>Feedback</h2>
<p>Please try the ABP Framework 3.2.0 RC and <a href="https://github.com/abpframework/abp/issues/new">provide feedback</a> to help us to release a more stable version. The planned release date for the <a href="https://github.com/abpframework/abp/milestone/43">3.2.0 final</a> version is October 01.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3e3ed00f-4c38-12d7-4f93-39f7b22fe597" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3e3ed00f-4c38-12d7-4f93-39f7b22fe597" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/introducing-the-angular-service-proxy-generation-jnimqnb4</guid>
      <link>https://abp.io/community/posts/introducing-the-angular-service-proxy-generation-jnimqnb4</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>angular</category>
      <category>ABP Framework</category>
      <title>Introducing the Angular Service Proxy Generation</title>
      <description>ABP Framework has introduced the new Angular Service Proxy Generation system with the version 3.1. This post introduces the service proxy generation system and highlights some important features.</description>
      <pubDate>Mon, 07 Sep 2020 08:29:12 Z</pubDate>
      <a10:updated>2026-10-02T14:58:39Z</a10:updated>
      <content:encoded><![CDATA[<h1>Introducing the Angular Service Proxy Generation</h1>
<p>ABP Angular Service Proxy System <strong>generates TypeScript services and models</strong> to consume your backend HTTP APIs developed using the ABP Framework. So, you <strong>don't manually create</strong> models for your server side DTOs and perform raw HTTP calls to the server.</p>
<p>ABP Framework has introduced the <strong>new</strong> Angular Service Proxy Generation system with the <strong>version 3.1</strong>. While this feature was available since the <a href="https://blog.abp.io/abp/ABP-Framework-v2_3_0-Has-Been-Released">v2.3</a>, it was not well covering some scenarios, like inheritance and generic types and had some known problems. <strong>With the v3.1, we've re-written</strong> it using the <a href="https://angular.io/guide/schematics">Angular Schematics</a> system. Now, it is much more stable and feature rich.</p>
<p>This post introduces the service proxy generation system and highlights some important features.</p>
<h2>Installation</h2>
<h3>ABP CLI</h3>
<p>You need to have the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> to use the system. So, install it if you haven't installed before:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>If you already have installed it before, you can update to the latest version:</p>
<pre><code class="language-shell">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>Project Configuration</h3>
<blockquote>
<p>If you've created your project with version 3.1 or later, you can skip this part since it will be already installed in your solution.</p>
</blockquote>
<p>For a solution that was created before v3.1, follow the steps below to configure the angular application:</p>
<ul>
<li>Add <code>@abp/ng.schematics</code> package to the <code>devDependencies</code> of the Angular project. Run the following command in the root folder of the angular application:</li>
</ul>
<pre><code class="language-bash">npm install @abp/ng.schematics --save-dev
</code></pre>
<ul>
<li>Add <code>rootNamespace</code> entry into the <code>apis/default</code> section in the <code>/src/environments/environment.ts</code>, as shown below:</li>
</ul>
<pre><code class="language-json">apis: {
  default: {
    ...
    rootNamespace: 'Acme.BookStore'
  },    
}
</code></pre>
<p><code>Acme.BookStore</code> should be replaced by the root namespace of your .NET project. This ensures to not create unnecessary nested folders while creating the service proxy code. This value is <code>AngularProxyDemo</code> for the example solution explained below.</p>
<ul>
<li>Finally, add the following paths to the <code>tsconfig.base.json</code> to have a shortcut while importing proxies:</li>
</ul>
<pre><code class="language-json">&quot;paths&quot;: {
    &quot;@proxy&quot;: [&quot;src/app/proxy/index.ts&quot;],
    &quot;@proxy/*&quot;: [&quot;src/app/proxy/*&quot;]
}
</code></pre>
<h2>Basic Usage</h2>
<h3>Project Creation</h3>
<blockquote>
<p>If you already have a solution, you can skip this section.</p>
</blockquote>
<p>You need to <a href="https://abp.io/get-started">create</a> your solution with the Angular UI. You can use the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> to create a new solution:</p>
<pre><code class="language-bash">abp new AngularProxyDemo -u angular
</code></pre>
<h4>Run the Application</h4>
<p>The backend application must be up and running to be able to use the service proxy code generation system.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started?UI=NG&amp;DB=EF&amp;Tiered=No">getting started</a> guide if you don't know details of creating and running the solution.</p>
</blockquote>
<h3>Backend</h3>
<p>Assume that we have an <code>IBookAppService</code> interface:</p>
<pre><code class="language-csharp">using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace AngularProxyDemo.Books
{
    public interface IBookAppService : IApplicationService
    {
        public Task&lt;List&lt;BookDto&gt;&gt; GetListAsync();
    }
}
</code></pre>
<p>That uses a <code>BookDto</code> defined as shown:</p>
<pre><code class="language-csharp">using System;
using Volo.Abp.Application.Dtos;

namespace AngularProxyDemo.Books
{
    public class BookDto : EntityDto&lt;Guid&gt;
    {
        public string Name { get; set; }

        public DateTime PublishDate { get; set; }
    }
}
</code></pre>
<p>And implemented as the following:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace AngularProxyDemo.Books
{
    public class BookAppService : ApplicationService, IBookAppService
    {
        public async Task&lt;List&lt;BookDto&gt;&gt; GetListAsync()
        {
            //TODO: get books from a database...
        }
    }
}
</code></pre>
<p>It simply returns a list of books. You probably want to get the books from a database, but it doesn't matter for this article.</p>
<h3>HTTP API</h3>
<p>Thanks to the <a href="https://docs.abp.io/en/abp/latest/API/Auto-API-Controllers">auto API controllers</a> system of the ABP Framework, we don't have to develop API controllers manually. Just <strong>run the backend (<em>HttpApi.Host</em>) application</strong> that shows the <a href="https://swagger.io/tools/swagger-ui/">Swagger UI</a> by default. You will see the <strong>GET</strong> API for the books:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-09-07-introducing-the-angular-service-proxy-generation/swagger.png" alt="swagger" /></p>
<h3>Service Proxy Generation</h3>
<p>Open a <strong>command line</strong> in the <strong>root folder of the Angular application</strong> and execute the following command:</p>
<pre><code class="language-bash">abp generate-proxy
</code></pre>
<p>It should produce an output like the following:</p>
<pre><code class="language-bash">...
CREATE src/app/proxy/books/book.service.ts (446 bytes)
CREATE src/app/proxy/books/models.ts (148 bytes)
CREATE src/app/proxy/books/index.ts (57 bytes)
CREATE src/app/proxy/index.ts (33 bytes)
</code></pre>
<blockquote>
<p><code>generate-proxy</code> command can take some some optional parameters for advanced scenarios (like <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">modular development</a>). You can take a look at the <a href="https://docs.abp.io/en/abp/latest/UI/Angular/Service-Proxies">documentation</a>.</p>
</blockquote>
<h4>The Generated Code</h4>
<p><code>src/app/proxy/books/book.service.ts</code>: This is the service that can be injected and used to get the list of books;</p>
<pre><code class="language-js">import type { BookDto } from './models';
import { RestService } from '@abp/ng.core';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class BookService {
  apiName = 'Default';

  getList = () =&gt;
    this.restService.request&lt;any, BookDto[]&gt;({
      method: 'GET',
      url: `/api/app/book`,
    },
    { apiName: this.apiName });

  constructor(private restService: RestService) {}
}
</code></pre>
<p><code>src/app/proxy/books/models.ts</code>: This file contains the modal classes corresponding to the DTOs defined in the server side;</p>
<pre><code class="language-js">import type { EntityDto } from '@abp/ng.core';

export interface BookDto extends EntityDto&lt;string&gt; {
  name: string;
  publishDate: string;
}
</code></pre>
<blockquote>
<p>There are a few more files have been generated to help you import the types easier.</p>
</blockquote>
<h4>How to Import</h4>
<p>You can now import the <code>BookService</code> into any Angular component and use the <code>getList()</code> method to get the list of books.</p>
<pre><code class="language-js">import { BookService, BookDto } from '../proxy/books';
</code></pre>
<p>You can also use the <code>@proxy</code> as a shortcut of the proxy folder:</p>
<pre><code class="language-js">import { BookService, BookDto } from '@proxy/books';
</code></pre>
<h3>About the Generated Code</h3>
<p>The generated code is;</p>
<ul>
<li><strong>Simple</strong>: It is almost identical to the code if you've written it yourself.</li>
<li><strong>Splitted</strong>: Instead of a single, large file;
<ul>
<li>It creates a separate <code>.ts</code> file for every backend <strong>service</strong>. <strong>Model</strong> (DTO) classes are also grouped per service.</li>
<li>It understands the <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">modularity</a>, so creates the services for your own <strong>module</strong> (or the module you've specified).</li>
</ul>
</li>
<li><strong>Object oriented</strong>;
<ul>
<li>Supports <strong>inheritance</strong> of server side DTOs and generates the code respecting to the inheritance structure.</li>
<li>Supports <strong>generic types</strong>.</li>
<li>Supports <strong>re-using type definitions</strong> across services and doesn't generate the same DTO multiple times.</li>
</ul>
</li>
<li><strong>Well-aligned to the backend</strong>;
<ul>
<li>Service <strong>method signatures</strong> match exactly with the services on the backend services. This is achieved by a special endpoint exposed by the ABP Framework that well defines the backend contracts.</li>
<li><strong>Namespaces</strong> are exactly matches to the backend services and DTOs.</li>
</ul>
</li>
<li><strong>Well-aligned with the ABP Framework</strong>;
<ul>
<li>Recognizes the <strong>standard ABP Framework DTO types</strong> (like <code>EntityDto</code>, <code>ListResultDto</code>... etc) and doesn't repeat these classes in the application code, but uses from the <code>@abp/ng.core</code> package.</li>
<li>Uses the <code>RestService</code> defined by the <code>@abp/ng.core</code> package which simplifies the generated code, keeps it short and re-uses all the logics implemented by the <code>RestService</code> (including error handling, authorization token injection, using multiple server endpoints... etc).</li>
</ul>
</li>
</ul>
<p>These are the main motivations behind the decision of creating a service proxy generation system, instead of using a pre-built tool like <a href="https://github.com/RicoSuter/NSwag">NSWAG</a>.</p>
<h2>Other Examples</h2>
<p>Let me show you a few more examples.</p>
<h3>Updating an Entity</h3>
<p>Assume that you added a new method to the server side application service, to update a book:</p>
<pre><code class="language-csharp">public Task&lt;BookDto&gt; UpdateAsync(Guid id, BookUpdateDto input);
</code></pre>
<p><code>BookUpdateDto</code> is a simple class defined shown below:</p>
<pre><code class="language-csharp">using System;

namespace AngularProxyDemo.Books
{
    public class BookUpdateDto
    {
        public string Name { get; set; }

        public DateTime PublishDate { get; set; }
    }
}
</code></pre>
<p>Let's re-run the <code>generate-proxy</code> command:</p>
<pre><code class="language-bash">abp generate-proxy
</code></pre>
<p>This command will re-generate the proxies by updating some files. Let's see some of the changes;</p>
<p><strong>book.service.ts</strong></p>
<pre><code class="language-js">import type { BookDto, BookUpdateDto } from './models';
import { RestService } from '@abp/ng.core';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class BookService {
  apiName = 'Default';

  getList = () =&gt;
    this.restService.request&lt;any, BookDto[]&gt;({
      method: 'GET',
      url: `/api/app/book`,
    },
    { apiName: this.apiName });

  update = (id: string, input: BookUpdateDto) =&gt;
    this.restService.request&lt;any, BookDto&gt;({
      method: 'PUT',
      url: `/api/app/book/${id}`,
      body: input,
    },
    { apiName: this.apiName });

  constructor(private restService: RestService) {}
}
</code></pre>
<p><code>update</code> function has been added to the <code>BookService</code> that gets an <code>id</code> and a <code>BookUpdateDto</code> as the parameters.</p>
<p><strong>models.ts</strong></p>
<pre><code class="language-js">import type { EntityDto } from '@abp/ng.core';

export interface BookDto extends EntityDto&lt;string&gt; {
  name: string;
  publishDate: string;
}

export interface BookUpdateDto {
  name: string;
  publishDate: string;
}
</code></pre>
<p>Added a new DTO class: <code>BookUpdateDto</code>.</p>
<h3>Advanced Example</h3>
<p>In this example, I want to show a DTO structure using inheritance, generics, arrays and dictionaries.</p>
<p>I've created an <code>IOrderAppService</code> as shown below:</p>
<pre><code class="language-csharp">using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace AngularProxyDemo.Orders
{
    public interface IOrderAppService : IApplicationService
    {
        public Task CreateAsync(OrderCreateDto input);
    }
}
</code></pre>
<p><code>OrderCreateDto</code> and the related DTOs are as the followings;</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using Volo.Abp.Data;

namespace AngularProxyDemo.Orders
{
    public class OrderCreateDto : IHasExtraProperties
    {
        public Guid CustomerId { get; set; }

        public DateTime CreationTime { get; set; }

        //ARRAY of DTOs
        public OrderDetailDto[] Details { get; set; }

        //DICTIONARY
        public Dictionary&lt;string, object&gt; ExtraProperties { get; set; }
    }
    
    public class OrderDetailDto : GenericDetailDto&lt;int&gt; //INHERIT from GENERIC
    {
        public string Note { get; set; }
    }
    
    //GENERIC class
    public abstract class GenericDetailDto&lt;TCount&gt;
    {
        public Guid ProductId { get; set; }

        public TCount Count { get; set; }
    }
}
</code></pre>
<p>When I run the <code>abp generate-proxy</code> command again, I see there are some created and updated files. Let's see some important ones;</p>
<p><code>src/app/proxy/orders/order.service.ts</code></p>
<pre><code class="language-js">import type { OrderCreateDto } from './models';
import { RestService } from '@abp/ng.core';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class OrderService {
  apiName = 'Default';

  create = (input: OrderCreateDto) =&gt;
    this.restService.request&lt;any, void&gt;({
      method: 'POST',
      url: `/api/app/order`,
      body: input,
    },
    { apiName: this.apiName });

  constructor(private restService: RestService) {}
}
</code></pre>
<p><code>src/app/proxy/orders/models.ts</code></p>
<pre><code class="language-js">export interface GenericDetailDto&lt;TCount&gt; {
  productId: string;
  count: TCount;
}

export interface OrderCreateDto {
  customerId: string;
  creationTime: string;
  details: OrderDetailDto[];
  extraProperties: Record&lt;string, object&gt;;
}

export interface OrderDetailDto extends GenericDetailDto&lt;number&gt; {
  note: string;
}
</code></pre>
<h2>Conclusion</h2>
<p><code>abp generate-proxy</code> is a very handy command that creates all the necessary code to consume your ABP based backend HTTP APIs. It generates a clean code that is well aligned to the backend services and benefits from the power of TypeScript (by using generics, inheritance...).</p>
<h2>The Documentation</h2>
<p>See <a href="https://docs.abp.io/en/abp/latest/UI/Angular/Service-Proxies">the documentation</a> for details of the Angular Service Proxy Generation.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/cbd91f71-17d3-0644-2a1d-39f779dbcb32" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/cbd91f71-17d3-0644-2a1d-39f779dbcb32" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-v3.1-final-has-been-released-7pf6cavh</guid>
      <link>https://abp.io/community/posts/abp-framework-v3.1-final-has-been-released-7pf6cavh</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework v3.1 Final Has Been Released</title>
      <description>Released ABP v3.1 final. Some new features: Angular Service Proxies, Authorization Code Flow for the Angular UI, Global Feature System etc. Learn more about what's new with v3.1 final release.</description>
      <pubDate>Fri, 04 Sep 2020 07:32:43 Z</pubDate>
      <a10:updated>2026-10-02T15:49:03Z</a10:updated>
      <content:encoded><![CDATA[<h1>ABP Framework 3.1 Final Has Been Released</h1>
<p>It is exciting for us to announce that we've released the ABP Framework &amp; ABP Commercial 3.1 today.</p>
<p>Since all the new features are already explained in details with the <a href="https://blog.abp.io/abp/ABP-Framework-v3.1-RC-Has-Been-Released">3.1 RC Announcement Post</a>, I will not repeat all the details here. Please read <a href="https://blog.abp.io/abp/ABP-Framework-v3.1-RC-Has-Been-Released">the RC post</a> for <strong>new feature and changes</strong> you may need to do for your solution while upgrading to the version 3.1.</p>
<h2>Creating New Solutions</h2>
<p>You can create a new solution with the ABP Framework version 3.1 by either using the <code>abp new</code> command or using the <strong>direct download</strong> tab on the <a href="https://abp.io/get-started">get started page</a>.</p>
<blockquote>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Getting-Started">getting started document</a> for details.</p>
</blockquote>
<h2>How to Upgrade an Existing Solution</h2>
<h3>Install/Update the ABP CLI</h3>
<p>First of all, install the ABP CLI or upgrade to the latest version.</p>
<p>If you haven't installed yet:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli
</code></pre>
<p>To update an existing installation:</p>
<pre><code class="language-bash">dotnet tool update -g Volo.Abp.Cli
</code></pre>
<h3>ABP UPDATE Command</h3>
<p><a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:</p>
<pre><code class="language-bash">abp update
</code></pre>
<p>After the update command, check <a href="https://blog.abp.io/abp/ABP-Framework-v3.1-RC-Has-Been-Released">the RC blog post</a> to learn if you need to make any changes in your solution.</p>
<blockquote>
<p>You may want to see the new <a href="https://docs.abp.io/en/abp/latest/Upgrading">upgrading document</a>.</p>
</blockquote>
<h2>About the version 3.2</h2>
<p>The planned schedule for the version 3.2 is like that;</p>
<ul>
<li><strong>September 17, 2020</strong>: 3.2.0-rc.1 (release candidate)</li>
<li><strong>October 1, 2020</strong>: 3.2.0 final (stable)</li>
</ul>
<p>You can check <a href="https://github.com/abpframework/abp/milestone/39">the GitHub milestone</a> to see the features/issues we are working on.</p>
<h2>ABP Community &amp; Articles</h2>
<p>We had lunched the <a href="https://community.abp.io/">ABP Community web site</a> a few weeks before. The core ABP team and the ABP community have started to create content for the community.</p>
<p>Here, the last three articles from the ABP Community:</p>
<ul>
<li><a href="https://community.abp.io/articles/abp-suite-how-to-add-the-user-entity-as-a-navigation-property-of-another-entity-furp75ex">ABP Suite: How to Add the User Entity as a Navigation Property of Another Entity</a> by <a href="https://github.com/ebicoglu">@ebicoglu</a></li>
<li><a href="https://community.abp.io/articles/reuse-abp-vnext-modules-to-quickly-implement-application-features-tdtmwd9w">Reuse ABP vNext Modules to Quickly Implement Application Features</a> by <a href="https://github.com/gdlcf88">@gdlcf88</a></li>
<li><a href="https://community.abp.io/articles/using-devextreme-components-with-the-abp-framework-zb8z7yqv">Using DevExtreme Components With the ABP Framework</a> by <a href="https://github.com/cotur">@cotur</a>.</li>
</ul>
<p>We are looking for your contributions; You can <a href="https://community.abp.io/articles/submit">submit your article</a>! We will promote your article to the community.</p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/8b3a47fa-6738-bc53-3fd5-39f76a34fdf2" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/8b3a47fa-6738-bc53-3fd5-39f76a34fdf2" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-v3.1-rc-has-been-released-xr24ygcz</guid>
      <link>https://abp.io/community/posts/abp-framework-v3.1-rc-has-been-released-xr24ygcz</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework v3.1 RC Has Been Released</title>
      <description>Released ABP v3.1 RC. Some new features: Angular Service Proxies, Authorization Code Flow for the Angular UI, Global Feature System etc. Learn more about what's new with v3.1 RC release.</description>
      <pubDate>Tue, 25 Aug 2020 07:27:34 Z</pubDate>
      <a10:updated>2026-10-02T18:21:25Z</a10:updated>
      <content:encoded><![CDATA[<p>Today, we are releasing the <strong>ABP Framework version 3.1 Release Candidate</strong> (RC). The development cycle for this version was <strong>~7 weeks</strong>. It was the longest development cycle for a feature version release ever. We have completed <strong>~150 issues</strong>, merged <strong>~150 PRs</strong> and made <strong>~1,000 commits</strong> only in the main <a href="https://github.com/abpframework/abp">abp repository</a>. See the related <a href="https://github.com/abpframework/abp/milestone/38?closed=1">milestone</a> on GitHub.</p>
<p>There were two main reasons of this long development cycle;</p>
<ul>
<li>We've switched to <strong>4-weeks</strong> release cycle (was discussed in <a href="https://github.com/abpframework/abp/issues/4692">this issue</a>).</li>
<li>We've <a href="https://github.com/abpframework/abp/issues/4881">re-written</a> the Angular service proxy generation system using the Angular schematics to make it more stable. There were some problems with the previous implementation.</li>
</ul>
<p>This long development cycle brings a lot of new features, improvements and bug fixes. I will highlight the fundamental features and changes in this blog post.</p>
<blockquote>
<p><code>3.1.0</code> final stable version has been published. See <a href="https://blog.abp.io/abp/ABP-Framework-v3.1-Final-Has-Been-Released">this post</a> for details.</p>
</blockquote>
<h2>About the Preview/Stable Version Cycle</h2>
<p>As mentioned above, it is planned to release a new stable feature version (like 3.1, 3.2, 3.3...) in every 4-weeks.</p>
<p>In addition, we are starting to deploy a <strong>preview version</strong> 2-weeks before the stable versions for every feature/major releases.</p>
<p>Today, we've released <code>3.1.0-rc.1</code> as the first preview version. We may release more previews if it is needed until the stable 3.1.0 version.</p>
<p><strong>The stable <code>3.1.0</code> version will be released on September 3, 2020.</strong> Next RC version, <code>3.2.0-rc.1</code>, is planned for September 17, 2020 (2 weeks after the stable 3.1.0 and 2 weeks before the stable 3.2.0).</p>
<p>We <strong>won't add new features</strong> to a version after publishing the preview version. We only will make <strong>bug fixes</strong> until the stable version. The new features being developed in this period will be available in the next version.</p>
<blockquote>
<p>We will use <code>-rc.x</code> suffix (like <code>3.1.0-rc.1</code> and <code>3.1.0-rc.2</code>) for preview releases. However, we may also publish with <code>-preview.x</code> suffix before RC (Release Candidate) releases, especially for major versions (like 4.0, 5.0...).</p>
</blockquote>
<h3>About the Nightly Builds</h3>
<p>Don't confuse preview versions vs nightly builds. When we say preview, we are mentioning the preview system explained above.</p>
<p>We will continue to publish <strong>nightly builds</strong> for all the <a href="https://abp.io/packages">ABP Framework packages</a>. Nightly pages are built from the development branch. You can refer to <a href="https://docs.abp.io/en/abp/latest/Nightly-Builds">this document</a> to learn how to use the nightly packages.</p>
<h2>Get Started with the RC Versions</h2>
<p>Please try the preview versions and provide feedback to us to release more stable versions. Please open an  issue on the <a href="https://github.com/abpframework/abp/issues/new">GitHub repository</a> if you find a bug or want to give feedback.</p>
<h3>Update the ABP CLI to the 3.1.0-rc.4</h3>
<p>Since this is the first preview version, you need to upgrade the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> to the <code>3.1.0-rc.4</code> to be able to use the preview features:</p>
<pre><code class="language-bash">dotnet tool update Volo.Abp.Cli -g --version 3.1.0-rc.4
</code></pre>
<h3>New Solutions</h3>
<p>The <a href="https://abp.io/">ABP.IO</a> platform and the <a href="https://docs.abp.io/en/abp/latest/CLI">ABP CLI</a> are compatible with the RC system. You can select the &quot;preview&quot; option on the <a href="https://abp.io/get-started">download page</a> or use the &quot;<strong>--preview</strong>&quot; parameter with the ABP CLI <a href="https://docs.abp.io/en/abp/latest/CLI?_ga=2.106435654.411298747.1597771169-1910388957.1594128976#new">new</a> command:</p>
<pre><code class="language-bash">abp new Acme.BookStore --preview
</code></pre>
<p>This command will create a new project with the latest RC/Preview version. Whenever the stable version is released, you can switch to the stable version for your solution using the <code>abp switch-to-stable</code> command in the root folder of your solution.</p>
<h3>Existing Solutions</h3>
<p>If you already have a solution and want to use/test the latest RC/Preview version, use the <code>abp switch-to-preview</code> command in the root folder of your solution. You can return back to the latest stable using the <code>abp switch-to-stable </code> command later.</p>
<blockquote>
<p>Note that the <code>abp switch-to-preview</code> command was being used to switch to nightly builds before the v3.1. Now, you should use the <code>abp switch-to-nightly</code> for <a href="https://docs.abp.io/en/abp/latest/Nightly-Builds">nightly builds</a>.</p>
</blockquote>
<h2>Breaking Changes / Special Notes</h2>
<h3>ABP &amp; ABP Commercial</h3>
<ul>
<li>You may need to upgrade the <code>Microsoft.Extensions.FileProviders.Embedded</code> package in your projects to <code>3.1.6</code> or a later version.</li>
<li>If you are using <strong>EF Core</strong>, you may need to <strong>add a new migration</strong> after upgrading the packages. Just run the standard &quot;Add-Migration&quot; command, check the generated migration code and execute the &quot;Update-Database&quot; command to apply changes to the database.</li>
<li>If you have implemented <strong>social/external logins</strong> for your MVC / Razor Page UI application before, you may want to check <a href="https://github.com/abpframework/abp/issues/4981">this issue</a>. We made some improvements and changes that you may want to take action for your application. Beginning from v3.1, the users created their accounts via social login can still set a local password to login with local username/email &amp; password.</li>
<li>See the &quot;Angular Service Proxies&quot; section below for the Angular applications.</li>
</ul>
<h3>ABP Commercial Only</h3>
<ul>
<li>We've <strong>moved favicons</strong> into <code>/wwwroot/images/favicon/</code> folder for the ASP.NET Core <strong>MVC / Razor Page UI</strong> applications. There are 10 favicon related files (including the <code>favicon.ico</code>) under this directory to better work with different browser and cases. You can create a new application to check this folder and copy the files into your own application. Then you can customize the icons for your own brand (hint: you can use a tool <a href="https://realfavicongenerator.net/">like that</a> to create the favicons with various formats).</li>
<li>Removed direct <strong>Twitter &amp; Facebook social login integrations</strong> from the <a href="https://commercial.abp.io/modules/Volo.Account.Pro">account module</a>, for <strong>MVC / Razor Pages UI</strong>. Follow <a href="https://github.com/abpframework/abp/blob/dev/docs/en/Authentication/Social-External-Logins.md">this documentation</a> to easily add social logins to your applications if you need. The account module provides all the infrastructure to handle social/external logins, you just need to configure it.</li>
</ul>
<h2>What's New with the ABP Framework 3.1 RC</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/abp-framework-release-v3.1.png" alt="abp-framework-release-v3.1" /></p>
<h3>Angular Service Proxies</h3>
<p>ABP provides a system to generate Angular service proxies (with TypeScript) to consume the HTTP APIs of your application. Service proxy generation system <strong>has been completely re-written</strong> with the ABP Framework 3.1. The main goal was to build more stable and feature rich system that is better aligned with other ABP Framework features (like <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">modularity</a>).</p>
<p>You will continue to use the same <code>abp generate-proxy</code> command, however it internally uses an NPM package that implements the command using the Angular schematics. It will come pre-configured for new solutions. However, implement the following steps for existing solutions;</p>
<ul>
<li>Add <code>@abp/ng.schematics</code> package to the devDependencies of the Angular project.</li>
<li>Add <code>rootNamespace</code> entry into the <code>/apis/default/</code> section in the <code>/src/environments/environment.ts</code>, as shown below:</li>
</ul>
<pre><code class="language-json">apis: {
  default: {
    url: 'https://localhost:44360',
    rootNamespace: 'Acme.BookStore' //&lt;-- ADD THIS
  },    
}
</code></pre>
<p><code>Acme.BookStore</code> should be replaced by the root namespace of your .NET project. This ensures to not create unnecessary nested folders.</p>
<ul>
<li>Finally, add the following paths to the <code>tsconfig.base.json</code> to have a shortcut while importing proxies:</li>
</ul>
<pre><code class="language-json">&quot;paths&quot;: {
    &quot;@proxy&quot;: [&quot;src/app/proxy/index.ts&quot;],
    &quot;@proxy/*&quot;: [&quot;src/app/proxy/*&quot;]
}
</code></pre>
<p><a href="https://docs.abp.io/en/abp/3.1/UI/Angular/Service-Proxies">See the documentation</a> to learn more about the service proxy generation for Angular applications.</p>
<blockquote>
<p>The <a href="https://docs.abp.io/en/abp/3.1/Tutorials/Part-1?UI=NG">application development tutorial</a> has been updated based on the new Angular Service proxy system.</p>
</blockquote>
<h3>Authorization Code Flow for the Angular UI</h3>
<p>We were using the <strong>resource owner password authentication</strong> flow for the Angular UI login page. We've implemented <strong>Authorization Code Flow</strong> for the Angular account module and made it <strong>default for new projects</strong>. With this change, the Angular application now redirects to the login page of the MVC UI which was implemented using the Identity Server 4. We also removed the client secret from the Angular side with this change.</p>
<p>Old behavior remains exist. If you want to switch to the new flow (which is recommended), follow the steps below:</p>
<ol>
<li><p>Add <code>authorization_code</code> to the <code>IdentityServerClientGrantTypes</code> table in the database, for the client used by the Angular UI (the <code>ClientId</code> is <code>YourProjectName_App</code> by default, in the <code>IdentityServerClients</code> table).</p>
</li>
<li><p>Add <code>http://localhost:4200</code> to <code>IdentityServerClientRedirectUris</code> and <code>IdentityServerClientPostLogoutRedirectUris</code> tables for the same client.</p>
</li>
<li><p>Set <code>RequireClientSecret</code> to <code>false</code> in the <code>IdentityServerClients</code> table for the same client.</p>
</li>
</ol>
<blockquote>
<p><a href="https://commercial.abp.io/">ABP Commercial</a> users can make these changes on the <a href="https://commercial.abp.io/modules/Volo.Identityserver.Ui">Identity Server Management UI</a>.</p>
</blockquote>
<ol start="4">
<li>Change the <code>oAuthConfig</code> section in the <code>src/environments/environment.ts</code> file of the Angular application.</li>
</ol>
<p>You can take <a href="https://gist.github.com/hikalkan/e7f6ae7f507b201783682dccaeadc5e3">this new configuration</a> as a reference. Main changes are;</p>
<ul>
<li>Added <code>responseType</code> as <code>code</code>.</li>
<li>Added <code>redirectUri</code></li>
<li>Added <code>offline_access</code> to the <code>scope</code>.</li>
<li>Removed <code>oidc: false</code> option.</li>
<li>Removed the client secret option.</li>
</ul>
<h3>Global Feature System</h3>
<p>The new &quot;Global Features&quot; system allows to <strong>enable/disable features of an application or a module</strong> in a central point. It is especially useful if you want to use a module but don't want to bring all its features into your application. If the module was so designed, you can enable only the features you need.</p>
<p>When you disable a feature;</p>
<ul>
<li>The <strong>database tables</strong> related to that feature should not be created in the database.</li>
<li>The <strong>HTTP APIs</strong> related to that feature should not be exposed. They returns 404 if they are directly requested.</li>
</ul>
<p>So, the goal is that; when you disable a feature, it should behave like that feature doesn't exists in your system at all.</p>
<p>There is <strong>no way to enable/disable a global feature on runtime</strong>. You should decide it in the development time (remember, even database tables are not being created for disabled global features, so you can't enable it on runtime).</p>
<blockquote>
<p>&quot;Global Features&quot; system is different than <a href="https://docs.abp.io/en/abp/latest/Features">SaaS/multi-tenancy features</a>, where you can enable/disable features for your tenants on runtime.</p>
</blockquote>
<p>Assume that you are using the <a href="https://github.com/abpframework/abp/tree/dev/modules/cms-kit">CMS Kit module</a> (this module is in a very early stage) where you only want to enable the comment feature:</p>
<pre><code class="language-csharp">GlobalFeatureManager.Instance.Modules.CmsKit().Comments.Enable();
</code></pre>
<p>You can check if a feature was enabled:</p>
<pre><code class="language-csharp">GlobalFeatureManager.Instance.IsEnabled&lt;CommentsFeature&gt;();
</code></pre>
<p>Or you can add <code>[RequiresGlobalFeature(...)]</code> attribute to a controller/page to disable it if the related feature was disabled:</p>
<pre><code class="language-csharp">//...
[RequiresGlobalFeature(typeof(CommentsFeature))]
public class CommentController :  AbpController
{
    //...
}
</code></pre>
<p>See the issue <a href="https://github.com/abpframework/abp/issues/5061">#5061</a> until this is fully documented.</p>
<h3>Social/External Logins</h3>
<p>Implemented the infrastructure for social/external logins in the account module. So, now you can easily configure your application to support social/external logins by <a href="https://github.com/abpframework/abp/blob/dev/docs/en/Authentication/Social-External-Logins.md">following the documentation</a>. Once you configure a provider, a button will appear on the login page to use this provider.</p>
<p>The social logins will work as expected even if you are using the Angular UI, since the Angular UI uses the MVC login using the authorization code flow implemented with this new version (as explained above).</p>
<h3>Forgot/Reset Password</h3>
<p>Implemented forgot password / password reset for the account module.</p>
<p>You can now enter your email address to get an email containing a <strong>password reset link</strong>:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/forgot-password.png" alt="forgot-password" /></p>
<p>When you click to the link, you are redirected to a password reset page to determine your new password:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/reset-password.png" alt="reset-password" /></p>
<h3>External Login System</h3>
<p>The standard Social/External Login system (like Facebook login) works via OpenID Connect. That means the user is redirected to the login provider, logins there and redirected to your application.</p>
<p>While this is pretty nice for most scenarios, sometimes you want a simpler external login mechanism: User enters username &amp; password in your own application's login form and you check the username &amp; password from another source, not from your own database.</p>
<p>ABP v3.1 introduces an External Login System to check username &amp; password from any source (from an external database, a REST service or from an LDAP / Active Directory server).</p>
<p>You can check the <a href="https://github.com/abpframework/abp/issues/4977#issuecomment-670006297">issue #4977</a> until it is fully documented.</p>
<p>We've implemented LDAP authentication for the ABP Commercial, using this new login extension system (see the ABP Commercial section below).</p>
<h3>User Security Logs</h3>
<p>The new <a href="https://github.com/abpframework/abp/issues/4492">Security Log System</a> (of the Identity module) automatically logs all authentication related operations (login, logout, change password...) to a <code>AbpSecurityLogs</code> table in the database.</p>
<h3>New BLOB Storage Providers</h3>
<p>Implemented <a href="https://github.com/abpframework/abp/blob/dev/docs/en/Blob-Storing-Aws.md">AWS</a> and <a href="https://github.com/abpframework/abp/blob/dev/docs/en/Blob-Storing-Aliyun.md">Aliyun</a> providers for the <a href="https://docs.abp.io/en/abp/latest/Blob-Storing">BLOB storing</a> system with this version.</p>
<h3>Module Entity Extensibility</h3>
<p>We had introduced a entity extension system that allows to add new properties to existing entities of depended modules by a simple configuration. When you add a new property, it appears on the create, edit and list views on the UI and created a new field in the related database table. We've implemented this system for the identity and tenant management modules, so you can extend entities of these modules. See <a href="https://github.com/abpframework/abp/blob/dev/docs/en/Module-Entity-Extensions.md">the documentation</a>.</p>
<h3>Other Features / Highlights</h3>
<p>Here, some other highlights from this release;</p>
<ul>
<li>UOW level caching system <a href="https://github.com/abpframework/abp/issues/4796">#4796</a></li>
<li>Refactored the console application template to better integrate to the host builder <a href="https://github.com/abpframework/abp/issues/5006">#5006</a></li>
<li><a href="https://www.nuget.org/packages/Volo.Abp.Ldap">Volo.Abp.Ldap</a> package now supports multi-tenancy.</li>
<li>Introduce <code>BasicAggregateRoot</code> base class <a href="https://github.com/abpframework/abp/issues/4808">#4808</a></li>
<li>Sets GUID Id in the <code>InsertAsync</code> method of the EF Core repository if it was not set by the developer <a href="https://github.com/abpframework/abp/pull/4634">#4634</a></li>
<li>Added <code>GetPagedListAsync</code> methods to the repository to simplify paging <a href="https://github.com/abpframework/abp/pull/4617">#4617</a></li>
<li>Configured <a href="https://prettier.io/">Prettier</a> for the startup template <a href="https://github.com/abpframework/abp/issues/4318">#4318</a></li>
<li>Defined new layout hooks for the MVC UI: before page content &amp; after page content <a href="https://github.com/abpframework/abp/issues/4008">#4008</a></li>
<li>Allow to put static resources (js, css... files) under the Components folder for ASP.NET Core MVC UI.</li>
<li>Upgraded to AutoMapper 10 and Quartz 3.1 for the related integration packages.</li>
</ul>
<h2>What's New with the ABP Commercial v3.1 RC</h2>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/abp-comm-release-v3.1.png" alt="abp-comm-release-v3.1" /></p>
<h3>Security Logs UI</h3>
<p>We've created a UI to report user security logs for authentication related operations, under the Identity Management menu:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/security-logs-ui.png" alt="security-logs-ui" /></p>
<p>Also, every user can see his/her own security logs by selecting the &quot;My security logs&quot; under the user menu:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/my-security-logs.png" alt="my-security-logs" /></p>
<h3>LDAP Authentication</h3>
<p>We've implemented LDAP authentication using the new external login system explained above. Also, created a UI to configure the server settings:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/ldap-settings-ui.png" alt="ldap-settings-ui" /></p>
<p>In this way, you can simply check passwords of the users from LDAP in the login page. If given username / password doesn't exists on LDAP, then it fallbacks to the local database, just like before.</p>
<p>Since it supports <strong>multi-tenancy</strong>, you can enable, disable and configure it for your tenants.</p>
<h3>Email / Phone Number Verification</h3>
<p>User profile management page now supports to Email &amp; Phone Number verification flow:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/email-phone-verification.png" alt="email-phone-verification" /></p>
<p>When user clicks to the <strong>verify</strong> button, a verification email/SMS (that has a verification code) sent to the user and the UI waits to submit this code.</p>
<h3>User Lock</h3>
<p>Implemented to <strong>lock a user</strong> for a given period of time. Locked users can not login to the application for the given period of time:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-08-25-abp-framework-v31-rc-has-been-released/user-lock.png" alt="user-lock" /></p>
<h3>ABP Suite: Angular UI Code Generation Revisited</h3>
<p>Angular UI code generation has been re-written using the Angular Schematics for the ABP Suite. It is now more stable and produces a better application code.</p>
<p>ABP Suite also supports code generation on module development.</p>
<h3>Others</h3>
<ul>
<li><strong>Social logins</strong> and <strong>authorization code flow</strong> are also implemented for the ABP Commercial, just as described above.</li>
<li>Added breadcrumb and file icons for the <strong>file management module</strong>.</li>
</ul>
<h2>The ABP Community</h2>
<p>We've lunched the <a href="https://community.abp.io/">community.abp.io</a> ~two weeks ago with its initial version. It only has &quot;Article submission&quot; system for now. We are developing new exciting features. There will be an update in a few days and we'll publish a new blog post for it.</p>
<h2>Conclusion</h2>
<p>The main goals of the 3.1 version were;</p>
<ul>
<li>Complete the missing <strong>authentication features</strong> (like social logins, LDAP authentication, authorization code flow for the Angular UI...) for the ABP Framework &amp; ABP Commercial.</li>
<li>Re-write a stable and feature complete <strong>Angular service proxy generation</strong> system for the ABP Framework and CRUD UI generation system for the ABP Commercial.</li>
<li>Develop a system to lunch <strong>preview versions</strong> of the platform. <code>3.1.0-rc.1</code> was the first preview version that has been published with this new system.</li>
<li>Complete the fundamental <strong>documentation &amp; tutorials</strong> (we've even created a <a href="https://www.youtube.com/watch?v=cJzyIFfAlp8&amp;list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ">video tutorial series</a>).</li>
</ul>
<p>ABP.IO platform will be more mature &amp; stable with the v3.1. Enjoy Coding!</p>
<p> </p>
<h2>Bonus: Articles!</h2>
<p>Beside developing our products, our team are constantly writing articles/tutorials on various topics. You may want to check the latest articles:</p>
<ul>
<li><a href="https://volosoft.com/blog/ASPNET-CORE-3.1-Social-Login-and-Multi-Tenancy">ASP.NET CORE 3.1 Social Login and Multi-Tenancy</a></li>
<li><a href="https://volosoft.com/blog/File-Upload-Download-with-BLOB-Storage-in-ASP.NET-Core-and-ABP">File Upload/Download with BLOB Storage System in ASP.NET Core &amp; ABP Framework</a></li>
<li><a href="https://volosoft.com/blog/Extracting-and-Hashing-Lazy-Loaded-CSS-in-Angular">Extracting and Hashing Lazy-Loaded CSS in Angular</a></li>
</ul>
<p> </p>
<blockquote>
<p>We’d love to hear from you. Please leave your comments, suggestions, feeedbacks below.</p>
</blockquote>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/66986c4e-e99a-6c81-330f-39f736b0b143" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/66986c4e-e99a-6c81-330f-39f736b0b143" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-v3.0-has-been-released-mvxmv0sp</guid>
      <link>https://abp.io/community/posts/abp-framework-v3.0-has-been-released-mvxmv0sp</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework v3.0 Has Been Released</title>
      <description>Released ABP v3.0. Some new features: Angular 10, The Oracle Integration Package, Azure BLOB Storage Provider etc. Learn more about what's new with v3.0 release.</description>
      <pubDate>Fri, 03 Jul 2020 06:12:54 Z</pubDate>
      <a10:updated>2026-10-02T12:11:58Z</a10:updated>
      <content:encoded><![CDATA[<p>We are excited to announce that the <strong>ABP Framework</strong> &amp; and the <strong>ABP Commercial</strong> version 3.0 have been released. As different than the regular release lifecycle, which is 2-weeks, this version has taken 4-weeks with <strong>119 <a href="https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3A3.0">issues</a></strong> closed, <strong>89 <a href="https://github.com/abpframework/abp/pulls?q=is%3Aopen+is%3Apr+milestone%3A3.0">pull requests</a></strong> merged and <strong>798 commits</strong> done in the main framework <a href="https://github.com/abpframework/abp">repository</a>.</p>
<p>Since this is a <strong>major version</strong>, it also includes some <strong>breaking changes</strong>. Don't panic, the changes are easy to adapt and will be explained below.</p>
<blockquote>
<p>See the <a href="https://github.com/abpframework/abp/releases">GitHub release notes</a> for a detailed change log.</p>
</blockquote>
<h2>What's New with the ABP Framework 3.0?</h2>
<p>This post will only cover the important features/changes. You can see all the changes on the <a href="https://github.com/abpframework/abp/releases/tag/3.0.0">GitHub release notes</a>.</p>
<h3>Angular 10!</h3>
<p>Angular version 10 has just been <a href="https://blog.angular.io/version-10-of-angular-now-available-78960babd41">released</a> and we've immediately migrated the <a href="https://docs.abp.io/en/abp/latest/Startup-Templates/Application">startup templates</a> to Angular 10! So, when you <a href="https://abp.io/get-started">create a new solution</a> with the Angular UI, you will take the advantage of the new Angular.</p>
<p>We've prepared a <a href="https://github.com/abpframework/abp/blob/dev/docs/en/UI/Angular/Migration-Guide-v3.md">migration guide</a> for the projects created an older version and want to migrate to Angular 10.</p>
<h3>The Oracle Integration Package</h3>
<p>We had created <a href="https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart">an integration package</a> for the Oracle for EF Core based applications using the Devart's library since the official Oracle EF Core package was not supporting the EF Core 3.1. It now supports as a <a href="https://www.nuget.org/packages/Oracle.EntityFrameworkCore/3.19.0-beta1">beta release</a>. While it is in beta, we've created <a href="https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle">the integration package</a>, so you can use it in your application.</p>
<p>See <a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Oracle">the documentation</a> for details.</p>
<h3>Azure BLOB Storage Provider</h3>
<p>We had created a <a href="https://docs.abp.io/en/abp/latest/Blob-Storing">BLOB storing system</a> in the previous version with a file system and database storage provider. This release introduces the Azure BLOB Storage provider. See <a href="https://docs.abp.io/en/abp/latest/Blob-Storing-Azure">the documentation</a>.</p>
<h3>Distributed Cache Bulk Operations &amp; the New Redis Cache Package</h3>
<p>The <a href="https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed">standard IDistributeCache</a> interface of the ASP.NET Core doesn't contain <strong>bulk operations</strong>, like setting multiple items with a single method/server call. ABP Framework introduces new methods those can be used for bulk operations on the ABP's <code>IDistributedCache&lt;T&gt;</code> interface:</p>
<ul>
<li>GetManyAsync / GetMany</li>
<li>SetManyAsync / SetMany</li>
</ul>
<p>Then we needed to implement these new methods for Redis cache and <a href="https://github.com/abpframework/abp/issues/4483">had to create</a> a Redis integration package which extends the Microsoft's implementation.</p>
<p>These methods are also used by the ABP Framework to cache settings, features and permissions for a user/role/tenant and brings a <strong>significant performance improvement</strong>.</p>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Caching">caching document</a> for details.</p>
<h3>Embedded Files Manifest Support for the Virtual File System</h3>
<p>Virtual File System now supports to use <code>GenerateEmbeddedFilesManifest</code> in your projects to add the <strong>real file/directory structure</strong> of your embedded resources in the compiled assembly. So, you can now access to the files without any file name restriction (previously, some special chars like <code>.</code> in the directory names was a problem in some cases)</p>
<p>See <a href="https://docs.abp.io/en/abp/latest/Virtual-File-System">the documentation</a> to learn how to take the advantage of new system.</p>
<h3>New Samples</h3>
<p>Based on the requests from the community, we've prepared two new sample applications:</p>
<ul>
<li><a href="https://github.com/abpframework/abp-samples/tree/master/StoredProcedureDemo">StoredProcedureDemo</a> demonstrates how to call stored procedures, views and functions inside a custom repository.</li>
<li><a href="https://github.com/abpframework/abp-samples/tree/master/OrganizationUnitSample">OrganizationUnitSample</a> shows how to use the organization unit system of the <a href="https://docs.abp.io/en/abp/latest/Modules/Identity">Identity module</a> for your entities.</li>
</ul>
<h3>DynamicStringLength &amp; DynamicMaxLength Attributes</h3>
<p>The standard <code>StringLength</code> and <code>MaxLength</code> data annotation attributes is useful to validate properties of a class when the class is used as a Model or <a href="https://docs.abp.io/en/abp/latest/Data-Transfer-Objects">DTO</a>. However, just like any other attribute, the length values should be literal (constant) values known at <strong>compile time</strong>.</p>
<p><strong>Example: Using the <code>StringLength</code></strong></p>
<pre><code class="language-csharp">public class CreateBookDto
{
    public const int MaxNameLength = 128; //CONSTANT!
    
    [StringLength(MaxNameLength)]
    public string Name { get; set; }
}
</code></pre>
<p>ABP Framework now has the <code>DynamicStringLength</code> &amp; <code>DynamicMaxLength</code> properties to allow to determine the lengths at <strong>runtime</strong>.</p>
<p><strong>Example: Using the <code>DynamicStringLength</code></strong></p>
<pre><code class="language-csharp">public class CreateBookDto
{
    public static int MaxNameLength { get; set; } = 128;
    
    [DynamicStringLength(typeof(CreateBookDto), nameof(MaxNameLength))]
    public string Name { get; set; }
}
</code></pre>
<p><code>DynamicStringLength</code> gets a class <strong>type</strong> and the <strong>name</strong> of a static property on this class to read the max length (there is also a minimum length option just like the <code>StringLength</code>).</p>
<p>This allows you to get the max value from a configuration and set on the application startup (generally, in the <code>PreConfigureServices</code> method of your <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">module</a>):</p>
<pre><code class="language-csharp">CreateBookDto.MaxNameLength = 200;
</code></pre>
<p>This feature is used by the <a href="https://docs.abp.io/en/abp/latest/Modules/Index">pre-built application modules</a>, so you can now override the max lengths of the properties defined in these modules.</p>
<h3>Auto Distributed Events</h3>
<p>ABP can <strong>automatically publish distributed events</strong> for all entities on their create, update and delete events. That's pretty useful since you commonly interest in these basic events in a distributed system.</p>
<p>This feature is <strong>mature and <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus#pre-defined-events">documented</a></strong> with the v3.0. You can easily configure some or all the entities to be published.</p>
<h3>IAsyncQueryableExecuter</h3>
<p>When you work with LINQ extension methods, you need to call <code>ToListAsync()</code>, <code>FirstOrDefaultAsync()</code>... methods on your queries. Unfortunately, these methods are <strong>not standard</strong> LINQ extension methods. They are defined in the <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore">Microsoft.EntityFrameworkCore</a> package (or in the <a href="https://www.nuget.org/packages/MongoDB.Driver/">MongoDB.Driver</a> package if you are using the MongoDB).</p>
<p>So, you need to depend on this package if you want to use the async extension methods. That breaks the layering and makes your application or domain layer depends on the EF Core / MongoDB package.</p>
<p><code>IAsyncQueryableExecuter</code> is a service defined by the ABP Framework to <strong>execute queries asynchronously without depending the specific provider</strong> (EF Core / MongoDB) package.</p>
<p>See <a href="https://docs.abp.io/en/abp/latest/Repositories#iqueryable-async-operations">the documentation</a> to read the details and learn our recommendations.</p>
<h3>API documentation</h3>
<p>We are now publishing <a href="https://docs.abp.io/api-docs/abp/3.0/api/index.html">API documents</a> for the ABP Framework and modules in every release. So, you can explore the ABP Framework classes much more easier than before. Click the the <strong>API Documentation</strong> link on the navigation menu of the <a href="https://docs.abp.io/en/abp/latest/">documentation</a>.</p>
<h3>Package List</h3>
<p>We have <a href="http://abp.io/packages">created a page</a> to list all the ABP-related official NuGet and NPM packages.</p>
<h3>Others</h3>
<ul>
<li>Implemented front-channel server-side clients <a href="https://identityserver4.readthedocs.io/en/latest/topics/signout.html">sign out</a> for the identity server.</li>
<li><code>abp.currentUser</code> (<code>CurrentUser</code> service in the Angular UI) now has a <code>roles</code> array that contains role names of the current user.</li>
<li>Upgraded all the NuGet and NPM package dependencies.</li>
<li>Introduced <code>ReadOnlyAppService</code> base class (which has only the get operations) in addition to the <code>CrudAppService</code> base class (which has get, create, update and delete operations).</li>
</ul>
<p>See the <a href="https://github.com/abpframework/abp/releases/tag/3.0.0">GitHub release notes</a> for others updates.</p>
<h2>What's New with the ABP Commercial 3.0?</h2>
<p>In addition to all the features coming with the ABP Framework, the ABP Commercial has additional features with this release, as always. This section covers the <a href="https://commercial.abp.io/">ABP Commercial</a> highlights in the version 3.0.</p>
<h3>New File Management Module</h3>
<p>We've created a new module that is used to store and manage files in your application. This new module is based on the <a href="https://docs.abp.io/en/abp/latest/Blob-Storing">BLOB Storing system</a>, so it can use different storage providers to store the file contents.</p>
<p><strong>Example screenshot</strong></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-07-03-abp-framework-v30-has-been-released/file-management-ui.png" alt="file-management-ui" /></p>
<p>You can upload, download and organize files in a hierarchical folder structure. It is also compatible to multi-tenancy and you can determine total size limit for your tenants. In the next versions, we will be working on a &quot;share&quot; system to share files between users in a more controlled way or share your files with your customers with a public link.</p>
<blockquote>
<p>File Management module is currently available only for the MVC / Razor Pages UI. We are working on the Angular UI and it will be released in the next versions.</p>
</blockquote>
<h2>Breaking Changes</h2>
<p>Since this is a major version, we've redesigned some APIs and introduced a few &quot;easy to fix&quot; breaking changes.</p>
<h3>ABP Framework</h3>
<ul>
<li>Changed some <strong>consts</strong> in the pre-built application modules to static properties that is possible to change by your code. If you've used these consts on an attribute, then use the <code>DynamicStringLength</code> as explained above.</li>
<li>Changed <code>ConcurrencyStamp</code> max length to 40. You need to <strong>add a database migration</strong> and update your database after upgrading the ABP Framework.</li>
<li>Using <code>~</code> instead of <code>^</code> for NPM package dependencies anymore, to be more stable.</li>
</ul>
<h3>ABP Commercial</h3>
<ul>
<li>Changed file names for the application logos. Previously, it was using separate logo files for each theme, like <code>theme1.png</code>, <code>theme1-reverse.png</code>, <code>theme2.png</code>, <code>theme2-reverse.png</code> (... <code>6</code>). Now, we have only two logo files: <code>logo-light.png</code> and <code>logo-dark.png</code>. So, rename your logo in the <code>wwwroot/images/logo/</code> folder for the MVC UI and <code>/src/assets/images/logo/</code> folder for the Angular UI.</li>
<li>We've added the <a href="https://docs.abp.io/api-docs/commercial/3.0/api/index.html">API documentation</a> for the ABP Commercial too.</li>
</ul>
<blockquote>
<p><strong>Also, see the <a href="https://github.com/abpframework/abp/blob/dev/docs/en/UI/Angular/Migration-Guide-v3.md">migration guide</a> for Angular UI</strong>.</p>
</blockquote>
<h2>Known Issues</h2>
<ul>
<li>3.0.0 version has a problem with tiered architecture. See <a href="https://github.com/abpframework/abp/pull/4564">this issue</a> to fix it for your application until we release the v3.0.1.</li>
</ul>
<h2>About the Next Versions</h2>
<p>We will continue to release a new minor/feature version in every two weeks. So, the next expected release date is <strong>2020-07-16</strong> for the version <strong>3.1</strong>.</p>
<p>In the next few versions, we will be focused on the <strong>Blazor UI</strong>, as promised on <a href="https://docs.abp.io/en/abp/latest/Road-Map">the road map</a>. We will continue to improve the documentation, create samples, add other new features and enhancements. Follow the <a href="https://twitter.com/abpframework">ABP Framework Twitter account</a> for the latest news...</p>
<h2>Bonus: Articles!</h2>
<p>Beside developing our products, our team are constantly writing articles/tutorials on various topics. You may want to check the latest articles:</p>
<ul>
<li><a href="https://volosoft.com/blog/what-is-new-in-angular-10">What is New in Angular 10?</a></li>
<li><a href="https://volosoft.com/blog/RealTime-Messaging-Distributed-Architecture-Abp-SingalR-RabbitMQ">Real-Time Messaging In A Distributed Architecture Using ABP, SignalR &amp; RabbitMQ</a></li>
<li><a href="https://volosoft.com/blog/attribute-directives-to-avoid-repetition-in-angular-templates">How to Use Attribute Directives to Avoid Repetition in Angular Templates</a></li>
</ul>
<p> </p>
<blockquote>
<p>We’d love to hear from you. Please leave your comments, suggestions, feeedbacks below.</p>
</blockquote>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/e408b58d-6881-ab44-5357-39f6257b4990" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/e408b58d-6881-ab44-5357-39f6257b4990" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-framework-v2.9.0-has-been-released-l7c6atbq</guid>
      <link>https://abp.io/community/posts/abp-framework-v2.9.0-has-been-released-l7c6atbq</link>
      <a10:author>
        <a10:name>hikalkan</a10:name>
        <a10:uri>https://abp.io/community/members/hikalkan</a10:uri>
      </a10:author>
      <category>release</category>
      <category>ABP Commercial</category>
      <category>ABP Framework</category>
      <title>ABP Framework v2.9.0 Has Been Released</title>
      <description>Released ABP v2.9.0. Some new features: Organization Units System, Blob Storing Package, EF Core Oracle Integration Package, Chat Module Angular UI etc. Learn more about what's new.</description>
      <pubDate>Fri, 05 Jun 2020 07:20:38 Z</pubDate>
      <a10:updated>2026-10-02T16:37:46Z</a10:updated>
      <content:encoded><![CDATA[<p>The <strong>ABP Framework</strong> &amp; and the <strong>ABP Commercial</strong> version 2.9 have been released, which are the last versions before v3.0! This post will cover <strong>what's new</strong> with these this release.</p>
<h2>What's New with the ABP Framework 2.9?</h2>
<p>You can see all the changes on the <a href="https://github.com/abpframework/abp/releases/tag/2.9.0">GitHub release notes</a>. This post will only cover the important features/changes.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/abp-framework-290-.png" alt="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/abp-framework-290-.png" /></p>
<h3>Pre-Compiling Razor Pages</h3>
<p>Pre-built pages (for <a href="https://docs.abp.io/en/abp/latest/Modules/Index">the application modules</a>) and view components were compiling on runtime until this version. Now, they are pre-compiled and we've measured that the application startup time (especially for the MVC UI) has been reduced more than 50%. In other words, it is <strong>two-times faster</strong> than the previous version. The speed change also effects when you visit a page for the first time.</p>
<p>Here, a test result for the startup application template with v2.8 and v.2.9:</p>
<h3>v2.8</h3>
<pre><code>2020-06-04 22:59:04.891 +08:00 [INF] Starting web host.
2020-06-04 22:59:07.662 +08:00 [INF] Now listening on: https://localhost:44391
2020-06-04 22:59:17.315 +08:00 [INF] Request finished in 7756.6218ms 200 text/html;

Total: 12.42s
</code></pre>
<h3>v2.9</h3>
<pre><code>2020-06-04 22:59:13.720 +08:00 [INF] Starting web host.
2020-06-04 22:59:16.639 +08:00 [INF] Now listening on: https://localhost:44369
2020-06-04 22:59:18.957 +08:00 [INF] Request finished in 1780.5461ms 200 text/html;

Total: 5.24s
</code></pre>
<p>You do nothing to get the benefit of the new approach. <a href="https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface">Overriding UI pages/components</a> are also just working as before. We will be working on more performance improvements in the v3.0.</p>
<h3>Organization Unit System</h3>
<p><a href="https://docs.abp.io/en/abp/latest/Modules/Identity">The Identity Module</a> now has the most requested feature: Organization Units!</p>
<p>Organization unit system is used to create a hierarchical organization tree in your application. You can then use this organization tree to authorize data and functionality in your application.</p>
<p>The documentation will come soon...</p>
<h3>New Blob Storing Package</h3>
<p>We've created a new <a href="https://www.nuget.org/packages/Volo.Abp.BlobStoring">Blob Storing package</a> to store arbitrary binary objects. It is generally used to store the content of the files in your application. This package provides an abstraction, so any application or <a href="https://docs.abp.io/en/abp/latest/Module-Development-Basics">module</a> can save and retrieve files independent from the actual storing provider.</p>
<p>There are two storage provider currently implemented:</p>
<ul>
<li><a href="https://www.nuget.org/packages/Volo.Abp.BlobStoring.FileSystem">Volo.Abp.BlobStoring.FileSystem</a> package stores objects/files in the local file system.</li>
<li><a href="https://github.com/abpframework/abp/tree/dev/modules/blob-storing-database">Volo.Abp.BlobStoring.Database</a> module stores objects/files in a database. It currently supports <a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core">Entity Framework Core</a> (so, you can use <a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Other-DBMS">any relational DBMS</a>) and <a href="https://docs.abp.io/en/abp/latest/MongoDB">MongoDB</a>.</li>
</ul>
<p><a href="https://github.com/abpframework/abp/issues/4098">Azure BLOB provider</a> will be available with v3.0. You can request other cloud providers or contribute yourself on the <a href="https://github.com/abpframework/abp/issues/new">GitHub repository</a>.</p>
<p>One of the benefits of the blob storing system is that it allows you to create multiple containers (each container is a blob storage) and use different storage providers for each container.</p>
<p><strong>Example: Use the default container to save and get a byte array</strong></p>
<pre><code class="language-csharp">public class MyService : ITransientDependency
{
    private readonly IBlobContainer _container;

    public MyService(IBlobContainer container)
    {
        _container = container;
    }

    public async Task FooAsync()
    {
        //Save a BLOB
        byte[] bytes = GetBytesFromSomeWhere();
        await _container.SaveAsync(&quot;my-unique-blob-name&quot;, bytes);
        
        //Retrieve a BLOB
        bytes = await _container.GetAllBytesAsync(&quot;my-unique-blob-name&quot;);
    }
}
</code></pre>
<p>It can work with <code>byte[]</code> and <code>Stream</code> objects.</p>
<p><strong>Example: Use a typed (named) container to save and get a stream</strong></p>
<pre><code class="language-csharp">public class MyService : ITransientDependency
{
    private readonly IBlobContainer&lt;TestContainer&gt; _container;

    public MyService(IBlobContainer&lt;TestContainer&gt; container)
    {
        _container = container;
    }

    public async Task FooAsync()
    {
        //Save a BLOB
        Stream stream = GetStreamFromSomeWhere();
        await _container.SaveAsync(&quot;my-unique-blob-name&quot;, stream);
        
        //Retrieve a BLOB
        stream = await _container.GetAsync(&quot;my-unique-blob-name&quot;);
    }
}
</code></pre>
<p><code>TestContainer</code> is an empty class that has no purpose than identifying the container:</p>
<pre><code class="language-csharp">[BlobContainerName(&quot;test&quot;)] //specifies the name of the container
public class TestContainer
{

}
</code></pre>
<p>A typed (named) container can be configured to use a different storing provider than the default one. It is a good practice to always use a typed container while developing re-usable modules, so the final application can configure provider for this container without effecting the other containers.</p>
<p><strong>Example: Configure the File System provider for the <code>TestContainer</code></strong></p>
<pre><code class="language-csharp">Configure&lt;AbpBlobStoringOptions&gt;(options =&gt;
{
    options.Containers.Configure&lt;TestContainer&gt;(configuration =&gt;
    {
        configuration.UseFileSystem(fileSystem =&gt;
        {
            fileSystem.BasePath = &quot;C:\\MyStorageFolder&quot;;
        });
    });
});
</code></pre>
<p>See the <a href="https://docs.abp.io/en/abp/latest/Blob-Storing">blob storing documentation</a> for more information.</p>
<h3>Oracle Integration Package for Entity Framework Core</h3>
<p>We've created an <a href="https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart">integration package for Oracle</a>, so you can easily switch to the Oracle for the EF Core. It is tested for the framework and pre-built modules.</p>
<p><a href="https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Oracle">See the documentation</a> to start using the Oracle integration package.</p>
<h3>Automatically Determining the Database Provider</h3>
<p>When you develop a <strong>reusable application module</strong> with EF Core integration, you generally want to develop your module <strong>DBMS independent</strong>. However, there are minor (sometimes major) differences between different DBMSs. If you perform a custom mapping based on the DBMS, you can now use <code>ModelBuilder.IsUsingXXX()</code> extension methods:</p>
<pre><code class="language-csharp">protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity&lt;Phone&gt;(b =&gt;
    {
        //...
        if (modelBuilder.IsUsingPostgreSql()) //Check if using PostgreSQL!
        {
            b.Property(x =&gt; x.Number).HasMaxLength(20);
        }
        else
        {
            b.Property(x =&gt; x.Number).HasMaxLength(32);
        }
    });
}
</code></pre>
<p>Beside the stupid example above, you can configure your mapping however you need!</p>
<h3>ABP CLI: Translate Command</h3>
<p><code>abp translate</code> is a new command that simplifies to translate <a href="https://docs.abp.io/en/abp/latest/Localization">localization</a> files when you have multiple JSON localization files in a source control repository.</p>
<p>The main purpose of this command is to <strong>translate the ABP Framework</strong> localization files (since the <a href="https://github.com/abpframework/abp">abp repository</a> has tens of localization files to be translated in different folders).</p>
<p>It is appreciated if you use this command to translate the framework resources <strong>for your mother language</strong>.</p>
<p>See <a href="https://docs.abp.io/en/abp/latest/CLI#translate">the documentation</a> to learn how to use it. Also see <a href="https://docs.abp.io/en/abp/latest/Contribution/Index">the contribution guide</a>.</p>
<h3>The New Virtual File System Explorer Module</h3>
<p>Thanks to <a href="https://github.com/realLiangshiwei">@realLiangshiwei</a> created and contributed a new module to explore files in the <a href="https://docs.abp.io/en/abp/latest/Virtual-File-System">Virtual File System</a>. It works for MVC UI and shows all the virtual files in the application. Example screenshots:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/virtual-file-explorer-11.png" alt="virtual-file-explorer-11" /></p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/virtual-file-explorer-2.png" alt="virtual-file-explorer-2" /></p>
<p><a href="https://docs.abp.io/en/abp/latest/Modules/Virtual-File-Explorer">See the documentation</a> to learn how to use it.</p>
<h3>Sample Application: SignalR with Tiered Architecture</h3>
<p>Implementing SignalR in a distributed/tiered architecture can be challenging. We've created a sample application that demonstrate how to implement it using the <a href="https://docs.abp.io/en/abp/latest/SignalR-Integration">SignalR integration</a> and the <a href="https://docs.abp.io/en/abp/latest/Distributed-Event-Bus">distributed event bus</a> system easily.</p>
<p>See <a href="https://github.com/abpframework/abp-samples/tree/master/SignalRTieredDemo">the source code</a> of the sample solution.</p>
<p><strong>An article is on the road</strong> that will deeply explain the solution. Follow the <a href="https://twitter.com/abpframework">@abpframework</a> Twitter account.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/signalr-tiered-demo.png" alt="signalr-tiered-demo" /></p>
<p><em>A picture from the article that shows the communication diagram of the solution</em></p>
<h3>About gRPC</h3>
<p>We've created a sample application to show how to create and consume gRPC endpoints in your ABP based applications.</p>
<p>See <a href="https://github.com/abpframework/abp-samples/tree/master/GrpcDemo">the source code</a> on GitHub.</p>
<p>We were planning to create gRPC endpoints for all the pre-built application modules, but we see that ASP.NET Core gRPC integration is not mature enough and doesn't support some common deployment scenarios yet. So, deferring this to the next versions (<a href="https://github.com/abpframework/abp/issues/2882#issuecomment-633080242">see this comment</a> for more). However, it is pretty standard if you want to use gRPC in your applications. ABP Framework has no issue with gRPC. Just check the <a href="https://github.com/abpframework/abp-samples/tree/master/GrpcDemo">sample application</a>.</p>
<h3>Others</h3>
<ul>
<li><a href="https://github.com/abpframework/abp/pull/3933">Time zone system</a> to support different time zones for an application.</li>
<li>Support for <a href="https://github.com/abpframework/abp/issues/4089">virtual path deployment</a> on IIS.</li>
<li>RTL support for the Angular UI.</li>
</ul>
<p>See the <a href="https://github.com/abpframework/abp/releases/tag/2.9.0">GitHub release notes</a> for others updates.</p>
<h2>What's New with the ABP Commercial 2.9</h2>
<p>In addition to all the features coming with the ABP Framework, the ABP Commercial has additional features with this release, as always. This section covers the <a href="https://commercial.abp.io/?ref=abpio">ABP Commercial</a> highlights in the version 2.9.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/abp-commercial-290.png" alt="abp-commercial-290" /></p>
<h3>Organization Unit Management UI</h3>
<p>We've created the UI for manage organization units, their members and roles for the ABP Commercial <a href="https://commercial.abp.io/modules/Volo.Identity.Pro">Identity Module</a>:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/organization-units.png" alt="organization-units" /></p>
<p>OU management is available for both of the MVC (Razor Pages) and the Angular user interfaces.</p>
<blockquote>
<p>See <a href="https://support.abp.io/QA/Questions/222/Bugs--Problems-v290#answer-3cf5eba3-0bf1-2aa1-cc5e-39f5a0750329">this entry</a> if you're upgrading your solution from an earlier version.</p>
</blockquote>
<h3>Chat Module Angular UI</h3>
<p>We had introduced a new <a href="https://commercial.abp.io/modules/Volo.Chat">chat module</a> in the previous version, which was only supporting the ASP.NET Core MVC / Razor Pages UI. Now, it has also an Angular UI option.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/abp-chat-module.png" alt="abp-chat-module" /></p>
<p><em>A screenshot from the chat module - two users are sending messages to each other</em></p>
<h3>Easy CRM Angular UI</h3>
<p>Easy CRM is a sample application that is built on the ABP Commercial to provide a relatively complex application to the ABP Commercial customers. In the version 2.7, we have lunched it with MVC / Razor Pages UI. With the 2.9 version, we are releasing the Angular UI for the Easy CRM application.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/easy-crm-1.png" alt="easy-crm-1" /></p>
<p><em>A screenshot from the &quot;Order Details&quot; page of the Easy CRM application.</em></p>
<p>See the <a href="https://docs.abp.io/en/commercial/latest/samples/easy-crm">Easy CRM document</a> to learn how to download and run it.</p>
<h3>Module Code Generation for the ABP Suite</h3>
<p><a href="https://commercial.abp.io/tools/suite">ABP Suite</a> is a tool that's main feature is to <a href="https://docs.abp.io/en/commercial/latest/abp-suite/generating-crud-page">generate code</a> for complete CRUD functionality for an entity, from database to the UI layer.</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/suite.png" alt="suite" /></p>
<p><em>A screenshot from the ABP Suite: Define the properties of a new entity and let it to create the application code for you!</em></p>
<p>It was working only for <a href="https://docs.abp.io/en/commercial/latest/startup-templates/application/index">the application template</a> until this release. Now, it supports to generate code for the <a href="https://docs.abp.io/en/commercial/latest/startup-templates/module/index">module projects</a> too. That's a great way to create reusable application modules by taking the power of the code generation.</p>
<p>In addition to this main feature, we added many minor enhancements on the ABP Suite in this release.</p>
<blockquote>
<p>Notice: Generating code for the module template is currently in beta. Please inform us if you find any bug.</p>
</blockquote>
<h3>Lepton Theme</h3>
<p><a href="https://commercial.abp.io/themes">Lepton Theme</a> is the commercial theme we've developed for the ABP Commercial;</p>
<ul>
<li>It is 100% bootstrap compatible - so you don't write theme specific HTML!</li>
<li>Provides different kind of styles - you see the material style in the picture below.</li>
<li>Provides different kind of layouts (side/top menu, fluid/boxed layout...).</li>
<li>It is lightweight, responsive and modern.</li>
<li>And... it is upgradeable with no cost! You just update a NuGet/NPM package to get the new features.</li>
</ul>
<p>We've create its own web site: <a href="http://leptontheme.com/">http://leptontheme.com/</a></p>
<p>You can view all the components together, independent from an application:</p>
<p><img src="https://raw.githubusercontent.com/abpframework/abp/dev/docs/en/Community-Articles/2020-06-05-abp-framework-v290-has-been-released/lepton-theme.png" alt="lepton-theme" /></p>
<p>This web site is currently in a very early stage. We will be documenting and improving this web site to be a reference for your development and explore the features of the theme.</p>
<h3>Coming Soon: The File management Module</h3>
<p>Based on the new blob storing system (introduced above), we've started to build a file management module that is used to manage (navigate/upload/download) a hierarchical file system on your application and share the files between your users and with your customers.</p>
<p>We plan to release the initial version with the ABP Commercial v3.0 and continue to improve it with the subsequent releases.</p>
<h2>About the Next Version: 3.0</h2>
<p>We have added many new features with the <a href="https://blog.abp.io/abp/ABP-v2.8.0-Releases-%26-Road-Map">v2.8</a> and v2.9. In the next version, we will completely focus on the <strong>documentation, performance improvements</strong> and and other enhancements as well as bug fixes.</p>
<p>For a long time, we were releasing a new feature version in every 2 weeks. We will continue to this approach after v3.0. But, as an exception to the v3.0, the development cycle will be ~4 weeks. <strong>The planned release date for the v3.0 is the July 1, 2020</strong>.</p>
<h2>Bonus: Articles!</h2>
<p>Beside developing our products, our team are constantly writing articles/tutorials on various topics. You may want to check the latest articles:</p>
<ul>
<li><a href="https://volosoft.com/blog/ASP.NET-CORE-3.1-Webhook-Implementation-Using-Pub-Sub/?ref=abpio">ASP.NET Core 3.1 WebHook Implementation Using Pub/Sub</a></li>
<li><a href="https://volosoft.com/blog/Using-Azure-Key-Vault-with-ASP.NET-Core/?ref=abpio">Using Azure Key Vault with ASP.NET Core</a></li>
</ul>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3ebfd478-57d5-8175-a7d1-39f595873aca" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3ebfd478-57d5-8175-a7d1-39f595873aca" medium="image" />
    </item>
  </channel>
</rss>