<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Yoann Blossier Codes]]></title><description><![CDATA[Yoann Blossier Codes]]></description><link>https://blog.toenn-vaot.fr</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1768004092910/7e9b33cb-608d-4f5e-968e-e9348bac548b.png</url><title>Yoann Blossier Codes</title><link>https://blog.toenn-vaot.fr</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 12:07:16 GMT</lastBuildDate><atom:link href="https://blog.toenn-vaot.fr/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to generate a database per tenant in multi-tenant system ?]]></title><description><![CDATA[The purpose is to be able to create a multi-tenant database system where each tenant have its own database. We will see the different steps to implement this configuration
Let’s go, begin with the STARTER KIT !
The database schema in code first
First...]]></description><link>https://blog.toenn-vaot.fr/how-to-generate-a-database-per-tenant-in-multi-tenant-system</link><guid isPermaLink="true">https://blog.toenn-vaot.fr/how-to-generate-a-database-per-tenant-in-multi-tenant-system</guid><category><![CDATA[multitenant]]></category><category><![CDATA[efcore]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[asp.net core]]></category><dc:creator><![CDATA[Yoann Blossier]]></dc:creator><pubDate>Sun, 12 Oct 2025 01:56:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760223252172/434268e5-7e47-4116-afc9-9b97b37f5732.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The purpose is to be able to create a multi-tenant database system where each tenant have its own database. We will see the different steps to implement this configuration</p>
<p>Let’s go, begin with the <strong>STARTER KIT</strong> !</p>
<h2 id="heading-the-database-schema-in-code-first">The database schema in code first</h2>
<p>First of all, we will create the database context. No matter what we put inside, it is just to describe the project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760223754588/3beca959-c834-4006-b24e-ae5777fcdff5.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760223779702/e21ffa9b-dba3-47f0-97d9-75a96d965940.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760223794165/ba997b12-bcac-4a24-a00c-b1776a77931f.png" alt class="image--center mx-auto" /></p>
<p>Import <strong>Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Tools</strong> in version <strong><mark>9.0.9</mark></strong></p>
<h3 id="heading-the-client-class">The <strong>Client</strong> class</h3>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant</span>;

<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> The client entity</span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Client</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The identifier</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The name</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The birthdate</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> DateTime BirthDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<h3 id="heading-the-multitenantcontext-class-using-sql-server">The <strong>MultitenantContext</strong> class (using SQL Server)</h3>
<blockquote>
<p>You have to import :</p>
<ul>
<li><p><strong>Microsoft.EntityFrameworkCore.SqlServer</strong> in version <strong><mark>9.0.9</mark></strong></p>
</li>
<li><p><strong>Microsoft.Extensions.Configuration.Abstractions</strong> in version <strong><mark>9.0.9</mark></strong></p>
</li>
</ul>
</blockquote>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MultitenantContext</span> : <span class="hljs-title">DbContext</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The clients DbSet</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> DbSet&lt;Client&gt; Clients { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration _configuration;

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Constructor</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="options"&gt;</span>The database context options instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="configuration"&gt;</span>The configuration instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MultitenantContext</span>(<span class="hljs-params">DbContextOptions&lt;MultitenantContext&gt; options, IConfiguration configuration</span>)
         : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>)</span>
        {
            _configuration = configuration;
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc /&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnConfiguring</span>(<span class="hljs-params">DbContextOptionsBuilder options</span>)</span>
        {
            options.UseSqlServer(_configuration.GetConnectionString(<span class="hljs-string">"Default"</span>));
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc /&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder builder</span>)</span>
        {
            <span class="hljs-keyword">base</span>.OnModelCreating(builder);

            builder.Entity&lt;Client&gt;(b =&gt;
            {
                b.HasKey(x =&gt; x.Id);
                b.Property(x =&gt; x.Name).IsRequired().HasMaxLength(<span class="hljs-number">256</span>);
                b.Property(x =&gt; x.BirthDate).IsRequired();
            });
        }
    }
}
</code></pre>
<h2 id="heading-the-api-project">The API project</h2>
<p>Next is the API project to request data</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760225302520/8ca940ac-8871-436a-9071-3726f25bc9da.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760225328034/99ae248f-deb7-4eac-a141-c9ee4e2a5a20.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760225350912/f4365921-1e21-4b2b-b4b8-dfe2a36c8ad3.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760225364166/8dce627c-8f50-4492-8b40-ccac86557fe2.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-clientscontroller-class">The <strong>ClientsController</strong> class</h3>
<blockquote>
<p>Remove the <strong>WeatherForecastController</strong> class and <strong>WeatherForecast</strong> model</p>
</blockquote>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Net;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> Multitenant.Api.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant.Api.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ClientsController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> MultitenantContext _context;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;ClientsController&gt; _logger;

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Constructor</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="context"&gt;</span>The database context<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="logger"&gt;</span>The logger instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ClientsController</span>(<span class="hljs-params">MultitenantContext context, ILogger&lt;ClientsController&gt; logger</span>)</span>
        {
            _context = context;
            _logger = logger;
        }

        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"clients"</span>)</span>]
        [<span class="hljs-meta">ProducesResponseType(typeof(IEnumerable&lt;ClientResource&gt;), (int)HttpStatusCode.OK)</span>]
        [<span class="hljs-meta">ProducesResponseType((int)HttpStatusCode.NoContent)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetAll</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">await</span> _context.Database.MigrateAsync();
            <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> _context.Clients.ToListAsync();
            <span class="hljs-keyword">var</span> result = response.ConvertAll(x =&gt; <span class="hljs-keyword">new</span> ClientResource { Name = x.Name, BirthDate = x.BirthDate });

            <span class="hljs-keyword">if</span>(result.Count &gt; <span class="hljs-number">0</span>)
                <span class="hljs-keyword">return</span> Ok(result);
            <span class="hljs-keyword">return</span> NoContent();
        }

        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"clients/{id:int}"</span>)</span>]
        [<span class="hljs-meta">ProducesResponseType(typeof(ClientResource), (int)HttpStatusCode.OK)</span>]
        [<span class="hljs-meta">ProducesResponseType((int)HttpStatusCode.NotFound)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetById</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>)</span>
        {
            <span class="hljs-keyword">await</span> _context.Database.MigrateAsync();
            <span class="hljs-keyword">var</span> client = <span class="hljs-keyword">await</span> _context.Clients.FindAsync(id);
            <span class="hljs-keyword">if</span> (client == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">return</span> NotFound();
            }
            <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">new</span> ClientResource { Name = client.Name, BirthDate = client.BirthDate };
            <span class="hljs-keyword">return</span> Ok(result);
        }
    }
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The <strong>await _context.Database.MigrateAsync()</strong> is here to ensure the database will be created and migrated. In real implementation, this call should be done in the Store implementation and not here !</div>
</div>

<h3 id="heading-the-clientresource-model">The <strong>ClientResource</strong> model</h3>
<blockquote>
<p>Create a folder <strong>Models</strong> in the project</p>
</blockquote>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant.Api.Models</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The client resource</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ClientResource</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The name</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The birthdate</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> DateTime BirthDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h3 id="heading-the-appsettingsjson">The <strong>appsettings</strong>.json</h3>
<pre><code class="lang-json">{
  <span class="hljs-attr">"Logging"</span>: {
    <span class="hljs-attr">"LogLevel"</span>: {
      <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Information"</span>,
      <span class="hljs-attr">"Microsoft.AspNetCore"</span>: <span class="hljs-string">"Warning"</span>
    }
  },
  <span class="hljs-attr">"AllowedHosts"</span>: <span class="hljs-string">"*"</span>,
  <span class="hljs-attr">"ConnectionStrings"</span>: {
    <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Data Source=.;Initial Catalog=Multitenant;Integrated Security=SSPI;Persist Security Info=False;TrustServerCertificate=false;"</span>
  }
}
</code></pre>
<h2 id="heading-the-multi-tenant-scenario">The multi-tenant scenario</h2>
<p>To handle the multi-tenant, try to understand the scenario. On each request, we want to identify the tenant calling the API and request its database to restitute their data.</p>
<p>So, to answer to this scenario, we have to do these steps:</p>
<ol>
<li><p>Be able to identify the tenant</p>
</li>
<li><p>Use the tenant to configure the DbContext connection string to target the right database</p>
</li>
</ol>
<h2 id="heading-the-multi-tenant-implementation">The multi-tenant implementation</h2>
<h3 id="heading-the-interface">The interface</h3>
<p>First of all, we have to define the tenant interface</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The tenant interface</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ITenant</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The tenant identifier</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> Guid TenantId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h3 id="heading-the-instance">The instance</h3>
<p>Now, the implementation</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant</span>;

<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> The tenant implementation</span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Tenant</span> : <span class="hljs-title">ITenant</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc/&gt;</span></span>
    <span class="hljs-keyword">public</span> Guid TenantId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<h3 id="heading-the-dependency-injection">The dependency injection</h3>
<p>Next is the dependency injection, add scoped the <strong>ITenant</strong> implementation.</p>
<pre><code class="lang-csharp">
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant.Api</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            <span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

            builder.Services.AddDbContext&lt;MultitenantContext&gt;();

            <span class="hljs-comment">//NOTICE: Configure the ITenant service to be resolved from the X-Tenant-Id header</span>
            builder.Services.AddHttpContextAccessor();
            builder.Services.AddScoped&lt;ITenant&gt;(sp =&gt;
            {
                <span class="hljs-keyword">var</span> tenantIdString = sp.GetRequiredService&lt;IHttpContextAccessor&gt;().HttpContext?.Request.Headers[<span class="hljs-string">"X-Tenant-Id"</span>];
                <span class="hljs-keyword">return</span> (!<span class="hljs-keyword">string</span>.IsNullOrEmpty(tenantIdString) &amp;&amp; Guid.TryParse(tenantIdString, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> tenantId) ? <span class="hljs-keyword">new</span> Tenant { TenantId = tenantId } : <span class="hljs-literal">null</span>)!;
            });

            builder.Services.AddControllers();
            <span class="hljs-comment">// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle</span>
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            <span class="hljs-keyword">var</span> app = builder.Build();

            <span class="hljs-comment">// Configure the HTTP request pipeline.</span>
            <span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();

            app.MapControllers();

            app.Run();
        }
    }
}
</code></pre>
<h3 id="heading-the-connection-string-prefix-or-suffix">The connection string prefix or suffix</h3>
<p>To be able to address a database per tenant, we have to change the database name in the connection string according to the tenant. To do it, we will pattern the connection string in the configuration file.</p>
<blockquote>
<p>I choose <strong>SUFFIX</strong> but you can change if you want to use <strong>PREFIX</strong> for sure</p>
</blockquote>
<pre><code class="lang-json">{
  <span class="hljs-attr">"Logging"</span>: {
    <span class="hljs-attr">"LogLevel"</span>: {
      <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Information"</span>,
      <span class="hljs-attr">"Microsoft.AspNetCore"</span>: <span class="hljs-string">"Warning"</span>
    }
  },
  <span class="hljs-attr">"AllowedHosts"</span>: <span class="hljs-string">"*"</span>,
  <span class="hljs-attr">"ConnectionStrings"</span>: {
    <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Data Source=.;Initial Catalog=Multitenant__Suffix__;Integrated Security=SSPI;Persist Security Info=False;TrustServerCertificate=false;"</span>
  }
}
</code></pre>
<h3 id="heading-the-database-context">The database context</h3>
<p>Now we have defined the bases, we have to change the database context to mutate per tenant. To do it, we will add the <strong>ITenant</strong> interface to change the connection string dynamically.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Multitenant</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MultitenantContext</span> : <span class="hljs-title">DbContext</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The clients DbSet</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> DbSet&lt;Client&gt; Clients { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration _configuration;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITenant _tenant;

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Constructor</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="options"&gt;</span>The database context options instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="tenant"&gt;</span>The tenant instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="configuration"&gt;</span>The configuration instance<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MultitenantContext</span>(<span class="hljs-params">DbContextOptions&lt;MultitenantContext&gt; options, ITenant tenant, IConfiguration configuration</span>)
         : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>)</span>
        {
            _tenant = tenant;
            _configuration = configuration;
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc /&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnConfiguring</span>(<span class="hljs-params">DbContextOptionsBuilder options</span>)</span>
        {
            <span class="hljs-keyword">var</span> connectionString = _configuration.GetConnectionString(<span class="hljs-string">"Default"</span>)?.Replace(<span class="hljs-string">"__Suffix__"</span>, _tenant?.TenantId.ToString() ?? <span class="hljs-string">"default"</span>);
            options.UseSqlServer(connectionString);
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc /&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder builder</span>)</span>
        {
            <span class="hljs-keyword">base</span>.OnModelCreating(builder);

            builder.Entity&lt;Client&gt;(b =&gt;
            {
                b.HasKey(x =&gt; x.Id);
                b.Property(x =&gt; x.Name).IsRequired().HasMaxLength(<span class="hljs-number">256</span>);
                b.Property(x =&gt; x.BirthDate).IsRequired();
            });
        }
    }
}
</code></pre>
<p>The <strong>default</strong> fallback value is used during the EF design-time and let you generate the <strong>default</strong> database and generate migrations.</p>
<h3 id="heading-the-migrations">The migrations</h3>
<p>To generate migrations, we need to use a special nuget package dedicated to this</p>
<ul>
<li><strong>Microsoft.EntityFrameworkCore.Design</strong> in version <strong><mark>9.0.9</mark></strong></li>
</ul>
<p>Import this package in the <strong>API project</strong> and set it at <strong>Startup project</strong></p>
<p>Now, open <strong>Package Manager Console</strong>, and type :</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Add-Migration</span> Init <span class="hljs-literal">-context</span> MultitenantContext
</code></pre>
<p>You will have a new folder <strong>Migrations</strong> containing the scripts to migrate the database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760230895483/aac9f57e-939e-4020-bbfe-30d4b78adb5f.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">ℹ</div>
<div data-node-type="callout-text">If you launch the command <strong>Update-Database</strong> you will generate the database Multitenant<strong>default</strong>. The <strong>default</strong> value comes from <strong>onConfiguring</strong> where we configure the fallback value in case the tenant value is null.</div>
</div>

<h3 id="heading-the-postman-collection">The POSTMAN collection</h3>
<p>There are multi ways to do the test, I will illustrate one of them with POSTMAN but you can choose what you prefer.</p>
<ol>
<li>Create a new collection by clicking on the <strong>New</strong> button and choose in the popup <strong>Collection</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760232215289/7ff88599-0585-4552-88ab-494c65923aa0.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li>Click on <strong>Add a request</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760232277974/6ba0e351-aea0-4b46-ab4f-4f27a6e7d78a.png" alt class="image--center mx-auto" /></p>
<ol start="3">
<li>Set the URI and keep the verb on <strong>GET.</strong> The host can be determined in the <strong>Properties/launchSettings.json</strong>. Search in <strong>profiles</strong>, the <strong>https</strong>. Take the first part of <strong>applicationUrl</strong> and add <strong>/clients</strong></li>
</ol>
<blockquote>
<p>For me, I will have <strong>https://localhost:7208/clients</strong></p>
</blockquote>
<ol start="4">
<li><p>Add a header <code>X-tenant-id</code> with the GUID <code>b9af52c6-0edd-4301-91fe-08dd10851075</code></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760233817143/562868b2-9b31-45fd-80f5-384cc8e80468.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Launch the API project</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760232518060/a0c5c195-0a2c-454f-805b-8cf968f92ee4.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>Launch the query in Postman by clicking on <strong>Send</strong> button. Show the result <code>204 No Content</code> and a new database created</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760233696529/ac65685f-7036-4081-8493-cc630f3ac91f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760233962751/1f94add0-8dd7-4b3d-a332-4386ee2a5017.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Thanks for reading. Now you know how to create a multi-tenant system with one database per tenant. Enjoy !</p>
<p><a target="_blank" href="https://github.com/Toenn-Vaot/efcore-multitenant-database"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760235238424/dbac30ce-8879-47bf-81b2-7de0288bb0b6.png" alt class="image--center mx-auto" /></a></p>
<hr />
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>Hi, I'm Yoann. I work as a full-stack developer, solution architect.</p>
<p>If you enjoyed this article, you might enjoy my other content, too.</p>
<p><strong>Github:</strong> <a target="_blank" href="https://github.com/yblossier"><strong>yblossier</strong></a></p>
<p><strong>LinkedIn:</strong> <a target="_blank" href="https://linkedin.com/in/yoannblossier"><strong>/in/yoannblossier</strong></a></p>
<p><strong>Buy Me A Coffee:</strong> <a target="_blank" href="https://www.buymeacoffee.com/yoannblossier"><strong>A special thank you for your support</strong></a> <strong>🍵</strong></p>
<p>Thank you for joining me today.</p>
<p>Yoann</p>
]]></content:encoded></item><item><title><![CDATA[How to use IHttpContextAccessor in library project ?]]></title><description><![CDATA[Maybe you already encounter this problem. You want to use the IHttpContextAccessor but it is not available and there is no indication to find the right package to use.
To solve this situation, you just have to use the Microsoft.AspNetCore.Http.Abstra...]]></description><link>https://blog.toenn-vaot.fr/how-to-use-ihttpcontextaccessor-in-library-project</link><guid isPermaLink="true">https://blog.toenn-vaot.fr/how-to-use-ihttpcontextaccessor-in-library-project</guid><category><![CDATA[asp.net core]]></category><category><![CDATA[dependency injection]]></category><category><![CDATA[.NET]]></category><category><![CDATA[.net core]]></category><dc:creator><![CDATA[Yoann Blossier]]></dc:creator><pubDate>Sat, 11 Oct 2025 21:34:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760221392280/b978c4bf-ba14-4aa5-b7a5-4ee93ecf20f4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Maybe you already encounter this problem. You want to use the IHttpContextAccessor but it is not available and there is no indication to find the right package to use.</p>
<p>To solve this situation, you just have to use the <a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Http.Abstractions"><strong>Microsoft.AspNetCore.Http.Abstractions</strong></a> package</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760218057667/ec21db59-4651-401b-9e8a-98b06b400b54.png" alt class="image--center mx-auto" /></p>
<p>That’s all folks™ !</p>
<hr />
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>Hi, I'm Yoann. I work as a full-stack developer, solution architect.</p>
<p>If you enjoyed this article, you might enjoy my other content, too.</p>
<p><strong>Github:</strong> <a target="_blank" href="https://github.com/yblossier"><strong>yblossier</strong></a></p>
<p><strong>LinkedIn:</strong> <a target="_blank" href="https://linkedin.com/in/yoannblossier"><strong>/in/yoannblossier</strong></a></p>
<p><strong>Buy Me A Coffee:</strong> <a target="_blank" href="https://www.buymeacoffee.com/yoannblossier"><strong>A special thank you for your support</strong></a> <strong>🍵</strong></p>
<p>Thank you for joining me today.</p>
<p>Yoann</p>
]]></content:encoded></item><item><title><![CDATA[Web.config - Add the intellisense]]></title><description><![CDATA[I previously explain how to create a custom configuration section in a web.config. But something miss if we want to do all the job.
If you share the library with your favorites colleagues and the haven't the documentation, it is better to include the...]]></description><link>https://blog.toenn-vaot.fr/webconfig-add-the-intellisense</link><guid isPermaLink="true">https://blog.toenn-vaot.fr/webconfig-add-the-intellisense</guid><category><![CDATA[ASP.NET]]></category><category><![CDATA[web.config]]></category><category><![CDATA[webforms,]]></category><category><![CDATA[configuration]]></category><category><![CDATA[intellisense]]></category><dc:creator><![CDATA[Yoann Blossier]]></dc:creator><pubDate>Mon, 19 Feb 2024 03:15:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zwsHjakE_iI/upload/4b24bd9d93912c10228ac416d35f071d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I previously explain <a target="_blank" href="https://hashnode.com/post/clss85qjh000308lb81t56i1r">how to create a custom configuration section in a <strong>web.config</strong></a>. But something miss if we want to do all the job.</p>
<p>If you share the library with your favorites colleagues and the haven't the documentation, it is better to include the magic part : INTELLISENSE.</p>
<p>I will show you how to realize the trick.</p>
<h2 id="heading-first-the-schema">First, the schema</h2>
<p>First of all, we have to create the XML schema which describe our custom configuration section structure. It is preferable to name the schema like <em>ClassnameOfSectionSchema.xsd</em>. In our case, <strong>PartnerConfigSectionSchema.xsd</strong>.</p>
<ol>
<li><p>Open the previous project in Visual Studio</p>
</li>
<li><p>In the library, add a new XML Schema</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708308089893/6d0e3823-2a2b-4a79-82af-8d9a31737ee7.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Press <strong>F7</strong> to edit the xml code of the schema</p>
</li>
<li><p>Copy/Paste the code below and replace the original code in the newly created schema</p>
</li>
</ol>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">xs:schema</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"PartnerConfigSectionSchema"</span> <span class="hljs-attr">targetNamespace</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span> <span class="hljs-attr">elementFormDefault</span>=<span class="hljs-string">"qualified"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span> <span class="hljs-attr">xmlns:mstns</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span>     <span class="hljs-attr">xmlns:xs</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig_T"</span>&gt;</span>     
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>       
            <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partner"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"add"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"value"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
                               <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>            
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"remove"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>      
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>       
                             <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"clear"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                                <span class="hljs-comment">&lt;!--tag is empty--&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>               
                            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"required"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The unique name of the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Enabled"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">default</span>=<span class="hljs-string">"false"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>Set to true to enabled the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientId"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client ID of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientSecret"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client secret of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"configSource"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"partnerConfig_T"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">xs:schema</span>&gt;</span>
</code></pre>
<blockquote>
<p>Ok sir ! Copy/paste is magic, but can you explain more ?</p>
</blockquote>
<p>Yes, I can ! Let me explain each part of the schema to let you understand well the role of each one.</p>
<h2 id="heading-explanations">Explanations</h2>
<h3 id="heading-header">Header</h3>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">xs:schema</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"PartnerConfigSectionSchema"</span> <span class="hljs-attr">targetNamespace</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span> <span class="hljs-attr">elementFormDefault</span>=<span class="hljs-string">"qualified"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span> <span class="hljs-attr">xmlns:mstns</span>=<span class="hljs-string">"http://tempuri.org/PartnerConfigSectionSchema.xsd"</span> <span class="hljs-attr">xmlns:xs</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema"</span>&gt;</span>
</code></pre>
<p>This part is the header of the schema where you can found the identifier in the property <em>id.</em></p>
<h3 id="heading-the-collection">The collection</h3>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig_T"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>       
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"add"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"value"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
                               <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>            
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"remove"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>      
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>       
                             <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"clear"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                            <span class="hljs-comment">&lt;!--tag is empty--&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>               
                            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"required"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The unique name of the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Enabled"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">default</span>=<span class="hljs-string">"false"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>Set to true to enabled the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientId"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client ID of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientSecret"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client secret of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"configSource"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
</code></pre>
<p>The big piece of the schema which detailed the structure of our custom section.</p>
<hr />
<p><strong>A. Let's start with the condensed view of the section :</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig_T"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>       
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"configSource"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
</code></pre>
<p>We retrieve here :</p>
<ul>
<li><p>xs:choice which details the content of the section</p>
</li>
<li><p>An attribute called configSource. It is a native attribute let use an external configuration source file instead writing into the web.config</p>
</li>
<li><p>xs:anyAttribute to indicate many other undeclared attribute can exists on the section element.</p>
</li>
</ul>
<hr />
<p><strong>B. Continue with the content part :</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig_T"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>       
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"add"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"value"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
                               <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>            
                        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"remove"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"key"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span>/&gt;</span>      
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>       
                             <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"clear"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                            <span class="hljs-comment">&lt;!--tag is empty--&gt;</span>                 
                                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>               
                            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"required"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               
                            <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The unique name of the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Enabled"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">default</span>=<span class="hljs-string">"false"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>Set to true to enabled the partner<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientId"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client ID of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:attribute</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ClientSecret"</span> <span class="hljs-attr">use</span>=<span class="hljs-string">"optional"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"xs:string"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">xs:annotation</span>&gt;</span>               <span class="hljs-tag">&lt;<span class="hljs-name">xs:documentation</span>&gt;</span>The client secret of the account to use for the partner's service(s)<span class="hljs-tag">&lt;/<span class="hljs-name">xs:documentation</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:annotation</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">xs:attribute</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">xs:anyAttribute</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"http://schemas.microsoft.com/XML-Document-Transform"</span> <span class="hljs-attr">processContents</span>=<span class="hljs-string">"strict"</span>/&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
    ...
<span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
</code></pre>
<p>We retrieve here an element <strong>partner</strong> which is defined by a complex type</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig_T"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">xs:choice</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">maxOccurs</span>=<span class="hljs-string">"unbounded"</span>&gt;</span>       
        <span class="hljs-tag">&lt;<span class="hljs-name">xs:element</span> <span class="hljs-attr">minOccurs</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">xs:complexType</span>&gt;</span>
                ...
            <span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">xs:element</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">xs:choice</span>&gt;</span>
    ...
<span class="hljs-tag">&lt;/<span class="hljs-name">xs:complexType</span>&gt;</span>
</code></pre>
<p>The complex contains multiple parts I will detailed below :</p>
<ol>
<li><p>The collection verbs to manipulate parameters :</p>
<ul>
<li><p><strong>add</strong>: To add a new element</p>
</li>
<li><p><strong>remove</strong>: To remove a new element</p>
</li>
<li><p><strong>clean</strong>: To remove all the element</p>
</li>
</ul>
</li>
<li><p>The attributes you can retrieve on the <strong>partner</strong> element :</p>
<ul>
<li><p><strong>Name</strong>: The name of the partner, marked as required</p>
</li>
<li><p><strong>Enabled</strong>: The flag indicating if the partner element is enabled or not</p>
</li>
<li><p><strong>ClientId</strong>: The client identifier for the partner API</p>
</li>
<li><p><strong>ClientSecret</strong>: The client secret for the partner API</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-usage">Usage</h2>
<p>Now we have the schema defined. I will show you how to use it to add intellisense in the web.config.</p>
<ol>
<li><p>Open the ASP.Net WebForms website with Visual Studio</p>
</li>
<li><p>Open the <strong>web.config</strong> file</p>
</li>
<li><p>On the <strong>Properties</strong> panel, expand the property <strong>Schemas</strong> by clicking on the <strong>...</strong></p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708312188004/69a661e0-8f6f-4384-b8c2-e79df7f12cfa.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708312247267/ac7aebc3-9f9d-491a-b68e-566edf0e48bc.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Click on <strong>Add</strong> and retrieve your <em>.xsd</em> file to add it in the list</p>
</li>
<li><p>Now you have the intellisense for the partner section directly when you type.</p>
</li>
</ol>
<p>Now, no excuse to help your colleagues, go for it 😎.</p>
<h2 id="heading-resources">Resources</h2>
<p>Please find the project illustrating this article on my Github, <a target="_blank" href="https://github.com/yblossier/custom-webconfig-section/">here</a>.</p>
<hr />
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>Hi, I'm Yoann. I work as a full-stack developer, solution architect.</p>
<p>If you enjoyed this article, you might enjoy my other content, too.</p>
<p><strong>Github:</strong><a target="_blank" href="https://github.com/yblossier">yblossier</a></p>
<p><strong>LinkedIn:</strong><a target="_blank" href="https://linkedin.com/in/yoannblossier"><strong>/in/yoannblossier</strong></a></p>
<p><strong>Buy Me A Coffee:</strong><a target="_blank" href="https://www.buymeacoffee.com/yoannblossier">A special thank you for your support</a><strong>🍵</strong></p>
<p>Thank you for joining me today.</p>
<p>Yoann</p>
]]></content:encoded></item><item><title><![CDATA[Web.config - Create your own custom section]]></title><description><![CDATA[Here's a topic that's really interesting for many developers who like to organize their code a bit.
Having a custom configuration section in a configuration file is the best approach when that configuration involves a business need, a connection to a...]]></description><link>https://blog.toenn-vaot.fr/webconfig-create-your-own-custom-section</link><guid isPermaLink="true">https://blog.toenn-vaot.fr/webconfig-create-your-own-custom-section</guid><category><![CDATA[web.config]]></category><category><![CDATA[ASP.NET]]></category><category><![CDATA[webforms,]]></category><category><![CDATA[configuration]]></category><dc:creator><![CDATA[Yoann Blossier]]></dc:creator><pubDate>Mon, 19 Feb 2024 00:55:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FHnnjk1Yj7Y/upload/593b1d8bb82febc0034770205d28e71e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here's a topic that's really interesting for many developers who like to organize their code a bit.</p>
<p>Having a custom configuration section in a configuration file is the best approach when that configuration involves a business need, a connection to a partner, a service, or something similar. But how exactly do you go about creating your own configuration section with its own properties?</p>
<p>As you'll see, it's actually pretty straightforward, and it's surprising we haven't done it before 😉.</p>
<hr />
<h2 id="heading-the-simple-section">The simple section</h2>
<p>The most simple configuration section is certainly the one you already use through the existing one <strong>AppSettings.</strong> Now lets see how to create a similar one.</p>
<ol>
<li><p>Create a new library project in Visual Studio here called <em>MyLibrary</em></p>
</li>
<li><p>Create a new class here called <em>MyCustomSection</em></p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">MyLibrary</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyCustomSection</span> : <span class="hljs-title">ConfigurationSection</span> 
    { 
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> MyCustomSection <span class="hljs-title">GetConfig</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> (MyCustomSection)ConfigurationManager.GetSection(SectionName) ?? <span class="hljs-keyword">new</span> MyCustomSection();
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The string name of the section in the configuration file as defined in its XML schema</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> SectionName = <span class="hljs-string">"mySection"</span>;

        [<span class="hljs-meta">System.Configuration.ConfigurationProperty(<span class="hljs-meta-string">""</span>, IsDefaultCollection = true, IsRequired = false)</span>]
        [<span class="hljs-meta">ConfigurationCollection(typeof(KeyValueConfigurationCollection), AddItemName = <span class="hljs-meta-string">"add"</span>)</span>]
        <span class="hljs-keyword">public</span> KeyValueConfigurationCollection Settings { 
            <span class="hljs-keyword">get</span> { 
                <span class="hljs-keyword">var</span> o = <span class="hljs-keyword">this</span>[<span class="hljs-string">""</span>];
                <span class="hljs-keyword">return</span> o <span class="hljs-keyword">as</span> KeyValueConfigurationCollection;
            } 
        }
    }
}
</code></pre>
<p>This class lets us use a new configuration section after previously declared in the head of the <strong>web.config</strong>.</p>
<ol>
<li><p>Create a new ASP.Net WebForms project in Visual Studio</p>
</li>
<li><p>Add your library in references</p>
</li>
<li><p>Edit the <strong>web.config</strong> as below</p>
</li>
</ol>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">configSections</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"mySection"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"MyLibrary.MyCustomSection, MyLibrary"</span> <span class="hljs-attr">requirePermission</span>=<span class="hljs-string">"false"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">configSections</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mySection</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"param1"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"value1"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"param2"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"value2"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mySection</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
</code></pre>
<h2 id="heading-the-complex-section">The complex section</h2>
<p>Now, since the definition of "complex" really depends on you and what you need, I'll cover a bit of everything here. Of course, it might not cover your specific case, but hey, everyone needs to put in some effort, right? 😎</p>
<p>I want to create a new section to handle the multiple parameter we can have to use to connect to an API provider as Google, Facebook, Twitter or our proper business partner.</p>
<p>Please find the class I wrote to illustrate. I will detail just after.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">MyLibrary</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span>    </span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The configuration section class determines the partners configuration elements</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PartnerConfigSection</span> : <span class="hljs-title">ConfigurationSection</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> PartnerConfigSection <span class="hljs-title">GetConfig</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> (PartnerConfigSection)ConfigurationManager.GetSection(SectionName) ?? <span class="hljs-keyword">new</span> PartnerConfigSection();
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The string name of the section in the configuration file as defined in its XML schema</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> SectionName = <span class="hljs-string">"partnerConfig"</span>;

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The XML namespace. Used to solve live compilation issue</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"xmlns"</span>, IsRequired = false)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> XmlNamespace
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">string</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"xmlns"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"xmlns"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The name of partners group</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"name"</span>, IsRequired = false)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">string</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"name"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"name"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> The partner configuration to use it(s) service(s)</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">""</span>, IsDefaultCollection = true, IsRequired = false)</span>]
        [<span class="hljs-meta">ConfigurationCollection(typeof(PartnerConfigurationElement), AddItemName = <span class="hljs-meta-string">"partner"</span>)</span>]
        <span class="hljs-keyword">public</span> PartnerConfigurationCollection Partners
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (PartnerConfigurationCollection)<span class="hljs-keyword">this</span>[<span class="hljs-string">""</span>]; }
        }
    }
}
</code></pre>
<p>In this class, you'll notice it has a <strong>Name</strong> property and <strong>Partners</strong> property as a collection.</p>
<p>There's also something interesting about the <strong>XmlNamespace</strong> property—it's only there to enable live compilation of the <em>web.config</em> when you use it. If you want proof rather than taking my word for it (which you should always do 😊), try removing it and see what happens 😉.</p>
<hr />
<p>Now, please found the <strong>PartnerConfigurationCollection</strong> class that I used for <em>Partners</em> property</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">MyLibrary</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The configuration element collection contains all definitions</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PartnerConfigurationCollection</span> : <span class="hljs-title">ConfigurationElementCollection</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Manage the element described by the <span class="hljs-doctag">&lt;paramref name="name"/&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="name"&gt;</span>The key value of the element to retrieve in the collection<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>The configuration element found in the collection<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">new</span> PartnerConfigurationElement <span class="hljs-keyword">this</span>[<span class="hljs-keyword">string</span> name]
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (PartnerConfigurationElement)<span class="hljs-keyword">this</span>.BaseGet((<span class="hljs-keyword">object</span>)name); }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">int</span> index = <span class="hljs-number">-1</span>; PartnerConfigurationElement configurationElement = (PartnerConfigurationElement)<span class="hljs-keyword">this</span>.BaseGet((<span class="hljs-keyword">object</span>)name); <span class="hljs-keyword">if</span> (configurationElement != <span class="hljs-literal">null</span>) { index = <span class="hljs-keyword">this</span>.BaseIndexOf(configurationElement); <span class="hljs-keyword">this</span>.BaseRemoveAt(index); } <span class="hljs-keyword">this</span>.BaseAdd(index, <span class="hljs-keyword">value</span>); }
        }
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Create a new element in the collection</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>The newly created element<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> ConfigurationElement <span class="hljs-title">CreateNewElement</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> PartnerConfigurationElement(); }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get the key of the configuration element</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="element"&gt;</span>The configuration element<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>The configuration element key<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">object</span> <span class="hljs-title">GetElementKey</span>(<span class="hljs-params">ConfigurationElement element</span>)</span> { <span class="hljs-keyword">return</span> ((PartnerConfigurationElement)element).Name; }
    }
}
</code></pre>
<p>And now, the class of the collection element use above.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Configuration;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">MyLibrary</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> The configuration element contains the configuration values of partner</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PartnerConfigurationElement</span> : <span class="hljs-title">ConfigurationElement</span>
    {
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get or set the name of partner use as unique key</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"Name"</span>, IsRequired = true)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">string</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"Name"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"Name"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get or set the status of availability of the identity provider</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"Enabled"</span>, DefaultValue = <span class="hljs-meta-string">"false"</span>, IsRequired = false)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> Enabled
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">bool</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"Enabled"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"Enabled"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get or set the identifier of customer for the partner usage</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"ClientId"</span>, IsRequired = false)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ClientId
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">string</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"ClientId"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"ClientId"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get or set the secret key of customer for the partner usage</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">"ClientSecret"</span>, IsRequired = false)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ClientSecret
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (<span class="hljs-keyword">string</span>)<span class="hljs-keyword">this</span>[<span class="hljs-string">"ClientSecret"</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">"ClientSecret"</span>] = <span class="hljs-keyword">value</span>; }
        }

        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get or set the parameters collection</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        [<span class="hljs-meta">ConfigurationProperty(<span class="hljs-meta-string">""</span>, IsDefaultCollection = true, IsRequired = false)</span>]
        [<span class="hljs-meta">ConfigurationCollection(typeof(KeyValueConfigurationCollection), AddItemName = <span class="hljs-meta-string">"add"</span>)</span>]
        <span class="hljs-keyword">public</span> KeyValueConfigurationCollection Parameters
        {
            <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> (KeyValueConfigurationCollection)<span class="hljs-keyword">this</span>[<span class="hljs-string">""</span>]; }
            <span class="hljs-keyword">set</span> { <span class="hljs-keyword">this</span>[<span class="hljs-string">""</span>] = <span class="hljs-keyword">value</span>; }
        }
    }
}
</code></pre>
<p>Now we have the entire definition of the custom configuration section and we can declare in the <strong>web.config</strong> to use it afterwards.</p>
<ol>
<li><p>Create a new ASP.Net WebForms project in Visual Studio</p>
</li>
<li><p>Add your library in references</p>
</li>
<li><p>Edit the <strong>web.config</strong> as below</p>
</li>
</ol>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>   
    <span class="hljs-tag">&lt;<span class="hljs-name">configSections</span>&gt;</span>     
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"partnerConfig"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"MyLibrary.PartnerConfigSection, MyLibrary"</span> <span class="hljs-attr">requirePermission</span>=<span class="hljs-string">"false"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">configSections</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">partnerConfig</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Partners</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">partner</span> <span class="hljs-attr">Name</span>=<span class="hljs-string">"Partner1"</span> <span class="hljs-attr">Enabled</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"param1"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"2"</span>/&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"https://api.test.com/"</span>/&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">partner</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">partner</span> <span class="hljs-attr">Name</span>=<span class="hljs-string">"Partner2"</span> <span class="hljs-attr">ClientId</span>=<span class="hljs-string">"12345"</span> <span class="hljs-attr">ClientSecret</span>=<span class="hljs-string">"azerty"</span> <span class="hljs-attr">Enabled</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">add</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"https://api.test.com/"</span>/&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">partner</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Partners</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">partnerConfig</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
</code></pre>
<p>We have seen the complex view of custom configuration section where we have mixed properties and collection elements in the same definition.</p>
<p>Now, you know how to do it, go for it.</p>
<h2 id="heading-resources">Resources</h2>
<p>Please find the project illustrating this article on my Github, <a target="_blank" href="https://github.com/yblossier/custom-webconfig-section/">here</a>.</p>
<hr />
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>Hi, I'm Yoann. I work as a full-stack developer, solution architect.</p>
<p>If you enjoyed this article, you might enjoy my other content, too.</p>
<p><strong>Github:</strong><a target="_blank" href="https://github.com/yblossier">yblossier</a></p>
<p><strong>LinkedIn:</strong><a target="_blank" href="https://linkedin.com/in/yoannblossier"><strong>/in/yoannblossier</strong></a></p>
<p><strong>Buy Me A Coffee:</strong><a target="_blank" href="https://www.buymeacoffee.com/yoannblossier">A special thank you for your support</a><strong>🍵</strong></p>
<p>Thank you for joining me today.</p>
<p>Yoann</p>
]]></content:encoded></item><item><title><![CDATA[REST API - Use EF Core to create a paged endpoint quickly]]></title><description><![CDATA[There is often the question from my colleagues about how to do a quick paged requests on records without typing a lot of SQL code in stored procedure or in code by filtering a collection of records.
The answer for this question comes with EF Core but...]]></description><link>https://blog.toenn-vaot.fr/rest-api-use-ef-core-to-create-a-paged-endpoint-quickly</link><guid isPermaLink="true">https://blog.toenn-vaot.fr/rest-api-use-ef-core-to-create-a-paged-endpoint-quickly</guid><category><![CDATA[.NET]]></category><category><![CDATA[API basics ]]></category><category><![CDATA[Pagination]]></category><category><![CDATA[entity framework]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Yoann Blossier]]></dc:creator><pubDate>Mon, 19 Feb 2024 00:03:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cckf4TsHAuw/upload/635b9a8a3855943e61bdc27447930e29.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There is often the question from my colleagues about how to do a quick paged requests on records without typing a lot of SQL code in stored procedure or in code by filtering a collection of records.</p>
<p>The answer for this question comes with EF Core but Entity Framework in general.</p>
<h2 id="heading-create-the-api-project">Create the API project</h2>
<ol>
<li><p>Open Visual Studio 2022</p>
</li>
<li><p>Create a new project (File / New / Project...)</p>
</li>
<li><p>Choose ASP.Net Core Web API (native AOT) to create a minimal API project</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708297635419/b6e20f2e-68b5-426d-8f4c-7d405de0b44d.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>I let you named and store it wherever you want</p>
</li>
<li><p>The project is now created. Now go on the endpoint creation.</p>
</li>
</ol>
<h2 id="heading-create-the-list-of-records">Create the list of records</h2>
<ol>
<li><p>Add the nuget package <strong>Swashbuckle.AspNetCore</strong> to the project.</p>
</li>
<li><p>Change the <strong>Program</strong> method by this one below</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-keyword">var</span> builder = WebApplication.CreateSlimBuilder(args);

        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        builder.Services.ConfigureHttpJsonOptions(options =&gt;
        {
            options.SerializerOptions.TypeInfoResolverChain.Insert(<span class="hljs-number">0</span>, AppJsonSerializerContext.Default);
        });

        <span class="hljs-keyword">var</span> app = builder.Build();
        app.UseSwagger();
        app.UseSwaggerUI();

        <span class="hljs-keyword">var</span> sampleTodos = <span class="hljs-keyword">new</span> Todo[] {
            <span class="hljs-keyword">new</span>(<span class="hljs-number">1</span>, <span class="hljs-string">"Walk the dog"</span>),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">2</span>, <span class="hljs-string">"Do the dishes"</span>, DateOnly.FromDateTime(DateTime.Now)),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">3</span>, <span class="hljs-string">"Do the laundry"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">1</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">4</span>, <span class="hljs-string">"Clean the bathroom"</span>),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">5</span>, <span class="hljs-string">"Clean the car"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">2</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">6</span>, <span class="hljs-string">"Buy vegetables to the grocery"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">1</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">7</span>, <span class="hljs-string">"Buy clothes for the wedding"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">15</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">8</span>, <span class="hljs-string">"Clean the bedroom"</span>),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">9</span>, <span class="hljs-string">"Mooing the lawn"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">2</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">10</span>, <span class="hljs-string">"Cut the rose bushes"</span>, DateOnly.FromDateTime(DateTime.Now.AddDays(<span class="hljs-number">2</span>))),
            <span class="hljs-keyword">new</span>(<span class="hljs-number">11</span>, <span class="hljs-string">"Cut the wood to prepare the winter"</span>),
        };

        <span class="hljs-keyword">var</span> todosApi = app.MapGroup(<span class="hljs-string">"/todos"</span>);
        todosApi.MapGet(<span class="hljs-string">"/"</span>, () =&gt; sampleTodos);
        todosApi.MapGet(<span class="hljs-string">"/{id}"</span>, (<span class="hljs-keyword">int</span> id) =&gt; sampleTodos.FirstOrDefault(a =&gt; a.Id == id) <span class="hljs-keyword">is</span> { } todo ? Results.Ok(todo) : Results.NotFound());

        app.Run();
    }
}
</code></pre>
<ol>
<li><p>Now we have a little collection of records with a Swagger user-interface to display the API</p>
</li>
<li><p>In the .csproj, add the <strong>JsonSerializerIsReflectionEnabledByDefault</strong> tag to let Swagger auto-discover and serialize the objects</p>
</li>
</ol>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    ...
    <span class="hljs-tag">&lt;<span class="hljs-name">PublishAot</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">PublishAot</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">JsonSerializerIsReflectionEnabledByDefault</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">JsonSerializerIsReflectionEnabledByDefault</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Swashbuckle.AspNetCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"6.5.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<ol>
<li><p>Open the <strong>launchSettings.json</strong> file in the <em>Properties</em> folder and change the <em>launchUrl</em> to <strong>swagger</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708298206333/696b1566-1cca-4233-8da4-9c1e64496a4b.png" alt /></p>
</li>
</ol>
<pre><code class="lang-json">{
  <span class="hljs-attr">"$schema"</span>: <span class="hljs-string">"http://json.schemastore.org/launchsettings.json"</span>,
  <span class="hljs-attr">"profiles"</span>: {
    <span class="hljs-attr">"http"</span>: {
      <span class="hljs-attr">"commandName"</span>: <span class="hljs-string">"Project"</span>,
      <span class="hljs-attr">"dotnetRunMessages"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"launchBrowser"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"launchUrl"</span>: <span class="hljs-string">"swagger"</span>,
      <span class="hljs-attr">"applicationUrl"</span>: <span class="hljs-string">"http://localhost:5241"</span>,
      <span class="hljs-attr">"environmentVariables"</span>: {
        <span class="hljs-attr">"ASPNETCORE_ENVIRONMENT"</span>: <span class="hljs-string">"Development"</span>
      }
    }
  }
}
</code></pre>
<ol>
<li>Launch the application</li>
</ol>
<h2 id="heading-create-the-endpoint-for-paged-list-of-records">Create the endpoint for paged list of records</h2>
<p>In the <strong>Program</strong> method, under the declared endpoints, add this line.</p>
<pre><code class="lang-csharp">todosApi.MapGet(<span class="hljs-string">"/page/{page}"</span>, (<span class="hljs-keyword">int</span> page) =&gt; sampleTodos.Skip((page - <span class="hljs-number">1</span>) * <span class="hljs-number">5</span>).Take(<span class="hljs-number">5</span>).ToArray() <span class="hljs-keyword">is</span>  { } todos ? Results.Ok(todos) : Results.NotFound() );
</code></pre>
<blockquote>
<p>Wow, only this code !</p>
</blockquote>
<p>Yes, let me detailed what we have done here !</p>
<ol>
<li><p>We add a new endpoint answering to the URL <em>https://&lt;hosturl:port&gt;/todos/page/&lt;pageid&gt;</em></p>
</li>
<li><p>We declare a new function with only the parameter page and where is role is to return the records of the requested page identifier</p>
</li>
<li><p>The body of the function, the real subject here :</p>
</li>
</ol>
<pre><code class="lang-csharp">sampleTodos.Skip((page - <span class="hljs-number">1</span>) * <span class="hljs-number">5</span>).Take(<span class="hljs-number">5</span>).ToArray()
</code></pre>
<p>Here, we will consider a page will contain only 5 records</p>
<p>Thanks to Entity Framework we can call the function <em>Skip()</em> on the collection <strong>sampleTodos</strong> to avoid the selection of the X first records of the collection. X is the number of records of the previous page we want to skip.</p>
<p>And just after skipping the first records, we call the function Take() on the result to only get the 5 records of the page. This function will take 5 records at maximum so even a page have less records it will works.</p>
<p>Thank you Entity Framework 😊</p>
<ol>
<li>Launch the application and try yourself with the new endpoint.</li>
</ol>
<hr />
<h2 id="heading-lets-connect"><strong>Let's Connect!</strong></h2>
<p>Hi, I'm Yoann. I work as a full-stack developer, solution architect.</p>
<p>If you enjoyed this article, you might enjoy my other content, too.</p>
<p><strong>Github:</strong> <a target="_blank" href="https://github.com/yblossier">yblossier</a></p>
<p><strong>LinkedIn:</strong> <a target="_blank" href="https://linkedin.com/in/yoannblossier"><strong>/in/yoannblossier</strong></a></p>
<p><strong>Buy Me A Coffee:</strong> <a target="_blank" href="https://www.buymeacoffee.com/yoannblossier">A special thank you for your support</a> <strong>🍵</strong></p>
<p>Thank you for joining me today.</p>
<p>Yoann</p>
]]></content:encoded></item></channel></rss>