πŸ› οΈC# in the Real World

Apply your C# skills to real-world programming including asynchronous code, RESTful APIs, and unit testing.

⏳ Asynchronous Programming with async/await

Welcome to the world of asynchronous programming in C#! In this chapter, you'll learn how to write responsive, efficient applications using `async`, `await`, and `Task`. You'll also discover how to manage concurrency, cancellation, and error handling like a pro.

πŸ’‘ Asynchronous Programming Basics

Asynchronous programming allows your application to perform multiple operations simultaneously. This is especially important for I/O-bound operations like file access, network requests, and database queries.

  • Use `async` to mark methods that can be awaited.
  • Use `await` to pause execution until a task completes.
  • `Task` represents an asynchronous operation that returns a value.
  • Asynchronous code runs on threads managed by the .NET runtime.

βœ… Writing Your First Async Method

public async Task<string> GetMessage()
{
    await Task.Delay(1000); // Simulate delay
    return "Hello from the asynchronous world!";
}

❌ Common Mistakes to Avoid

  • Don't block async methods with `.Result` or `.Wait()` β€” this can cause deadlocks!
  • Avoid nesting `async` methods too deeply β€” keep your code flat and readable.
  • Don't forget to add the `ConfigureAwait(false)` when working with libraries.

πŸ’‘ Working with Task Objects

Understand how `Task` works is crucial for mastering async programming. A `Task` can be in one of several states: Running, WaitingToRun, Canceled, or Completed.

βœ… Concurrency and Parallelism

Concurrency is about managing multiple operations at the same time. Parallelism is a specific implementation of concurrency where those operations run on multiple threads.

var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();

await Task.WhenAll(task1, task2);

πŸ’‘ Cancellation in Async Methods

Use `CancellationToken` to gracefully cancel long-running operations. This is especially important for user-initiated tasks like file uploads or database queries.

public async Task DoWorkAsync(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        // Perform work
        await Task.Delay(100);
    }
}

βœ… Error Handling in Async Code

Async methods can throw exceptions just like synchronous ones. Use `try-catch` blocks to handle errors, but remember that exceptions thrown inside `await` expressions are caught in the surrounding `catch` block.

try
{
    await DangerousOperationAsync();
}
catch (Exception ex)
{
    // Handle exception
}

🌍 Calling and Creating Web APIs

Welcome to the exciting world of working with Web APIs in C#! In this chapter, you'll learn how to both consume and create powerful web APIs using modern C# technologies. We'll cover everything from making HTTP requests to external services, to building your own RESTful APIs from scratch.

πŸ’‘ Calling External APIs with HttpClient

The HttpClient class is a powerful tool for making HTTP requests to external web services. It's designed to be both easy-to-use and highly customizable.

using System.Net.Http;

public async Task<string> GetWeatherForecastAsync()
{
    var client = new HttpClient();
    var response = await client.GetAsync("https://api.weather.com/forecast");
    return await response.Content.ReadAsStringAsync();
}

πŸ’‘ Key Points About HttpClient

  • HttpClient is a thread-safe and reusable HTTP client handler.
  • Always use the async/await pattern with HttpClient for non-blocking operations.
  • Dispose of HttpClient instances properly to avoid memory leaks.

❌ Common Mistakes When Using HttpClient

  • Don't create new HttpClient instances for every request - reuse them.
  • Avoid blocking calls with .Result or .Wait() as this can cause deadlocks.
  • Never swallow exceptions without proper logging and handling.

πŸ’‘ Building RESTful APIs with ASP.NET Core

Creating your own web APIs in C# is easier than ever thanks to the powerful ASP.NET Core framework. You'll use controllers, routing, and dependency injection to build robust APIs.

[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
    [HttpGet]
    public IActionResult GetForecast()
    {
        var forecast = new WeatherForecast
        {
            Temperature = 75,
            Summary = "Sunny"
        };
        return Ok(forecast);
    }
}

πŸ’‘ Core Concepts in API Development

  • Controllers define the entry points for your API endpoints.
  • Routing determines how incoming requests are mapped to controller actions.
  • Use Dependency Injection to manage services and their lifecycles.
  • Always include proper error handling with try/catch blocks and custom exceptions.

πŸ’‘ Best Practices for API Design

  • Follow the RESTful principles for a clean and intuitive API design.
  • Use proper HTTP status codes (e.g., 200 OK, 404 Not Found).
  • Include meaningful error messages in your responses.
  • Document your APIs using Swagger/OpenAPI specifications.

πŸ’‘ Advanced API Design Considerations

As you build more complex APIs, there are several important concepts to keep in mind:

  • Implement proper caching mechanisms for frequently accessed data.
  • Use rate limiting to prevent abuse of your API endpoints.
  • Consider implementing API versioning to maintain backward compatibility.

πŸ’‘ Security Best Practices for APIs

Securing your APIs is absolutely critical. Here are some must-follow security practices:

  • Always use HTTPS for all API communications.
  • Implement proper authentication and authorization mechanisms (e.g., JWT, OAuth2).
  • Sanitize user inputs to prevent SQL injection and other attacks.
  • Use CORS policies to restrict access to your APIs.

πŸ’‘ Real-World Applications of Web APIs

Web APIs are the backbone of modern web applications. They power everything from mobile apps to single-page web applications. Here are some common use cases:

  • Data fetching and manipulation (e.g., weather forecasts, product listings).
  • Authentication services (e.g., user login, token generation).
  • Integration with third-party services (e.g., payment gateways, social media platforms).

πŸ’‘ Final Thoughts & Next Steps

Congratulations! You've now learned the fundamentals of calling and creating web APIs in C#. To continue your learning journey, consider exploring these topics:

  • Advanced API security techniques (e.g., WebSockets, GraphQL).
  • Building real-time APIs using SignalR.
  • Optimizing API performance with caching and load balancing.

🧫 Testing in C#

Welcome to our section on Unit Testing in C#! Writing tests for your code is an essential part of modern software development. It ensures your code works as expected, catches bugs early, and helps maintain the quality of your application.

πŸ’‘ Why Unit Test?

  • Ensures code works as expected before deployment
  • Catches bugs early in the development process
  • Serves as documentation for how your code should behave
  • Provides confidence when making changes to existing code

πŸ’‘ Popular Testing Frameworks in C#

  • xUnit: The most popular testing framework for .NET
  • NUnit: Another widely used framework with rich features
  • MSTest: Microsoft's own testing framework that integrates well with Visual Studio

πŸ’‘ Dependency Injection in Tests

When writing unit tests, we often want to test a component in isolation. This is where dependency injection comes into play. By injecting mock dependencies, we can control the behavior of external components during testing.

public class Calculator
{
    private readonly ILogger<Calculator> _logger;

    public Calculator(ILogger<Calculator> logger)
    {
        _logger = logger;
    }

    public int Add(int a, int b)
    {
        var result = a + b;
        _logger.LogInformation("Added {a} and {b} to get {result}", a, b, result);
        return result;
    }
}

πŸ’‘ Using Moq for Mocking

Moq is a popular mocking framework for .NET. It allows you to create mock implementations of interfaces and classes, which can be used in your unit tests.

[TestMethod]
public void Add_ValidInput_ReturnsCorrectResult()
{
    // Create mock logger
    var mockLogger = new Mock<ILogger<Calculator>>();

    // Create calculator with mock logger
    var calculator = new Calculator(mockLogger.Object);

    // Test the add method
    int result = calculator.Add(2, 3);

    // Verify results and logging
    Assert.AreEqual(5, result);
    mockLogger.Verify(l => l.LogInformation(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once());
}

βœ… Best Practices for Unit Tests

  • Test one thing at a time (Single Responsibility Principle)
  • Keep tests independent of each other
  • Use meaningful test names that describe what is being tested
  • Mock external dependencies to isolate the component under test
  • Run tests frequently as part of your development workflow

❌ Common Pitfalls to Avoid

  • Don't test implementation details - test behavior
  • Avoid writing tests that depend on external systems (use mocks instead)
  • Don't skip writing tests because they seem too time-consuming (they save time in the long run)
  • Don't use real databases or external services in unit tests

Quiz

Question 1 of 15

What keyword is used to mark a method as asynchronous in C#?

  • async
  • await
  • Task
  • thread