<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dipendra Neupane</title>
    <description>The latest articles on DEV Community by Dipendra Neupane (@dneupane).</description>
    <link>https://dev.to/dneupane</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F62717%2F5bbf4b70-c2b6-4b51-b254-e8aec4796adc.png</url>
      <title>DEV Community: Dipendra Neupane</title>
      <link>https://dev.to/dneupane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dneupane"/>
    <language>en</language>
    <item>
      <title>Before you blame EF Core for a slow API, check this.</title>
      <dc:creator>Dipendra Neupane</dc:creator>
      <pubDate>Sat, 17 Oct 2026 03:12:29 +0000</pubDate>
      <link>https://dev.to/dneupane/before-you-blame-ef-core-for-a-slow-api-check-this-446</link>
      <guid>https://dev.to/dneupane/before-you-blame-ef-core-for-a-slow-api-check-this-446</guid>
      <description>&lt;p&gt;"The query is slow" is one of the most common misdiagnoses I see. Often, the query is fine, and the problem lies elsewhere. Next time you hit a slow endpoint, check these too.&lt;/p&gt;

&lt;p&gt;⚡𝗧𝗵𝗿𝗲𝗮𝗱 𝗽𝗼𝗼𝗹 𝘀𝘁𝗮𝗿𝘃𝗮𝘁𝗶𝗼𝗻&lt;/p&gt;

&lt;p&gt;You call DoSomethingAsync() and then block on it with .Wait() or .Result. That thread now sits there waiting, and another thread from the pool may be needed to finish the async work.&lt;/p&gt;

&lt;p&gt;Under a burst of requests, this quickly eats up thread pool threads, and the whole API slows down, not just that endpoint.&lt;/p&gt;

&lt;p&gt;⚡𝗖𝗼𝗻𝗻𝗲𝗰𝘁𝗶𝗼𝗻 𝗽𝗼𝗼𝗹 𝗲𝘅𝗵𝗮𝘂𝘀𝘁𝗶𝗼𝗻&lt;/p&gt;

&lt;p&gt;Quite similar to thread pool starvation, but for database connections. Once the app has used up every available connection, new requests have to wait for one to free up. The query itself might take 5ms, but the request waits seconds before it even runs.&lt;/p&gt;

&lt;p&gt;Common causes: connections or DbContexts not disposed properly, long-running queries, or a pool size that's too small for your load.&lt;/p&gt;

&lt;p&gt;⚡𝗟𝗼𝗰𝗸𝗶𝗻𝗴 𝗮𝗻𝗱 𝗯𝗹𝗼𝗰𝗸𝗶𝗻𝗴&lt;/p&gt;

&lt;p&gt;Locking is normal. SQL Server locks data while a transaction works with it, so another transaction can't make a conflicting change at the same time.&lt;/p&gt;

&lt;p&gt;Blocking is when another transaction has to wait for that lock. A little is fine. It becomes a problem when a transaction holds the lock for too long, and your "slow" query is really just stuck in a queue.&lt;/p&gt;

&lt;p&gt;⚡𝗦𝗲𝗿𝗶𝗮𝗹𝗶𝘇𝗮𝘁𝗶𝗼𝗻&lt;/p&gt;

&lt;p&gt;Turning a large or deeply nested object into JSON takes time. Returning entities directly is a common trap because navigation properties can pull in huge object graphs. Return DTOs with only what the client needs.&lt;/p&gt;

&lt;p&gt;⚡𝗛𝗶𝗱𝗱𝗲𝗻 𝗽𝗲𝗿-𝗿𝗲𝗾𝘂𝗲𝘀𝘁 𝘄𝗼𝗿𝗸&lt;/p&gt;

&lt;p&gt;Before a request reaches your controller, it may already go through logging, tracing, auth checks, and other middleware. After the controller, there's serialization, response logging, and so on.&lt;/p&gt;

&lt;p&gt;Most of this is necessary. But an expensive logging setup or one extra DB call in an auth handler runs on every single request. Know what happens before and after your code runs.&lt;/p&gt;

&lt;p&gt;There's still plenty to tune inside EF Core itself. But knowing where else time goes is what makes debugging faster.&lt;/p&gt;

&lt;p&gt;What's the strangest cause you've found behind a "slow query"?&lt;/p&gt;

&lt;p&gt;I share more engineering notes and production lessons on LinkedIn: &lt;a href="https://www.linkedin.com/in/dipneupane" rel="noopener noreferrer"&gt;Dipendra Neupane.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>performance</category>
    </item>
    <item>
      <title>𝗪𝗵𝗮𝘁 𝘄𝗼𝗿𝗸𝘀 𝗳𝗼𝗿 𝗦𝗶𝗴𝗻𝗮𝗹𝗥 𝗹𝗼𝗰𝗮𝗹𝗹𝘆 𝗰𝗮𝗻 𝗳𝗮𝗶𝗹 𝗶𝗻 𝗽𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻</title>
      <dc:creator>Dipendra Neupane</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:28:14 +0000</pubDate>
      <link>https://dev.to/dneupane/-3khm</link>
      <guid>https://dev.to/dneupane/-3khm</guid>
      <description>&lt;p&gt;Here's what I've learned while taking SignalR web applications from local development to production.&lt;/p&gt;

&lt;p&gt;⚡𝗔𝘂𝘁𝗵 𝘄𝗼𝗿𝗸𝘀 𝗱𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝘁𝗹𝘆.&lt;/p&gt;

&lt;p&gt;Browsers don't let the client set the Authorization header on the WebSocket handshake, so the access token goes in the query string.&lt;/p&gt;

&lt;p&gt;⚡𝗜𝘁 𝗰𝗮𝗻 𝗳𝗮𝗹𝗹 𝗯𝗮𝗰𝗸 𝗳𝗿𝗼𝗺 𝗪𝗲𝗯𝗦𝗼𝗰𝗸𝗲𝘁𝘀 𝘄𝗶𝘁𝗵𝗼𝘂𝘁 𝗯𝗿𝗲𝗮𝗸𝗶𝗻𝗴 𝘆𝗼𝘂𝗿 𝗮𝗽𝗽.&lt;/p&gt;

&lt;p&gt;Locally, you may be using WebSockets without realizing it. In production, a missing IIS WebSocket feature can prevent WebSockets from being used.&lt;/p&gt;

&lt;p&gt;SignalR can then fall back to Server-Sent Events or Long Polling.&lt;/p&gt;

&lt;p&gt;⚡𝗜𝗻𝗰𝗼𝗺𝗶𝗻𝗴 𝗺𝗲𝘀𝘀𝗮𝗴𝗲𝘀 𝗮𝗿𝗲 𝗹𝗶𝗺𝗶𝘁𝗲𝗱 𝘁𝗼 𝟯𝟮 𝗞𝗕 𝗯𝘆 𝗱𝗲𝗳𝗮𝘂𝗹𝘁.&lt;/p&gt;

&lt;p&gt;SignalR's maximum receive message size defaults to 32 KB for a single incoming hub message. If it exceeds this limit, SignalR throws an error, and the connection is closed.&lt;/p&gt;

&lt;p&gt;You can increase the message size limit, but blindly increasing it will also increase memory usage.&lt;/p&gt;

&lt;p&gt;⚡𝗜𝘁 𝘄𝗼𝗿𝗸𝘀 𝘄𝗶𝘁𝗵 𝗼𝗻𝗲 𝘀𝗲𝗿𝘃𝗲𝗿, 𝘁𝗵𝗲𝗻 𝗯𝗿𝗲𝗮𝗸𝘀 𝘄𝗵𝗲𝗻 𝘆𝗼𝘂 𝘀𝗰𝗮𝗹𝗲.&lt;/p&gt;

&lt;p&gt;With multiple API instances, each SignalR connection belongs to a specific server. If another instance sends a message, it doesn’t automatically know about the connections on the other servers.&lt;/p&gt;

&lt;p&gt;If your SignalR server is running behind a load balancer, plan for cross-server message distribution using a backplane such as Redis or Azure SignalR Service.&lt;/p&gt;

&lt;p&gt;The irony is, I switched to Ably after learning all of these hard lessons.&lt;/p&gt;

&lt;p&gt;What's the hardest SignalR issue you've hit in production?&lt;/p&gt;

&lt;p&gt;I share more engineering notes and production lessons on LinkedIn: &lt;a href="https://www.linkedin.com/in/dipneupane" rel="noopener noreferrer"&gt;Dipendra Neupane&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>devops</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Webhooks Aren't Notifications. They're Distributed Systems.</title>
      <dc:creator>Dipendra Neupane</dc:creator>
      <pubDate>Thu, 08 Oct 2026 18:40:52 +0000</pubDate>
      <link>https://dev.to/dneupane/webhooks-arent-notifications-theyre-distributed-systems-17e8</link>
      <guid>https://dev.to/dneupane/webhooks-arent-notifications-theyre-distributed-systems-17e8</guid>
      <description>&lt;p&gt;Here are a few lessons I learned while working with Stripe Webhooks in production.&lt;/p&gt;

&lt;p&gt;⚡𝗬𝗼𝘂𝗿 𝗛𝗧𝗧𝗣 𝘀𝘁𝗮𝘁𝘂𝘀 𝗰𝗼𝗱𝗲 𝗶𝘀 𝘆𝗼𝘂𝗿 𝗿𝗲𝘁𝗿𝘆 𝗽𝗼𝗹𝗶𝗰𝘆.&lt;/p&gt;

&lt;p&gt;Returning 200 tells Stripe the event was received and processed successfully. Stripe won't retry it again. &lt;/p&gt;

&lt;p&gt;If your business logic fails, you should return a 5xx status code so that Stripe automatically retries the event delivery&lt;/p&gt;

&lt;p&gt;⚡𝗧𝗵𝗲 𝗲𝘃𝗲𝗻𝘁 𝘆𝗼𝘂 𝗿𝗲𝗰𝗲𝗶𝘃𝗲 𝗶𝘀 𝗮 𝗵𝗶𝗻𝘁, 𝗻𝗼𝘁 𝘁𝗵𝗲 𝘁𝗿𝘂𝘁𝗵.&lt;/p&gt;

&lt;p&gt;Webhook events may arrive late or out of order. Don't trust the payload. Refetch the current state from a source of truth and act accordingly.&lt;/p&gt;

&lt;p&gt;⚡𝗗𝗼𝗻'𝘁 𝗱𝗼 𝘀𝗹𝗼𝘄 𝘄𝗼𝗿𝗸 𝗶𝗻𝘀𝗶𝗱𝗲 𝘁𝗵𝗲 𝗪𝗲𝗯𝗵𝗼𝗼𝗸 𝗲𝘃𝗲𝗻𝘁.&lt;/p&gt;

&lt;p&gt;Stripe has a timeout threshold. If the endpoint doesn't respond quickly enough, Stripe considers it a failure and retries.&lt;/p&gt;

&lt;p&gt;Process the slow work asynchronously outside the webhook handler.&lt;/p&gt;

&lt;p&gt;Do you have any hard-learned lessons about Webhooks or Stripe? I'd love to know about that.&lt;/p&gt;

&lt;p&gt;I share more engineering notes and production lessons on LinkedIn: &lt;a href="https://www.linkedin.com/in/dipneupane" rel="noopener noreferrer"&gt;Dipendra Neupane&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webhook</category>
      <category>stripe</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
