<?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" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Rajasekar Newsletter ]]></title><description><![CDATA[I write about .NET, C#, WebAPI, SQL, Entity Framework, Clean code, Software engineering, and more every week]]></description><link>https://rajasekarsu.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!LtVX!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab853350-fe65-4716-bffa-158cf0bb55fe_500x500.png</url><title>Rajasekar Newsletter </title><link>https://rajasekarsu.substack.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 24 Jun 2026 22:09:33 GMT</lastBuildDate><atom:link href="https://rajasekarsu.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rajasekar]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[rajasekarsu@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[rajasekarsu@substack.com]]></itunes:email><itunes:name><![CDATA[Rajasekar Su]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rajasekar Su]]></itunes:author><googleplay:owner><![CDATA[rajasekarsu@substack.com]]></googleplay:owner><googleplay:email><![CDATA[rajasekarsu@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rajasekar Su]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Stop the Clash: Simple Guide to EF Core Concurrency]]></title><description><![CDATA[What is "concurrency"?]]></description><link>https://rajasekarsu.substack.com/p/ef-core-concurrency-guide</link><guid isPermaLink="false">https://rajasekarsu.substack.com/p/ef-core-concurrency-guide</guid><dc:creator><![CDATA[Rajasekar Su]]></dc:creator><pubDate>Mon, 23 Feb 2026 09:46:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LtVX!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab853350-fe65-4716-bffa-158cf0bb55fe_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What is "concurrency"?</h2><p>Concurrency happens when <strong>two users change the same row at the same time</strong>.</p><p>Think of this like two people try to book the <strong>last seat</strong> for a show</p><ul><li><p>User A selects the seat at 10:01.</p></li><li><p>User B selects the same seat at 10:02.</p></li><li><p>Both hit "Book" around the same time.</p></li></ul><p>Only one can win.<br>This is concurrency: <strong>two people acting on the same data</strong>, overlapping in time.</p><h2>When does it happen?</h2><ul><li><p>Two tabs of your app edit the same item.</p></li><li><p>Two services update the same record.</p></li><li><p>A user edits an old page and clicks Save after someone else already saved.</p></li></ul><p>It is common in apps with many users.</p><h2>When do we need to handle it?</h2><ul><li><p>When <strong>losing another person&#8217;s change is not okay</strong>.</p></li><li><p>Orders, money, stock count, booking seats, important text fields.</p></li></ul><h2>When is it not necessary?</h2><ul><li><p>Data that can be rebuilt.</p></li><li><p>Logs, caches, or places where "last save wins" is fine.</p></li><li><p>Solo tools where only one person edits.</p></li></ul><h2>How EF Core helps (the simple idea)</h2><p>EF Core uses <strong>optimistic concurrency</strong> by default.</p><ul><li><p>We <strong>do not lock</strong> the row while reading.</p></li><li><p>We <strong>add a special field</strong> called a <strong>concurrency token</strong> (most common: <code>rowversion</code>).</p></li><li><p>On save, EF checks if that token changed.</p></li><li><p>If it changed, EF throws <code>DbUpdateConcurrencyException</code>.<br>That means: "Somebody else changed this first. Decide what to do."</p></li></ul><p>This avoids silent overwrites.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://rajasekarsu.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Rajasekar Newsletter! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>The easy, safe setup (SQL Server)</h2><h3>Step 1: Add a <code>rowversion</code> column in your model</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">public class Post
{
public int Id { get; set; }
public string Title { get; set; } = "";
public string Content { get; set; } = "";
// EF Core will treat this as a concurrency token
[Timestamp] // or configure via Fluent API
public byte[] RowVersion { get; set; } = Array.Empty&lt;byte&gt;();
}</code></pre></div><p><strong>Fluent API (optional alternative):</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">modelBuilder.Entity&lt;Post&gt;()
.Property(p =&gt; p.RowVersion)
.IsRowVersion();</code></pre></div><p>That&#8217;s it. EF will now include <code>RowVersion</code> in the <code>WHERE</code> clause of the <code>UPDATE</code>.</p><div><hr></div><h2>What happens under the hood?</h2><p>EF Core runs an update like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">UPDATE Posts
SET Title = @p1, Content = @p2
WHERE Id = @id AND RowVersion = @originalRowVersion;</code></pre></div><p>-- If 0 rows updated =&gt; someone else changed it =&gt; throw</p><div><hr></div><h2>EF Core example</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">try
{
  await context.SaveChangesAsync();
  return Results.Ok("Saved");
}

catch (DbUpdateConcurrencyException)
{
  return Results.Conflict("Someone else changed this. Please refresh.");
}</code></pre></div><p>This simple pattern <strong>detects</strong> the conflict. Now let&#8217;s <strong>resolve</strong> it.</p><div><hr></div><h2>Three simple ways to resolve a conflict</h2><blockquote><p>Pick one based on your app&#8217;s rules.</p></blockquote><h3>1) <strong>Store Wins</strong> (refresh, show latest, let user edit again)</h3><p>This is the <strong>safest default</strong> for text fields.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    foreach (var entry in ex.Entries)
    {
        var dbValues = await entry.GetDatabaseValuesAsync();

        if (dbValues is null)
        {
            // Someone deleted it
            entry.State = EntityState.Detached;
        }
        else
        {
            // Load latest values from DB into the entity
            entry.OriginalValues.SetValues(dbValues);
            entry.CurrentValues.SetValues(dbValues);
            entry.State = EntityState.Unchanged;
        }
    }

    // Tell the user "Data changed. Please try again."
    throw; // or return a 409/Conflict
}</code></pre></div><p><strong>Why it&#8217;s good:</strong><br>No one loses data. The user sees the latest copy and tries again.</p><h3>2) <strong>Client Wins</strong> (force your changes to overwrite)</h3><p>Use only when <strong>your update must override</strong>. Be careful.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    foreach (var entry in ex.Entries)
    {
        // Accept that DB has changed; update our Original to DB values,
        // so the next Save will succeed and overwrite
        var dbValues = await entry.GetDatabaseValuesAsync();
        if (dbValues is not null)
        {
            entry.OriginalValues.SetValues(dbValues);
        }
    }

    await context.SaveChangesAsync(); // force overwrite now
}</code></pre></div><p><strong>Warning:</strong> This can erase someone else&#8217;s change.</p><h3>3) <strong>Merge</strong> (pick field by field)</h3><p>Great for rich text or forms. Show "Yours vs Theirs".</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    var entry = ex.Entries.Single();
    var dbValues = await entry.GetDatabaseValuesAsync();
    var clientValues = entry.CurrentValues;

    if (dbValues is null)
    {
        // Deleted by someone else
        entry.State = EntityState.Detached;
        throw;
    }

    // Example rule:
    // Keep my Title, but keep DB Content (just as a demo)
    clientValues["Title"]   = clientValues["Title"];
    clientValues["Content"] = dbValues["Content"];

    // Update Original to DB so next save passes
    entry.OriginalValues.SetValues(dbValues);

    await context.SaveChangesAsync();
}</code></pre></div><p><strong>Tip:</strong> In a UI, show both versions and let the user choose.</p><h2>How to handle Web APIs (disconnected clients)</h2><p>When you <strong>attach</strong> a DTO, you must set the <strong>original</strong> <code>RowVersion</code>, or EF can&#8217;t detect conflicts.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">// dto includes Id, Title, Content, RowVersion
var post = new Post
{
    Id = dto.Id,
    Title = dto.Title,
    Content = dto.Content
};

context.Attach(post);

// This is key: tell EF what the original token was
context.Entry(post).Property(p =&gt; p.RowVersion).OriginalValue = dto.RowVersion;

// Mark which fields changed
context.Entry(post).Property(p =&gt; p.Title).IsModified = true;
context.Entry(post).Property(p =&gt; p.Content).IsModified = true;

await context.SaveChangesAsync();</code></pre></div><h2>When you need locks (rare)</h2><p>If you <strong>must</strong> block others while you work (like a money move), use a <strong>transaction</strong> and a lock hint.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">await using var tx = await context.Database.BeginTransactionAsync();

var item = await context.Posts
    .FromSqlInterpolated($@"
        SELECT * FROM Posts WITH (UPDLOCK, ROWLOCK)
        WHERE Id = {id}")
    .SingleAsync();

item.Title = "Critical update";

await context.SaveChangesAsync();
await tx.CommitAsync();</code></pre></div><p><strong>Use sparingly.</strong> Locks can slow things down or deadlock.</p><h2>Quick checklist</h2><ul><li><p>Add <code>RowVersion</code> (<code>rowversion</code> in SQL Server; mark as <code>[Timestamp]</code>).</p></li><li><p>Catch <code>DbUpdateConcurrencyException</code>.</p></li><li><p>Pick a rule: <strong>Store Wins</strong>, <strong>Client Wins</strong>, or <strong>Merge</strong>.</p></li><li><p>For APIs, <strong>set </strong><code>OriginalValue</code> for the token.</p></li><li><p>Use locks only for <strong>critical</strong> cases.</p></li></ul><h2>Final thoughts</h2><p>Start with <strong>RowVersion</strong> and <strong>Store Wins</strong>.<br>Add a merge screen if users often edit the same fields.<br>Use locks only when you must.</p>]]></content:encoded></item><item><title><![CDATA[Top 10 Tips for Crafting Stellar .NET APIs]]></title><description><![CDATA[Hello together!]]></description><link>https://rajasekarsu.substack.com/p/top-10-tips-for-crafting-stellar-apis</link><guid isPermaLink="false">https://rajasekarsu.substack.com/p/top-10-tips-for-crafting-stellar-apis</guid><dc:creator><![CDATA[Rajasekar Su]]></dc:creator><pubDate>Fri, 05 Jan 2024 18:06:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LtVX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab853350-fe65-4716-bffa-158cf0bb55fe_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello together!</p><p>Welcome you all for my first edition of the newsletter.</p><p>As a full stack developer, I often create APIs using .NET core with the following best practices. </p><p>APIs should be error free, easy to understand/maintain, secure, have reliable performance, developer friendly and much more. Without following any best practices, it is difficult to achieve all the above.</p><p>Designing efficient and maintainable APIs is crucial for the success of any software project. Here are some best practices and tips for designing APIs using .NET</p><ul><li><p><strong>Follow RESTful Principles:</strong></p><ul><li><p>Example: Design resource URIs meaningfully, like <code>/users</code> for user-related operations and <code>/orders</code> for order-related actions.</p></li></ul></li><li><p><strong>Versioning is Key:</strong></p><ul><li><p>Example: Ensure backward compatibility by versioning your API, such as <code>/v1/users</code> and <code>/v2/users</code>.</p></li></ul></li><li><p><strong>Meaningful and Consistent Naming:</strong></p><ul><li><p>Example: Choose clear and consistent names, like <code>GET /products</code> for fetching products.</p></li></ul></li><li><p><strong>Use Standard Data Formats:</strong></p><ul><li><p>Example: Embrace JSON for both request and response payloads to maintain consistency.</p></li></ul></li><li><p><strong>Robust Input Validation:</strong></p><ul><li><p>Example: Validate user input on the server side to prevent injection attacks, ensuring data integrity.</p></li></ul></li><li><p><strong>Effective Error Handling:</strong></p><ul><li><p>Example: Return detailed error messages with appropriate HTTP status codes, like 404 for resource not found.</p></li></ul></li><li><p><strong>Authentication &amp; Authorization:</strong></p><ul><li><p>Example: Implement OAuth (or JWT) for secure token-based authentication and authorize users based on roles.</p></li></ul></li><li><p><strong>Enforce HTTPS:</strong></p><ul><li><p>Example: Protect data transmission by enforcing HTTPS, securing communications between clients and the server.</p></li></ul></li><li><p><strong>Pagination &amp; Filtering:</strong></p><ul><li><p>Example: Implement pagination for large datasets, like <code>/products?page=1&amp;pageSize=10</code> for a paginated product list.</p></li></ul></li><li><p><strong>Comprehensive Documentation:</strong></p><ul><li><p>Example: Create detailed documentation using tools like Swagger, explaining each endpoint, request/response formats, and authentication.</p></li></ul></li></ul><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://rajasekarsu.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Rajasekar Newsletter. Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div>]]></content:encoded></item><item><title><![CDATA[🚀 Just start...]]></title><description><![CDATA[Introduction to my newsletter]]></description><link>https://rajasekarsu.substack.com/p/just-start</link><guid isPermaLink="false">https://rajasekarsu.substack.com/p/just-start</guid><dc:creator><![CDATA[Rajasekar Su]]></dc:creator><pubDate>Fri, 05 Jan 2024 14:42:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f8324f8-48a4-415b-920c-c986e04af464_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128075; <strong>Hello, Awesome Readers!</strong></p><p>Let me Introduce myself and share my story&#8230;!</p><p>I am a .NET software developer based on India (<a href="https://rajasekardev.substack.com/about">Know more about me</a>) with 12+ years of experience and currently working Full-time as a software consultant.  </p><p>I am like most traditional developers, who only work on their jobs and often come online to find solutions for technical issues or learn something which is required for my projects. </p><p>Later I was introduced to twitter where I can see lot of the developers share their coding knowledge through posts, YouTube videos and few shares about their newsletters. Even some developers creating SaaS products and promoting the same.</p><blockquote><p>Now it&#8217;s very clear, I need to jump on the same bandwagon (online tech community). </p></blockquote><p>I explored ways to share my technical knowledge. For example, way back in 2014 I created <em><a href="https://rajasekardev.medium.com/hi-bab06b9e9ab0">my first post</a></em> on Medium, but I was not serious about creating posts. After a few years, I created Ghost blogs on DigitalOcean but that too involves some technical issues (I was trying to blog on sub-folder /blog) and left that idea. Tried blogspot and WordPress but not posting anything on those platforms. </p><p>I was continuing to motivate myself and learning online including <em><a href="https://getinvolved.hanselman.com/">Become a Social Developer!</a> </em>and some other articles. One fine day, I decided to stop exploring the internet for motivation and planned to create something meaningful.</p><p>&#128161;Finally, I created <em><a href="https://rajasekar.dev/">my blog</a></em> on <em><a href="https://hashnode.com/">Hashnode </a></em>and as of now created couple of posts. Simultaneously, I share my blog posts on LinkedIn, twitter, and cross post on dev.to/medium.com.</p><div class="pullquote"><p>As a passionate software developer, in this newsletter I will share valuable tips, tutorials, latest trends and more on .NET development.</p></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://rajasekarsu.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><em>Subscribe to receive new posts and support my work.</em></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Coming soon]]></title><description><![CDATA[This is Rajasekar Newsletter .]]></description><link>https://rajasekarsu.substack.com/p/coming-soon</link><guid isPermaLink="false">https://rajasekarsu.substack.com/p/coming-soon</guid><dc:creator><![CDATA[Rajasekar Su]]></dc:creator><pubDate>Tue, 05 Sep 2023 13:13:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LtVX!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab853350-fe65-4716-bffa-158cf0bb55fe_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Rajasekar Newsletter .</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://rajasekarsu.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://rajasekarsu.substack.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>