Managing CORS and Testing - Building a Sample API in C# Course
When working with web APIs in C#, CORS (Cross-Origin Resource Sharing) often becomes a roadblock—especially when your frontend and backend live on different domains or ports. It’s a common scenario in modern software development, where APIs serve frontend clients like Blazor WebAssembly, Angular, or React.
In his video tutorial on "Managing CORS and Testing - Building a Sample API in C# Course", Tim Corey demonstrates how to manage CORS effectively while building and testing a sample API. This approach helps developers not only fix cross-origin issues but also prepare for more advanced testing techniques, like unit tests, integration tests, and automated workflows.
Let’s dive into the video and follow Tim’s guidance step by step.
Setting Up the Blazor Frontend
Tim begins the lesson by creating a simple Blazor WebAssembly frontend project named SampleTestUI. This frontend is not production-ready—rather, it’s a test project to verify connectivity with the API and intentionally trigger a CORS issue.
Tim uses the .NET 9 template and opts out of authentication or PWA features.
The purpose of the frontend is to simulate real-world API calls and expose test failures related to cross-origin requests.
- He modifies the homepage to call the /courses API endpoint and display a list of courses with associated images.
The frontend uses a simple model class (CourseModel) created separately, rather than sharing the model with the API. Tim emphasizes that frontend models should be separate from data access models to reduce coupling and increase maintainability (2:28). This is an important principle when writing maintainable tests and testable code.
Writing the API Call
To fetch data from the API:
Tim injects an HttpClient.
He writes an async method using Http.GetFromJsonAsync<List
>(). - The method is hardcoded with the local API URL (4:00), serving as a simple test to validate communication between the frontend and the backend.
There’s no test method or error handling here, just a straightforward call. This setup mirrors the early steps in writing unit tests, where you start by validating the basic interaction between components.
Building the Data Fetch Logic and UI
After hardcoding the API URL at 4:00, Tim focuses on building the core logic to fetch course data from the API and display it in the Blazor frontend. This is a crucial step in validating that the frontend can interact with the backend, even before writing automated tests or using a testing framework.
First, he ensures the correct URL is used from the API's launchSettings.json — grabbing the HTTPS address and appending /courses to form the complete endpoint. This is important because browsers often reject non-HTTPS API calls from secure pages.
courses = await Http.GetFromJsonAsync<List<CourseModel>>("https://localhost:port/courses");
courses = await Http.GetFromJsonAsync<List<CourseModel>>("https://localhost:port/courses");
Displaying the Data
Once data is fetched, Tim writes a simple UI loop using Razor syntax to iterate through the courses list:
@foreach (var c in courses) { <a href="@c.CourseUrl"> <img width="300" src="@c.CourseImage" /> </a> }
@foreach (var c in courses) { <a href="@c.CourseUrl"> <img width="300" src="@c.CourseImage" /> </a> }
Each course is shown as an image wrapped in a hyperlink. Tim notes that the images are large (1920x1080), so he limits the width to 300px to avoid overwhelming the page.
This output acts as a visual confirmation that the API data is correctly flowing into the frontend. It mimics the kind of feedback you’d want from a test method passing—if the images show up, the request succeeded.
Preparing for Launch
Before running the application, Tim configures multiple startup projects in Visual Studio. He sets the API project to start first, followed by the Blazor frontend. This order is essential to ensure the API is ready by the time the frontend tries to fetch data.
This final step at 6:30 sets the stage for running the test—and encountering the CORS error—which is where the next part of the tutorial begins.
Hitting the CORS Wall
As Tim launches both projects simultaneously using Visual Studio’s solution explorer, the frontend attempts to call the API—but fails. The browser’s console displays a familiar message:
"Access to fetch at ‘[API URL]’ from origin ‘[Frontend URL]’ has been blocked by CORS policy..."(7:02)
This is where understanding and managing CORS becomes essential. Without proper headers in place, the browser blocks requests from one origin to another.
Creating a CORS Configuration Class
Rather than cluttering Program.cs, Tim creates a dedicated class named CorsConfig in a Startup folder. He uses a static class structure to apply the same configuration pattern used for Swagger and OpenAPI setup.
This aligns with clean code practices and makes the application more testable. Modular configurations like this also make it easier to write unit test methods later, because the logic is isolated and easier to mock or override.
Applying a Permissive CORS Policy
Tim defines a very open CORS policy to allow full cross-origin access:
policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
This setup is useful in test-driven development and integration testing, where external services or frontend apps need full access to the API. Tim calls this policy "AllowAll" and stores the name in a constant to prevent typos and inconsistencies (11:00):
private const string AllowAllPolicy = "AllowAll";
private const string AllowAllPolicy = "AllowAll";
He points out that this should not be used in production, but it’s ideal for testing APIs locally or inside Docker containers where developers are experimenting or writing unit tests against real endpoints.
Integrating the Configuration in Program.cs
Tim registers the CORS services and applies the configuration in Program.cs:
builder.Services.AddCorsServices(); app.ApplyCorsConfig();
builder.Services.AddCorsServices(); app.ApplyCorsConfig();
This modularity improves code quality, and makes it easier to add mocking frameworks or inject test behaviors in the future. It reflects how you'd structure things for unit testing in C#, where having centralized configurations can simplify test setup.
Retesting the Frontend
After applying the CORS fix, Tim reruns both applications. This time, the Blazor frontend works as expected—course data loads successfully, and each course image links to the relevant URL.
Importantly, no changes were made to the frontend. The entire fix happened at the API level, through proper CORS configuration.
Lessons in Testing and Setup Strategy
Though Tim doesn’t dive into unit testing frameworks directly in this video, his approach lays the groundwork for it. Here’s how:
He separates concerns cleanly, enabling the use of test classes and mock objects in the future.
The dedicated CORS setup file could be reused or replaced with a mock configuration during tests.
- His quick frontend project acts like a manual integration test—an early validation before writing full unit test projects.
This mirrors how you'd approach testing in Visual Studio:
Create a unit test project alongside your main application.
Use Test Explorer to run all test methods and track results.
Mock external dependencies like HTTP requests, database calls, or config files.
- Write simple unit tests to validate expected behavior, then expand to cover test cases with edge conditions.
Unit Testing Considerations for CORS Scenarios
While Tim's video is primarily about configuring CORS, the implications for software testing are clear:
You can create unit test methods that validate your configuration services.
Using mocking frameworks, simulate external factors such as different origins or HTTP methods.
Run test executions as part of your CI/CD process to confirm your test methods pass consistently.
- Incorporate tests into the Visual Studio Test Explorer to keep track of failures and ensure stability.
Conclusion
In this video tutorial, Tim Corey offers a practical example of managing CORS in a C# Web API while building a simple Blazor frontend to test connectivity. His approach is not just about fixing a browser error—it sets up a structure that encourages maintainable code, clean architecture, and easy extension into automated testing.
From here, developers can confidently move forward into writing unit tests, setting up integration tests, and using tools like Visual Studio, Test Explorer, and mocking frameworks to improve code quality and reliability.
Whether you’re learning how to start testing, write your first unit test, or ensure test methods fail when expected, this lesson provides the foundation for a strong development process. And most importantly—it all starts by getting the architecture and configuration right.