<?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: QueryWrangler</title>
    <description>The latest articles on DEV Community by QueryWrangler (@querywrangler).</description>
    <link>https://dev.to/querywrangler</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%2F4019788%2Fc1c52f36-6203-467a-a53d-c01086b46f2c.png</url>
      <title>DEV Community: QueryWrangler</title>
      <link>https://dev.to/querywrangler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/querywrangler"/>
    <language>en</language>
    <item>
      <title>Silent Login Failures After Every Azure Deploy? Check Your Data Protection Keys</title>
      <dc:creator>QueryWrangler</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:11:36 +0000</pubDate>
      <link>https://dev.to/querywrangler/silent-login-failures-after-every-azure-deploy-check-your-data-protection-keys-470i</link>
      <guid>https://dev.to/querywrangler/silent-login-failures-after-every-azure-deploy-check-your-data-protection-keys-470i</guid>
      <description>&lt;p&gt;If your ASP.NET Core app on Azure App Service randomly logs everyone out — or breaks anti-forgery tokens — after every deployment or restart, and there's no error message telling you why, there's a good chance the culprit is where your Data Protection keys are stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;Everything works fine right after a deploy. Then, at some point — after a restart, a scale event, or the next deployment — users start getting logged out unexpectedly, or you see anti-forgery token validation failures with no obvious cause. There's no clear exception pointing at the real problem. Cookies just silently stop validating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong assumption
&lt;/h2&gt;

&lt;p&gt;The natural assumption is that ASP.NET Core's Data Protection system — which encrypts things like auth cookies and anti-forgery tokens — just works out of the box in Azure App Service, the same way it does in local development.&lt;/p&gt;

&lt;p&gt;By default, it doesn't persist the way you'd expect in a cloud hosting environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core's Data Protection system generates a set of cryptographic keys used to protect cookies and tokens. If those keys aren't stored somewhere stable, every time the app restarts, scales out to another instance, or gets redeployed, it can end up with a &lt;em&gt;different&lt;/em&gt; set of keys than before — which means anything encrypted with the old keys (existing auth cookies, anti-forgery tokens) suddenly fails to validate. Azure App Service's default file system behavior doesn't guarantee key persistence across these events the way a traditional single-server deployment would.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Explicitly persist the Data Protection keys to a stable location — the App Service's &lt;code&gt;HOME&lt;/code&gt; directory works well, since it's persisted storage that survives restarts and deployments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDataProtection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PersistKeysToFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DirectoryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HOME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;@"\ASP.NET\DataProtection-Keys"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetApplicationName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YourAppName"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting an explicit &lt;code&gt;ApplicationName&lt;/code&gt; is also worth doing — it keeps the key ring scoped correctly if you ever have multiple apps sharing the same underlying storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;Anywhere your ASP.NET Core app runs across multiple instances, restarts, or redeployments — which is essentially every cloud hosting scenario — Data Protection key persistence isn't optional, even though the framework won't warn you about it. The failure mode is especially nasty because there's no exception with a clear cause; it just looks like intermittent, unexplainable auth problems. If you're seeing silent logouts or anti-forgery failures that seem to correlate with deploys or restarts, this is the first place to look.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>azure</category>
      <category>security</category>
    </item>
    <item>
      <title>5 Lessons from Migrating a Legacy WPF Desktop App to the Cloud</title>
      <dc:creator>QueryWrangler</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:08:27 +0000</pubDate>
      <link>https://dev.to/querywrangler/5-lessons-from-migrating-a-legacy-wpf-desktop-app-to-the-cloud-17g9</link>
      <guid>https://dev.to/querywrangler/5-lessons-from-migrating-a-legacy-wpf-desktop-app-to-the-cloud-17g9</guid>
      <description>&lt;p&gt;Migrating a legacy WPF desktop application to a cloud-based web platform is one of those projects that sounds straightforward in a planning meeting and turns out to be full of quiet traps in practice. Here are the lessons that mattered most.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The old app's UI logic is really business logic in disguise
&lt;/h2&gt;

&lt;p&gt;Desktop apps built over many years tend to accumulate business rules directly inside event handlers and code-behind — validation, workflow decisions, calculations — because there was never a strong reason to separate them. When you move to the web, you can't just "reskin" the UI; you have to excavate the actual business logic buried inside years of button-click handlers first. Budget real time for this. It's usually much bigger than it looks from the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Feature parity is a moving target, not a checklist
&lt;/h2&gt;

&lt;p&gt;It's tempting to treat migration as "make the new thing do everything the old thing did." In practice, users only really tell you about the features they use &lt;em&gt;after&lt;/em&gt; they hit a gap in the new system. Plan for an extended period of "wait, we also need X" discoveries, even after what felt like thorough requirements gathering.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Authentication and session models don't translate directly
&lt;/h2&gt;

&lt;p&gt;A desktop app running under a Windows user's identity has a completely different security model than a web app serving many concurrent users over HTTP. Single sign-on, token-based auth, and session/state management all need to be rebuilt from first principles — not adapted from whatever the desktop app was doing, because in most cases it wasn't doing anything comparable at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Your database becomes a shared, concurrent resource for the first time
&lt;/h2&gt;

&lt;p&gt;Desktop apps often assume single-user or low-concurrency access patterns, even when technically pointed at a shared backend. Moving to the web means real concurrent access, and that surfaces problems the old app never had to deal with — race conditions, locking assumptions, and queries that were "fast enough" for one user at a time but not for many.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The migration is also a chance to fix years of small compromises
&lt;/h2&gt;

&lt;p&gt;Every legacy system carries small workarounds — a field repurposed for something it wasn't meant for, a status value that means three different things depending on context. Migration forces you to look directly at these because you have to explain them to a new codebase. Treat that as an opportunity, not just overhead: cleaning up a handful of these quietly pays for itself many times over during the life of the new system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;A desktop-to-cloud migration is rarely just a technology swap. It's an opportunity to separate business logic from UI, rebuild security properly for a multi-user world, and confront the small inherited compromises that never got addressed the first time around. The projects that go well treat it as an architectural rewrite with a familiar UI on top — not a lift-and-shift with a new coat of paint.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>dotnet</category>
      <category>cloud</category>
    </item>
    <item>
      <title>JWT Validation Against an RSA Public Key: The ValidAlgorithms Gotcha</title>
      <dc:creator>QueryWrangler</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:06:10 +0000</pubDate>
      <link>https://dev.to/querywrangler/jwt-validation-against-an-rsa-public-key-the-validalgorithms-gotcha-15k5</link>
      <guid>https://dev.to/querywrangler/jwt-validation-against-an-rsa-public-key-the-validalgorithms-gotcha-15k5</guid>
      <description>&lt;p&gt;If you're validating JWTs signed with RSA in .NET and getting a signature validation failure even though you're &lt;em&gt;certain&lt;/em&gt; the public key is correct, there's a good chance the problem isn't your key at all — it's how you've configured &lt;code&gt;ValidAlgorithms&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;You set up token validation like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;validationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ValidateIssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rsaSecurityKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ValidAlgorithms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"RS256"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other parameters&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The public key is correct. You've verified it against the signing certificate. And yet token validation still fails with a signature error, as if the key were wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong assumption
&lt;/h2&gt;

&lt;p&gt;The natural assumption is that &lt;code&gt;"RS256"&lt;/code&gt; is &lt;code&gt;"RS256"&lt;/code&gt; — a single, standard algorithm identifier that any RSA-signed JWT will use, and any validator will recognize.&lt;/p&gt;

&lt;p&gt;Not every token issuer sends that identifier in the same format.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;Some identity providers — particularly older or WCF-based token services — express the signing algorithm as a full URI rather than the short JWT-standard name. Instead of &lt;code&gt;"RS256"&lt;/code&gt;, the token's header may specify something like &lt;code&gt;"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"&lt;/code&gt;. If your &lt;code&gt;ValidAlgorithms&lt;/code&gt; list only contains the short-form name, tokens signed with the URI-form algorithm identifier get rejected outright — even though the actual cryptographic signature is completely valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Include both the short-form and URI-form algorithm identifiers in &lt;code&gt;ValidAlgorithms&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;validationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ValidateIssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rsaSecurityKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ValidAlgorithms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"RS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other parameters&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once both forms are present, tokens get validated correctly regardless of which identifier format the issuing service used to describe its signing algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;If you're integrating JWT validation with an identity provider you don't fully control — especially anything with roots in WCF or older enterprise SSO systems — don't assume the algorithm identifier will always arrive in the modern short form. Check the actual token header (a JWT decoder makes this trivial) before assuming your key or your validation logic is at fault. A "signature invalid" error can be entirely about algorithm identifier mismatch, with the signature itself being perfectly fine.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>security</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Getting Auto-Generated IDs Back from Oracle in .NET: The RETURNING INTO Trap</title>
      <dc:creator>QueryWrangler</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:01:07 +0000</pubDate>
      <link>https://dev.to/querywrangler/getting-auto-generated-ids-back-from-oracle-in-net-the-returning-into-trap-cc1</link>
      <guid>https://dev.to/querywrangler/getting-auto-generated-ids-back-from-oracle-in-net-the-returning-into-trap-cc1</guid>
      <description>&lt;p&gt;If you've ever inserted a row into Oracle from .NET and needed the auto-generated ID back immediately — say, to use in a follow-up insert — you've probably reached for &lt;code&gt;RETURNING INTO&lt;/code&gt;. And you've probably also hit a confusing type mismatch or invalid cast error trying to read the value back out. Here's why, and the fix that actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;You write an insert like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INSERT INTO MY_TABLE (NAME) VALUES (:p_name) RETURNING ID INTO :p_id"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;idParam&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OracleDbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParameterDirection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idParam&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;idParam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- blows up here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It compiles fine. It runs without SQL errors. And then the cast to &lt;code&gt;int&lt;/code&gt; throws — or worse, silently gives you a value that doesn't behave the way you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong assumption
&lt;/h2&gt;

&lt;p&gt;The natural assumption is that an Oracle &lt;code&gt;NUMBER&lt;/code&gt; column maps cleanly to a .NET &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;decimal&lt;/code&gt;, the same way it would with most other databases — declare the output parameter type, cast the result, done.&lt;/p&gt;

&lt;p&gt;Oracle's &lt;code&gt;NUMBER&lt;/code&gt; type doesn't map that simply through &lt;code&gt;OracleDbType.Int32&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;Oracle's &lt;code&gt;NUMBER&lt;/code&gt; type is really a variable-precision decimal, not a fixed-width integer. When you bind an output parameter as &lt;code&gt;OracleDbType.Int32&lt;/code&gt;, you're asking ODP.NET to coerce Oracle's native numeric representation into a shape it doesn't naturally fit — which is where the cast failures and unexpected values creep in, especially once IDs get large or the underlying sequence has any quirks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Bind the output parameter as &lt;code&gt;OracleDbType.Decimal&lt;/code&gt;, and cast through &lt;code&gt;OracleDecimal&lt;/code&gt; instead of straight to &lt;code&gt;int&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INSERT INTO MY_TABLE (NAME) VALUES (:p_name) RETURNING ID INTO :p_id"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;idParam&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OracleDbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParameterDirection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idParam&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;OracleDecimal&lt;/span&gt; &lt;span class="n"&gt;oracleId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OracleDecimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;idParam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oracleId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToInt32&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// clean, safe conversion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going through &lt;code&gt;OracleDecimal&lt;/code&gt; respects Oracle's actual numeric type instead of fighting it, and gives you a safe, explicit path to whatever .NET type you actually need afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;Any time you're pulling a value back out of Oracle via &lt;code&gt;RETURNING INTO&lt;/code&gt;, default to &lt;code&gt;OracleDbType.Decimal&lt;/code&gt; for numeric columns and cast through &lt;code&gt;OracleDecimal&lt;/code&gt;, rather than assuming a direct match to &lt;code&gt;Int32&lt;/code&gt; or &lt;code&gt;Int64&lt;/code&gt;. It's a small pattern, but it's the difference between a clean insert-and-return flow and a cryptic runtime cast exception that has nothing to do with your actual logic.&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>The ORA-01008 Trap: Why Your Oracle .NET Bind Variables Keep Failing</title>
      <dc:creator>QueryWrangler</dc:creator>
      <pubDate>Tue, 07 Jul 2026 14:59:45 +0000</pubDate>
      <link>https://dev.to/querywrangler/the-ora-01008-trap-why-your-oracle-net-bind-variables-keep-failing-3f58</link>
      <guid>https://dev.to/querywrangler/the-ora-01008-trap-why-your-oracle-net-bind-variables-keep-failing-3f58</guid>
      <description>&lt;p&gt;If you've worked with Oracle.ManagedDataAccess in .NET and hit &lt;code&gt;ORA-01008: not all variables bound&lt;/code&gt; on a query that looks completely correct, you're not alone. This one cost me hours across a service with two dozen separate database calls — and the fix, once you see it, is almost embarrassingly simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;You write a query like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM MY_TABLE WHERE ID = :p_id AND STATUS = :p_status"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks right. The parameter names match the bind variables. And yet: &lt;code&gt;ORA-01008: not all variables bound&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong assumption
&lt;/h2&gt;

&lt;p&gt;The natural assumption is that Oracle matches parameters to bind variables by position — same as it would with a plain ADO.NET provider talking to SQL Server. So if you've added your parameters in the same order they appear in the SQL, you'd expect it to just work.&lt;/p&gt;

&lt;p&gt;Oracle.ManagedDataAccess doesn't default to that behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;By default, OracleCommand in Oracle.ManagedDataAccess binds parameters by position, not by name — but only if you don't explicitly say otherwise. The moment your parameter count or order drifts even slightly from the SQL text (which happens easily once queries get edited, reordered, or grow additional conditions over time), the binding silently breaks, and you get ORA-01008.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Set &lt;code&gt;BindByName = true&lt;/code&gt; explicitly on every command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM MY_TABLE WHERE ID = :p_id AND STATUS = :p_status"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindByName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- this line saves you hours&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OracleParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"p_status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once &lt;code&gt;BindByName = true&lt;/code&gt; is set, Oracle matches parameters to bind variables by their names, not their position — which matches how everyone actually reads and writes the SQL. Order stops mattering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;If you're working with Oracle.ManagedDataAccess in any non-trivial .NET application, make &lt;code&gt;BindByName = true&lt;/code&gt; a non-negotiable line in every single command — consider wrapping it into a base helper or extension method so it's impossible to forget. One missed instance in a codebase with dozens of Oracle calls is all it takes to lose an afternoon to a cryptic error that has nothing to do with your actual SQL.&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
