<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://codejack.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://codejack.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-10-17T23:49:51-04:00</updated><id>https://codejack.com/feed.xml</id><title type="html">CodeJack</title><subtitle>Programming notes and guides on C#, .NET, Azure, and the Microsoft stack.</subtitle><entry><title type="html">10 Tips for Writing Effective Unit Tests in .NET</title><link href="https://codejack.com/2025/01/10-tips-for-writing-effective-unit-tests-in-net/" rel="alternate" type="text/html" title="10 Tips for Writing Effective Unit Tests in .NET" /><published>2025-01-20T02:00:54-05:00</published><updated>2025-01-20T02:00:54-05:00</updated><id>https://codejack.com/2025/01/10-tips-for-writing-effective-unit-tests-in-net</id><content type="html" xml:base="https://codejack.com/2025/01/10-tips-for-writing-effective-unit-tests-in-net/"><![CDATA[<p><strong>Unit testing in .NET ensures your code works as expected, catches bugs early, and makes updates safer.</strong> Here’s a quick guide to writing better tests:</p>
<ul>
<li><strong>Clear Test Names</strong>: Use descriptive names like <code>CalculatorAdd.DoesReturnCorrectSumGivenTwoPositiveNumbers</code>.</li>
<li><strong>Arrange-Act-Assert</strong>: Structure tests into setup, action, and verification for clarity.</li>
<li><strong>Test One Thing</strong>: Focus each test on a single behavior or scenario.</li>
<li><strong>Edge Cases</strong>: Test nulls, empty values, boundaries, and invalid inputs.</li>
<li><strong>Reliable Tests</strong>: Avoid flaky tests by isolating dependencies and using mocks or stubs.</li>
<li><strong>Mocks and Stubs</strong>: Simulate external dependencies to test your code in isolation.</li>
<li><strong>Exception Handling</strong>: Verify your code handles errors gracefully.</li>
<li><strong>Specific Assertions</strong>: Write clear, focused checks with meaningful failure messages.</li>
<li><strong>Automate Tests</strong>: Integrate tests into CI/CD pipelines for consistent execution.</li>
<li><strong>Keep Tests Updated</strong>: Regularly review and organize tests to reflect code changes.</li>
</ul>
<h2 id="1-use-clear-and-consistent-test-names" tabindex="-1" class="sb">1. Use Clear and Consistent Test Names</h2>
<p>When a test fails, its name should instantly explain what went wrong without needing to dig into the code. A good naming convention highlights the class, method, scenario, and expected result being tested.</p>
<p>In .NET, a common naming format looks like this:</p>
<pre><code>ClassNameMethodName.DoesXGivenY
</code></pre>
<p>For example, instead of a generic name like <code>TestCalculatorAdd</code>, go for something more descriptive like <code>CalculatorAdd.DoesReturnCorrectSumGivenTwoPositiveNumbers</code>. This makes it clear you&#8217;re testing the <code>Add</code> method in the <code>Calculator</code> class with positive numbers as inputs.</p>
<p>For more detailed cases, the Given-When-Then format works well alongside the Arrange-Act-Assert structure (discussed in the next section). Using clear and consistent names not only makes debugging easier but also keeps your tests organized and acts as a form of documentation for how your system behaves.</p>
<p>Test names should also be specific enough to differentiate similar scenarios. For example, <code>CalculatorDivide.ThrowsDivideByZeroException_WhenDivisorIsZero</code> clearly outlines the condition being tested.</p>
<p>Once you&#8217;ve nailed the naming, using the Arrange-Act-Assert pattern will help keep your tests readable and easy to manage.</p>
<h2 id="2-follow-the-arrange-act-assert-pattern" tabindex="-1" class="sb">2. Follow the Arrange, Act, Assert Pattern</h2>
<p>The Arrange, Act, Assert (AAA) pattern is a simple way to organize unit tests, making them easier to read, maintain, and debug. By breaking tests into three clear steps, it becomes much simpler to identify problems when something goes wrong.</p>
<p>Here’s what each step involves:</p>
<ul>
<li><strong>Arrange</strong>: Set up everything needed for the test, like inputs and preconditions.</li>
<li><strong>Act</strong>: Perform the action or call the method you’re testing.</li>
<li><strong>Assert</strong>: Check if the result matches what you expected.</li>
</ul>
<h3 id="example-testing-the-add-method" tabindex="-1">Example: Testing the Add Method</h3>
<p>Let’s say you’re testing the <code>Add</code> method in a Calculator class. Here’s how it might look:</p>
<pre><code class="language-csharp">[TestMethod]
public void TestAddition()
{
    // Arrange
    var calculator = new Calculator();
    var num1 = 5;
    var num2 = 3;

    // Act
    var result = calculator.Add(num1, num2);

    // Assert
    Assert.AreEqual(8, result);
}
</code></pre>
<p>If this test fails, the AAA structure helps you figure out whether the issue is in the setup (Arrange), the action (Act), or the verification (Assert). To keep things clear, always visually separate these three parts, place assertions at the end, and stick to one Act phase per test.</p>
<p>Tools like <a href="https://xunit.net/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">xUnit</a> and <a href="https://nunit.org/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">NUnit</a>, two popular .NET testing frameworks, work well with the AAA pattern and offer helpful attributes and assertions to streamline your testing process <a href="https://ardalis.com/mastering-unit-tests-dotnet-best-practices-naming-conventions/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<h2 id="3-keep-each-test-focused-on-one-thing" tabindex="-1" class="sb">3. Keep Each Test Focused on One Thing</h2>
<p>When writing unit tests, keeping each test focused on a single behavior or scenario is key. This approach makes it easier to pinpoint issues when something goes wrong and keeps your test suite organized.</p>
<p>Here’s an example of a <strong>test that tries to do too much</strong>:</p>
<pre><code class="language-csharp">[TestMethod]
public void CalculatorOperations_MultipleChecks()
{
    var calculator = new Calculator();

    // Testing multiple operations
    var addResult = calculator.Add(5, 3);
    Assert.AreEqual(8, addResult);

    var subtractResult = calculator.Subtract(10, 4);
    Assert.AreEqual(6, subtractResult);

    var multiplyResult = calculator.Multiply(3, 3);
    Assert.AreEqual(9, multiplyResult);
}
</code></pre>
<p>This test mixes several behaviors, making it harder to identify which operation failed if the test doesn’t pass.</p>
<p>Instead, focus on <strong>one behavior per test</strong>:</p>
<pre><code class="language-csharp">[TestMethod]
public void Add_PositiveNumbers_ReturnsCorrectSum()
{
    var calculator = new Calculator();
    var result = calculator.Add(5, 3);
    Assert.AreEqual(8, result);
}
</code></pre>
<h3 id="why-focused-tests-work-better" tabindex="-1">Why Focused Tests Work Better</h3>
<p>Tests that focus on a single behavior come with several advantages:</p>
<ul>
<li><strong>Easier Debugging</strong>: If a test fails, you’ll know exactly where the problem lies without digging through unrelated code.</li>
<li><strong>Simpler Maintenance</strong>: Updating tests is straightforward since each one targets a specific functionality.</li>
<li><strong>Clearer Documentation</strong>: Focused tests act as self-explanatory examples of how a particular feature works.</li>
</ul>
<p>Microsoft’s Engineering Fundamentals Playbook highlights this principle:</p>
<blockquote>
<p>&quot;Unit tests should be short and test only one thing. This makes it easy to diagnose when there was a failure without needing something like which line number the test failed at.&quot; <a href="https://microsoft.github.io/code-with-engineering-playbook/automated-testing/unit-testing/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[3]</sup></a></p>
</blockquote>
<h3 id="tips-for-writing-focused-tests" tabindex="-1">Tips for Writing Focused Tests</h3>
<ul>
<li><strong>Use Descriptive Names</strong>: Clearly describe the behavior being tested in the test name.</li>
<li><strong>Stick to One Behavior</strong>: Test only one scenario at a time, following the AAA (Arrange-Act-Assert) pattern for clarity.</li>
<li><strong>Mock Dependencies</strong>: Replace external dependencies with mocks to isolate the behavior under test.</li>
<li><strong>Limit Assertions</strong>: Only include assertions directly tied to the behavior being validated.</li>
</ul>
<h2 id="4-test-boundary-and-edge-cases" tabindex="-1" class="sb">4. Test Boundary and Edge Cases</h2>
<p>Testing boundary and edge cases is essential for ensuring your .NET applications can handle unexpected scenarios without breaking. These tests often expose bugs that standard tests might miss.</p>
<p>Here are some critical edge cases to consider:</p>
<ul>
<li><strong>Null, Empty, and Boundary Values</strong>: Check how your code handles <code>null</code> references, empty collections, and minimum/maximum values.</li>
<li><strong>Invalid Data Types</strong>: Ensure your application properly handles unexpected input types.</li>
<li><strong>Out-of-Range Values</strong>: Test values that are outside the acceptable range to prevent unexpected behavior.</li>
</ul>
<h3 id="example-testing-edge-cases-in-net" tabindex="-1">Example: Testing Edge Cases in .NET</h3>
<pre><code class="language-csharp">[TestClass]
public class StringProcessorTests
{
    [TestMethod]
    public void ProcessString_NullInput_ThrowsArgumentNullException()
    {
        var processor = new StringProcessor();
        Assert.ThrowsException&lt;ArgumentNullException&gt;(() =&gt; processor.Process(null));
    }

    [TestMethod]
    public void ProcessString_EmptyString_ReturnsEmptyString()
    {
        var processor = new StringProcessor();
        var result = processor.Process(string.Empty);
        Assert.AreEqual(string.Empty, result);
    }

    [TestMethod]
    public void ProcessString_MaxLengthString_ProcessesCorrectly()
    {
        var processor = new StringProcessor();
        var input = new string('A', 1000); // Maximum allowed length
        var result = processor.Process(input);
        Assert.IsNotNull(result);
    }
}
</code></pre>
<h3 id="using-parameterized-testing" tabindex="-1">Using Parameterized Testing</h3>
<p>Parameterized testing makes it easier to test multiple edge cases with less code:</p>
<pre><code class="language-csharp">[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(int.MaxValue)]
public void Calculate_EdgeCases_HandlesCorrectly(int input)
{
    var calculator = new Calculator();
    Assert.DoesNotThrow(() =&gt; calculator.Calculate(input));
}
</code></pre>
<h3 id="common-edge-case-scenarios" tabindex="-1">Common Edge Case Scenarios</h3>
<table style="width:100%;">
<thead>
<tr>
<th><strong>Scenario Type</strong></th>
<th><strong>Examples to Test</strong></th>
<th><strong>Why It Matters</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Numeric Values</td>
<td>0, -1, int.MaxValue, int.MinValue</td>
<td>Prevents overflow or underflow errors</td>
</tr>
<tr>
<td>Collections</td>
<td>Empty list, single item, max size</td>
<td>Ensures proper collection behavior</td>
</tr>
<tr>
<td>Dates</td>
<td>Leap years, boundary dates, invalid dates</td>
<td>Verifies date calculations and accuracy</td>
</tr>
<tr>
<td>Strings</td>
<td>Empty, null, max length, special characters</td>
<td>Handles edge cases in string processing</td>
</tr>
</tbody>
</table>
<p>Thoroughly testing edge cases not only improves reliability but also ensures your application behaves consistently across various environments.</p>
<h2 id="5-make-tests-reliable-and-repeatable" tabindex="-1" class="sb">5. Make Tests Reliable and Repeatable</h2>
<p>Creating reliable and repeatable unit tests is key to maintaining a solid testing suite for .NET applications. Flaky tests can waste time and undermine confidence in your test results.</p>
<h3 id="tips-for-improving-test-reliability" tabindex="-1">Tips for Improving Test Reliability</h3>
<ul>
<li><strong>Isolate Dependencies</strong>: Swap out external services, databases, and APIs with controlled test doubles like mocks or stubs.</li>
<li><strong>Use Self-Contained Test Data</strong>: Ensure each test uses its own data to prevent interference between tests.</li>
<li><strong>Handle Async Code Properly</strong>: Always await asynchronous operations and set timeouts to avoid flaky behavior.</li>
</ul>
<p>Here’s an example of how you can boost test reliability:</p>
<pre><code class="language-csharp">// Before: Test with external dependency
[TestMethod]
public async Task GetUserData_ReturnsUserInfo()
{
    var service = new UserService(new LiveApiClient()); // Direct dependency on live API
    var result = await service.GetUserData(123);
    Assert.IsNotNull(result);
}

// After: Test with a controlled dependency
[TestMethod]
public async Task GetUserData_ReturnsUserInfo()
{
    var service = new UserService(new TestApiClient()); // Using a test double
    var result = await service.GetUserData(123);
    Assert.IsNotNull(result);
    Assert.AreEqual(&quot;John Doe&quot;, result.Name);
}
</code></pre>
<h3 id="common-issues-and-how-to-address-them" tabindex="-1">Common Issues and How to Address Them</h3>
<table style="width:100%;">
<thead>
<tr>
<th>Issue</th>
<th>Impact</th>
<th>Solution</th>
</tr>
</thead>
<tbody>
<tr>
<td>External Dependencies</td>
<td>Failures due to external systems</td>
<td>Replace with mocks/stubs</td>
</tr>
<tr>
<td>Time-sensitive Logic</td>
<td>Errors from timing inconsistencies</td>
<td>Use fixed or simulated time values</td>
</tr>
<tr>
<td>Shared State</td>
<td>Tests interfering with each other</td>
<td>Ensure isolated test data</td>
</tr>
<tr>
<td>Randomized Inputs</td>
<td>Unpredictable test results</td>
<td>Use fixed seed values</td>
</tr>
</tbody>
</table>
<h6 id="sbb-itb-29cd4f6" tabindex="-1">sbb-itb-29cd4f6</h6>
<h2 id="6-use-mocks-and-stubs-for-dependencies" tabindex="-1" class="sb">6. Use Mocks and Stubs for Dependencies</h2>
<p>When writing unit tests in .NET, it&#8217;s important to isolate the code being tested from external dependencies. This is where <strong>mocks</strong> and <strong>stubs</strong> come into play. Mocks help verify interactions, while stubs provide predefined responses.</p>
<h3 id="mocks-vs-stubs-whats-the-difference" tabindex="-1">Mocks vs. Stubs: What’s the Difference?</h3>
<p>Though both are used to isolate dependencies, they serve different purposes:</p>
<ul>
<li><strong>Mocks</strong>: Check if specific methods were called with the expected parameters, verifying behavior.</li>
<li><strong>Stubs</strong>: Return predefined values, helping simulate certain scenarios.</li>
</ul>
<p>Here’s a practical example using the <a href="https://www.nuget.org/packages/Moq/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Moq</a> framework:</p>
<pre><code class="language-csharp">// Stub to return a specific user
var userRepositoryStub = new Mock&lt;IUserRepository&gt;();
userRepositoryStub.Setup(r =&gt; r.GetUserById(123))
    .Returns(new User { Id = 123, Name = &quot;John Doe&quot; });

// Mock to verify email interactions
var emailServiceMock = new Mock&lt;IEmailService&gt;();
emailServiceMock.Setup(s =&gt; s.SendEmail(It.IsAny&lt;string&gt;(), It.IsAny&lt;string&gt;()))
    .Returns(Task.CompletedTask);

var userService = new UserService(userRepositoryStub.Object, emailServiceMock.Object);
await userService.NotifyUser(123);

// Verify the email service was called
emailServiceMock.Verify(s =&gt; s.SendEmail(&quot;John Doe&quot;, It.IsAny&lt;string&gt;()), Times.Once);
</code></pre>
<h3 id="best-practices-and-pitfalls-to-avoid" tabindex="-1">Best Practices and Pitfalls to Avoid</h3>
<table style="width:100%;">
<thead>
<tr>
<th><strong>Practice</strong></th>
<th><strong>Why It Matters</strong></th>
<th><strong>Example</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Mock Only External Dependencies</td>
<td>Reduces unnecessary complexity</td>
<td>Focus on external services, not simple objects</td>
</tr>
<tr>
<td>Use Descriptive Mock Setups</td>
<td>Improves readability and clarity</td>
<td>Clearly define mock behavior</td>
</tr>
<tr>
<td>Verify Critical Interactions</td>
<td>Keeps tests focused on key logic</td>
<td>Check calls that impact business outcomes</td>
</tr>
</tbody>
</table>
<h3 id="key-tips-for-using-mocks-and-stubs" tabindex="-1">Key Tips for Using Mocks and Stubs</h3>
<ol>
<li><strong>Mock only what’s external</strong>: Concentrate on dependencies like services or APIs, not simple objects.</li>
<li><strong>Keep setups simple</strong>: Make mock configurations clear and relevant to the test.</li>
<li><strong>Test behavior, not implementation</strong>: Focus on what the code does, not how it does it.</li>
<li><strong>Avoid overusing mocks</strong>: Use them only when they add value &#8211; don’t mock everything.</li>
</ol>
<p>Frameworks like Moq and <a href="https://nsubstitute.github.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">NSubstitute</a> make it easier to create and manage test doubles. By isolating dependencies effectively, you can keep tests focused and dependable, which is critical for building maintainable code. We&#8217;ll explore more testing techniques in the upcoming sections.</p>
<h2 id="7-verify-behavior-when-exceptions-are-thrown" tabindex="-1" class="sb">7. Verify Behavior When Exceptions Are Thrown</h2>
<p>Handling exceptions properly is a key part of building reliable .NET applications. Testing how your code responds to exceptions ensures your app can handle errors gracefully.</p>
<h3 id="testing-specific-exceptions" tabindex="-1">Testing Specific Exceptions</h3>
<p>Always test for specific exception types instead of catching general ones. Here&#8217;s an example using xUnit to check for an <code>ArgumentNullException</code>:</p>
<pre><code class="language-csharp">[Fact]
public void ProcessOrder_ThrowsArgumentNullException_WhenOrderIsNull()
{
    // Arrange
    var orderService = new OrderService();
    Order order = null;

    // Act &amp; Assert
    Assert.Throws&lt;ArgumentNullException&gt;(() =&gt; orderService.ProcessOrder(order));
}
</code></pre>
<h3 id="common-exception-testing-patterns" tabindex="-1">Common Exception Testing Patterns</h3>
<p>Use these patterns to test various exception scenarios effectively:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Pattern</th>
<th>Example Scenario</th>
</tr>
</thead>
<tbody>
<tr>
<td>Direct Exception Testing</td>
<td>Validating null parameters</td>
</tr>
<tr>
<td>Message Validation</td>
<td>Ensuring custom error messages</td>
</tr>
<tr>
<td>Nested Exceptions</td>
<td>Testing wrapped database errors</td>
</tr>
<tr>
<td>Async Exception Testing</td>
<td>Validating exceptions in async code</td>
</tr>
</tbody>
</table>
<h3 id="using-mocks-for-exception-testing" tabindex="-1">Using Mocks for Exception Testing</h3>
<p>Mocks are helpful when you need to simulate exceptions during testing. For instance:</p>
<pre><code class="language-csharp">var mockRepository = new Mock&lt;IOrderRepository&gt;();
mockRepository.Setup(r =&gt; r.SaveOrder(It.IsAny&lt;Order&gt;()))
    .Throws(new DatabaseException(&quot;Connection failed&quot;));

Assert.Throws&lt;DatabaseException&gt;(() =&gt; new OrderService(mockRepository.Object).ProcessOrder(new Order()));
</code></pre>
<p>This approach allows you to test how your application handles exceptions from external dependencies.</p>
<h3 id="best-practices-for-exception-testing" tabindex="-1">Best Practices for Exception Testing</h3>
<ul>
<li><strong>Test one scenario per test</strong>: Keep your tests focused and use clear, descriptive names.</li>
<li><strong>Validate exception type and details</strong>: Ensure you&#8217;re checking both the type and any relevant information (e.g., messages).</li>
<li><strong>Test recovery paths</strong>: Confirm your application can recover or respond appropriately.</li>
</ul>
<p>For async methods, you can use <code>Assert.ThrowsAsync</code> to validate exceptions:</p>
<pre><code class="language-csharp">[Fact]
public async Task ProcessOrderAsync_ThrowsTimeoutException_WhenServiceUnavailable()
{
    var orderService = new OrderService();
    await Assert.ThrowsAsync&lt;TimeoutException&gt;(
        () =&gt; orderService.ProcessOrderAsync(new Order())
    );
}
</code></pre>
<h2 id="8-write-specific-and-clear-assertions" tabindex="-1" class="sb">8. Write Specific and Clear Assertions</h2>
<p>In the Arrange-Act-Assert pattern, assertions confirm whether your tests meet the expected outcomes. Writing clear and specific assertions helps pinpoint issues during debugging.</p>
<h3 id="adding-descriptive-assertion-messages" tabindex="-1">Adding Descriptive Assertion Messages</h3>
<p>Adding a descriptive message to your assertions makes debugging easier by providing context:</p>
<pre><code class="language-csharp">// Generic assertion:
Assert.True(result.IsValid);

// Improved assertion with context:
Assert.True(result.IsValid, 
    &quot;Order validation failed: Expected valid order with ID 12345&quot;);
</code></pre>
<h3 id="keeping-assertions-focused" tabindex="-1">Keeping Assertions Focused</h3>
<p>Each assertion should validate a single condition. If you&#8217;re testing multiple properties, split them into separate assertions to improve clarity:</p>
<pre><code class="language-csharp">// Combined assertion:
Assert.True(order.IsValid &amp;&amp; order.Total &gt; 0 &amp;&amp; order.Items.Count &gt; 0);

// Separate assertions for clarity:
Assert.True(order.IsValid, &quot;Order should be valid&quot;);
Assert.True(order.Total &gt; 0, &quot;Order total should be greater than zero&quot;);
Assert.True(order.Items.Count &gt; 0, &quot;Order should contain items&quot;);
</code></pre>
<h3 id="common-assertion-types" tabindex="-1">Common Assertion Types</h3>
<p>Here are some of the most commonly used assertion types:</p>
<ul>
<li><strong>Equality Assertions</strong>: Compare values directly, e.g., <code>Assert.Equal(expected, actual)</code>.</li>
<li><strong>Collection Assertions</strong>: Check contents of a list, e.g., <code>Assert.Contains(item, collection)</code>.</li>
<li><strong>Type Assertions</strong>: Verify object types, e.g., <code>Assert.IsType&lt;Type&gt;(object)</code>.</li>
</ul>
<h3 id="leveraging-framework-specific-features" tabindex="-1">Leveraging Framework-Specific Features</h3>
<p>Some frameworks, like xUnit, offer advanced features such as fluent assertions, which can make your tests more expressive:</p>
<pre><code class="language-csharp">var order = new Order();
order.Items.Should()
    .NotBeNull()
    .And.HaveCount(3)
    .And.Contain(item =&gt; item.Price &gt; 0);
</code></pre>
<h3 id="tips-for-writing-effective-assertions" tabindex="-1">Tips for Writing Effective Assertions</h3>
<ul>
<li>Use the right assertion type for your test.</li>
<li>Include meaningful failure messages for easier debugging.</li>
<li>Avoid combining multiple checks in a single assertion to keep your tests clean and focused.</li>
</ul>
<h2 id="9-automate-test-execution" tabindex="-1" class="sb">9. Automate Test Execution</h2>
<p>Automating test execution streamlines quality checks and helps identify issues early in .NET development. It saves time and ensures tests are run consistently under controlled conditions, making your development process more reliable.</p>
<h3 id="setting-up-automated-test-runners" tabindex="-1">Setting Up Automated Test Runners</h3>
<p>.NET tools like xUnit and NUnit come with test runners that let you automate test execution directly from your command line or IDE. These frameworks can easily integrate with your workflow, helping you maintain consistent testing practices.</p>
<h3 id="continuous-integration-pipeline-integration" tabindex="-1">Continuous Integration Pipeline Integration</h3>
<p>Integrating automated tests into CI pipelines such as <a href="https://azure.microsoft.com/en-us/products/devops" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure DevOps</a>, <a href="https://docs.github.com/actions" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">GitHub Actions</a>, or <a href="https://www.jenkins.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Jenkins</a> ensures that every code change is automatically tested. This approach helps catch issues before deployment, keeping your codebase stable.</p>
<h3 id="test-execution-strategy" tabindex="-1">Test Execution Strategy</h3>
<p>Set up automated tests to run during key events like code pushes, pull requests, or scheduled intervals. For larger test suites, consider enabling parallel test execution to minimize runtime and improve efficiency.</p>
<h3 id="test-result-reporting" tabindex="-1">Test Result Reporting</h3>
<p>Configure test runners to generate detailed reports, including execution times, pass/fail rates, and failure specifics. Clear and actionable reports allow teams to quickly address problems, maintaining the quality of the code throughout the development cycle.</p>
<h3 id="best-practices-for-test-automation" tabindex="-1">Best Practices for Test Automation</h3>
<ul>
<li>Use consistent test environments</li>
<li>Set appropriate timeouts</li>
<li>Monitor execution times to spot inefficiencies</li>
<li>Ensure test data does not interfere with results</li>
<li>Regularly clean up test artifacts to avoid clutter</li>
</ul>
<p>A well-automated test execution process is only effective if your tests are organized and kept up-to-date. We&#8217;ll dive into maintaining and organizing tests next <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</p>
<h2 id="10-keep-tests-updated-and-organized" tabindex="-1" class="sb">10. Keep Tests Updated and Organized</h2>
<p>Keeping your unit tests in good shape is essential for maintaining the reliability of your .NET applications over time. As your code evolves, your tests need to evolve with it to stay effective and trustworthy.</p>
<h3 id="regular-test-review-and-updates" tabindex="-1">Regular Test Review and Updates</h3>
<p>Make updating tests a regular part of your development process. Use <a href="https://visualstudio.microsoft.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Visual Studio</a>&#8216;s test explorer to quickly spot and fix failing or outdated tests. Always track test updates in version control alongside code changes. This ensures transparency and keeps your tests aligned with the latest code.</p>
<h3 id="test-organization-and-refactoring" tabindex="-1">Test Organization and Refactoring</h3>
<p>Structure your test projects to reflect your production code layout. Use categories and clear naming conventions to make tests easier to find and run.</p>
<table style="width:100%;">
<thead>
<tr>
<th>Organization Level</th>
<th>Purpose</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Solution Structure</td>
<td>Match production code hierarchy</td>
<td>Tests/OrderProcessing</td>
</tr>
<tr>
<td>Test Categories</td>
<td>Group related functionality</td>
<td>[TestCategory(&quot;Payment&quot;)]</td>
</tr>
<tr>
<td>File Naming</td>
<td>Identify test scope clearly</td>
<td>OrderProcessingTests.cs</td>
</tr>
<tr>
<td>Method Organization</td>
<td>Group methods logically</td>
<td>ValidPayments, InvalidInputs</td>
</tr>
</tbody>
</table>
<p>Once your tests are properly organized, focus on refactoring them for clarity and efficiency. For example, you can extract reusable setups, use test data builders, or merge duplicate tests. Microsoft&#8217;s Azure DevOps team has shown how these steps can save significant time on test maintenance <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</p>
<h3 id="automation-support" tabindex="-1">Automation Support</h3>
<p>Automation tools can make test maintenance easier. Tools like <a href="https://www.jetbrains.com/resharper/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">ReSharper</a> or Visual Studio can help you identify duplicate code, suggest improvements, and automate repetitive refactoring tasks.</p>
<blockquote>
<p>&quot;The key to successful testing is to write tests that are easy to understand and maintain.&quot; &#8211; Roy Osherove, Author of &quot;The Art of Unit Testing&quot; <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a></p>
</blockquote>
<p>Finally, ensure all test changes are tracked in your version control system, with clear commit messages explaining the updates. This keeps your team informed and helps everyone understand how the tests are evolving.</p>
<h2 id="conclusion" tabindex="-1" class="sb">Conclusion</h2>
<p>Using these ten tips can help you write unit tests that improve reliability and simplify development in .NET applications. Unit tests don’t just catch bugs early &#8211; they also act as a guide to how your system should behave.</p>
<p>The benefits are clear. For example, Microsoft&#8217;s Azure DevOps team has demonstrated that well-maintained tests save time on debugging and improve overall reliability. Practices like using clear naming, following the Arrange-Act-Assert pattern, and keeping test scopes focused make debugging easier and improve readability and maintainability for development teams.</p>
<p>To make the most of these practices, tools like xUnit, NUnit, Visual Studio, and ReSharper can be incredibly helpful. And as the .NET ecosystem continues to grow, keeping up with the latest testing tools and techniques is crucial. Resources such as the .NET Newsletter (dotnetnews.co) can help you stay informed.</p>
<blockquote>
<p>&quot;Unit testing helps ensure your code works as intended. However, you can learn why a unit fails to pass only if you write simple and readable tests.&quot; &#8211; BrightSec <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a></p>
</blockquote>
<p>Effective unit testing is more than just writing tests &#8211; it’s about creating a testing strategy that evolves alongside your codebase. By consistently applying these tips, your team can build durable .NET applications while cutting down on debugging time and reducing maintenance work <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a><a href="https://ardalis.com/mastering-unit-tests-dotnet-best-practices-naming-conventions/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/08/nunit-vs-xunit-vs-mstest-comparing-net-testing-frameworks/" style="display: inline;">NUnit vs xUnit vs MSTest: Comparing .NET Testing Frameworks</a></li>
<li>TDD in .NET: Benefits, Challenges, Examples</li>
<li>Red-Green-Refactor: TDD Guide for C#</li>
<li><a href="/2025/01/best-practices-for-unit-testing-in-net/" style="display: inline;">Best Practices for Unit Testing in .NET</a></li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn essential tips for writing effective unit tests in .NET to enhance code reliability, catch bugs early, and streamline development.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_0b662fdbe78b3c41a87f29f6c9c2185b-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_0b662fdbe78b3c41a87f29f6c9c2185b-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Best Practices for Unit Testing in .NET</title><link href="https://codejack.com/2025/01/best-practices-for-unit-testing-in-net/" rel="alternate" type="text/html" title="Best Practices for Unit Testing in .NET" /><published>2025-01-18T22:00:00-05:00</published><updated>2025-01-18T22:00:00-05:00</updated><id>https://codejack.com/2025/01/best-practices-for-unit-testing-in-net</id><content type="html" xml:base="https://codejack.com/2025/01/best-practices-for-unit-testing-in-net/"><![CDATA[<p><strong>Unit testing in .NET helps you catch bugs early, ensure code reliability, and improve maintainability.</strong> By testing individual components like methods in isolation, you can confirm they work as expected without relying on external systems.</p>
<h3 id="key-takeaways" tabindex="-1">Key Takeaways:</h3>
<ul>
<li><strong>Why Unit Testing Matters</strong>: Detect bugs early, boost confidence in changes, and improve design quality.</li>
<li><strong>Core Principles</strong>: Tests should be reliable, fast, focused, and independent.</li>
<li><strong>Frameworks</strong>: Popular options include <a href="https://nunit.org/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">NUnit</a> (custom attributes, parallel execution) and <a href="https://xunit.net/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">xUnit</a> (modern design, dependency injection).</li>
<li><strong>Best Practices</strong>:
<ul>
<li>Name tests clearly (e.g., <code>MethodName_StateUnderTest_ExpectedBehavior</code>).</li>
<li>Organize tests by feature or component.</li>
<li>Use mocking tools like <a href="https://github.com/devlooped/moq" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Moq</a> to isolate dependencies.</li>
<li>Follow the Arrange-Act-Assert (AAA) pattern for clarity.</li>
</ul>
</li>
<li><strong>Advanced Techniques</strong>: Parameterized tests reduce redundancy, while CI/CD automation ensures consistent quality.</li>
</ul>
<p>For fast, reliable .NET testing, focus on clear naming, proper organization, and automation. These practices save time and ensure your application remains robust.</p>
<h2 id="core-principles-of-unit-testing" tabindex="-1" class="sb">Core Principles of Unit Testing</h2>
<h3 id="what-makes-a-good-unit-test" tabindex="-1">What Makes a Good Unit Test</h3>
<p>When working with unit testing in .NET, certain principles ensure your tests are both effective and easy to maintain. Tests should consistently produce the same results under identical conditions and remain self-contained to simplify debugging and upkeep.</p>
<p>Here’s what defines a well-crafted unit test:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Principle</th>
<th>Description</th>
<th>Impact</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Reliability</strong></td>
<td>Tests yield consistent results</td>
<td>Boosts confidence in code changes</td>
</tr>
<tr>
<td><strong>Independence</strong></td>
<td>Tests don’t depend on each other</td>
<td>Makes debugging and maintenance easier</td>
</tr>
<tr>
<td><strong>Speed</strong></td>
<td>Executes quickly</td>
<td>Encourages frequent testing during development</td>
</tr>
<tr>
<td><strong>Focus</strong></td>
<td>Tests one scenario at a time</td>
<td>Simplifies diagnosing failures</td>
</tr>
</tbody>
</table>
<p>Quick test execution is crucial. It provides immediate feedback, allowing developers to identify and resolve issues early in the development process. This ongoing feedback loop is a cornerstone of efficient software development.</p>
<p>Choosing the right testing framework is another critical step in streamlining your unit testing process.</p>
<h3 id="selecting-a-testing-framework" tabindex="-1">Selecting a Testing Framework</h3>
<p>The framework you choose plays a big role in how smoothly you can implement unit tests in .NET applications. Two popular choices stand out, each with its own strengths:</p>
<p><strong>NUnit</strong> features:</p>
<ul>
<li>Support for multiple testing styles (unit, integration, acceptance)</li>
<li>Extensive assertion options</li>
<li>Customizable test attributes</li>
<li>Parallel test execution for better performance</li>
</ul>
<p><strong>xUnit</strong> stands out with:</p>
<ul>
<li>A modern design that simplifies testing</li>
<li>Built-in support for dependency injection</li>
<li>Theory-based testing for data-driven scenarios</li>
<li>Minimal setup requirements</li>
</ul>
<p>Both frameworks integrate well with IDEs and CI/CD pipelines, making them solid picks for .NET projects. Your decision will often depend on your team&#8217;s familiarity with the tool and the specific needs of your project.</p>
<p>No matter which framework you choose, applying the Arrange-Act-Assert pattern ensures your tests are easy to read and maintain <a href="https://microsoft.github.io/code-with-engineering-playbook/automated-testing/unit-testing/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[4]</sup></a><a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</p>
<h2 id="best-practices-for-writing-unit-tests" tabindex="-1" class="sb">Best Practices for Writing Unit Tests</h2>
<h3 id="naming-tests-clearly" tabindex="-1">Naming Tests Clearly</h3>
<p>Clear and consistent test names make it easier to understand their purpose at a glance. A helpful naming pattern is <code>MethodName_StateUnderTest_ExpectedBehavior</code>. This format describes the method being tested, the conditions, and the expected outcome. For example, instead of a vague name like <code>TestCalculate()</code>, use something like <code>Calculate_NegativeAmount_ThrowsArgumentException()</code>.</p>
<table style="width:100%;">
<thead>
<tr>
<th>Component</th>
<th>Example</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Method Name</strong></td>
<td><code>Calculate</code></td>
<td>Identifies the method being tested</td>
</tr>
<tr>
<td><strong>State/Input</strong></td>
<td><code>NegativeAmount</code></td>
<td>Describes the test conditions</td>
</tr>
<tr>
<td><strong>Expected Result</strong></td>
<td><code>ThrowsArgumentException</code></td>
<td>States the expected outcome</td>
</tr>
</tbody>
</table>
<h3 id="organizing-tests-effectively" tabindex="-1">Organizing Tests Effectively</h3>
<p>Clear names are essential, but organizing your tests well ensures they remain easy to manage as the suite grows. A good approach is to mirror the structure of your production code. This makes it intuitive to find and update tests when changes occur.</p>
<p>For example, create folders for different test types, such as unit and integration tests, and group related tests together. A simple directory structure might look like this:</p>
<pre><code>Tests/
  ├── UnitTests/
  │   ├── CalculatorTests/
  │   │   ├── AdditionTests.cs
  │   │   └── DivisionTests.cs
  │   └── ValidationTests/
  └── IntegrationTests/
</code></pre>
<p>This setup makes it easier for developers to locate tests and keeps unit tests distinct from integration tests <a href="https://ardalis.com/mastering-unit-tests-dotnet-best-practices-naming-conventions/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<h3 id="handling-dependencies-in-tests" tabindex="-1">Handling Dependencies in Tests</h3>
<p>Managing dependencies is key to ensuring tests are isolated and reliable. Mocking frameworks like Moq can help you simulate dependencies without relying on actual implementations, making your tests more focused and easier to maintain.</p>
<p>Here&#8217;s an example using Moq to handle dependencies:</p>
<pre><code class="language-csharp">[Test]
public void ProcessOrder_ValidOrder_SendsConfirmationEmail()
{
    // Arrange
    var mockEmailService = new Mock&lt;IEmailService&gt;();
    var orderProcessor = new OrderProcessor(mockEmailService.Object);
    var order = new Order { Id = 1 };

    // Act
    orderProcessor.ProcessOrder(order);

    // Assert
    mockEmailService.Verify(x =&gt; x.SendEmail(
        It.IsAny&lt;string&gt;(), 
        It.Is&lt;string&gt;(s =&gt; s.Contains(order.Id.ToString()))
    ), Times.Once);
}
</code></pre>
<p>Keep your mocks simple and focused so the tests remain easy to read and maintain <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</p>
<p>For more tips and updates on unit testing and .NET development, consider subscribing to the .NET Newsletter, which shares daily insights and techniques.</p>
<h2 id="advanced-techniques-for-unit-testing" tabindex="-1" class="sb">Advanced Techniques for Unit Testing</h2>
<h3 id="using-the-arrange-act-assert-pattern" tabindex="-1">Using the Arrange-Act-Assert Pattern</h3>
<p>The Arrange-Act-Assert (AAA) pattern helps structure your tests into three clear sections: setup, action, and verification. This makes tests easier to read and debug. Here&#8217;s how it looks in practice:</p>
<pre><code class="language-csharp">[Test]
public void CalculateDiscount_PremiumCustomer_Returns20PercentOff()
{
    // Arrange
    var customer = new Customer { Type = CustomerType.Premium };
    var discountCalculator = new DiscountCalculator();

    // Act
    var discount = discountCalculator.Calculate(customer);

    // Assert
    Assert.That(discount, Is.EqualTo(0.20));
}
</code></pre>
<h3 id="writing-small-focused-tests" tabindex="-1">Writing Small, Focused Tests</h3>
<p>Focus each test on verifying just one behavior. This keeps tests simple and makes debugging easier. Here&#8217;s a comparison:</p>
<pre><code class="language-csharp">// Good: Single, focused test
[Test]
public void ValidateEmail_EmptyString_ThrowsArgumentException()
{
    var validator = new EmailValidator();
    Assert.Throws&lt;ArgumentException&gt;(() =&gt; validator.Validate(&quot;&quot;));
}

// Bad: Testing multiple behaviors in one test
[Test]
public void ValidateEmail_MultipleScenarios() // Avoid this
{
    var validator = new EmailValidator();
    Assert.Throws&lt;ArgumentException&gt;(() =&gt; validator.Validate(&quot;&quot;));
    Assert.True(validator.Validate(&quot;test@example.com&quot;));
    Assert.False(validator.Validate(&quot;invalid@email&quot;));
}
</code></pre>
<h3 id="using-parameterized-tests" tabindex="-1">Using Parameterized Tests</h3>
<p>Parameterized tests let you test the same logic with different inputs, cutting down on repetitive code. Here&#8217;s an example:</p>
<pre><code class="language-csharp">[Test]
[TestCase(0, 1, 1)]
[TestCase(1, 2, 3)]
[TestCase(5, 3, 8)]
public void Add_WhenCalled_ReturnsSumOfNumbers(int first, int second, int expected)
{
    var calculator = new Calculator();
    var result = calculator.Add(first, second);
    Assert.That(result, Is.EqualTo(expected));
}
</code></pre>
<h6 id="sbb-itb-29cd4f6" tabindex="-1">sbb-itb-29cd4f6</h6>
<h2 id="incorporating-unit-testing-into-development" tabindex="-1" class="sb">Incorporating Unit Testing into Development</h2>
<h3 id="automating-tests-with-cicd" tabindex="-1">Automating Tests with CI/CD</h3>
<p>Integrating unit tests into your CI pipelines is a smart way to catch issues early and ensure consistent quality. Tools like <a href="https://azure.microsoft.com/en-us/products/devops" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure DevOps</a> make it simple to run .NET tests automatically with every commit, saving time and effort.</p>
<p>Here’s how to get the most out of CI/CD automation:</p>
<ul>
<li>Run tests in parallel to speed up build times.</li>
<li>Set up detailed test result reports to analyze failures.</li>
<li>Track code coverage to ensure thorough testing.</li>
<li>Configure automatic alerts for test failures to address issues promptly.</li>
</ul>
<p>Automation handles the repetitive tasks, but keeping tests effective requires clear team guidelines.</p>
<h3 id="creating-team-standards-for-testing" tabindex="-1">Creating Team Standards for Testing</h3>
<p>Automation is just one piece of the puzzle. Establishing team-wide standards is essential for keeping your tests reliable and manageable over time. For tips on writing clear test names, check out the &#8216;Naming Tests Clearly&#8217; section.</p>
<p>Here are some ways to ensure high-quality tests across your team:</p>
<ul>
<li>Regularly review code with a focus on test quality.</li>
<li>Use automated tools to enforce testing guidelines.</li>
<li>Document both best practices and common mistakes in testing.</li>
<li>Share successful strategies and techniques within the team.</li>
</ul>
<p>Your team’s standards should cover:</p>
<ul>
<li>Organizing tests by feature or component for clarity.</li>
<li>Setting minimum coverage benchmarks (e.g., 80% for critical business logic).</li>
<li>Outlining documentation expectations for tests.</li>
<li>Establishing a process for reviewing test code.</li>
</ul>
<p>For teams that want to stay ahead with the latest testing techniques, the .NET Newsletter is a great resource. It offers practical advice and insights from the broader .NET community, helping teams refine their unit testing practices.</p>
<h2 id="summary-and-further-learning" tabindex="-1" class="sb">Summary and Further Learning</h2>
<h3 id="key-points-to-remember" tabindex="-1">Key Points to Remember</h3>
<p>Unit testing in .NET works best when approached thoughtfully to ensure it remains effective over time. Here are some practices that top development teams follow:</p>
<ul>
<li>Use mocking to isolate dependencies, making tests more reliable and easier to manage.</li>
<li>Organize tests by feature, and stick to clear naming conventions that immediately explain the purpose of each test <a href="https://www.bytehide.com/blog/unit-testing-csharp" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[3]</sup></a>.</li>
<li>Monitor key metrics like code coverage and test frequency to keep improving test quality. Automated testing not only boosts code quality but also cuts down on debugging time <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</li>
</ul>
<p>For a deeper dive into these strategies and to stay informed about new developments, check out expert resources and insights.</p>
<h3 id="learn-more-with-the-net-newsletter" tabindex="-1">Learn More with the .NET Newsletter</h3>
<p>The .NET Newsletter is a great way to keep up with the latest in .NET, C#, ASP<a href="https://dotnet.microsoft.com/en-us/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">.NET</a>, and <a href="https://azure.microsoft.com/en-us" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure</a>. It offers practical tips and updates that can help developers refine their unit testing techniques and stay informed about broader .NET advancements.</p>
<p>If you&#8217;re looking to sharpen your skills further, try:</p>
<ul>
<li>Learning advanced testing patterns and tools</li>
<li>Reviewing real-world examples of testing in action</li>
<li>Joining discussions within the .NET developer community</li>
</ul>
<p>Ongoing learning ensures your testing approach grows alongside your applications.</p>
<h2 id="faqs" tabindex="-1" class="sb">FAQs</h2>
<h3 id="what-are-unit-test-best-practices" tabindex="-1">What are unit test best practices?</h3>
<p>Unit testing in .NET benefits from following time-tested practices to create reliable and maintainable tests. Here&#8217;s a breakdown of key recommendations from industry experts:</p>
<p><strong>Test Structure and Organization</strong></p>
<ul>
<li>Stick to the Arrange-Act-Assert pattern, ensuring each test focuses on a single scenario.</li>
<li>Use clear naming conventions, like <code>MethodName_Scenario_ExpectedBehavior</code>, to make test purposes obvious <a href="https://ardalis.com/mastering-unit-tests-dotnet-best-practices-naming-conventions/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</li>
</ul>
<p><strong>Test Independence and Reliability</strong></p>
<ul>
<li>Use mocking tools like Moq to isolate dependencies, as mentioned earlier.</li>
<li>Ensure tests are consistent and provide the same results every time they run.</li>
<li>Avoid dependencies between tests, which can lead to chain-reaction failures <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</li>
</ul>
<table style="width:100%;">
<thead>
<tr>
<th>Best Practice</th>
<th>Example Implementation</th>
<th>Benefit</th>
</tr>
</thead>
<tbody>
<tr>
<td>Clear Naming</td>
<td>Use descriptive names, e.g., &#8216;Naming Tests Clearly&#8217;</td>
<td>Makes test intent immediately obvious</td>
</tr>
<tr>
<td>Test Isolation</td>
<td>Mock dependencies with tools like Moq</td>
<td>Keeps results unaffected by external factors</td>
</tr>
<tr>
<td>Single Responsibility</td>
<td>Test one behavior per test case</td>
<td>Simplifies debugging when tests fail</td>
</tr>
</tbody>
</table>
<p><strong>Automation and Integration</strong></p>
<ul>
<li>Integrate unit tests into your CI/CD pipeline to ensure continuous validation.</li>
<li>Monitor test coverage and quality metrics to spot gaps and opportunities for improvement <a href="https://brightsec.com/blog/unit-testing-best-practices/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>.</li>
</ul>
<p>To elevate your testing game, explore modern testing frameworks and tools that align with these principles. Regular code reviews and team discussions can also help maintain a consistent testing approach across your projects <a href="https://ardalis.com/mastering-unit-tests-dotnet-best-practices-naming-conventions/" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/08/nunit-vs-xunit-vs-mstest-comparing-net-testing-frameworks/" style="display: inline;">NUnit vs xUnit vs MSTest: Comparing .NET Testing Frameworks</a></li>
<li><a href="/2024/09/top-7-dependency-injection-best-practices-for-net/" style="display: inline;">Top 7 Dependency Injection Best Practices for .NET</a></li>
<li>TDD in .NET: Benefits, Challenges, Examples</li>
<li>Red-Green-Refactor: TDD Guide for C#</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn essential unit testing practices in .NET to enhance code reliability, maintainability, and catch bugs early.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_301bb10037f3ad645b82114f39992d1b-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_301bb10037f3ad645b82114f39992d1b-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">YARP Load Balancing in .NET: Setup Guide</title><link href="https://codejack.com/2025/01/yarp-load-balancing-in-net-setup-guide/" rel="alternate" type="text/html" title="YARP Load Balancing in .NET: Setup Guide" /><published>2025-01-16T00:20:29-05:00</published><updated>2025-01-16T00:20:29-05:00</updated><id>https://codejack.com/2025/01/yarp-load-balancing-in-net-setup-guide</id><content type="html" xml:base="https://codejack.com/2025/01/yarp-load-balancing-in-net-setup-guide/"><![CDATA[<p><strong>Want to optimize traffic distribution in your .NET applications? <a href="https://microsoft.github.io/reverse-proxy/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">YARP</a> (Yet Another Reverse Proxy) makes it simple.</strong> This guide walks you through setting up YARP for load balancing, ensuring reliability, scalability, and performance for your backend services.</p>
<h3 id="key-steps" tabindex="-1">Key Steps:</h3>
<ol>
<li><strong>Install YARP</strong>: Add the <code>Yarp.ReverseProxy</code> NuGet package to your ASP.NET Core project.</li>
<li><strong>Configure Routes and Clusters</strong>: Define routing rules and backend destinations in <code>appsettings.json</code>.</li>
<li><strong>Choose Load Balancing Strategies</strong>: Options include RoundRobin, LeastRequests, and PowerOfTwoChoices.</li>
<li><strong>Test Your Setup</strong>: Use tools like <code>curl</code>, <a href="https://en.wikipedia.org/wiki/ApacheBench" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Apache Benchmark</a>, or k6 to verify traffic distribution and performance.</li>
</ol>
<p>YARP also supports health checks, custom load balancing strategies, and seamless integration with containerized environments like <a href="https://www.docker.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Docker</a> and <a href="https://kubernetes.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Kubernetes</a>. Follow this guide to get started!</p>
<h2 id="setting-up-yarp-load-balancing" tabindex="-1" class="sb">Setting Up <a href="https://microsoft.github.io/reverse-proxy/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">YARP</a> Load Balancing</h2>
<p><img decoding="async" src="/assets/images/imported/77de6ce5ba3bc9759d25.jpg" alt="YARP" style="width:100%;"></p>
<p>Now that you&#8217;re familiar with YARP basics, let&#8217;s get into the setup process. We&#8217;ll cover creating a project, configuring YARP, and setting up load balancing.</p>
<h3 id="creating-an-aspnet-core-project" tabindex="-1">Creating an ASP.NET Core Project</h3>
<p>First, create a new ASP.NET Core web API project. You can use <a href="https://visualstudio.microsoft.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Visual Studio</a> or the .NET CLI for this. Here&#8217;s how:</p>
<ol>
<li>
Open Visual Studio and select <strong>&quot;Create a new project&quot;</strong>.
</li>
<li>
Choose the <strong>&quot;ASP.NET Core Web API&quot;</strong> template.
</li>
<li>
Add the YARP.ReverseProxy NuGet package using the following command:</p>
<pre><code class="language-powershell">dotnet add package Yarp.ReverseProxy
</code></pre>
</li>
</ol>
<p>Next, enable YARP in your project by configuring it in <code>Program.cs</code>. Add the reverse proxy services like this:</p>
<pre><code class="language-csharp">builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection(&quot;ReverseProxy&quot;));
</code></pre>
<p>Once the project is ready, you&#8217;ll need to configure routing and load balancing in <code>appsettings.json</code>.</p>
<h3 id="configuring-yarp-with-appsettingsjson" tabindex="-1">Configuring YARP with appsettings.json</h3>
<p>In the <code>appsettings.json</code> file, define the routes and clusters needed for YARP to function. Here&#8217;s an example:</p>
<pre><code class="language-json">{
  &quot;ReverseProxy&quot;: {
    &quot;Routes&quot;: {
      &quot;route1&quot;: {
        &quot;ClusterId&quot;: &quot;backendCluster&quot;,
        &quot;Match&quot;: {
          &quot;Path&quot;: &quot;{**catch-all}&quot;
        }
      }
    },
    &quot;Clusters&quot;: {
      &quot;backendCluster&quot;: {
        &quot;Destinations&quot;: {
          &quot;destination1&quot;: {
            &quot;Address&quot;: &quot;https://backend1.example.com&quot;
          },
          &quot;destination2&quot;: {
            &quot;Address&quot;: &quot;https://backend2.example.com&quot;
          }
        },
        &quot;LoadBalancingPolicy&quot;: &quot;RoundRobin&quot;
      }
    }
  }
}
</code></pre>
<p>This setup defines a route (<code>route1</code>) that directs traffic to a cluster (<code>backendCluster</code>) with two destinations. The <code>LoadBalancingPolicy</code> is set to &quot;RoundRobin&quot; by default. You can adjust this based on your needs.</p>
<h3 id="load-balancing-strategies" tabindex="-1">Load Balancing Strategies</h3>
<p>YARP supports several load balancing strategies. Here&#8217;s a quick overview:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Strategy</th>
<th>Description</th>
<th>Best Used When</th>
</tr>
</thead>
<tbody>
<tr>
<td>RoundRobin</td>
<td>Sends requests sequentially to each server</td>
<td>Equal distribution is needed</td>
</tr>
<tr>
<td>LeastRequests</td>
<td>Chooses the server with the fewest active requests</td>
<td>Servers have different capacities</td>
</tr>
<tr>
<td>PowerOfTwoChoices</td>
<td>Randomly picks two servers and selects the less busy one</td>
<td>Balances performance and complexity</td>
</tr>
<tr>
<td>Random</td>
<td>Selects a server at random</td>
<td>Simple distribution works fine</td>
</tr>
<tr>
<td>FirstAlphabetical</td>
<td>Picks servers in alphabetical order</td>
<td>Useful for testing setups</td>
</tr>
</tbody>
</table>
<p>To apply a specific strategy, update the <code>LoadBalancingPolicy</code> in your cluster configuration. For example, to use &quot;LeastRequests&quot;:</p>
<pre><code class="language-json">&quot;Clusters&quot;: {
  &quot;backendCluster&quot;: {
    &quot;LoadBalancingPolicy&quot;: &quot;LeastRequests&quot;
  }
}
</code></pre>
<p>YARP also includes passive health monitoring to skip servers that aren&#8217;t functioning properly <a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>. For more advanced needs, you can create custom load balancing strategies by extending YARP&#8217;s base classes.</p>
<h2 id="implementing-and-testing-yarp-load-balancing" tabindex="-1" class="sb">Implementing and Testing YARP Load Balancing</h2>
<h3 id="setting-up-backend-services" tabindex="-1">Setting Up Backend Services</h3>
<p>To configure YARP load balancing, you&#8217;ll need multiple instances of your backend service. You can duplicate the project or use configuration overrides to run the same API on different ports. Here&#8217;s an example of setting up an instance:</p>
<pre><code class="language-csharp">var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls(&quot;http://localhost:5001&quot;);
</code></pre>
<p>Next, update the <code>appsettings.json</code> file to define the backend services for YARP:</p>
<pre><code class="language-json">{
  &quot;ReverseProxy&quot;: {
    &quot;Clusters&quot;: {
      &quot;apiCluster&quot;: {
        &quot;Destinations&quot;: {
          &quot;api1&quot;: { &quot;Address&quot;: &quot;http://localhost:5001&quot; },
          &quot;api2&quot;: { &quot;Address&quot;: &quot;http://localhost:5002&quot; },
          &quot;api3&quot;: { &quot;Address&quot;: &quot;http://localhost:5003&quot; }
        },
        &quot;LoadBalancingPolicy&quot;: &quot;PowerOfTwoChoices&quot;,
        &quot;HealthCheck&quot;: {
          &quot;Active&quot;: { &quot;Enabled&quot;: true }
        }
      }
    }
  }
}
</code></pre>
<h3 id="testing-the-load-balancer" tabindex="-1">Testing the Load Balancer</h3>
<p>Once your backend services are set up, it&#8217;s time to test the load balancer. Add request tracking and a health check endpoint to your application:</p>
<pre><code class="language-csharp">app.Use(async (context, next) =&gt;
{
    var logger = context.RequestServices.GetRequiredService&lt;ILogger&lt;Program&gt;&gt;();
    logger.LogInformation($&quot;Request received at {DateTime.UtcNow}: {context.Request.Path}&quot;);

    // Health check endpoint
    if (context.Request.Path == &quot;/health&quot;)
    {
        await context.Response.WriteAsJsonAsync(new { 
            Status = &quot;Healthy&quot;,
            Timestamp = DateTime.UtcNow
        });
        return;
    }
    await next();
});

app.MapGet(&quot;/instance-info&quot;, (HttpContext context) =&gt; Results.Ok(new {
    InstanceId = Environment.MachineName,
    Port = context.Connection.LocalPort,
    Timestamp = DateTime.UtcNow
}));
</code></pre>
<p>Now, test the setup using these methods:</p>
<ul>
<li><strong>Manual testing with curl</strong>:</li>
</ul>
<pre><code class="language-bash">curl http://localhost:5000/instance-info
</code></pre>
<ul>
<li><strong>Load testing with Apache Benchmark</strong>:</li>
</ul>
<pre><code class="language-bash">ab -n 1000 -c 10 http://localhost:5000/instance-info
</code></pre>
<ul>
<li><strong>Performance testing with k6</strong>:</li>
</ul>
<pre><code class="language-javascript">import http from 'k6/http';
export default function () {
    http.get('http://localhost:5000/instance-info');
}
</code></pre>
<p>Keep an eye on the following metrics to assess how well the load balancer is working:</p>
<ul>
<li>Distribution of requests across backends</li>
<li>Response times</li>
<li>Error rates</li>
<li>Health status of instances</li>
</ul>
<p>For production systems, consider using tools like <a href="https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Application Insights</a> or <a href="https://prometheus.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Prometheus</a> to get detailed insights into traffic and server health <a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a><a href="https://github.com/Azure-Samples/azure-openai-reverse-proxy" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[3]</sup></a>.</p>
<h6 id="sbb-itb-29cd4f6" tabindex="-1">sbb-itb-29cd4f6</h6>
<h2 id="advanced-topics-and-best-practices" tabindex="-1" class="sb">Advanced Topics and Best Practices</h2>
<h3 id="improving-scalability-and-performance" tabindex="-1">Improving Scalability and Performance</h3>
<p>Selecting the right load balancing strategy &#8211; like <strong>RoundRobin</strong>, <strong>LeastRequests</strong>, or <strong>PowerOfTwoChoices</strong> &#8211; is key to boosting scalability and performance. For a deeper dive, check out the earlier section on Load Balancing Strategies.</p>
<p>To keep tabs on performance, you can add custom middleware to track crucial metrics. Here&#8217;s an example in C#:</p>
<pre><code class="language-csharp">app.Use(async (context, next) =&gt;
{
    var timer = Stopwatch.StartNew();
    try
    {
        await next();
    }
    finally
    {
        timer.Stop();
        var logger = context.RequestServices.GetRequiredService&lt;ILogger&lt;Program&gt;&gt;();
        logger.LogInformation($&quot;Request processed in {timer.ElapsedMilliseconds}ms&quot;);
    }
});
</code></pre>
<p>After fine-tuning your load balancing approach, deploying YARP in a containerized setup ensures it can handle production-level demands with ease.</p>
<h3 id="deploying-yarp-with-docker-or-kubernetes" tabindex="-1">Deploying YARP with <a href="https://www.docker.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Docker</a> or <a href="https://kubernetes.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Kubernetes</a></h3>
<p><img decoding="async" src="/assets/images/imported/1b1c971f6ea65ebe7969.jpg" alt="Docker" style="width:100%;"></p>
<p>Using container platforms like Docker and Kubernetes allows you to maximize YARP&#8217;s load balancing capabilities while ensuring smooth orchestration. Here&#8217;s a simple Dockerfile for deploying YARP in a production environment:</p>
<pre><code class="language-dockerfile">FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY [&quot;YarpProxy.csproj&quot;, &quot;./&quot;]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT [&quot;dotnet&quot;, &quot;YarpProxy.dll&quot;]
</code></pre>
<p>To ensure reliability, you can integrate YARP&#8217;s health checks with Kubernetes liveness probes. Here&#8217;s an example configuration:</p>
<pre><code class="language-yaml">livenessProbe:
  httpGet:
    path: /health
    port: 80
</code></pre>
<p>For production, it&#8217;s smart to enable rate limiting and utilize YARP&#8217;s health checks to safeguard backend services and handle traffic surges effectively. These features also reroute requests away from unhealthy instances automatically <a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>. If you&#8217;re dealing with complex setups, you can extend YARP&#8217;s default behavior to create custom load balancing strategies tailored to your business needs while retaining its core architectural benefits <a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<h2 id="conclusion-and-key-takeaways" tabindex="-1" class="sb">Conclusion and Key Takeaways</h2>
<h3 id="review-of-setup-process" tabindex="-1">Review of Setup Process</h3>
<p>Setting up YARP for load balancing in .NET applications involves three main steps: creating an ASP.NET Core project, adding YARP services with <code>builder.Services.AddReverseProxy()</code>, and configuring routes and clusters in <code>appsettings.json</code> <a href="https://www.milanjovanovic.tech/blog/horizontally-scaling-aspnetcore-apis-with-yarp-load-balancing" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>. Here&#8217;s a quick breakdown:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Phase</th>
<th>Description</th>
<th>Key Components</th>
</tr>
</thead>
<tbody>
<tr>
<td>Initial Setup</td>
<td>Creating the project and integrating YARP</td>
<td>ASP.NET Core project, YARP NuGet package</td>
</tr>
<tr>
<td>Configuration</td>
<td>Defining routes and clusters</td>
<td>appsettings.json, load balancing strategies</td>
</tr>
<tr>
<td>Implementation</td>
<td>Connecting backend services and testing</td>
<td>Health checks, performance monitoring</td>
</tr>
</tbody>
</table>
<p>Once these steps are complete, you&#8217;re ready to see why YARP is a great option for .NET developers.</p>
<h3 id="why-choose-yarp" tabindex="-1">Why Choose YARP?</h3>
<p>YARP delivers high performance, scalability, and adaptability for .NET applications. Its seamless integration with ASP.NET Core includes features like built-in health checks and rate limiting. Plus, it supports multiple load balancing policies, such as RoundRobin, LeastRequests, and PowerOfTwoChoices, allowing you to fine-tune traffic distribution based on your needs <a href="https://www.milanjovanovic.tech/blog/horizontally-scaling-aspnetcore-apis-with-yarp-load-balancing" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a><a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a>.</p>
<blockquote>
<p>&quot;YARP is a robust and flexible reverse proxy solution tailored for .NET developers. Whether you need simple routing, complex load balancing, or advanced transformations, YARP provides the tools you need to build a performant and scalable reverse proxy.&quot; <a href="https://ijanggmu.hashnode.dev/exploring-yarp-the-reverse-proxy-for-net-developers" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[2]</sup></a></p>
</blockquote>
<h3 id="stay-updated-with-the-net-newsletter" tabindex="-1">Stay Updated with the .NET Newsletter</h3>
<p>YARP is constantly evolving, and keeping up with its new features and best practices is essential for optimizing your systems. The .NET Newsletter offers daily updates on YARP and related technologies, helping you stay ahead in load balancing and distributed systems.</p>
<p>What you’ll find:</p>
<ul>
<li>Updates on the latest YARP features</li>
<li>Real-world implementation case studies</li>
<li>Insights into trends in reverse proxy and load balancing</li>
</ul>
<p>Stay informed to make the most of YARP in your projects.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/wcf-performance-monitoring-top-tools-and-counters/" style="display: inline;">WCF Performance Monitoring: Top Tools &#038; Counters</a></li>
<li>gRPC with .NET Core: Step-by-Step Guide</li>
<li>OpenTelemetry for .NET Microservices: Guide</li>
<li>Message Queue Patterns in .NET: Core Guide</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn how to set up YARP for effective load balancing in .NET applications, enhancing performance and reliability for backend services.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_5bbebf489b2aedecfdb2d6a7ec046308-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_5bbebf489b2aedecfdb2d6a7ec046308-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Message Queue Implementation in .NET Core</title><link href="https://codejack.com/2025/01/message-queue-implementation-in-net-core/" rel="alternate" type="text/html" title="Message Queue Implementation in .NET Core" /><published>2025-01-14T00:09:04-05:00</published><updated>2025-01-14T00:09:04-05:00</updated><id>https://codejack.com/2025/01/message-queue-implementation-in-net-core</id><content type="html" xml:base="https://codejack.com/2025/01/message-queue-implementation-in-net-core/"><![CDATA[<p>Message queues are essential for building scalable and reliable .NET Core applications. They act as intermediaries between components, ensuring smooth communication even during high traffic or failures. In this guide, you&#8217;ll learn:</p>
<ul>
<li><strong>What are Message Queues?</strong> Tools like <a href="https://www.rabbitmq.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">RabbitMQ</a> and <a href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure Service Bus</a> manage message delivery between producers and consumers.</li>
<li><strong>Why use them?</strong> They improve reliability, scalability, and system performance by decoupling components and buffering traffic.</li>
<li><strong>How to implement?</strong> Use RabbitMQ with <a href="https://www.docker.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Docker</a> or Azure Service Bus for cloud-based solutions. Configuration and code examples are provided for both.</li>
<li><strong>Best Practices:</strong> Optimize performance with batching and prefetching, handle errors with retry logic, and secure your queues with encryption and access controls.</li>
</ul>
<p><strong>Quick Comparison of RabbitMQ vs. Azure Service Bus</strong></p>
<table style="width:100%;">
<thead>
<tr>
<th>Feature</th>
<th>RabbitMQ</th>
<th>Azure Service Bus</th>
</tr>
</thead>
<tbody>
<tr>
<td>Setup</td>
<td>Local (Docker) or cloud</td>
<td>Cloud-based (Azure)</td>
</tr>
<tr>
<td>Protocol</td>
<td>AMQP</td>
<td>AMQP, HTTP</td>
</tr>
<tr>
<td>Ideal Use Case</td>
<td>High-speed, local messaging</td>
<td>Cloud integrations</td>
</tr>
</tbody>
</table>
<p>This article covers everything you need to start using message queues in .NET Core, from setup to advanced tips for performance and security.</p>
<h2 id="setting-up-a-message-queue-in-net-core" tabindex="-1" class="sb">Setting Up a Message Queue in .NET Core</h2>
<p>Let’s walk through the steps to implement message queues in your .NET Core application.</p>
<h3 id="tools-and-prerequisites" tabindex="-1">Tools and Prerequisites</h3>
<p>Here’s what you’ll need to get started:</p>
<ul>
<li><strong>.NET Core SDK (3.0 or higher)</strong>: The development platform for building your application.</li>
<li><strong><a href="https://visualstudio.microsoft.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Visual Studio</a> (2022 or higher)</strong>: Recommended IDE for development.</li>
<li><strong>C# (8.0 or higher)</strong>: Programming language.</li>
<li><strong>Message Broker</strong>: Choose between RabbitMQ or Azure Service Bus.</li>
</ul>
<p>You’ll also need specific <a href="https://www.nuget.org/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">NuGet</a> packages based on the message broker:</p>
<ul>
<li><strong>For RabbitMQ</strong>:
<ul>
<li><a href="https://masstransit.io/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">MassTransit</a></li>
<li>MassTransit.RabbitMQ</li>
</ul>
</li>
<li><strong>For Azure Service Bus</strong>:
<ul>
<li>Azure.Messaging.ServiceBus</li>
<li>Azure.Identity</li>
</ul>
</li>
</ul>
<h3 id="installing-and-configuring-rabbitmq" tabindex="-1">Installing and Configuring <a href="https://www.rabbitmq.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">RabbitMQ</a></h3>
<p><img decoding="async" src="/assets/images/imported/e9de47d63501873c77e0.jpg" alt="RabbitMQ" style="width:100%;"></p>
<p>To set up RabbitMQ, you can install it directly or use Docker for local development. Here’s the Docker command to spin up RabbitMQ:</p>
<pre><code class="language-bash">docker run -d --hostname my-rabbitmq-server --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
</code></pre>
<p>Next, configure the RabbitMQ connection in your <code>appsettings.json</code> file:</p>
<pre><code class="language-json">&quot;RabbitMQ&quot;: {  
  &quot;HostName&quot;: &quot;localhost&quot;,  
  &quot;UserName&quot;: &quot;guest&quot;,  
  &quot;Password&quot;: &quot;guest&quot;,
  &quot;VirtualHost&quot;: &quot;/&quot;
}
</code></pre>
<p>Here’s how you can establish a basic connection in your application:</p>
<pre><code class="language-csharp">var factory = new ConnectionFactory
{
    HostName = &quot;localhost&quot;,
    UserName = &quot;guest&quot;,
    Password = &quot;guest&quot;,
    VirtualHost = &quot;/&quot;
};

using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
</code></pre>
<p>If you’re looking for a cloud-based option, Azure Service Bus is another excellent choice.</p>
<h3 id="setting-up-azure-service-bus" tabindex="-1">Setting Up <a href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure Service Bus</a></h3>
<p><img decoding="async" src="/assets/images/imported/25ccf8f4ebb46cc6113e.jpg" alt="Azure Service Bus" style="width:100%;"></p>
<p>First, create a Service Bus namespace in the Azure portal. Once it’s set up, retrieve the connection string and add it to your application. Here’s an example of how to use it in code:</p>
<pre><code class="language-csharp">using Azure.Messaging.ServiceBus;

string connectionString = &quot;&lt;your_connection_string&gt;&quot;;
await using ServiceBusClient client = new(connectionString);
</code></pre>
<p>To send messages, you’ll need a sender and a message batch:</p>
<pre><code class="language-csharp">ServiceBusSender sender = client.CreateSender(&quot;&lt;queue_name&gt;&quot;);
ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();
</code></pre>
<p>With these steps, you’re ready to integrate message queues into your .NET Core application. Whether you choose RabbitMQ or Azure Service Bus, both options can handle your messaging needs effectively.</p>
<h2 id="using-message-queues-in-net-core" tabindex="-1" class="sb">Using Message Queues in .NET Core</h2>
<p>Once RabbitMQ or Azure Service Bus is set up, you can start sending and receiving messages in .NET Core. Below, we’ll walk through the process.</p>
<h3 id="creating-and-sending-messages" tabindex="-1">Creating and Sending Messages</h3>
<p>To send messages using RabbitMQ, you’ll need a publisher service. This service converts messages into JSON and sends them to a queue using <code>BasicPublish</code>. Here&#8217;s a simple example:</p>
<pre><code class="language-csharp">public async Task PublishMessageAsync&lt;T&gt;(T message, string queueName)
{
    var factory = new ConnectionFactory { HostName = &quot;localhost&quot; };
    using var connection = factory.CreateConnection();
    using var channel = connection.CreateModel();

    var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
    channel.BasicPublish(exchange: &quot;&quot;, routingKey: queueName, basicProperties: null, body: body);
}
</code></pre>
<h3 id="receiving-and-processing-messages" tabindex="-1">Receiving and Processing Messages</h3>
<p>For receiving messages, you’ll need a consumer service that listens to the queue and processes incoming messages:</p>
<pre><code class="language-csharp">using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =&gt;
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine($&quot;Received: {message}&quot;);
};

channel.BasicConsume(queue: &quot;my_queue&quot;, autoAck: true, consumer: consumer);
</code></pre>
<p>This setup allows your application to process messages asynchronously, ensuring smooth communication between different services.</p>
<h3 id="example-with-rabbitmq" tabindex="-1">Example with RabbitMQ</h3>
<p>Here’s a practical example using RabbitMQ to handle order validation in an e-commerce system:</p>
<pre><code class="language-csharp">// Order message model
public class OrderMessage
{
    public int OrderId { get; set; }
    public DateTime OrderTime { get; set; }
    public decimal TotalAmount { get; set; }
}

// Publishing an order message
await PublishMessageAsync(order, &quot;order_validation_queue&quot;);

// Consuming order messages
consumer.Received += (model, ea) =&gt;
{
    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
    var order = JsonConvert.DeserializeObject&lt;OrderMessage&gt;(message);
    ValidateAndProcessOrder(order);
};
</code></pre>
<p>This example shows how RabbitMQ can help separate order validation from other parts of your application. Although this example focuses on RabbitMQ, Azure Service Bus works in a similar way, following comparable patterns for sending and receiving messages.</p>
<h6 id="sbb-itb-29cd4f6" tabindex="-1">sbb-itb-29cd4f6</h6>
<h2 id="best-practices-for-message-queue-implementation" tabindex="-1" class="sb">Best Practices for Message Queue Implementation</h2>
<p>Now that we&#8217;ve gone over how to use message queues, let&#8217;s dive into some practical tips to ensure they run smoothly and securely.</p>
<h3 id="boosting-performance" tabindex="-1">Boosting Performance</h3>
<p>To keep your message queue system running efficiently, consider <strong>message batching</strong> and <strong>prefetching</strong>. Batching minimizes network overhead by sending multiple messages together:</p>
<pre><code class="language-csharp">var batch = channel.CreateBasicPublishBatch();
batch.Add(exchange: &quot;&quot;, routingKey: queueName, body: messageBody);
batch.Publish();
</code></pre>
<p>Prefetching, on the other hand, allows consumers to handle several messages at once, cutting down on fetching delays:</p>
<pre><code class="language-csharp">channel.BasicQos(prefetchSize: 0, prefetchCount: 10, global: false);
</code></pre>
<h3 id="managing-errors-and-retries" tabindex="-1">Managing Errors and Retries</h3>
<p>Performance is essential, but so is resilience. Your system should gracefully handle failures. Here&#8217;s an example of retry logic that uses exponential backoff:</p>
<pre><code class="language-csharp">public async Task ProcessMessageWithRetryAsync&lt;T&gt;(T message, Func&lt;T, Task&gt; processor)
{
    int maxRetries = 3;
    for (int attempt = 0; attempt &lt; maxRetries; attempt++)
    {
        try
        {
            await processor(message);
            return;
        }
        catch (Exception)
        {
            if (attempt == maxRetries - 1) throw;
            await Task.Delay((int)Math.Pow(2, attempt) * 1000);
        }
    }
}
</code></pre>
<p>This approach helps ensure that transient issues don&#8217;t derail your entire system.</p>
<h3 id="securing-your-message-queues" tabindex="-1">Securing Your Message Queues</h3>
<p>Security is a must. Start by setting up <strong>authentication</strong>, <strong>authorization</strong>, and <strong>encryption</strong>. For example, you can configure SSL/TLS to secure connections:</p>
<pre><code class="language-csharp">var factory = new ConnectionFactory
{
    HostName = &quot;localhost&quot;,
    Port = 5671,
    Ssl = new SslOption
    {
        Enabled = true,
        ServerName = &quot;your_server_name&quot;
    }
};
</code></pre>
<p>Additionally, implement role-based access controls and encrypt messages containing sensitive information. Use monitoring tools to catch unusual activity or potential threats as they happen.</p>
<p>Here&#8217;s a quick comparison of common message queue setups:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Configuration</th>
<th>Throughput</th>
<th>Best For</th>
</tr>
</thead>
<tbody>
<tr>
<td>Single Consumer</td>
<td>Up to 1,000 msg/s</td>
<td>Simple workflows</td>
</tr>
<tr>
<td>Batch Processing</td>
<td>Up to 10,000 msg/s</td>
<td>Bulk operations</td>
</tr>
<tr>
<td>Parallel Consumers</td>
<td>Up to 50,000 msg/s</td>
<td>High-volume processing</td>
</tr>
</tbody>
</table>
<h2 id="conclusion-and-next-steps" tabindex="-1" class="sb">Conclusion and Next Steps</h2>
<h3 id="key-points" tabindex="-1">Key Points</h3>
<p>In this guide, we’ve covered the essentials of using message queues in .NET Core, from setting up the basics to more advanced configurations. The success of your implementation rests on three main factors: <strong>performance</strong>, <strong>error handling</strong>, and <strong>security</strong>. These elements are the foundation for creating systems that can process large volumes of messages efficiently while keeping data accurate and systems stable.</p>
<p>Here’s what to prioritize as you work on your message queues:</p>
<ul>
<li><strong>Boost performance</strong> with techniques like batching, prefetching, and parallel processing.</li>
<li><strong>Strengthen error handling</strong> by using retry mechanisms and dead-letter queues.</li>
<li><strong>Secure your system</strong> by implementing proper authentication, authorization, and encryption.</li>
</ul>
<p>Start small with straightforward workflows and scale up as your needs grow. Keep an eye on throughput and failure rates to ensure your system performs as expected. Staying up to date with the latest tools and methods is also key to long-term success.</p>
<h3 id="further-learning" tabindex="-1">Further Learning</h3>
<p>Want to deepen your knowledge? Subscribe to the <a href="https://dotnetnews.co" style="display: inline;">.NET Newsletter</a> for updates on .NET Core and messaging best practices. Try out different patterns like RabbitMQ’s batch publishing or Azure Service Bus’s retry policies to discover what works best for your specific needs. Regularly track metrics like message throughput, latency, and failure rates to keep your system running smoothly.</p>
<p>For development, you might start with in-memory message buses to test and refine your messaging patterns. Once validated, transition to a more robust message queue system for production <a href="https://www.milanjovanovic.tech/blog/lightweight-in-memory-message-bus-using-dotnet-channels" target="_blank" style="display: inline;" rel="nofollow noopener noreferrer"><sup>[1]</sup></a>. This step-by-step approach helps you build confidence while preparing for real-world demands.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/dependency-injection-in-net-core-principles-and-examples/" style="display: inline;">Dependency Injection in .NET Core: Principles &#038; Examples</a></li>
<li>OpenTelemetry for .NET Microservices: Guide</li>
<li>Message Queue Patterns in .NET: Core Guide</li>
<li><a href="/2025/01/yarp-load-balancing-in-net-setup-guide/" style="display: inline;">YARP Load Balancing in .NET: Setup Guide</a></li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn how to implement message queues in .NET Core for improved scalability and reliability in your applications.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_96b6e0741d9e68da9afe74724747e9ff-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_96b6e0741d9e68da9afe74724747e9ff-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Handling Range Requests in .NET 9 Behind Azure Front Door</title><link href="https://codejack.com/2024/12/handling-range-requests-in-net-9-behind-azure-front-door/" rel="alternate" type="text/html" title="Handling Range Requests in .NET 9 Behind Azure Front Door" /><published>2024-12-20T10:47:38-05:00</published><updated>2024-12-20T10:47:38-05:00</updated><id>https://codejack.com/2024/12/handling-range-requests-in-net-9-behind-azure-front-door</id><content type="html" xml:base="https://codejack.com/2024/12/handling-range-requests-in-net-9-behind-azure-front-door/"><![CDATA[<p class="wp-block-paragraph">When deploying a <strong>.NET 9 application</strong> behind Azure Front Door with <strong>response compression enabled</strong>, you might encounter unexpected issues with static files, such as HTTP <code>416 Range Not Satisfiable</code> errors. These arise because Front Door often sends <strong>byte-range requests</strong> for optimization, which your application may not handle properly by default.</p>



<p class="wp-block-paragraph">To address this, you can configure your app to <strong>remove incoming <code>Range</code> headers</strong> and explicitly communicate that range requests are not supported by adding the <code>Accept-Ranges: none</code> header to all responses.</p>



<h3 class="wp-block-heading">Code to Fix Range Request Issues</h3>



<p class="wp-block-paragraph">Place this middleware <strong>before any static file handling code</strong> in your <code>Program.cs</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""><code>// Middleware to remove "Range" headers from requests
app.Use(async (context, next) =>
{
    if (context.Request.Headers.ContainsKey("Range"))
    {
        context.Request.Headers.Remove("Range");
    }
    await next();
});

// Middleware to add "Accept-Ranges: none" in responses
app.Use(async (context, next) =>
{
    await next();
    context.Response.Headers["Accept-Ranges"] = "none";
});</code></pre>



<h3 class="wp-block-heading">Why This Is Needed</h3>



<p class="wp-block-paragraph">When <strong>compression</strong> is enabled in Azure Front Door, it may send range requests to optimize bandwidth. However, if your app does not properly support or handle range requests, it can result in errors for static files.</p>



<ul class="wp-block-list">
<li><strong>What the code does</strong>:
<ul class="wp-block-list">
<li>Removes the <code>Range</code> header from incoming requests to prevent partial content handling.</li>



<li>Adds the <code>Accept-Ranges: none</code> header to responses, telling clients that range requests are not supported.</li>
</ul>
</li>



<li><strong>Why it matters</strong>:
<ul class="wp-block-list">
<li>Ensures smooth file delivery without unnecessary errors.</li>



<li>Helps maintain compatibility with Front Door&#8217;s caching and compression optimizations.</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">Where to Place It</h3>



<p class="wp-block-paragraph">The placement of this middleware is crucial:</p>



<ol class="wp-block-list">
<li><strong>Before Static File Middleware</strong>: It must come before any call to <code>app.UseStaticFiles()</code>  so that static file handling bypasses range processing entirely.</li>



<li><strong>General Structure</strong>:</li>
</ol>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""><code>   app.Use(async (context, next) =>
   {
       // Remove Range header
   });

   app.Use(async (context, next) =>
   {
       // Add Accept-Ranges header
   });

   // Static file handling (generic or ABP-specific)
   app.UseStaticFiles();</code></pre>



<h3 class="wp-block-heading">When You Don’t Need This</h3>



<p class="wp-block-paragraph">If compression is <strong>disabled</strong> in Azure Front Door or your app doesn’t rely on static files, this fix may not be necessary. But when compression is active, this small adjustment ensures seamless compatibility.</p>



<p class="wp-block-paragraph">By handling this proactively, you can avoid frustrating issues in production environments. Happy coding! 🚀</p>]]></content><author><name>feech</name></author><category term="Uncategorized" /><category term="azure" /><category term="csharp" /><summary type="html"><![CDATA[When deploying a .NET 9 application behind Azure Front Door with response compression enabled, you might encounter unexpected issues with static files, such as HTTP 416 Range Not Satisfiable errors. These...]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2024/12/416err-5.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2024/12/416err-5.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Exception Handling in C# Multithreaded Apps: Guide</title><link href="https://codejack.com/2024/11/exception-handling-in-c-multithreaded-apps-guide/" rel="alternate" type="text/html" title="Exception Handling in C# Multithreaded Apps: Guide" /><published>2024-11-21T00:04:55-05:00</published><updated>2024-11-21T00:04:55-05:00</updated><id>https://codejack.com/2024/11/exception-handling-in-c-multithreaded-apps-guide</id><content type="html" xml:base="https://codejack.com/2024/11/exception-handling-in-c-multithreaded-apps-guide/"><![CDATA[<p>Here&#8217;s what you need to know about handling errors in C# multithreaded applications:</p>
<p><strong>Key Points:</strong></p>
<ul>
<li>Traditional try-catch blocks aren&#8217;t enough for multithreaded apps</li>
<li>Unhandled exceptions can crash your entire application</li>
<li>The <a href="https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Task Parallel Library</a> (TPL) is your best friend for error management</li>
</ul>
<p>Here&#8217;s how to handle errors in multithreaded C# apps:</p>
<ol>
<li><strong>Thread-Level Handling:</strong></li>
</ol>
<pre><code class="language-csharp">Thread workerThread = new Thread(() =&gt; {
    try {
        // Your code here
    }
    catch (Exception ex) {
        // Handle error
    }
});
</code></pre>
<ol start="2">
<li><strong>Task-Based Handling:</strong></li>
</ol>
<pre><code class="language-csharp">try {
    await Task.Run(() =&gt; {
        // Your async code
    });
}
catch (AggregateException ex) {
    // Handle multiple errors
}
</code></pre>
<ol start="3">
<li><strong>Global Error Handling:</strong></li>
</ol>
<pre><code class="language-csharp">TaskScheduler.UnobservedTaskException += (sender, e) =&gt; {
    // Catch unhandled task errors
};
</code></pre>
<table style="width:100%;">
<thead>
<tr>
<th>Error Handling Method</th>
<th>Best For</th>
<th>Main Benefit</th>
</tr>
</thead>
<tbody>
<tr>
<td>try-catch blocks</td>
<td>Single threads</td>
<td>Simple, direct handling</td>
</tr>
<tr>
<td>TPL/Tasks</td>
<td>Multiple async operations</td>
<td>Manages multiple errors</td>
</tr>
<tr>
<td>Global handlers</td>
<td>Application-wide coverage</td>
<td>Catches unhandled exceptions</td>
</tr>
</tbody>
</table>
<p><strong>Bottom line:</strong> Don&#8217;t let exceptions slip through the cracks. Implement proper error handling at thread, task, and application levels to keep your multithreaded C# apps stable and reliable.</p>
<h2 id="related-video-from-youtube" tabindex="-1" class="sb">Related video from YouTube</h2>
<p><iframe class="sb-iframe" src="https://www.youtube.com/embed/gb5qKcjf2x0" frameborder="0" loading="lazy" allowfullscreen style="width: 100%; height: auto; aspect-ratio: 16/9;"></iframe></p>
<h2 id="basic-methods-for-thread-error-handling" tabindex="-1" class="sb">Basic Methods for Thread Error Handling</h2>
<p>Handling errors in multithreaded C# applications is critical to keep things running smoothly. Let’s break down some key techniques you can rely on to deal with exceptions in multithreading.</p>
<h3 id="how-to-use-try-catch-in-threads" tabindex="-1">How to Use try-catch in Threads</h3>
<p>When using <code>try-catch</code> within threaded code, you need to carefully manage both error handling and resource cleanup. The best way to do this is to wrap everything inside the thread&#8217;s execution code with <code>try-catch</code> and use a <code>finally</code> block for cleaning up resources afterwards.</p>
<p>Here’s an example:</p>
<pre><code class="language-csharp">Thread workerThread = new Thread(() =&gt; {
    try {
        // Your thread's main work goes here
    }
    catch (Exception ex) {
        // Log the error or take appropriate action
    }
    finally {
        // Clean up resources here if needed
    }
});
</code></pre>
<blockquote>
<p>&quot;The <code>Application.ThreadException</code> event can be used to catch unhandled exceptions from threads, but it does not catch exceptions from threads that are not started via the <code>Application.Run</code> method.&quot;</p>
</blockquote>
<h3 id="sending-errors-using-thread.join" tabindex="-1">Sending Errors Using Thread.Join</h3>
<p><code>Thread.Join</code> helps you bridge the gap between worker threads and the main thread by enabling error propagation. It’s especially handy when you need the main thread to know what went wrong in a worker thread and address it centrally.</p>
<table style="width:100%;">
<thead>
<tr>
<th><strong>Error Handling Method</strong></th>
<th><strong>Purpose</strong></th>
<th><strong>Best Used When</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>try-catch in Thread</td>
<td>To handle errors locally</td>
<td>Dealing with thread-specific errors</td>
</tr>
<tr>
<td>Thread.Join</td>
<td>To report errors to main</td>
<td>Syncing errors with the main thread</td>
</tr>
<tr>
<td>finally block</td>
<td>For resource cleanup</td>
<td>Ensuring cleanup regardless of issues</td>
</tr>
</tbody>
</table>
<p>This table gives you a quick snapshot of when to apply each approach.</p>
<h3 id="program-wide-error-handling" tabindex="-1">Program-Wide Error Handling</h3>
<p>If you want to catch unhandled exceptions across all threads, program-wide error handling is the way to go. This kind of setup acts like a safety net for your application, making sure exceptions don’t bring everything crashing down.</p>
<p>Here’s how you can wire it up:</p>
<pre><code class="language-csharp">Application.ThreadException += new ThreadExceptionEventHandler((sender, e) =&gt; {
    // Place your centralized error handling code here
});
</code></pre>
<p>Using a centralized error strategy ensures consistency and simplifies managing exceptions throughout your app. A key point to remember when rethrowing exceptions in this approach is to use <code>throw</code> instead of <code>throw ex</code>, as this preserves the original stack trace.</p>
<p>Unmanaged exceptions in threads can lead to application crashes, so it’s vital to think ahead and combine thread-level and system-level error handling. This way, you safeguard both your threads and the overall application stability.</p>
<h2 id="error-handling-with-task-parallel-library" tabindex="-1" class="sb">Error Handling with <a href="https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Task Parallel Library</a></h2>
<p><img decoding="async" src="/assets/images/imported/8df4fda1fdaa163185a2.jpg" alt="Task Parallel Library" style="width:100%;"></p>
<p>The Task Parallel Library (TPL) simplifies error handling in multithreaded C# applications using the <code>AggregateException</code> class. This makes managing exceptions from parallel tasks much more efficient and streamlined.</p>
<h3 id="how-aggregateexception-works" tabindex="-1">How AggregateException Works</h3>
<p><code>AggregateException</code> serves as a container to collect multiple exceptions that might occur during parallel operations. Instead of tracking errors scattered across threads, you can access all exceptions through a single object.</p>
<pre><code class="language-csharp">try {
    Parallel.Invoke(
        () =&gt; RiskyOperation1(),
        () =&gt; RiskyOperation2(),
        () =&gt; RiskyOperation3()
    );
}
catch (AggregateException ae) {
    foreach (var ex in ae.InnerExceptions) {
        // Process each exception
    }
}
</code></pre>
<h3 id="key-aggregateexception-methods" tabindex="-1">Key <code>AggregateException</code> Methods</h3>
<p>The <code>AggregateException</code> class includes methods like <code>Flatten()</code> and <code>Handle()</code>, which are helpful for breaking down nested exceptions and selectively processing specific types of errors.</p>
<table style="width:100%;">
<thead>
<tr>
<th>Method</th>
<th>Purpose</th>
<th>Usage Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Flatten()</strong></td>
<td>Unwraps nested <code>AggregateException</code> objects</td>
<td>Useful for tasks with multiple nested exceptions</td>
</tr>
<tr>
<td><strong>Handle()</strong></td>
<td>Filters and processes specific exceptions</td>
<td>Ideal for managing certain exception types</td>
</tr>
<tr>
<td><strong>InnerExceptions</strong></td>
<td>Lists all underlying exceptions</td>
<td>Enables easy iteration through all errors</td>
</tr>
</tbody>
</table>
<blockquote>
<p><em>&quot;Using <code>throw;</code> instead of <code>throw ex;</code> when re-throwing an exception keeps the original stack trace intact, which is key for debugging.&quot;</em></p>
</blockquote>
<h3 id="managing-errors-with-task-methods" tabindex="-1">Managing Errors with Task Methods</h3>
<p>When handling exceptions in tasks, the TPL offers tools like the <code>Task.Wait()</code> method and <code>Task.Exception</code> property. These ensure that errors are caught and handled systematically.</p>
<pre><code class="language-csharp">Task task = Task.Run(() =&gt; {
    // Code that may throw exceptions
});

try {
    task.Wait();
}
catch (AggregateException ae) {
    ae.Handle(ex =&gt; {
        if (ex is OperationCanceledException) {
            // Handle task cancellation
            return true;
        }
        return false; // Re-throw other exceptions
    });
}
</code></pre>
<p>When using TPL, it’s important to adopt good error-handling practices. Specifically, handle specific exceptions first to ensure clarity and structure. Avoid suppressing exceptions without proper logging or error management; this fosters better stability and easier debugging of your applications.</p>
<h6 id="sbb-itb-29cd4f6" class="sb-banner" style="color:transparent!important;line-height:0!important;padding:0!important;margin:0!important;">sbb-itb-29cd4f6</h6>
<h2 id="tips-for-better-thread-error-handling" tabindex="-1" class="sb">Tips for Better Thread Error Handling</h2>
<p>Handling errors effectively in C# multithreaded applications requires more than adding try-catch blocks. Below, you&#8217;ll find practical tips to improve your application&#8217;s reliability and make troubleshooting much less painful.</p>
<h3 id="write-informative-error-logs" tabindex="-1">Write Informative Error Logs</h3>
<p>Detailed error logs are essential for understanding what went wrong, especially in production. A good log entry should provide context, including the thread ID, timestamp, and the application’s state when the issue occurred.</p>
<pre><code class="language-csharp">private static void LogThreadException(Exception ex)
{
    var logEntry = $&quot;[Thread {Thread.CurrentThread.ManagedThreadId}] &quot; +
                   $&quot;Exception Type: {ex.GetType().Name}\n&quot; +
                   $&quot;Message: {ex.Message}\n&quot; +
                   $&quot;Stack Trace: {ex.StackTrace}&quot;;

    Logger.Error(logEntry);
}
</code></pre>
<blockquote>
<p>&quot;When rethrowing exceptions, always use <code>throw;</code> instead of <code>throw ex;</code> to keep the original stack trace intact. It’s a small step that makes debugging much easier.&quot;</p>
</blockquote>
<h3 id="avoid-hiding-errors" tabindex="-1">Avoid Hiding Errors</h3>
<p>Suppressing errors might seem convenient at first &#8211; but it often leads to bigger headaches later. Instead of sweeping exceptions under the rug, adopt strategies that handle them with clarity.</p>
<table style="width:100%;">
<thead>
<tr>
<th><strong>Error Handling Pattern</strong></th>
<th><strong>Why Use It</strong></th>
<th><strong>How to Implement</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Centralized Handler</td>
<td>Ensures a unified approach to processing errors.</td>
<td>Implement global exception handlers.</td>
</tr>
<tr>
<td>Specific Exception Catching</td>
<td>Focuses on handling only what’s necessary.</td>
<td>Catch specific exceptions before general ones.</td>
</tr>
<tr>
<td>Logging Strategy</td>
<td>Tracks errors effectively with added context.</td>
<td>Include rich details in your logs.</td>
</tr>
</tbody>
</table>
<h3 id="design-for-recovery" tabindex="-1">Design for Recovery</h3>
<p>When errors occur, your application should aim to recover instead of failing completely. Build mechanisms to handle failures gracefully and avoid cascading problems.</p>
<pre><code class="language-csharp">public async Task ExecuteWithRetry(Func&lt;Task&gt; operation)
{
    int maxRetries = 3;
    for (int i = 0; i &lt; maxRetries; i++)
    {
        try
        {
            await operation();
            return;
        }
        catch (Exception ex) when (i &lt; maxRetries - 1)
        {
            LogThreadException(ex);
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i)));
        }
    }
}
</code></pre>
<blockquote>
<p>&quot;In complex applications, centralized exception handling offers an easier way to maintain uniform procedures and simplifies debugging across multiple layers.&quot;</p>
</blockquote>
<h2 id="advanced-error-handling-methods" tabindex="-1" class="sb">Advanced Error Handling Methods</h2>
<p>In modern C# applications, dealing with complex asynchronous operations and nested tasks requires thoughtful error handling. Let&#8217;s dive into some techniques that help ensure efficient error management, especially in multithreaded environments.</p>
<h3 id="handling-errors-in-async%2Fawait" tabindex="-1">Handling Errors in async/await</h3>
<p>Handling errors in asynchronous methods can be tricky. Using <code>try-catch</code> blocks correctly inside <code>async</code> methods is crucial. It&#8217;s important to manage exceptions within the <code>async</code> method itself instead of wrapping <code>await</code> calls directly.</p>
<pre><code class="language-csharp">public async Task ProcessDataAsync()
{
    try
    {
        await Task.Delay(100); // Simulating work
        throw new InvalidOperationException(&quot;Processing failed&quot;);
    }
    catch (Exception ex)
    {
        await LogAsync($&quot;Error during processing: {ex.Message}&quot;);
        throw; // Preserve the original stack trace
    }
}
</code></pre>
<blockquote>
<p>&quot;When you use exception handling, less code is executed in normal conditions.&quot; &#8211; Microsoft Learn, Best practices for exceptions.</p>
</blockquote>
<h3 id="capturing-unhandled-task-errors" tabindex="-1">Capturing Unhandled Task Errors</h3>
<p>Unhandled task errors can wreak havoc when left unnoticed, often surfacing only when it&#8217;s too late. The <code>TaskScheduler.UnobservedTaskException</code> event acts as a safeguard, catching exceptions that otherwise wouldn&#8217;t be observed.</p>
<pre><code class="language-csharp">TaskScheduler.UnobservedTaskException += (sender, e) =&gt;
{
    e.SetObserved(); // Prevent process termination

    var aggregateEx = e.Exception as AggregateException;
    foreach (var ex in aggregateEx.InnerExceptions)
    {
        Logger.Error($&quot;Unobserved Task Exception: {ex.Message}&quot;);
    }
};
</code></pre>
<h3 id="dealing-with-nested-task-errors" tabindex="-1">Dealing with Nested Task Errors</h3>
<p>Handling nested tasks can get complicated as exceptions may originate from multiple layers. The <code>AggregateException</code> class is an effective way to handle these cases. Below are strategies for addressing nested task errors:</p>
<table style="width:100%;">
<thead>
<tr>
<th><strong>Strategy</strong></th>
<th><strong>Purpose</strong></th>
<th><strong>How To Apply</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Flatten Exceptions</td>
<td>Make nested exceptions easier to process</td>
<td>Call <code>AggregateException.Flatten()</code></td>
</tr>
<tr>
<td>Manage Child Task Errors</td>
<td>Keep track of multiple child tasks</td>
<td>Use <code>Task.WhenAll</code> within <code>try-catch</code></td>
</tr>
<tr>
<td>Selective Error Handling</td>
<td>Handle specific exception types</td>
<td>Implement <code>AggregateException.Handle()</code></td>
</tr>
</tbody>
</table>
<p>Here&#8217;s an example of managing nested task errors using these methods:</p>
<pre><code class="language-csharp">public async Task ExecuteNestedTasksAsync()
{
    try
    {
        var tasks = new List&lt;Task&gt;();
        for (int i = 0; i &lt; 3; i++)
        {
            tasks.Add(Task.Run(() =&gt; ProcessDataAsync()));
        }

        await Task.WhenAll(tasks);
    }
    catch (AggregateException ae)
    {
        ae.Handle(ex =&gt;
        {
            if (ex is InvalidOperationException)
            {
                Logger.Error($&quot;Operation failed: {ex.Message}&quot;);
                return true;
            }
            return false;
        });
    }
}
</code></pre>
<blockquote>
<p>&quot;Never swallow exceptions. That is, you should never hide the error that has occurred.&quot; &#8211; InfoWorld, Best practices for handling exceptions in C#.</p>
</blockquote>
<h2 id="summary" tabindex="-1" class="sb">Summary</h2>
<h3 id="key-takeaways" tabindex="-1">Key Takeaways</h3>
<p>Handling exceptions in multithreaded C# applications requires careful planning to prevent crashes and ensure reliable error handling. The core principle involves using <em>try-catch blocks</em> effectively, prioritizing specific exception types over generic catches. This becomes even more critical as modern applications increasingly use the async/await pattern.</p>
<p>Another crucial element is centralized exception handling, which provides consistency and helps to maintain proper error hierarchies. As emphasized in Microsoft&#8217;s guidance:</p>
<blockquote>
<p>&quot;When creating custom exception classes, always derive from the Exception class, not from the ApplicationException class.&quot;</p>
</blockquote>
<p>This approach helps ensure well-structured and predictable error handling in your applications.</p>
<p>Here’s a breakdown of some key practices for multithreaded exception handling:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Practice</th>
<th>How to Apply</th>
<th>Why It Matters</th>
</tr>
</thead>
<tbody>
<tr>
<td>Exception Propagation</td>
<td>Let exceptions bubble to higher levels</td>
<td>Ensures errors are handled appropriately</td>
</tr>
<tr>
<td>Resource Management</td>
<td>Use <code>finally</code> blocks or <code>using</code> statements</td>
<td>Guarantees proper cleanup, even in error situations</td>
</tr>
<tr>
<td>Logging Strategy</td>
<td>Centralize your logging mechanisms</td>
<td>Simplifies debugging and improves monitoring</td>
</tr>
<tr>
<td>Custom Exceptions</td>
<td>Design exceptions specific to your application</td>
<td>Adds clarity and useful details to error messages</td>
</tr>
</tbody>
</table>
<h3 id="further-learning-resources" tabindex="-1">Further Learning Resources</h3>
<p>If you want to dive deeper, there are plenty of resources that can help you sharpen your skills in exception handling for multithreaded applications. For daily updates and best practices in C# and .NET development, check out the <a href="https://dotnetnews.co" style="display: inline;">.NET Newsletter</a>.</p>
<p>Here are some suggested learning paths:</p>
<ul>
<li><strong>Microsoft Documentation</strong>: Deep dive into official patterns and recommendations for handling exceptions.</li>
<li><strong>Unit Testing Practices</strong>: Master techniques to test exception scenarios effectively.</li>
<li><strong>Modern Logging Frameworks</strong>: Discover tools and frameworks for detailed and centralized error logging.</li>
</ul>
<h2 id="faqs" tabindex="-1" class="sb">FAQs</h2>
<h3 id="how-to-handle-task-exceptions-in-c%23%3F" tabindex="-1">How to handle task exceptions in C#?</h3>
<p>Handling exceptions in C# tasks requires a clear strategy for managing errors that can arise during asynchronous operations. A common and effective approach is to use <strong>try-catch blocks</strong> tailored for async workflows.</p>
<p>Here’s an example of how you can manage task exceptions:</p>
<pre><code class="language-csharp">try
{
    await Task.Run(() =&gt; {
        // Logic for the task
        throw new InvalidOperationException(&quot;Operation failed.&quot;);
    });
}
catch (InvalidOperationException ex)
{
    // Handle specific exceptions here
    Logger.LogError($&quot;Operation error: {ex.Message}&quot;);
}
catch (Exception ex)
{
    // Catch all other exceptions
    Logger.LogError($&quot;Unexpected error: {ex.Message}&quot;);
}
</code></pre>
<p>When working with <strong>parallel tasks</strong>, it&#8217;s essential to manage <code>AggregateException</code>, which is designed to handle scenarios where multiple exceptions may occur at the same time.</p>
<table style="width:100%;">
<thead>
<tr>
<th>Exception Handling Method</th>
<th>Perfect For</th>
<th>Main Advantage</th>
</tr>
</thead>
<tbody>
<tr>
<td>Try-catch blocks</td>
<td>Single task scenarios</td>
<td>Keeps the stack trace intact</td>
</tr>
<tr>
<td>AggregateException</td>
<td>Parallel tasks</td>
<td>Handles and collects multiple exceptions</td>
</tr>
<tr>
<td>Global exception handler</td>
<td>Application-level management</td>
<td>Detects and addresses missed exceptions</td>
</tr>
</tbody>
</table>
<blockquote>
<p>&quot;<em>Use <code>throw;</code> instead of <code>throw ex;</code> when rethrowing exceptions. This way, the original stack trace remains intact for better debugging.</em>&quot;</p>
</blockquote>
<p>If you need to manage exceptions across many tasks systematically, a <strong>global exception handler</strong> can streamline this process. It ensures consistency in how errors are handled and prevents unhandled exceptions in multi-threaded applications. This can be particularly useful for larger, more complex systems.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/winforms-exception-handling-best-practices/" style="display: inline;">WinForms Exception Handling: Best Practices</a></li>
<li><a href="/2024/09/aspnet-mvc-exception-handling-6-methods-explained/" style="display: inline;">ASP.NET MVC Exception Handling: 6 Methods Explained</a></li>
<li>Async Event Handlers: Keep WinForms UI Responsive</li>
<li>gRPC Error Handling in ASP.NET Core: Best Practices</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn essential techniques for effective error handling in C# multithreaded applications to ensure stability and reliability.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_37fa603961183f0977a9fcbe5639f78c-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_37fa603961183f0977a9fcbe5639f78c-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Large Object Heap in .NET: Best Practices</title><link href="https://codejack.com/2024/11/large-object-heap-in-net-best-practices/" rel="alternate" type="text/html" title="Large Object Heap in .NET: Best Practices" /><published>2024-11-18T00:03:13-05:00</published><updated>2024-11-18T00:03:13-05:00</updated><id>https://codejack.com/2024/11/large-object-heap-in-net-best-practices</id><content type="html" xml:base="https://codejack.com/2024/11/large-object-heap-in-net-best-practices/"><![CDATA[<p>The Large Object Heap (LOH) in .NET is a special memory area for objects larger than 85,000 bytes. Understanding and managing it properly is crucial for building fast, efficient .NET applications.</p>
<p>Key points:</p>
<ul>
<li>LOH is for objects ≥85,000 bytes (e.g., large arrays or strings)</li>
<li>It&#8217;s handled differently than smaller objects to optimize memory and CPU cache usage</li>
<li>Improper LOH management can lead to memory fragmentation and performance issues</li>
</ul>
<p>Best practices for LOH management:</p>
<ol>
<li>Avoid creating large objects frequently</li>
<li>Use object pooling to reuse large objects</li>
<li>Break large objects into smaller chunks when possible</li>
<li>Plan object sizes to keep them under 85KB if feasible</li>
<li>Use tools like <a href="https://github.com/microsoft/Microsoft.IO.RecyclableMemoryStream" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">RecyclableMemoryStream</a> to reduce LOH allocations</li>
<li>Monitor LOH behavior with performance counters</li>
<li>Consider periodic app restarts or application pool recycling</li>
<li>Use ArrayPool&lt;T&gt; or MemoryPool&lt;T&gt; for large array management</li>
<li>Implement batch processing or paging for large datasets</li>
<li>Stay updated with the latest .NET features for LOH improvements</li>
</ol>
<h2 id="related-video-from-youtube" tabindex="-1" class="sb">Related video from YouTube</h2>
<p><iframe class="sb-iframe" src="https://www.youtube.com/embed/-qtT1wWJi3A" frameborder="0" loading="lazy" allowfullscreen style="width: 100%; height: auto; aspect-ratio: 16/9;"></iframe></p>
<h2 id="what-is-the-large-object-heap%3F" tabindex="-1" class="sb">What is the Large Object Heap?</h2>
<p>The Large Object Heap (LOH) is a key part of .NET&#8217;s memory management. It&#8217;s where objects 85,000 bytes or larger go. The LOH works differently from the Small Object Heap (SOH), which handles smaller objects.</p>
<h3 id="core-concepts" tabindex="-1">Core Concepts</h3>
<p>The LOH is all about managing big objects, usually arrays or strings. Here&#8217;s why it matters:</p>
<p>1. <strong>Size Threshold</strong></p>
<p>Objects 85,000 bytes or bigger end up in the LOH. This number isn&#8217;t random &#8211; it&#8217;s picked to balance speed and memory use.</p>
<p>2. <strong>Garbage Collection Behavior</strong></p>
<p>The LOH only gets cleaned during a full garbage collection (Gen 2 collection). This means big objects hang around longer, which can be good or bad.</p>
<p>3. <strong>No Compaction</strong></p>
<p>The LOH doesn&#8217;t compact during garbage collection by default. This can lead to memory gaps over time, which might slow things down.</p>
<p>Maoni Stephens from Microsoft&#8217;s CLR team says:</p>
<blockquote>
<p>&quot;Large objects are expensive. The allocation cost is high because the CLR needs to clear the memory for a newly allocated large object to satisfy the CLR guarantee that memory for all newly allocated objects is cleared.&quot;</p>
</blockquote>
<p>This shows why understanding the LOH is crucial for fast apps.</p>
<h3 id="loh-vs-small-object-heap%3A-key-differences" tabindex="-1">LOH vs Small Object Heap: Key Differences</h3>
<p>Let&#8217;s compare the LOH to the Small Object Heap:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Aspect</th>
<th>Large Object Heap (LOH)</th>
<th>Small Object Heap (SOH)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Object Size</td>
<td>≥ 85,000 bytes</td>
<td>&lt; 85,000 bytes</td>
</tr>
<tr>
<td>Garbage Collection</td>
<td>Only during full GC (Gen 2)</td>
<td>More often, generational</td>
</tr>
<tr>
<td>Compaction</td>
<td>Not compacted by default</td>
<td>Regularly compacted</td>
</tr>
<tr>
<td>Fragmentation Risk</td>
<td>Higher</td>
<td>Lower</td>
</tr>
<tr>
<td>Memory Clearing</td>
<td>Slow (e.g., 16ms for 16MB on 2GHz CPU)</td>
<td>Faster</td>
</tr>
</tbody>
</table>
<p>These differences matter for .NET developers:</p>
<p>1. <strong>Performance Impact</strong></p>
<p>Creating and destroying big objects often can slow your app. On a 2GHz machine, making a 16MB object takes about 16ms &#8211; that&#8217;s a long time in computer terms!</p>
<p>2. <strong>Memory Fragmentation</strong></p>
<p>Because the LOH doesn&#8217;t compact, it can get fragmented. This might make your app run out of memory even when there&#8217;s technically enough space.</p>
<p>3. <strong>Garbage Collection Pauses</strong></p>
<p>Full GCs, which clean the LOH, take longer and can make your app pause noticeably.</p>
<p>To avoid these issues, try:</p>
<ul>
<li><strong>Object Pooling</strong>: Reuse big objects instead of making new ones all the time.</li>
<li><strong>Size Planning</strong>: If you can, keep objects under 85,000 bytes to avoid the LOH.</li>
<li><strong>Pinning</strong>: For big objects you need to keep, consider pinning them so they don&#8217;t move during garbage collection.</li>
</ul>
<p>Andrew Hunter, a .NET memory expert, warns:</p>
<blockquote>
<p>&quot;Large objects pose a special problem for the runtime: they can&#8217;t be reliably moved by copying as they would require twice as much memory for garbage collection.&quot;</p>
</blockquote>
<p>This shows why you need to be careful with big objects in .NET apps.</p>
<h2 id="common-loh-problems" tabindex="-1" class="sb">Common LOH Problems</h2>
<p>The Large Object Heap (LOH) in .NET handles objects bigger than 85,000 bytes. But it&#8217;s not all smooth sailing. Let&#8217;s dive into the challenges developers face when working with the LOH.</p>
<h3 id="loh-garbage-collection%3A-a-different-beast" tabindex="-1">LOH Garbage Collection: A Different Beast</h3>
<p>Garbage collection in the LOH? It&#8217;s not your typical cleanup:</p>
<ul>
<li>Only happens during a full (Generation 2) collection</li>
<li>No automatic compaction (by default)</li>
<li>Uses a sweep algorithm, creating a free list from dead objects</li>
</ul>
<p>This unique approach can lead to some headaches. Take allocating a 16MB object on a 2GHz machine. It eats up about 16ms. Why so long? Maoni Stephens from Microsoft&#8217;s CLR team explains:</p>
<blockquote>
<p>&quot;Large objects are expensive. The allocation cost is high because the CLR needs to clear the memory for a newly allocated large object to satisfy the CLR guarantee that memory for all newly allocated objects is cleared.&quot;</p>
</blockquote>
<p>Want to dodge these issues? Try these tricks:</p>
<ol>
<li>Object pooling: Reuse large objects instead of creating new ones</li>
<li>Pinning: Keep large objects in place during garbage collection</li>
</ol>
<h3 id="the-memory-fragmentation-nightmare" tabindex="-1">The Memory Fragmentation Nightmare</h3>
<p>Memory fragmentation is the LOH&#8217;s biggest headache. Here&#8217;s the deal:</p>
<ul>
<li>Removed objects leave &quot;holes&quot; in memory</li>
<li>These gaps pile up, causing fragmentation</li>
<li>Result? You might run out of memory even when there&#8217;s space available</li>
</ul>
<p>Andrew Hunter, a .NET memory guru, puts it this way:</p>
<blockquote>
<p>&quot;The design of the Large Object Heap means that its&#8217; worse case will occur when the short-lived arrays are large and can vary in size a bit, and if the longer-lived arrays are small.&quot;</p>
</blockquote>
<p>This fragmentation can throw a wrench in your plans. Imagine a program meant to process thousands of 16MB files and create 90KB summaries. It might crash after just a few hundred files due to LOH fragmentation.</p>
<p>How bad can it get? In extreme cases, a whopping 99.9% of free memory can be eaten up by large fragments. Yikes!</p>
<p>To fight fragmentation:</p>
<ol>
<li>Avoid using 85KB+ objects for permanent storage</li>
<li>Break large objects into smaller chunks</li>
<li>Restart your app or recycle the application pool periodically</li>
</ol>
<p>Got .NET 4.5.1 or later? You can try a one-time LOH compaction:</p>
<pre><code class="language-csharp">GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
</code></pre>
<p>But be careful &#8211; this process can take a while.</p>
<h2 id="how-to-manage-loh-memory" tabindex="-1" class="sb">How to Manage LOH Memory</h2>
<p>Managing Large Object Heap (LOH) memory is key for .NET developers building efficient apps. Let&#8217;s look at some practical ways to handle memory use and large object allocation.</p>
<h3 id="using-recyclablememorystream" tabindex="-1">Using <a href="https://github.com/microsoft/Microsoft.IO.RecyclableMemoryStream" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">RecyclableMemoryStream</a></h3>
<p><img decoding="async" src="/assets/images/imported/84e497c2a2f048a1fdd8.jpg" alt="RecyclableMemoryStream" style="width:100%;"></p>
<p>The RecyclableMemoryStream library is a great tool for managing LOH memory. It cuts down on memory fragmentation and boosts app performance.</p>
<p>Here&#8217;s why it&#8217;s so useful:</p>
<ul>
<li>It stops LOH allocations by using pooled buffers</li>
<li>It reduces GC pressure with fewer generation 2 garbage collections</li>
<li>It helps prevent memory leaks</li>
</ul>
<p>Ionut Apostol, a software engineer, used RecyclableMemoryStream in an <a href="https://dotnet.microsoft.com/en-us/apps/aspnet" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">ASP.NET Core</a> app. He said:</p>
<blockquote>
<p>&quot;By leveraging the RecyclableMemoryStream library, we&#8217;re now reusing memory when making HTTP requests without adding much complexity.&quot;</p>
</blockquote>
<p>The result? The app went from handling 16,000 to 20,000 requests per second &#8211; a 25% jump using the same resources.</p>
<p>Want to use RecyclableMemoryStream in your project? Here&#8217;s a code snippet:</p>
<pre><code class="language-csharp">RecyclableMemoryStreamManager _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
using var memoryStream = _recyclableMemoryStreamManager.GetStream();
bodyStream.Seek(0, SeekOrigin.Begin);
bodyStream.CopyTo(memoryStream);
</code></pre>
<p>This works well for logging HTTP requests, reusing memory streams instead of making new ones each time.</p>
<h3 id="planning-object-sizes" tabindex="-1">Planning Object Sizes</h3>
<p>Planning object sizes is another key way to manage LOH memory. Remember, objects over 85,000 bytes go into the LOH, which can cause fragmentation.</p>
<p>Here are some tips:</p>
<ol>
<li>Use multiple smaller arrays instead of one big one</li>
<li>Make custom classes like <code>LargeList&lt;T&gt;</code> that use an array of arrays</li>
<li>Allocate space upfront if you know you&#8217;ll need a large data structure</li>
<li>Don&#8217;t use objects bigger than 85KB for long-term storage</li>
</ol>
<p>Andrew Hunter, a .NET memory expert, says:</p>
<blockquote>
<p>&quot;The best way to prevent fragmentation from occurring is to ensure that no objects above 85k in size are used for permanent storage.&quot;</p>
</blockquote>
<p>These strategies can make a big difference. For example, a program that processed thousands of 16MB files and made 90KB summaries was failing after a few hundred files due to LOH fragmentation. By breaking down the large objects and managing memory better, the developers could process tens of thousands of files without problems.</p>
<h6 id="sbb-itb-29cd4f6" class="sb-banner" style="color:transparent!important;line-height:0!important;padding:0!important;margin:0!important;">sbb-itb-29cd4f6</h6>
<h2 id="ways-to-improve-performance" tabindex="-1" class="sb">Ways to Improve Performance</h2>
<p>Let&#8217;s dive into how managing the Large Object Heap (LOH) can make your .NET app faster.</p>
<h3 id="reducing-large-object-creation" tabindex="-1">Reducing Large Object Creation</h3>
<p>Creating fewer large objects is key. Here&#8217;s why it matters and how to do it:</p>
<p>Large objects (&gt;85KB) are expensive to create. They take time and can mess up your memory. Making a 16MB object on a 2GHz machine? That&#8217;s about 16ms &#8211; forever in computer time!</p>
<p>How to cut down on large objects:</p>
<ol>
<li>
<strong>Use object pooling</strong><br />
Don&#8217;t keep making and trashing big objects. Reuse them from a pool instead. It&#8217;s way faster and keeps your memory tidy.
</li>
<li>
<strong>Break big objects into smaller bits</strong><br />
If you can, redesign your data to use several small arrays instead of one big one. This keeps stuff off the LOH and reduces memory fragmentation.
</li>
<li>
<strong>Try ArrayPool&lt;T&gt;</strong><br />
For big arrays, ArrayPool&lt;T&gt; from System.Buffers is your friend. It gives you a pool of arrays to reuse, which is easier on your garbage collector.
</li>
</ol>
<p>Here&#8217;s how to use ArrayPool&lt;T&gt;:</p>
<pre><code class="language-csharp">using System.Buffers;

public class LargeObject : IDisposable
{
    private byte[] _buffer;
    private ArrayPool&lt;byte&gt; _pool;

    public LargeObject()
    {
        _pool = ArrayPool&lt;byte&gt;.Shared;
        _buffer = _pool.Rent(1024 * 1024); // Get a 1MB buffer
    }

    public void Dispose()
    {
        if (_buffer != null)
        {
            _pool.Return(_buffer);
            _buffer = null;
        }
    }
}

// How to use it
using (var obj = new LargeObject())
{
    // Use the object
}
</code></pre>
<p>This approach is great when you&#8217;re creating and getting rid of LargeObject instances a lot.</p>
<ol start="4">
<li>
<strong>MemoryPool&lt;T&gt; for huge arrays</strong><br />
Dealing with massive datasets? MemoryPool&lt;T&gt; from System.Buffers might be your best bet. It&#8217;s good at handling tons of memory.
</li>
<li>
<strong>Batch processing or paging</strong><br />
Instead of loading everything at once, process data in chunks. It&#8217;s easier on your memory and can speed things up overall.
</li>
</ol>
<p>Michael Sydney Balloni, a software engineer, says:</p>
<blockquote>
<p>&quot;Reducing large object creation is crucial for improving performance.&quot;</p>
</blockquote>
<p>These strategies can really boost your app&#8217;s performance. For example, a Microsoft team made their ASP.NET Core app handle 25% more requests (from 16,000 to 20,000 per second) by tweaking how they manage large objects.</p>
<p>The main thing? Be smart about object sizes and how long they stick around. Keep objects under 85KB when you can, and manage the big ones carefully. This helps you dodge a lot of LOH performance problems.</p>
<p>Don&#8217;t forget to use memory profiling tools. They&#8217;ll help you spot memory leaks or inefficient allocation patterns, so you can focus on what really matters for speeding up your app.</p>
<h2 id="rules-for-better-loh-management" tabindex="-1" class="sb">Rules for Better LOH Management</h2>
<p>Managing the Large Object Heap (LOH) is key for optimizing .NET apps. Here&#8217;s how to handle large objects more efficiently:</p>
<h3 id="memory-planning-tips" tabindex="-1">Memory Planning Tips</h3>
<p>1. <strong>Don&#8217;t store large objects long-term</strong></p>
<p>Avoid using objects larger than 85KB for long-term storage. Andrew Hunter, a .NET memory expert, says:</p>
<blockquote>
<p>&quot;The best way to prevent fragmentation from occurring is to ensure that no objects above 85k in size are used for permanent storage.&quot;</p>
</blockquote>
<p>2. <strong>Split large objects</strong></p>
<p>Use multiple smaller arrays instead of one big one for large data structures. This cuts down on LOH fragmentation.</p>
<p>3. <strong>Allocate space upfront</strong></p>
<p>If you know you&#8217;ll need a big data structure, allocate enough space for it right away. This helps avoid repeated allocations and deallocations that can cause fragmentation.</p>
<p>4. <strong>Use the right Stream implementations</strong></p>
<p>For objects that might be large (&gt;85,000 bytes), use appropriate Stream implementations. This keeps them off the LOH. For example, when working with a large JSON file, deserialize from a Stream instead of reading the whole thing into memory.</p>
<p>5. <strong>Keep an eye on garbage collection</strong></p>
<p>Watch your garbage collection metrics to keep memory usage in check. Michael Shpilt from Michael&#8217;s Coding Spot notes:</p>
<blockquote>
<p>&quot;The #1 culprit of memory problems is without any doubt memory leaks.&quot;</p>
</blockquote>
<p>For big apps, try to keep garbage collection time under 10%. If it hits 20%, you might have a problem.</p>
<p>6. <strong>Use mutable cache objects</strong></p>
<p>Update existing objects instead of making new ones. This can help cut down on LOH allocations and ease garbage collection pressure.</p>
<p>7. <strong>Try object pooling</strong></p>
<p>Reuse large objects from a pool instead of constantly creating and destroying them. This works well for objects you allocate and deallocate often.</p>
<p>8. <strong>Recycle your application pool</strong></p>
<p>For apps that run for a long time, recycling the application pool now and then can help manage memory and reduce LOH fragmentation.</p>
<p>9. <strong>Be careful with LOH compaction</strong></p>
<p>In .NET Framework 4.5.1 and later, you can compact the LOH programmatically:</p>
<pre><code class="language-csharp">GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
</code></pre>
<p>But use this sparingly &#8211; it can take a while.</p>
<p>10. <strong>Use new .NET features</strong></p>
<p>Keep up with the latest .NET versions. They often include improvements for LOH management. Brandon Bay, Lead Program Manager for GC in .NET Framework, said:</p>
<blockquote>
<p>&quot;In .NET 4.5, we made two improvements to the large object heap. First, we significantly improved the way the runtime manages the free list, thereby making more effective use of fragments.&quot;</p>
</blockquote>
<h2 id="finding-and-fixing-loh-issues" tabindex="-1" class="sb">Finding and Fixing LOH Issues</h2>
<p>Let&#8217;s dive into how to spot and solve Large Object Heap (LOH) problems in .NET apps. We&#8217;ll look at some handy tools and methods to diagnose and fix these issues.</p>
<h3 id="performance-monitors" tabindex="-1">Performance Monitors</h3>
<p>Performance monitors are key for tracking LOH behavior. Here&#8217;s what you need to know:</p>
<h4 id="clr-memory-performance-counters" tabindex="-1">CLR Memory Performance Counters</h4>
<p>The .NET CLR gives us some useful counters to watch:</p>
<ul>
<li>LargeObjectHeapsize</li>
<li>Gen0heapsize, Gen1heapsize, Gen2heapsize</li>
<li>PercentTimeinGC</li>
<li>AllocatedBytesPersec</li>
</ul>
<p>Here&#8217;s a real example from <a href="https://www.saotn.org/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Sysadmins of the North</a>:</p>
<pre><code class="language-json">&quot;reilink.nl(domain)(4.0)(pool)&quot;: {
  &quot;LargeObjectHeapsize&quot;: 74864,
  &quot;Gen0heapsize&quot;: 1660248,
  &quot;Gen2heapsize&quot;: 2805364,
  &quot;Gen1heapsize&quot;: 341388,
  &quot;NumberTotalreservedBytes&quot;: 33546240,
  &quot;NumberTotalcommittedBytes&quot;: 7282688,
  &quot;PercentTimeinGC&quot;: 48,
  &quot;AllocatedBytesPersec&quot;: 80405312
}
</code></pre>
<p>This shows a LargeObjectHeapsize of 74,864 bytes and a PercentTimeinGC of 48%. That high GC percentage? Not good.</p>
<h4 id="deeper-analysis-tools" tabindex="-1">Deeper Analysis Tools</h4>
<p>For a closer look, try &quot;dotnet trace&quot; and &quot;PerfView&quot;. They&#8217;ll show you memory allocation patterns and garbage collection behavior.</p>
<p>Memory profilers are also super helpful. As Andrew Hunter, a .NET memory expert, puts it:</p>
<blockquote>
<p>&quot;The best approach available at the moment is to combine a memory profiler with the performance counters.&quot;</p>
</blockquote>
<p>This combo helps you link LOH behavior to specific code and object allocations.</p>
<h4 id="heap-fragmentation-diagram" tabindex="-1">Heap Fragmentation Diagram</h4>
<p>This visual tool shows you:</p>
<ul>
<li>Total size of pinned objects</li>
<li>Total size of all objects in the heap segment</li>
<li>Total size of free memory in the heap segment</li>
</ul>
<p>It&#8217;s great for spotting fragmentation patterns.</p>
<h3 id="what-to-watch-for" tabindex="-1">What to Watch For</h3>
<p>Keep an eye out for:</p>
<ul>
<li>Fast-growing LargeObjectHeapsize</li>
<li>High PercentTimeinGC (over 10%)</li>
<li>Lots of large object allocations and deallocations</li>
<li>Big gaps in the LOH</li>
</ul>
<h3 id="real-world-example" tabindex="-1">Real-World Example</h3>
<p>A developer on Stack Overflow had a memory leak in their 64-bit app. The app was always calculating and sending data to a remote host, hitting the LOH hard.</p>
<p>Using memory profilers, they found:</p>
<ol>
<li>Small (1056 byte) object arrays stuck in the LOH.</li>
<li>These arrays mixed with free memory blocks, showing fragmentation.</li>
</ol>
<p>Brian Rasmussen on Stack Overflow explained the cause:</p>
<blockquote>
<p>&quot;The problem has been identified as fragmentation of the LOH caused by the string intern table!&quot;</p>
</blockquote>
<p>The app was interning entity IDs during unmarshalling, causing LOH fragmentation.</p>
<h3 id="how-to-fix-it" tabindex="-1">How to Fix It</h3>
<ol>
<li>Don&#8217;t store objects bigger than 85KB for long.</li>
<li>Use the right data structures for big, long-lived data sets.</li>
<li>Try object pooling for large objects you create often.</li>
<li>Keep an eye on LOH behavior with the tools we talked about.</li>
</ol>
<h2 id="conclusion" tabindex="-1" class="sb">Conclusion</h2>
<p>Managing the Large Object Heap (LOH) in .NET is key for building efficient apps. Here&#8217;s what you need to know:</p>
<p>The LOH is for objects over 85,000 bytes. It doesn&#8217;t compact automatically, which can lead to fragmentation. To avoid this, limit long-term storage of large objects.</p>
<p>When possible, break big objects into smaller pieces. This helps dodge LOH allocations and cuts down on fragmentation risks.</p>
<p>Object pooling is your friend. Reuse large objects instead of making new ones all the time. It&#8217;s a great way to cut allocation costs and ease GC pressure.</p>
<p>Keep an eye on your app&#8217;s performance. Watch metrics like LargeObjectHeapsize and PercentTimeinGC. CLR Memory Performance Counters can give you useful insights.</p>
<p>Stay up-to-date with new .NET features. For example, .NET Framework 4.5.1 lets you compact the LOH programmatically:</p>
<pre><code class="language-csharp">GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
</code></pre>
<p>But use this sparingly &#8211; it can be slow.</p>
<p>For big, long-lived data sets, think about custom data structures. Something like <code>LargeList&lt;T&gt;</code> that uses an array of arrays can manage memory better.</p>
<p>If you know you&#8217;ll need a large data structure, allocate space for it upfront. This can help avoid repeated allocations and deallocations that lead to fragmentation.</p>
<p>Remember, good LOH management is all about balance. These strategies can help, but always test and profile your specific use cases.</p>
<p>Want to stay in the loop on .NET? Check out the <a href="https://dotnetnews.co" style="display: inline;">.NET Newsletter</a>. It&#8217;s a daily dose of .NET, C#, ASP.NET, Azure, and related tech, curated by Jasen Fici. It&#8217;s a great way to keep up with the latest in the .NET world.</p>
<h2 id="faqs" tabindex="-1" class="sb">FAQs</h2>
<h3 id="what's-the-size-threshold-for-the-large-object-heap-in-c%23%3F" tabindex="-1">What&#8217;s the size threshold for the large object heap in C#?</h3>
<p>In C#, objects 85,000 bytes or larger get placed on the Large Object Heap (LOH). The .NET team picked this number after performance testing. When you ask for 85,000 bytes or more, C# automatically puts that object on the LOH.</p>
<h3 id="how-can-i-track-the-size-of-the-large-object-heap%3F" tabindex="-1">How can I track the size of the large object heap?</h3>
<p>There&#8217;s a performance counter for that. It shows you how big the LOH is in bytes, including empty space. This counter updates after each garbage collection, not every time something&#8217;s added. It&#8217;s a quick way to see how much memory the LOH is using and spot potential memory issues.</p>
<h3 id="what's-special-about-the-loh%3F" tabindex="-1">What&#8217;s special about the LOH?</h3>
<p>The LOH is a separate memory area in .NET for big objects. It&#8217;s handled differently by the garbage collector because of the objects&#8217; size. Andrew Hunter from Simple Talk puts it well:</p>
<blockquote>
<p>&quot;When an object is large, some of its attributes become more significant than if the object is small. For instance, compacting it &#8211; that is, copying it in memory elsewhere on the heap &#8211; can be expensive.&quot;</p>
</blockquote>
<p>That&#8217;s why big objects go to the LOH. It&#8217;s a way to manage memory better, especially for large .NET apps. The garbage collector treats these objects differently to keep things running smoothly.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/top-7-dependency-injection-best-practices-for-net/" style="display: inline;">Top 7 Dependency Injection Best Practices for .NET</a></li>
<li><a href="/2024/09/winforms-exception-handling-best-practices/" style="display: inline;">WinForms Exception Handling: Best Practices</a></li>
<li><a href="/2024/09/wcf-message-size-reduction-techniques/" style="display: inline;">WCF Message Size Reduction Techniques</a></li>
<li>Object Pool Pattern in ASP.NET Core</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn best practices for managing the Large Object Heap in .NET to optimize memory usage and improve application performance.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_254660902e5189e210f8933a9e3dcc34-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_254660902e5189e210f8933a9e3dcc34-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Static Classes in C#: Complete Guide 2024</title><link href="https://codejack.com/2024/11/static-classes-in-c-complete-guide-2024/" rel="alternate" type="text/html" title="Static Classes in C#: Complete Guide 2024" /><published>2024-11-16T00:14:23-05:00</published><updated>2024-11-16T00:14:23-05:00</updated><id>https://codejack.com/2024/11/static-classes-in-c-complete-guide-2024</id><content type="html" xml:base="https://codejack.com/2024/11/static-classes-in-c-complete-guide-2024/"><![CDATA[<p>Static classes in C# are powerful tools for organizing code, but they come with specific use cases and limitations. Here&#8217;s what you need to know:</p>
<ul>
<li><strong>Definition</strong>: Static classes contain only static members and can&#8217;t be instantiated.</li>
<li><strong>Key Features</strong>:
<ul>
<li>No instance creation</li>
<li>Can&#8217;t be inherited</li>
<li>Only static members allowed</li>
<li>Accessed directly through the class name</li>
</ul>
</li>
</ul>
<p><strong>When to use static classes</strong>:</p>
<ul>
<li>Utility functions</li>
<li>Constant storage</li>
<li>Extension methods</li>
<li>Factory methods</li>
</ul>
<p><strong>When to avoid</strong>:</p>
<ul>
<li>Stateful operations</li>
<li>When inheritance is needed</li>
<li>For easier unit testing</li>
<li>If you prefer dependency injection</li>
</ul>
<p><strong>Best practices</strong>:</p>
<ol>
<li>Keep static classes focused and simple</li>
<li>Ensure thread safety in multi-threaded scenarios</li>
<li>Handle errors properly in static methods</li>
<li>Consider alternatives like dependency injection for more flexible code</li>
</ol>
<p>Static classes in C# offer a clean way to organize utility functions and constants, but use them judiciously to maintain code flexibility and testability.</p>
<h2 id="related-video-from-youtube" tabindex="-1" class="sb">Related video from YouTube</h2>
<p><iframe class="sb-iframe" src="https://www.youtube.com/embed/fMBHpAVKHsM" frameborder="0" loading="lazy" allowfullscreen style="width: 100%; height: auto; aspect-ratio: 16/9;"></iframe></p>
<h2 id="parts-of-a-static-class" tabindex="-1" class="sb">Parts of a Static Class</h2>
<p>Static classes in C# are handy for organizing utility functions and constants. Let&#8217;s break down their key components.</p>
<h3 id="static-fields-and-properties" tabindex="-1">Static Fields and Properties</h3>
<p>These are the data containers of a static class. They store information shared across all uses of the class.</p>
<p><strong>Static Fields</strong></p>
<p>Static fields are class-level variables. They&#8217;re great for data that should be consistent across all uses of the class.</p>
<p>Here&#8217;s a quick example for a banking app:</p>
<pre><code class="language-csharp">public static class BankingConstants
{
    public static readonly decimal MinimumBalance = 100.00m;
    public static readonly decimal OverdraftFee = 35.00m;
}
</code></pre>
<p>You can access <code>MinimumBalance</code> and <code>OverdraftFee</code> from anywhere without creating an instance.</p>
<p><strong>Static Properties</strong></p>
<p>Static properties are similar to fields but give you more control. They&#8217;re useful when you need to add logic to accessing or changing data.</p>
<p>Check out this example tracking app usage:</p>
<pre><code class="language-csharp">public static class AppStats
{
    private static int _userCount = 0;

    public static int UserCount
    {
        get { return _userCount; }
        set
        {
            if (value &gt;= 0)
            {
                _userCount = value;
            }
        }
    }
}
</code></pre>
<p>Here, <code>UserCount</code> makes sure the user count never goes negative.</p>
<h3 id="static-methods-and-constructors" tabindex="-1">Static Methods and Constructors</h3>
<p>These are the workhorses of static classes, providing functionality without needing to create an object.</p>
<p><strong>Static Methods</strong></p>
<p>Static methods are class-level functions. They&#8217;re perfect for utility functions that don&#8217;t need object-specific data.</p>
<p>Here&#8217;s a string manipulation example:</p>
<pre><code class="language-csharp">public static class StringHelper
{
    public static string Reverse(string input)
    {
        char[] charArray = input.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }

    public static bool IsPalindrome(string input)
    {
        string reversed = Reverse(input);
        return input.Equals(reversed, StringComparison.OrdinalIgnoreCase);
    }
}
</code></pre>
<p>You can call these methods directly on the class:</p>
<pre><code class="language-csharp">string reversed = StringHelper.Reverse(&quot;Hello&quot;);
bool isPalindrome = StringHelper.IsPalindrome(&quot;racecar&quot;);
</code></pre>
<p><strong>Static Constructors</strong></p>
<p>Static constructors set up static members. They run automatically before the class is first used, making sure everything&#8217;s ready to go.</p>
<p>Here&#8217;s a database config example:</p>
<pre><code class="language-csharp">public static class DatabaseConfig
{
    public static string ConnectionString { get; private set; }

    static DatabaseConfig()
    {
        ConnectionString = &quot;Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;&quot;;
    }
}
</code></pre>
<p>This constructor sets up the <code>ConnectionString</code> property before anything tries to use it.</p>
<p>Static constructors are great for complex setup or preparing resources needed throughout your app. Here&#8217;s a logging example from Microsoft:</p>
<pre><code class="language-csharp">public static class Logger
{
    private static readonly string _logFilePath;

    static Logger()
    {
        _logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, &quot;app.log&quot;);
        if (!File.Exists(_logFilePath))
        {
            File.Create(_logFilePath).Dispose();
        }
    }

    public static void Log(string message)
    {
        File.AppendAllText(_logFilePath, message + Environment.NewLine);
    }
}
</code></pre>
<p>This sets up a log file when <code>Logger</code> is first used, so logging is ready whenever you need it.</p>
<p>A few things to remember about static constructors:</p>
<ul>
<li>They don&#8217;t have access modifiers or parameters</li>
<li>They run automatically</li>
<li>They only run once, even in multithreaded scenarios</li>
</ul>
<h2 id="memory-and-performance" tabindex="-1" class="sb">Memory and Performance</h2>
<p>Static classes in C# can be a double-edged sword for memory usage and performance. Let&#8217;s break it down.</p>
<h3 id="memory-usage" tabindex="-1">Memory Usage</h3>
<p>Static classes can save memory in some cases. How? They don&#8217;t create objects on the heap when you call their methods. This can be a big win if you&#8217;d otherwise be making lots of instances of a class.</p>
<p>Take this math utility class:</p>
<pre><code class="language-csharp">public static class MathUtils
{
    public static double Square(double number)
    {
        return number * number;
    }
}
</code></pre>
<p>Every time you use <code>MathUtils.Square(5)</code>, you&#8217;re not making a new object. That&#8217;s more efficient than creating instances of a non-static class, which would use at least 16 bytes each time.</p>
<p>But here&#8217;s the catch: static classes stick around for your whole app&#8217;s life. So if they&#8217;re big or hold onto a lot of data, that might not be ideal.</p>
<h3 id="working-with-multiple-threads" tabindex="-1">Working with Multiple Threads</h3>
<p>Static classes can be tricky with multithreading. Why? They have one state for all threads. This can lead to race conditions and weird behavior if you&#8217;re not careful.</p>
<p>Here&#8217;s an example of a static class that could cause problems:</p>
<pre><code class="language-csharp">public static class Worker
{
    private static string Log = &quot;&quot;;
    private static bool InProgress = false;

    public static async Task Work()
    {
        if (InProgress)
        {
            Log += &quot;Process already started. Exiting.\n&quot;;
            return;
        }

        InProgress = true;
        Log += $&quot;Started at: {DateTime.Now}\n&quot;;

        await Task.Delay(5000); // Simulating work

        Log += &quot;Finished work.\n&quot;;
        Log += $&quot;Ended at: {DateTime.Now}\n&quot;;
        InProgress = false;
    }
}
</code></pre>
<p>If multiple threads call <code>Work()</code> at the same time, they might mess with each other, leading to wrong logs or unexpected behavior.</p>
<p>So how do you make static classes play nice with multiple threads? Here are some ideas:</p>
<ol>
<li>Use thread-safe collections like <code>ConcurrentDictionary&lt;TKey, TValue&gt;</code>.</li>
<li>Use <code>lock</code> statements to make sure only one thread can access important parts at a time.</li>
<li>Use <code>Lazy&lt;T&gt;</code> for expensive setups. It makes sure things only happen once, even with multiple threads.</li>
<li>Sometimes, it&#8217;s better to use instance methods with dependency injection instead of static classes. This can make testing easier and be safer with threads.</li>
</ol>
<p>Static classes can be fast, but you need to be careful in multithreaded situations. As Harvey Williams, a software developer, puts it:</p>
<blockquote>
<p>&quot;Generally in a majority of my classes I won&#8217;t use static classes. Although static classes are quicker to instantiate (in terms of processing time and developer writing time), they&#8217;re not exactly perfect for all situations.&quot;</p>
</blockquote>
<h2 id="guidelines-and-tips" tabindex="-1" class="sb">Guidelines and Tips</h2>
<p>Static classes in C# can be useful, but they&#8217;re not always the best choice. Let&#8217;s look at when to use them, when to skip them, and how to make them better.</p>
<h3 id="when-to-use-static-classes" tabindex="-1">When to Use Static Classes</h3>
<p>Static classes work well for utility functions or constants that don&#8217;t need object-specific data. Good uses include:</p>
<ol>
<li>
<strong>Helper Functions</strong>: For operations that don&#8217;t rely on instance state, like string or math operations.
</li>
<li>
<strong>Constants</strong>: To store app-wide constants or config values.
</li>
<li>
<strong>Extension Methods</strong>: Add methods to existing types without changing them.
</li>
<li>
<strong>Factory Methods</strong>: Create objects from a central place without keeping state.
</li>
</ol>
<p>Here&#8217;s how Microsoft&#8217;s <code>System.Math</code> class uses static methods:</p>
<pre><code class="language-csharp">public static double SquareRoot = Math.Sqrt(25);
public static double Sine = Math.Sin(Math.PI / 2);
</code></pre>
<h3 id="when-not-to-use-static-classes" tabindex="-1">When Not to Use Static Classes</h3>
<p>Static classes aren&#8217;t right for every situation. Avoid them when:</p>
<ol>
<li>
<strong>You Need to Keep State</strong>: Static classes last the whole app lifetime, which can cause issues in multi-threaded setups.
</li>
<li>
<strong>You Want Polymorphism</strong>: Static classes can&#8217;t be inherited or use interfaces, limiting their flexibility.
</li>
<li>
<strong>You Need Isolated Testing</strong>: Static methods are hard to mock or stub, making unit testing tougher.
</li>
<li>
<strong>You Prefer Dependency Injection</strong>: Static classes can create hidden dependencies, making your code less modular and harder to maintain.
</li>
</ol>
<h3 id="tips-for-better-code" tabindex="-1">Tips for Better Code</h3>
<p>To write better static classes and dodge common issues:</p>
<ol>
<li>
<strong>Keep It Simple</strong>: Static classes should do one job well. If your class is getting big, split it up.
</li>
<li>
<strong>Think About Threads</strong>: If your static class manages shared state, make sure it&#8217;s thread-safe. Use thread-safe collections or sync mechanisms when needed.
</li>
<li>
<strong>Handle Errors</strong>: Make sure static methods can handle unexpected inputs gracefully. Here&#8217;s an example:
</li>
</ol>
<pre><code class="language-csharp">public static class StringUtility
{
    public static string Reverse(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            throw new ArgumentException(&quot;Input string can't be null or empty&quot;, nameof(input));
        }

        char[] charArray = input.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }
}
</code></pre>
<ol start="4">
<li>
<strong>Document Well</strong>: Clearly explain what your static classes and methods do. This is key since static methods often serve as utility functions used across an app.
</li>
<li>
<strong>Look at Alternatives</strong>: Before making a static class, think about whether a singleton pattern or dependency injection might work better.
</li>
<li>
<strong>Consider Performance</strong>: While static methods can be slightly faster, don&#8217;t sacrifice clear, maintainable code for tiny speed gains.
</li>
</ol>
<p>As Henrique Siebert Domareski, a software development author, says:</p>
<blockquote>
<p>&quot;Static classes can be used when you need to implement some kind of utility classes that do not need many modifications, classes such as extension, helper, constant, etc.&quot;</p>
</blockquote>
<h6 id="sbb-itb-29cd4f6" class="sb-banner" style="color:transparent!important;line-height:0!important;padding:0!important;margin:0!important;">sbb-itb-29cd4f6</h6>
<h2 id="common-uses" tabindex="-1" class="sb">Common Uses</h2>
<p>Static classes in C# are go-to tools for developers. Let&#8217;s look at how they&#8217;re used in real-world coding.</p>
<h3 id="math-and-helper-functions" tabindex="-1">Math and Helper Functions</h3>
<p>Static classes are perfect for math operations and utility functions that don&#8217;t need object-specific data. They keep your code tidy and easy to maintain.</p>
<p>Take the <code>System.Math</code> class in .NET. It&#8217;s a static powerhouse of math functions:</p>
<pre><code class="language-csharp">double squareRoot = Math.Sqrt(25);
double powerResult = Math.Pow(2, 3);
double sineValue = Math.Sin(Math.PI / 2);
</code></pre>
<p>With <code>Math</code>, you can crunch numbers without breaking a sweat.</p>
<p>You can also whip up your own helper classes. Here&#8217;s a <code>StringUtility</code> class that flips strings around:</p>
<pre><code class="language-csharp">public static class StringUtility
{
    public static string Reverse(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            throw new ArgumentException(&quot;Input string can't be null or empty&quot;, nameof(input));
        }

        char[] charArray = input.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }

    public static bool IsPalindrome(string input)
    {
        string reversed = Reverse(input);
        return input.Equals(reversed, StringComparison.OrdinalIgnoreCase);
    }
}
</code></pre>
<p>Now you can use these string tricks anywhere in your code without creating new objects.</p>
<h3 id="settings-and-object-creation" tabindex="-1">Settings and Object Creation</h3>
<p>Static classes also shine when it comes to managing app settings and creating objects. They make your code structure simpler and easier to maintain.</p>
<p>For app settings, a static class can be your one-stop shop:</p>
<pre><code class="language-csharp">public static class AppConfig
{
    public static string ApiKey { get; } = &quot;your-api-key-here&quot;;
    public static int MaxRetries { get; } = 3;
    public static TimeSpan Timeout { get; } = TimeSpan.FromSeconds(30);
}
</code></pre>
<p>Now you can grab settings from anywhere:</p>
<pre><code class="language-csharp">int retries = AppConfig.MaxRetries;
</code></pre>
<p>Static classes are also great for the Factory Method pattern. As Eric Martin, Principal Engineer at <a href="https://stackify.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Stackify</a>, puts it:</p>
<blockquote>
<p>&quot;The key elements to implement this pattern are simple: the factory method must be public, static, and return an instance of the class in which it is defined.&quot;</p>
</blockquote>
<p>Check out <code>TimeSpan.FromDays()</code> in .NET:</p>
<pre><code class="language-csharp">TimeSpan twoWeeks = TimeSpan.FromDays(14);
</code></pre>
<p>This approach gives you clear, named methods for creating objects. It&#8217;s easier to read and cuts down on the need for multiple constructors.</p>
<h2 id="fixing-common-problems" tabindex="-1" class="sb">Fixing Common Problems</h2>
<p>Static classes in C# can be tricky. Let&#8217;s look at some common issues and how to fix them.</p>
<h3 id="memory-and-startup-issues" tabindex="-1">Memory and Startup Issues</h3>
<p>Static classes hang around for your whole app&#8217;s life. This can cause problems if you&#8217;re not careful.</p>
<p><strong>Memory Hogs</strong></p>
<p>Static classes can eat up memory. Why? They&#8217;re always there, even when you&#8217;re not using them. And they keep all their data.</p>
<p>To keep static classes slim:</p>
<ol>
<li>Only keep what you really need as static.</li>
<li>Use lazy loading. Only grab data when you first need it.</li>
</ol>
<p>Here&#8217;s how lazy loading looks:</p>
<pre><code class="language-csharp">public static class ConfigManager
{
    private static Lazy&lt;string&gt; _apiKey = new Lazy&lt;string&gt;(() =&gt; LoadApiKey());

    public static string ApiKey =&gt; _apiKey.Value;

    private static string LoadApiKey()
    {
        // Load API key from configuration
        return &quot;your-api-key-here&quot;;
    }
}
</code></pre>
<p>This way, <code>ApiKey</code> only loads when you first use it, not at startup.</p>
<p><strong>Startup Order Surprises</strong></p>
<p>Static constructors can mess up your startup. They only run once, but you can&#8217;t control when. This can lead to weird bugs.</p>
<p>To avoid startup problems:</p>
<ol>
<li>Keep static constructors simple. Don&#8217;t put complex logic in them.</li>
<li>Use static methods to set things up. This gives you more control.</li>
</ol>
<h3 id="testing-static-classes" tabindex="-1">Testing Static Classes</h3>
<p>Testing static classes is tough. You can&#8217;t mock them easily, and they can keep state between tests. But don&#8217;t worry, we&#8217;ve got some tricks.</p>
<p><strong>Wrapper Classes to the Rescue</strong></p>
<p>One good way is to wrap static classes in non-static classes. This lets you mock and inject them in tests.</p>
<p>Here&#8217;s an example:</p>
<pre><code class="language-csharp">public interface IFileWrapper
{
    string ReadAllText(string path);
}

public class FileWrapper : IFileWrapper
{
    public string ReadAllText(string path)
    {
        return File.ReadAllText(path);
    }
}

public class MyClass
{
    private readonly IFileWrapper _fileWrapper;

    public MyClass(IFileWrapper fileWrapper)
    {
        _fileWrapper = fileWrapper;
    }

    public string ReadFile(string path)
    {
        return _fileWrapper.ReadAllText(path);
    }
}
</code></pre>
<p>Now you can mock <code>IFileWrapper</code> in tests:</p>
<pre><code class="language-csharp">[Fact]
public void ReadFile_ShouldReturnFileContents()
{
    var mockFileWrapper = new Mock&lt;IFileWrapper&gt;();
    mockFileWrapper.Setup(fw =&gt; fw.ReadAllText(It.IsAny&lt;string&gt;()))
                   .Returns(&quot;Mocked file contents&quot;);

    var myClass = new MyClass(mockFileWrapper.Object);
    var result = myClass.ReadFile(&quot;test.txt&quot;);

    Assert.Equal(&quot;Mocked file contents&quot;, result);
}
</code></pre>
<p><strong>Fixing Old Code</strong></p>
<p>If you&#8217;ve got lots of static classes, don&#8217;t panic. Here&#8217;s how to make them more testable:</p>
<ol>
<li>Find the static class. Let&#8217;s say it&#8217;s a <code>Logger</code> with a static <code>Write</code> method.</li>
<li>Make an interface. Create an <code>ILogger</code> interface with the methods you need.</li>
<li>Make a wrapper. Create a non-static class that wraps the static calls.</li>
<li>Use dependency injection. Update your code to use the interface instead of static calls.</li>
</ol>
<p>Here&#8217;s a before and after:</p>
<p>Before:</p>
<pre><code class="language-csharp">public class ProductService
{
    public void CreateProduct(Product product)
    {
        // Some logic here
        Logger.Write($&quot;Created product: {product.Name}&quot;);
    }
}
</code></pre>
<p>After:</p>
<pre><code class="language-csharp">public interface ILogger
{
    void Write(string message);
}

public class LoggerWrapper : ILogger
{
    public void Write(string message)
    {
        Logger.Write(message);
    }
}

public class ProductService
{
    private readonly ILogger _logger;

    public ProductService(ILogger logger)
    {
        _logger = logger;
    }

    public void CreateProduct(Product product)
    {
        // Some logic here
        _logger.Write($&quot;Created product: {product.Name}&quot;);
    }
}
</code></pre>
<p>Now you can mock the logger in your tests. This makes your code much easier to test.</p>
<h2 id="summary" tabindex="-1" class="sb">Summary</h2>
<p>Static classes in C# are handy for organizing code, but they have pros and cons. Here&#8217;s a quick rundown:</p>
<p>Static classes are containers for static members. You can&#8217;t create instances of them, inherit from them, or put instance members in them. They&#8217;re great for utility functions and constants that don&#8217;t need object-specific data.</p>
<p>Use static classes for:</p>
<ul>
<li>Utility functions (like math operations)</li>
<li>App-wide constants</li>
<li>Extension methods</li>
<li>Factory methods</li>
</ul>
<p>Avoid static classes when:</p>
<ul>
<li>You need to keep state across threads</li>
<li>You want to use inheritance or interfaces</li>
<li>You need to isolate unit tests</li>
</ul>
<p>Performance-wise, static classes can be a bit faster because you don&#8217;t need to create instances. But don&#8217;t sacrifice code quality for tiny speed gains.</p>
<p>Some tips:</p>
<ol>
<li>Keep static classes focused</li>
<li>Use thread-safe tools for multi-threaded code</li>
<li>Handle errors properly in static methods</li>
<li>Think about using dependency injection for more flexible code</li>
</ol>
<p>Let&#8217;s look at a real-world example: Microsoft&#8217;s <code>System.Math</code> class. It&#8217;s a static class that does math stuff without needing to create an object:</p>
<pre><code class="language-csharp">double squareRoot = Math.Sqrt(25);
double powerResult = Math.Pow(2, 3);
double sineValue = Math.Sin(Math.PI / 2);
</code></pre>
<p>This makes the code simpler and easier to read.</p>
<p>Testing static classes can be tricky. One way to make it easier is to wrap static stuff in regular classes that use interfaces. This lets you mock things for testing.</p>
<p>Remember, static classes stick around for the whole time your app is running. This is fine for small, often-used tools, but be careful with big static collections or resources.</p>
<p>Static classes are just one tool in C#. Use them when they make sense, but always think about what your project needs and how easy your code will be to maintain in the future.</p>
<p>To keep up with C# and .NET news, including tips on static classes, check out the .NET Newsletter (https://dotnetnews.co). It&#8217;s a daily update put together by Jasen Fici that covers all things .NET.</p>
<h2 id="faqs" tabindex="-1" class="sb">FAQs</h2>
<p>Let&#8217;s dive into some common questions about static classes in C#:</p>
<h3 id="what-are-static-classes%3F" tabindex="-1">What are static classes?</h3>
<p>Static classes in C# are unique. You can&#8217;t create objects from them using <code>new</code>. They&#8217;re containers for static members only, like utility methods or constants that don&#8217;t need object-specific data.</p>
<h3 id="why-use-static-class-in-c%23%3F" tabindex="-1">Why use static class in C#?</h3>
<p>Static classes have some perks:</p>
<p>1. <strong>Compiler checks</strong></p>
<p>The compiler makes sure you don&#8217;t accidentally add instance members.</p>
<p>2. <strong>Memory efficiency</strong></p>
<p>No instances means potential memory savings.</p>
<p>3. <strong>Organization</strong></p>
<p>They&#8217;re great for grouping related utility functions or constants.</p>
<p>A Microsoft Learn contributor says:</p>
<blockquote>
<p>&quot;The advantage of using a static class is that the compiler can check to make sure that no instance members are accidentally added.&quot;</p>
</blockquote>
<h3 id="what-are-the-limitations-of-a-static-class%3F" tabindex="-1">What are the limitations of a static class?</h3>
<p>Static classes have some restrictions:</p>
<ul>
<li>Can&#8217;t be inherited from</li>
<li>Only inherit from <code>Object</code></li>
<li>No instance constructors (but can have static ones)</li>
<li>Can&#8217;t implement interfaces</li>
</ul>
<h3 id="when-should-we-use-static-class-in-c%23%3F" tabindex="-1">When should we use static class in C#?</h3>
<p>Use static classes for:</p>
<ul>
<li>Utility functions (like math operations)</li>
<li>Constants (app-wide settings)</li>
<li>Extension methods (adding functionality to existing types)</li>
</ul>
<p>Here&#8217;s an example using the built-in <code>Math</code> class:</p>
<pre><code class="language-csharp">double result = Math.Sqrt(16); // Using a static method
</code></pre>
<h3 id="what-are-static-members-in-c%23%3F" tabindex="-1">What are static members in C#?</h3>
<p>Static members belong to the class itself, not specific instances. They&#8217;re shared across all instances and can be used without creating an object. This includes:</p>
<ul>
<li>Static fields</li>
<li>Static properties</li>
<li>Static methods</li>
<li>Static events</li>
</ul>
<p>Here&#8217;s a quick example:</p>
<pre><code class="language-csharp">public static class Logger
{
    public static void Log(string message)
    {
        Console.WriteLine($&quot;[{DateTime.Now}] {message}&quot;);
    }
}

// Usage
Logger.Log(&quot;This is a log message&quot;);
</code></pre>
<p>Static classes and members are powerful tools in C#. They&#8217;re great for utility functions and shared resources, but remember their limitations when deciding whether to use them in your code.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/08/c-sortedlist-tutorial-with-examples/" style="display: inline;">C# SortedList Tutorial with Examples</a></li>
<li><a href="/2024/09/c-method-overloading-examples-beginner-guide/" style="display: inline;">C# Method Overloading Examples &#8211; Beginner Guide</a></li>
<li>Object Pool Pattern in ASP.NET Core</li>
<li>Async Event Handlers: Keep WinForms UI Responsive</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Explore the advantages, limitations, and best practices for using static classes in C# to streamline your coding and enhance performance.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_bdac6d7dd2e795d92ec8046453d032b1-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_bdac6d7dd2e795d92ec8046453d032b1-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">JSON Parsing Error Handling in .NET</title><link href="https://codejack.com/2024/11/json-parsing-error-handling-in-net/" rel="alternate" type="text/html" title="JSON Parsing Error Handling in .NET" /><published>2024-11-12T00:19:47-05:00</published><updated>2024-11-12T00:19:47-05:00</updated><id>https://codejack.com/2024/11/json-parsing-error-handling-in-net</id><content type="html" xml:base="https://codejack.com/2024/11/json-parsing-error-handling-in-net/"><![CDATA[<p>: A Quick Guide</p>
<p>Struggling with JSON parsing errors in your .NET app? Here&#8217;s what you need to know:</p>
<ul>
<li><strong>Main Error Types</strong>: FormatException and JsonException</li>
<li><strong>Key Impacts</strong>: App crashes, data corruption, performance slowdowns</li>
</ul>
<p>Quick fixes:</p>
<ol>
<li>Use try-catch blocks</li>
<li>Implement custom error handling middleware</li>
<li>Set up JsonSerializerOptions for flexibility</li>
<li>Add custom error handlers</li>
<li>Use schema validation</li>
</ol>
<p>Pro tip: Reuse JsonSerializerOptions instances to boost performance. Microsoft tests show it can be 200x faster!</p>
<p>Remember: Good error handling isn&#8217;t just about catching errors &#8211; it&#8217;s about giving useful feedback to guide developers.</p>
<p>Stay tuned for code examples, advanced fixes, and <a href="https://azure.microsoft.com/en-us" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure</a>-specific tips to make your JSON parsing bulletproof.</p>
<h2 id="related-video-from-youtube" tabindex="-1" class="sb">Related video from YouTube</h2>
<p><iframe class="sb-iframe" src="https://www.youtube.com/embed/zRFPPKh1Rq0" frameborder="0" loading="lazy" allowfullscreen style="width: 100%; height: auto; aspect-ratio: 16/9;"></iframe></p>
<h2 id="finding-and-fixing-json-errors" tabindex="-1" class="sb">Finding and Fixing JSON Errors</h2>
<p>JSON parsing errors can be a pain. But don&#8217;t worry &#8211; we&#8217;ve got some tricks up our sleeve to spot and fix these issues in your .NET apps.</p>
<h3 id="setting-up-jsonserializeroptions" tabindex="-1">Setting Up JsonSerializerOptions</h3>
<p>The <code>JsonSerializerOptions</code> class is your secret weapon for JSON parsing. Here&#8217;s how to set it up:</p>
<pre><code class="language-csharp">JsonSerializerOptions options = new JsonSerializerOptions
{
    WriteIndented = true,
    PropertyNameCaseInsensitive = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
</code></pre>
<p>This setup makes your parsing more flexible. It&#8217;s less likely to break because of case sensitivity or null values.</p>
<p>Here&#8217;s a cool fact: reusing your <code>JsonSerializerOptions</code> instance can seriously speed things up. Microsoft ran a test where they serialized a small object 100,000 times. With a reused options instance, it took just 190 milliseconds. Creating a new instance each time? A whopping 40,140 milliseconds!</p>
<h3 id="adding-error-handlers" tabindex="-1">Adding Error Handlers</h3>
<p>Want to keep track of parsing errors? Custom error handlers are the way to go. Check out this example using <a href="https://www.newtonsoft.com/json/help/html/introduction.htm" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Json.NET</a>:</p>
<pre><code class="language-csharp">List&lt;string&gt; errors = new List&lt;string&gt;();
List&lt;DateTime&gt; dates = JsonConvert.DeserializeObject&lt;List&lt;DateTime&gt;&gt;(jsonString, 
    new JsonSerializerSettings 
    { 
        Error = delegate(object sender, ErrorEventArgs args) 
        { 
            errors.Add(args.ErrorContext.Error.Message);
            args.ErrorContext.Handled = true;
        },
        Converters = { new IsoDateTimeConverter() }
    });
</code></pre>
<p>This setup catches errors during deserialization, logs them, and keeps on trucking. It&#8217;s super handy when you&#8217;re dealing with big datasets and don&#8217;t want a few errors to stop everything.</p>
<blockquote>
<p>&quot;Error handling lets you catch an error and choose whether to handle it and continue with serialization or let the error bubble up and be thrown in your application.&quot; &#8211; Json.NET Documentation</p>
</blockquote>
<p>Got an ASP.NET Core app? You can set up global JSON options like this:</p>
<pre><code class="language-csharp">builder.Services.Configure&lt;Microsoft.AspNetCore.Http.Json.JsonOptions&gt;(options =&gt; 
{
    options.SerializerOptions.PropertyNameCaseInsensitive = false;
    options.SerializerOptions.PropertyNamingPolicy = null;
    options.SerializerOptions.WriteIndented = true;
});
</code></pre>
<p>This ensures your whole app handles JSON the same way, cutting down on surprise parsing errors.</p>
<h2 id="code-examples-and-methods" tabindex="-1" class="sb">Code Examples and Methods</h2>
<p>Let&#8217;s look at some practical ways to handle JSON parsing errors in .NET. These methods will help keep your app running smoothly when JSON throws a curveball.</p>
<h3 id="try-catch-blocks" tabindex="-1">Try-Catch Blocks</h3>
<p>Try-catch blocks are your first defense against JSON parsing errors. They let you handle exceptions without crashing your app. Here&#8217;s how:</p>
<pre><code class="language-csharp">try 
{
    string jsonString = File.ReadAllText(@&quot;C:/temp/json.txt&quot;);
    Rootobject root = JsonConvert.DeserializeObject&lt;Rootobject&gt;(jsonString);

    Console.WriteLine($&quot;Record Locator: {root.RecordLocator[0].PNR}&quot;);
    Console.WriteLine($&quot;Balance Due: {root.PNRAmount.BalanceDue}&quot;);
}
catch (JsonReaderException jre)
{
    Console.WriteLine($&quot;JSON parsing error: {jre.Message}&quot;);
    // Log the error or take action
}
catch (Exception ex)
{
    Console.WriteLine($&quot;Unexpected error: {ex.Message}&quot;);
    // Handle other exceptions
}
</code></pre>
<p>This example catches JSON-specific exceptions separately from general ones. It&#8217;s a smart way to handle errors more precisely.</p>
<h3 id="error-handling-middleware" tabindex="-1">Error Handling Middleware</h3>
<p>For ASP.NET Core apps, custom middleware can handle JSON parsing errors across your entire application. Here&#8217;s an example:</p>
<pre><code class="language-csharp">public class JsonExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger&lt;JsonExceptionMiddleware&gt; _logger;

    public JsonExceptionMiddleware(RequestDelegate next, ILogger&lt;JsonExceptionMiddleware&gt; logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (JsonException jsonEx)
        {
            _logger.LogError(jsonEx, &quot;JSON parsing error occurred&quot;);

            context.Response.StatusCode = StatusCodes.Status400BadRequest;
            context.Response.ContentType = &quot;application/json&quot;;

            var errorResponse = new 
            {
                error = &quot;Invalid JSON format&quot;,
                details = jsonEx.Message
            };

            await context.Response.WriteAsync(JsonSerializer.Serialize(errorResponse));
        }
    }
}
</code></pre>
<p>To use this middleware, add it to your app&#8217;s request pipeline in <code>Startup.cs</code>:</p>
<pre><code class="language-csharp">app.UseMiddleware&lt;JsonExceptionMiddleware&gt;();
</code></pre>
<p>This middleware catches JSON exceptions, logs them, and returns a user-friendly JSON response. It&#8217;s a clean way to handle JSON parsing errors throughout your app.</p>
<blockquote>
<p>&quot;You can prevent this exception by adding predicates in front.&quot; &#8211; Jiachen Li, Microsoft Q&amp;A Contributor</p>
</blockquote>
<p>This tip suggests checking for null values or property existence before accessing them. It&#8217;s a simple way to reduce JSON parsing errors before they happen.</p>
<h6 id="sbb-itb-29cd4f6" class="sb-banner" style="color:transparent!important;line-height:0!important;padding:0!important;margin:0!important;">sbb-itb-29cd4f6</h6>
<h2 id="tips-and-solutions" tabindex="-1" class="sb">Tips and Solutions</h2>
<p>Let&#8217;s explore some practical ways to handle JSON parsing errors and compare different methods.</p>
<h3 id="error-prevention-tips" tabindex="-1">Error Prevention Tips</h3>
<p>It&#8217;s easier to prevent JSON parsing errors than to fix them. Here are some proven strategies:</p>
<p>1. <strong>Check before you leap</strong></p>
<p>Before accessing JSON keys, make sure they exist. This simple check can stop many <code>NullReferenceException</code> errors in their tracks:</p>
<pre><code class="language-csharp">if (jsonObject.ContainsKey(&quot;records&quot;) &amp;&amp; jsonObject[&quot;records&quot;] != null)
{
    var records = jsonObject[&quot;records&quot;].AsArray();
    // Do stuff with records
}
</code></pre>
<p>2. <strong>Embrace strong typing</strong></p>
<p>Ditch dynamic objects like <code>JObject</code>. Instead, turn your JSON into strongly-typed C# classes. This way, you&#8217;ll catch more errors when you compile, not when you run.</p>
<p>3. <strong>Validate your JSON</strong></p>
<p>Use tools like <code>Newtonsoft.Json.Schema</code> to check your JSON against a predefined structure. It&#8217;s like having a bouncer for your data &#8211; only the right stuff gets in.</p>
<p>4. <strong>Be nice to null</strong></p>
<p>When you&#8217;re making custom JSON converters, tell them how to handle null values:</p>
<pre><code class="language-csharp">public class CustomConverter : JsonConverter&lt;string&gt;
{
    public override bool HandleNull =&gt; true;

    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetString() ?? &quot;Default value&quot;;
    }

    // Write method goes here
}
</code></pre>
<p>5. <strong>Match names with JsonPropertyName</strong></p>
<p>If your C# property names don&#8217;t match your JSON keys, use <code>[JsonPropertyName(&quot;jsonKey&quot;)]</code> to play matchmaker.</p>
<h3 id="error-handling-methods%3A-the-showdown" tabindex="-1">Error Handling Methods: The Showdown</h3>
<p>Let&#8217;s pit different error handling approaches against each other:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Method</th>
<th>Good Stuff</th>
<th>Not-So-Good Stuff</th>
<th>Best For</th>
</tr>
</thead>
<tbody>
<tr>
<td>Try-Catch Blocks</td>
<td>Easy to use, catches specific issues</td>
<td>Can clutter your code if overused</td>
<td>Handling errors in specific spots</td>
</tr>
<tr>
<td>Global Error Middleware</td>
<td>Centralizes error handling, keeps code clean</td>
<td>Might not give enough control for every situation</td>
<td>Managing errors across your whole app</td>
</tr>
<tr>
<td>Custom JsonConverter</td>
<td>Gives you fine-grained control</td>
<td>Takes more setup, can get tricky with nested objects</td>
<td>Dealing with specific data types or formats</td>
</tr>
<tr>
<td>Schema Validation</td>
<td>Catches structure problems early, gives detailed error messages</td>
<td>Needs you to maintain schemas, adds some processing time</td>
<td>APIs that need strict data contracts</td>
</tr>
</tbody>
</table>
<p>Each method has its place. Often, a mix works best. Microsoft suggests using try-catch for specific spots and global error middleware for overall app toughness.</p>
<p>Remember, good error handling isn&#8217;t just about catching errors &#8211; it&#8217;s about giving useful feedback. As Khalid Abuhakmeh from <a href="https://www.jetbrains.com/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">JetBrains</a> says:</p>
<blockquote>
<p>&quot;Good error messages are like good documentation. They guide developers to the root cause and suggest potential fixes.&quot;</p>
</blockquote>
<p>Handling errors well can make your life (and your users&#8217; lives) much easier. Choose your methods wisely, and may your JSON always parse smoothly!</p>
<h2 id="advanced-error-fixes" tabindex="-1" class="sb">Advanced Error Fixes</h2>
<p>Let&#8217;s dive into some powerful techniques for tackling complex JSON parsing issues in .NET.</p>
<h3 id="custom-json-converters" tabindex="-1">Custom JSON Converters</h3>
<p>Custom JSON converters are your secret weapon for tricky JSON structures. Here&#8217;s a converter that handles Unix Epoch timestamps:</p>
<pre><code class="language-csharp">public class UnixEpochDateTimeConverter : JsonConverter&lt;DateTime&gt;
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        long unixTime = reader.GetInt64();
        return DateTimeOffset.FromUnixTimeSeconds(unixTime).DateTime;
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        long unixTime = new DateTimeOffset(value).ToUnixTimeSeconds();
        writer.WriteNumberValue(unixTime);
    }
}
</code></pre>
<p>To use it:</p>
<pre><code class="language-csharp">var options = new JsonSerializerOptions();
options.Converters.Add(new UnixEpochDateTimeConverter());
</code></pre>
<p>These converters can be a game-changer for inconsistent JSON formats. They give you control over serialization and deserialization, helping you handle cases where a property might be a string in one instance and an object in another.</p>
<h3 id="json-schema-validation" tabindex="-1">JSON Schema Validation</h3>
<p>JSON Schema acts like a bouncer for your data. It catches structural errors before they cause havoc in your app. Here&#8217;s how to use it with <a href="https://github.com/RicoSuter/NJsonSchema" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">NJsonSchema</a>:</p>
<pre><code class="language-csharp">using NJsonSchema;

var schema = JsonSchema.FromType&lt;Person&gt;();
var errors = schema.Validate(&quot;{\&quot;name\&quot;:null,\&quot;hobbies\&quot;:[\&quot;Coding\&quot;,123]}&quot;);

foreach (var error in errors)
{
    Console.WriteLine($&quot;Error: {error.Path} - {error.Kind}&quot;);
}
</code></pre>
<p>This code checks a JSON string against a schema based on a Person class. It&#8217;ll catch issues like null values in required fields or wrong data types.</p>
<p>Json.NET also supports schema validation:</p>
<pre><code class="language-csharp">JSchema schema = JSchema.Parse(File.ReadAllText(&quot;schema.json&quot;));
JObject person = JObject.Parse(File.ReadAllText(&quot;person.json&quot;));

bool isValid = person.IsValid(schema, out IList&lt;string&gt; errorMessages);
if (!isValid)
{
    foreach (string error in errorMessages)
    {
        Console.WriteLine(error);
    }
}
</code></pre>
<h3 id="common-errors-and-solutions" tabindex="-1">Common Errors and Solutions</h3>
<p>Here&#8217;s a quick guide to some frequent JSON parsing errors:</p>
<table style="width:100%;">
<thead>
<tr>
<th>Error</th>
<th>Cause</th>
<th>Solution</th>
</tr>
</thead>
<tbody>
<tr>
<td>Unexpected token &lt; in JSON at position 0</td>
<td>Got HTML instead of JSON</td>
<td>Check your API endpoint</td>
</tr>
<tr>
<td>Cannot deserialize the current JSON object</td>
<td>JSON and C# class mismatch</td>
<td>Update your class or use a custom converter</td>
</tr>
<tr>
<td>Error parsing JSON</td>
<td>Malformed JSON</td>
<td>Validate with JSONLint before parsing</td>
</tr>
<tr>
<td>The JSON value could not be converted to System.DateTime</td>
<td>Wrong date format</td>
<td>Use a custom DateTime converter</td>
</tr>
</tbody>
</table>
<p>When you&#8217;re stuck, look at the raw JSON. It can reveal a lot about what&#8217;s going wrong.</p>
<p>Don&#8217;t forget about middleware in ASP.NET Core apps. You can create custom error handling middleware to catch and log JSON parsing errors across your entire application. It&#8217;s a neat way to centralize your error handling instead of scattering try-catch blocks everywhere.</p>
<h2 id="azure-specific-settings" tabindex="-1" class="sb"><a href="https://azure.microsoft.com/en-us" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure</a>-Specific Settings</h2>
<p><img decoding="async" src="/assets/images/imported/d78a889c4a924e639906.jpg" alt="Azure" style="width:100%;"></p>
<p>When working with JSON parsing in Azure .NET apps, you need to know a few key things. Let&#8217;s look at the Azure settings that can help you handle JSON parsing better.</p>
<h3 id="azure-app-service-settings" tabindex="-1"><a href="https://azure.microsoft.com/en-us/products/app-service" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure App Service</a> Settings</h3>
<p><img decoding="async" src="/assets/images/imported/3d31299559e04e662c36.jpg" alt="Azure App Service" style="width:100%;"></p>
<p>Azure App Service lets you manage settings for different environments without redeploying. Here&#8217;s how to use it for JSON parsing:</p>
<p>1. <strong>Environment Variables</strong></p>
<p>Azure App Service shows settings as environment variables. You can access your JSON configs right in your code without parsing extra files.</p>
<p>2. <strong>App Settings</strong></p>
<p>Use the Azure portal to change app settings. These override your local <code>appsettings.json</code> file when deployed. For example:</p>
<pre><code class="language-csharp">var jsonOptions = JsonSerializerOptions.Parse(Environment.GetEnvironmentVariable(&quot;JSON_OPTIONS&quot;));
</code></pre>
<p>3. <strong>Slot-specific Settings</strong></p>
<p>For staging, use deployment slots with slot-specific settings. This lets you test JSON parsing configs before going to production.</p>
<p>Keep in mind: changing app settings in Azure restarts your app. Plan updates to avoid downtime.</p>
<h3 id="handling-connection-strings" tabindex="-1">Handling Connection Strings</h3>
<p>Connection strings often have JSON-formatted data. Here&#8217;s how to handle them safely in Azure:</p>
<p>1. <strong><a href="https://learn.microsoft.com/en-us/azure/key-vault/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure Key Vault</a> Integration</strong></p>
<p>Instead of putting JSON connection strings in app settings, use Azure Key Vault. It&#8217;s safer for sensitive JSON data.</p>
<p>2. <strong>Environment-specific Prefixes</strong></p>
<p>Azure adds prefixes to connection strings based on their type. For a SQL connection named &quot;MyJsonData&quot;:</p>
<pre><code class="language-csharp">var jsonConnectionString = Environment.GetEnvironmentVariable(&quot;SQLCONNSTR_MyJsonData&quot;);
</code></pre>
<p>3. <strong>JSON in Connection Strings</strong></p>
<p>If your connection string has JSON, escape special characters. Azure&#8217;s connection string parser can be picky about formatting.</p>
<p>A .NET developer at Contoso Ltd. shared this:</p>
<blockquote>
<p>&quot;We had problems with our JSON config parsing until we figured out Azure was adding prefixes to our connection strings. Once we updated our code to use &#8216;CUSTOMCONNSTR_&#8217; prefix for our JSON data source, it all worked.&quot;</p>
</blockquote>
<h2 id="wrap-up-and-next-steps" tabindex="-1" class="sb">Wrap-up and Next Steps</h2>
<p>We&#8217;ve covered a lot about handling JSON parsing errors in .NET. Let&#8217;s recap the key points and look at how to stay in the loop.</p>
<h3 id="main-points-review" tabindex="-1">Main Points Review</h3>
<p>Here&#8217;s what we learned about managing JSON parsing errors:</p>
<p>1. <strong>JsonSerializerOptions</strong></p>
<p>These options let you tweak how JSON gets handled. For example, setting <code>PropertyNameCaseInsensitive = true</code> can fix issues with property names that don&#8217;t match exactly.</p>
<p>2. <strong>Error handling middleware</strong></p>
<p>For ASP.NET Core apps, this is a central spot to catch and log JSON errors. It&#8217;s like having a safety net for your whole app.</p>
<p>3. <strong>Custom JSON converters</strong></p>
<p>These are your secret weapons for tricky JSON. Remember the UnixEpochDateTimeConverter we talked about? It&#8217;s a great example of solving specific JSON problems.</p>
<p>4. <strong>JSON Schema validation</strong></p>
<p>Think of this as your first line of defense. It catches structure issues before they cause trouble in your app. NJsonSchema is a handy tool for this.</p>
<h3 id="staying-updated" tabindex="-1">Staying Updated</h3>
<p>Want to keep up with the latest JSON tricks and .NET news? The .NET Newsletter is a good bet. Here&#8217;s what you&#8217;ll get:</p>
<ul>
<li>Daily updates on .NET, C#, ASP.NET, and Azure</li>
<li>Weekly spotlights on developers and libraries</li>
<li>News about new features and best practices</li>
</ul>
<p>For example, they recently covered some cool improvements in System.Text.Json that came with .NET 8. These include better support for Native AOT apps and new features like handling read-only members.</p>
<p>Here&#8217;s an interesting fact from the newsletter: In .NET 8, publishing a self-contained Native AOT app shrunk the binary size by 23% compared to .NET 7 &#8211; from 3.4 MB to 2.6 MB. That&#8217;s pretty impressive, and it could help make your JSON parsing (and your whole app) run smoother.</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/winforms-exception-handling-best-practices/" style="display: inline;">WinForms Exception Handling: Best Practices</a></li>
<li><a href="/2024/09/aspnet-mvc-exception-handling-6-methods-explained/" style="display: inline;">ASP.NET MVC Exception Handling: 6 Methods Explained</a></li>
<li><a href="/2024/09/wcf-message-size-reduction-techniques/" style="display: inline;">WCF Message Size Reduction Techniques</a></li>
<li>gRPC Error Handling in ASP.NET Core: Best Practices</li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn effective strategies for handling JSON parsing errors in .NET applications, including custom converters and middleware solutions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_94b78143fab51d60c3634c2345e874c9-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_94b78143fab51d60c3634c2345e874c9-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C# Exception Filters: Quick Guide [2024]</title><link href="https://codejack.com/2024/11/c-exception-filters-quick-guide-2024/" rel="alternate" type="text/html" title="C# Exception Filters: Quick Guide [2024]" /><published>2024-11-12T00:05:39-05:00</published><updated>2024-11-12T00:05:39-05:00</updated><id>https://codejack.com/2024/11/c-exception-filters-quick-guide-2024</id><content type="html" xml:base="https://codejack.com/2024/11/c-exception-filters-quick-guide-2024/"><![CDATA[<p>Exception filters in C# are a game-changer for error handling. Here&#8217;s what you need to know:</p>
<ul>
<li>Introduced in C# 6.0 (2015)</li>
<li>Allow precise exception catching with the <code>when</code> keyword</li>
<li>Preserve stack traces for better debugging</li>
<li>Can improve performance by avoiding unnecessary stack unwinding</li>
</ul>
<p>Key benefits:</p>
<ol>
<li>Cleaner code with less nesting</li>
<li>More accurate error handling</li>
<li>Faster execution in some scenarios</li>
</ol>
<p>Basic syntax:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw
}
catch (ExceptionType ex) when (condition)
{
    // Handle exception
}
</code></pre>
<p>Example:</p>
<pre><code class="language-csharp">catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
    Console.WriteLine(&quot;Resource not found. Check the URL.&quot;);
}
</code></pre>
<p>Remember: Use filters for specific error conditions, not for general exception handling.</p>
<p>This guide covers everything from basic usage to advanced techniques, common problems, and best practices for C# exception filters.</p>
<h2 id="related-video-from-youtube" tabindex="-1" class="sb">Related video from YouTube</h2>
<p><iframe class="sb-iframe" src="https://www.youtube.com/embed/b2TZ_xG4qEI" frameborder="0" loading="lazy" allowfullscreen style="width: 100%; height: auto; aspect-ratio: 16/9;"></iframe></p>
<h2 id="what-are-exception-filters" tabindex="-1" class="sb">What Are Exception Filters</h2>
<p>Exception filters in C# let you catch exceptions based on specific conditions. They were added in C# 6.0 back in 2015.</p>
<h3 id="how-to-write-exception-filters" tabindex="-1">How to Write Exception Filters</h3>
<p>You use the <code>when</code> keyword to create an exception filter:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw an exception
}
catch (ExceptionType ex) when (condition)
{
    // Handle the exception if the condition is true
}
</code></pre>
<p>Here&#8217;s a real-world example:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw an ArgumentException
}
catch (ArgumentException ex) when (ex.Message.Contains(&quot;The name of the user is too short&quot;))
{
    Console.WriteLine(&quot;User name is too short. Please try again.&quot;);
}
</code></pre>
<p>This catches the exception only if the message mentions a short user name.</p>
<h3 id="main-advantages" tabindex="-1">Main Advantages</h3>
<p>Exception filters have some key benefits:</p>
<p>1. <strong>Stack Traces Stay Intact</strong></p>
<p>They don&#8217;t mess with the stack trace. This is huge for debugging. You can see where the error started, not just where it was last caught.</p>
<blockquote>
<p>&quot;Exception filters are preferable to catching and rethrowing because they leave the stack unharmed. If the exception later causes the stack to be dumped, you can see where it originally came from, rather than just the last place it was rethrown.&quot; &#8211; Stack Overflow user</p>
</blockquote>
<p>2. <strong>Cleaner Code</strong></p>
<p>The <code>when</code> keyword makes your error handling more readable. It&#8217;s easier to understand what&#8217;s going on at a glance.</p>
<p>3. <strong>Less Nesting</strong></p>
<p>You don&#8217;t need as many nested if-statements in your catch blocks. This makes your code simpler.</p>
<p>4. <strong>Better Performance</strong></p>
<p>Exception filters can be faster because they don&#8217;t unwind the stack unnecessarily.</p>
<p>Thomas Levesque, a C# expert, says:</p>
<blockquote>
<p>&quot;Correctly understood and used, they can make it much easier to diagnose problems in your code.&quot;</p>
</blockquote>
<p>Here&#8217;s a practical example showing how powerful exception filters can be:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw different types of exceptions
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
    Console.WriteLine(&quot;The endpoint you are trying to reach cannot be found. Please check the URL&quot;);
}
catch (CustomException ex) when (ex.HttpStatusCode == 404)
{
    // Handle CustomException exceptions with an HTTP code of 404
}
catch (Exception ex) when (ex is ArgumentException || ex is FormatException || ex is OverflowException)
{
    // Handle ArgumentException, FormatException, and OverflowException exceptions
}
</code></pre>
<p>This example shows how you can handle different exceptions and conditions in a clean, easy-to-read way.</p>
<h2 id="using-exception-filters-in-code" tabindex="-1" class="sb">Using Exception Filters in Code</h2>
<p>Exception filters in C# let you handle errors with precision. Here&#8217;s how to use them:</p>
<h3 id="basic-code-examples" tabindex="-1">Basic Code Examples</h3>
<p>The basic syntax for exception filters looks like this:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw an exception
}
catch (ExceptionType ex) when (condition)
{
    // Handle the exception if the condition is true
}
</code></pre>
<p>Here&#8217;s a real-world example:</p>
<pre><code class="language-csharp">try
{
    int result = 10 / int.Parse(&quot;0&quot;);
}
catch (DivideByZeroException ex) when (ex.Message.Contains(&quot;zero&quot;))
{
    Console.WriteLine(&quot;You can't divide by zero!&quot;);
}
</code></pre>
<p>This code only catches a <code>DivideByZeroException</code> if the message has &quot;zero&quot; in it. It&#8217;s a simple way to handle specific errors.</p>
<h3 id="practical-examples" tabindex="-1">Practical Examples</h3>
<p>Let&#8217;s look at how exception filters work in real situations:</p>
<p><strong>Handling HTTP Errors</strong></p>
<p>When you&#8217;re working with web services, you often need to deal with different HTTP status codes:</p>
<pre><code class="language-csharp">try
{
    var response = await client.GetAsync(&quot;https://api.example.com/data&quot;);
    response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
    Console.WriteLine(&quot;Can't find that resource. Double-check your URL.&quot;);
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
    Console.WriteLine(&quot;Authentication failed. Check your login info.&quot;);
}
</code></pre>
<p>This example shows how to handle specific HTTP status codes, which can make your error messages more helpful.</p>
<p><strong>Custom Exception Handling</strong></p>
<p>Exception filters are great for dealing with custom exceptions:</p>
<pre><code class="language-csharp">try
{
    ProcessConfig(configData);
}
catch (CustomException ex) when (ex.ErrorCode == 404)
{
    Console.WriteLine($&quot;Can't find that config: {ex.Message}&quot;);
}
catch (CustomException ex) when (ex.ErrorCode == 400)
{
    Console.WriteLine($&quot;That config isn't valid: {ex.Message}&quot;);
}
</code></pre>
<p>This approach lets you handle errors based on specific properties of your custom exceptions.</p>
<p><strong>Multiple Exception Types</strong></p>
<p>You can use exception filters to handle several exception types in one catch block:</p>
<pre><code class="language-csharp">try
{
    // Code that might throw various exceptions
}
catch (Exception ex) when (ex is ArgumentException || ex is FormatException || ex is OverflowException)
{
    Console.WriteLine($&quot;Input error: {ex.Message}&quot;);
}
</code></pre>
<p>This technique can make your code cleaner by grouping related exceptions.</p>
<p>Exception filters are powerful, but use them wisely. Too many can make your code hard to follow. As Bill Wagner, who wrote &quot;Effective C#&quot;, puts it:</p>
<blockquote>
<p>&quot;The exception filters in C# 6 cut back on the cumbersome error-handling code commonplace to earlier releases.&quot;</p>
</blockquote>
<h2 id="advanced-filter-methods" tabindex="-1" class="sb">Advanced Filter Methods</h2>
<p>Exception filters in C# let you handle tricky error situations. Let&#8217;s look at some smart ways to use them.</p>
<h3 id="dealing-with-multiple-exceptions" tabindex="-1">Dealing with Multiple Exceptions</h3>
<p>Want to handle different errors in different ways? Exception filters are your friend. Check out this real-world example from Microsoft:</p>
<pre><code class="language-csharp">try
{
    HelixApi = GetHelixApi();
    AnonymousApi = ApiFactory.GetAnonymous(BaseUri);
    System.Threading.Tasks.Task.Run(() =&gt; ExecuteCore(_cancel.Token)).GetAwaiter().GetResult();
}
catch (RestApiException ex) when (ex.Response.Status == (int)HttpStatusCode.Unauthorized)
{
    Log.LogError(FailureCategory.Build, &quot;Helix operation returned 'Unauthorized'. Did you forget to set HelixAccessToken?&quot;);
}
catch (RestApiException ex) when (ex.Response.Status == (int)HttpStatusCode.Forbidden)
{
    Log.LogError(FailureCategory.Build, &quot;Helix operation returned 'Forbidden'.&quot;);
}
catch (OperationCanceledException ocex) when (ocex.CancellationToken == _cancel.Token)
{
    return false;
}
catch (ArgumentException argEx) when (argEx.Message.StartsWith(&quot;Helix API does not contain an entry &quot;))
{
    if (FailOnMissingTargetQueue)
    {
        Log.LogError(FailureCategory.Build, argEx.Message);
    }
    else
    {
        Log.LogWarning($&quot;{argEx.Message} (FailOnMissingTargetQueue is false, so this is just a warning.)&quot;);
    }
}
catch (Exception ex)
{
    Log.LogErrorFromException(FailureCategory.Helix, ex, true, true, null);
}
</code></pre>
<p>This code handles different HTTP status codes, cancellations, and custom error messages. It&#8217;s like having a different plan for each type of problem.</p>
<h3 id="creating-your-own-exceptions" tabindex="-1">Creating Your Own Exceptions</h3>
<p>Sometimes, you need exceptions that fit your specific app. Here&#8217;s how to make and use one:</p>
<pre><code class="language-csharp">public class InvalidNameException : Exception
{
    public InvalidNameException() { }
    public InvalidNameException(string message) : base(message) { }
    public InvalidNameException(string message, Exception inner) : base(message, inner) { }
}

public void ValidateName(string name)
{
    if (string.IsNullOrWhiteSpace(name))
        throw new InvalidNameException(&quot;Name cannot be empty or null.&quot;);
}

try
{
    ValidateName(null);
}
catch (InvalidNameException ex) when (ex.Message.Contains(&quot;empty or null&quot;))
{
    Console.WriteLine(&quot;Please provide a valid name.&quot;);
}
</code></pre>
<p>This code creates a special <code>InvalidNameException</code>. The filter checks if the error message talks about an empty or null name. It&#8217;s like having a custom alarm for a specific problem.</p>
<p>You can even add extra info to your custom exceptions:</p>
<pre><code class="language-csharp">public class InvalidAgeException : Exception
{
    public int Age { get; }
    public InvalidAgeException(int age)
    {
        Age = age;
        Data.Add(&quot;Age&quot;, Age);
    }
}

try
{
    throw new InvalidAgeException(15);
}
catch (InvalidAgeException ex) when (ex.Age &lt; 18)
{
    Console.WriteLine($&quot;User is underage: {ex.Age} years old&quot;);
}
</code></pre>
<p>This example shows how to include the age in the exception. It&#8217;s like attaching a note to your error message with extra details.</p>
<h6 id="sbb-itb-29cd4f6" class="sb-banner" style="color:transparent!important;line-height:0!important;padding:0!important;margin:0!important;">sbb-itb-29cd4f6</h6>
<h2 id="filters-vs.-old-methods" tabindex="-1" class="sb">Filters vs. Old Methods</h2>
<p>Exception filters in C# 6.0 changed the game for error handling. They&#8217;re a step up from the old catch-and-rethrow methods. Let&#8217;s break down why they&#8217;re often the smarter choice.</p>
<h3 id="what's-new%3F" tabindex="-1">What&#8217;s New?</h3>
<p>Filters shine in three main areas: stack traces, code readability, and speed.</p>
<p><strong>Stack Traces</strong></p>
<p>Old methods often messed up stack traces, making bug-hunting a pain. Filters? They keep the full trace intact. Here&#8217;s how it looks:</p>
<pre><code class="language-csharp">// Old way
try
{
    // Code that might break
}
catch (Exception ex)
{
    if (ex.Message.Contains(&quot;specific error&quot;))
    {
        // Handle it
    }
    else
    {
        throw; // Keeps stack trace
        // or
        throw ex; // Resets stack trace
    }
}

// New way with filters
try
{
    // Code that might break
}
catch (Exception ex) when (ex.Message.Contains(&quot;specific error&quot;))
{
    // Handle it
}
</code></pre>
<p>The old way? You had to choose between keeping or resetting the stack trace. Filters? They just work, no extra steps needed.</p>
<p><strong>Cleaner Code</strong></p>
<p>Filters make your code easier to read and manage. No more nested ifs in catch blocks. Just use <code>when</code> to set your conditions.</p>
<p>Mike Magruder from <a href="https://en.wikipedia.org/wiki/Common_Language_Runtime" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">CLR</a> has some advice:</p>
<blockquote>
<p>&quot;The key is to only read information from either the exception object itself, or from immutable global state, and to not change any global state.&quot;</p>
</blockquote>
<p>Stick to this, and your filters will play nice with the rest of your code.</p>
<p><strong>Speed Boost</strong></p>
<p>Filters can be faster than old methods. Here&#8217;s why: In the old way, the CLR always unwinds the stack when it hits a catch block. That&#8217;s slow.</p>
<p>With filters, it checks the condition first. If it doesn&#8217;t match, it skips the catch block entirely. That can save a lot of processing time.</p>
<p>Let&#8217;s compare:</p>
<pre><code class="language-csharp">// Old way (slower)
static void Method_PlainCatchBlock() 
{
    try 
    {
        MethodThrowing();
    } 
    catch (Exception e) 
    {
        if (e.Message == &quot;Specific Error&quot;) 
        {
            Console.WriteLine(&quot;Handled Specific Error&quot;);
        } 
        else 
        {
            throw;
        }
    }
}

// New way with filter (faster)
static void Method_Filter() 
{
    try 
    {
        MethodThrowing();
    } 
    catch(Exception e) when (e.Message == &quot;Specific Error&quot;) 
    {
        Console.WriteLine(&quot;Handled Specific Error&quot;);
    }
}
</code></pre>
<p>In tests, the filter version consistently beats the old method, especially when exceptions are common but you only need to handle specific ones.</p>
<p>Bill Wagner, who wrote &quot;Effective C#&quot;, puts it well:</p>
<blockquote>
<p>&quot;The exception filters in C# 6 cut back on the cumbersome error-handling code commonplace to earlier releases.&quot;</p>
</blockquote>
<p>So, not only is your code cleaner, it&#8217;s also more efficient. That&#8217;s a win-win.</p>
<h2 id="common-problems-and-solutions" tabindex="-1" class="sb">Common Problems and Solutions</h2>
<p>Let&#8217;s dive into some issues developers often face with exception filters in C# and how to fix them.</p>
<h3 id="debugger-stopping-at-custom-exceptions" tabindex="-1">Debugger Stopping at Custom Exceptions</h3>
<p>Ever had your debugger stop at custom exceptions when you&#8217;re just trying to validate input? It&#8217;s a real pain.</p>
<p>Here&#8217;s how to fix it:</p>
<p>Double-check your exception filter settings. Believe it or not, a simple typo in the namespace can cause this. As one developer put it:</p>
<blockquote>
<p>&quot;In the end I was very close with my PS. It was a pretty silly mistake: I had a typo in the namespace.&quot;</p>
</blockquote>
<p>So, make sure your namespace is spot-on in those exception filter settings.</p>
<h3 id="unhandled-exceptions-in-filters" tabindex="-1">Unhandled Exceptions in Filters</h3>
<p>Here&#8217;s a tricky one: what happens when your filter throws an exception? Your program might just crash. Take a look at this code:</p>
<pre><code class="language-csharp">try {
    throw new Exception(&quot;Forced Exception&quot;);
}
catch (Exception ex) when (MethodThatThrowsAnException()) {
    Console.WriteLine(&quot;Filtered handler 1&quot;);
}

private bool MethodThatThrowsAnException() {
    throw new Exception(&quot;MethodThatThrowsAnException&quot;);
}
</code></pre>
<p>Run this, and you&#8217;ll get:</p>
<blockquote>
<p>Unhandled Exception: System.Exception: MethodThatThrowsAnException</p>
</blockquote>
<p>The fix? Make sure your filter conditions are rock-solid. If there&#8217;s a chance they might throw an exception, handle it in the filter or use a simpler condition.</p>
<h3 id="performance-concerns" tabindex="-1">Performance Concerns</h3>
<p>Exception filters are cool, but they can slow things down if you&#8217;re not careful. Exceptions are WAY slower than normal code.</p>
<p>So, what should you do? Only use try-catch for REAL exceptions. For everyday stuff like parsing integers, there are faster ways. For example, <code>Int32.TryParse</code> is thousands of times quicker than a try-catch.</p>
<p>As Mohammad Mobasher says:</p>
<blockquote>
<p>&quot;Always bear in mind that exceptions are considerably slower than normal code flow.&quot;</p>
</blockquote>
<h3 id="testing-and-speed-tips" tabindex="-1">Testing and Speed Tips</h3>
<p>Want to find and fix exception filter problems fast? Here&#8217;s how:</p>
<ol>
<li>
Use <a href="https://visualstudio.microsoft.com/vs/" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Visual Studio</a>&#8216;s debugging features. Turn on first chance exceptions to catch all exceptions as they happen.
</li>
<li>
Get to know the Exception Settings Window. Michael Shpilt, a coding expert, says:</p>
<blockquote>
<p>&quot;The exception settings window is one of the most important debugging windows. You should always be aware whether you are currently breaking on exceptions or not.&quot;</p>
</blockquote>
</li>
<li>
When you&#8217;re dealing with &quot;exceptions&quot; that you expect, look for alternatives to exception handling. Like using <code>TryParse</code> instead of catching FormatExceptions for input checks.
</li>
<li>
Use exception filters to keep the original context of an exception. This helps you debug and figure out what was going on when things went wrong.
</li>
<li>
Keep your filter conditions simple and clear. It makes your code easier to read and less likely to have bugs in the filters themselves.
</li>
</ol>
<h2 id="conclusion" tabindex="-1" class="sb">Conclusion</h2>
<p>Exception filters in C# have changed the game for error handling since C# 6.0 in 2015. They&#8217;re a big deal for developers, making exception management more precise and efficient.</p>
<p>Here&#8217;s why exception filters are so important:</p>
<ol>
<li>They keep the stack trace intact. As one Stack Overflow user put it:</li>
</ol>
<blockquote>
<p>&quot;Exception filters are preferable to catching and rethrowing because they leave the stack unharmed. If the exception later causes the stack to be dumped, you can see where it originally came from, rather than just the last place it was rethrown.&quot;</p>
</blockquote>
<p>This is huge for debugging and figuring out what went wrong.</p>
<ol start="2">
<li>
They make your code cleaner and easier to read. The <code>when</code> keyword lets you set specific conditions for catching exceptions, so you don&#8217;t need as many nested if-statements.
</li>
<li>
They&#8217;re faster. Unlike regular catch blocks, exception filters don&#8217;t mess with the stack unnecessarily. This can speed things up, especially when exceptions happen a lot.
</li>
<li>
They&#8217;re flexible. You can use them with both built-in and custom exceptions, and handle multiple exception types in one catch block.
</li>
<li>
They come with best practices. Mike Magruder from CLR says:
</li>
</ol>
<blockquote>
<p>&quot;The key is to only read information from either the exception object itself, or from immutable global state, and to not change any global state.&quot;</p>
</blockquote>
<p>This keeps your exception handling predictable and avoids side effects.</p>
<p>Bill Wagner, who wrote &quot;Effective C#: 50 Specific Ways to Improve Your C#, Second Edition&quot;, sums it up nicely:</p>
<blockquote>
<p>&quot;The exception filters in C# 6 cut back on the cumbersome error-handling code commonplace to earlier releases.&quot;</p>
</blockquote>
<p>Less boilerplate code means cleaner code and fewer chances for errors in your exception handling.</p>
<p>Exception filters show how Microsoft is working to make developers more productive and improve code quality. If you want to stay in the loop on C# and .NET, check out the .NET Newsletter (https://dotnetnews.co). It gives you daily updates on C#, <a href="https://dotnet.microsoft.com/en-us/apps/aspnet" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">ASP.NET</a>, <a href="https://azure.microsoft.com/en-us" target="_blank" rel="nofollow noopener noreferrer" style="display: inline;">Azure</a>, and related tech from various sources.</p>
<h2 id="faqs" tabindex="-1" class="sb">FAQs</h2>
<h3 id="how-to-filter-exceptions-in-c%23%3F" tabindex="-1">How to filter exceptions in C#?</h3>
<p>In C#, you can filter exceptions using the <code>when</code> keyword in your catch clause. Here&#8217;s the basic syntax:</p>
<pre><code class="language-csharp">catch (ExceptionType ex) when (boolean expression)
</code></pre>
<p>Let&#8217;s look at a real-world example:</p>
<pre><code class="language-csharp">try
{
    DatabaseUpdate();
}
catch (SQLException e) when (e.Message.Contains(&quot;MySQL&quot;))
{
    Console.WriteLine(&quot;MySQL error: Oops!&quot;);
}
catch (SQLException e) when (e.Message.Contains(&quot;Oracle&quot;))
{
    Console.WriteLine(&quot;Oracle error: Yikes!&quot;);
}
</code></pre>
<p>This approach lets you handle different scenarios for the same exception type. It&#8217;s like having a bouncer at a club who only lets in certain types of errors!</p>
<h3 id="what-are-exception-filters-in-c%23%3F" tabindex="-1">What are exception filters in C#?</h3>
<p>Exception filters are like bouncers for your catch blocks. They decide which errors get VIP treatment. Introduced in C# 6.0, these filters let you add conditions to your exception handling.</p>
<p>Here&#8217;s what you need to know:</p>
<ol>
<li>They use the <code>when</code> keyword followed by a boolean expression.</li>
<li>They don&#8217;t mess with the stack, keeping the original error info intact.</li>
<li>They can make your code run faster by avoiding unnecessary error handling.</li>
</ol>
<p>As software engineer Eli Arbel puts it:</p>
<blockquote>
<p>&quot;Exception filters are preferable to catching and rethrowing because they leave the stack unharmed.&quot;</p>
</blockquote>
<p>Think of exception filters as a way to write smarter, more efficient error-handling code. No more spaghetti-like nested if-statements in your catch blocks!</p>
<h2>Related Blog Posts</h2>
<ul>
<li><a href="/2024/09/winforms-exception-handling-best-practices/" style="display: inline;">WinForms Exception Handling: Best Practices</a></li>
<li><a href="/2024/09/aspnet-mvc-exception-handling-6-methods-explained/" style="display: inline;">ASP.NET MVC Exception Handling: 6 Methods Explained</a></li>
<li>Async Event Handlers: Keep WinForms UI Responsive</li>
<li><a href="/2024/11/json-parsing-error-handling-in-net/" style="display: inline;">JSON Parsing Error Handling in .NET</a></li>
</ul>
<p></p>]]></content><author><name>feech</name></author><category term="General" /><summary type="html"><![CDATA[Learn how C# exception filters improve error handling with precise conditions, preserving stack traces, and enhancing code readability.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://codejack.com/wp-content/uploads/2025/02/image_5e70a6a359d5cf8d7285d9725dd218e3-scaled.jpg" /><media:content medium="image" url="https://codejack.com/wp-content/uploads/2025/02/image_5e70a6a359d5cf8d7285d9725dd218e3-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>