The "OneOf" library in.NET Core offers a quick and efficient mechanism for C# programmers to interact with discriminated unions (sum types). It is advantageous for portraying situations with numerous possible outcomes or states because it enables you to design types that can hold values of different types but only one value at a time.

We'll cover how to utilize "OneOf" as a return type in a.NET Core Web API in this section:

Create a Web API Project with the.NET 6.0 framework as the target in Step 1.
Installing the "OneOf" NuGet package is step two.

Create API endpoints that return a "OneOf" type in step 3.

Let's examine the illustration.
using Microsoft.AspNetCore.Mvc;
using OneOf;

namespace OneOfTutorial.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class SampleController : ControllerBase
    {
        /// <summary>
        /// returnType : default, error
        /// </summary>
        /// <param name="returnType"></param>
        /// <returns></returns>
        [HttpGet("data/{returnType}")]
        public IActionResult GetData([FromRoute] string returnType ="default")
        {

            var data = GetDataByType(returnType);
            return Ok(data.Value);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="recordType"></param>
        /// <returns></returns>
            private OneOf<MyDataModel,ErrorViewModel> GetDataByType(string recordType)
            {

                try
                {
                    if (recordType == "error")
                        throw new Exception("Returning Error View Model");
                    var data = new MyDataModel
                    {
                        Id = 1,
                        Name = "default message"
                    };
                    return data;
                }
                catch (Exception ex)
                {
                    // Handle errors and return ErrorViewModel
                    var errorViewModel = new ErrorViewModel
                    {
                        StatusCode = 500,
                        ErrorMessage = ex.Message
                    };
                    return errorViewModel;

                }
            }
        }

        public class MyDataModel
        {
            public int Id { get; set; }
            public string? Name { get; set; }
        }

        public class ErrorViewModel
        {
            public int StatusCode { get; set; }
            public string? ErrorMessage { get; set; }
        }
}

This code defines a SampleController class that inherits from ControllerBase, and it contains two action methods: GetData and GetDataByType. The controller demonstrates how to use the OneOf type in a .NET Core Web API to handle different response types based on a specified returnType.

  • GetData Action Method: This action method is an HTTP GET endpoint that takes a returnType as a parameter from the route (e.g., "/data/default" or "/data/error"). The GetData method then calls the private GetDataByType method to get the data based on the returnType. It returns an IActionResult, and in this case, it returns an OkObjectResult with the value extracted from the OneOf<MyDataModel, ErrorViewModel> response.
  • GetDataByType Private Method: This private method is called by the GetData action method and takes a recordType parameter that determines the type of data to return. If the recordType is "error", the method throws an exception to simulate an error scenario. It then returns an ErrorViewModel wrapped in the OneOf type. If the recordType is not "error", the method creates a MyDataModel instance with default values, and it returns the MyDataModel wrapped in the OneOf type.
  • MyDataModel and ErrorViewModel Classes: These are two simple model classes representing the data and the error response, respectively. They are used to demonstrate the OneOf usage.


To summarize, the SampleController class defines two endpoints. The GetData endpoint takes a returnType parameter, calls the GetDataByType method to get the data, and then returns the data as an OkObjectResult. The GetDataByType method determines the type of data to return based on the recordType parameter, either a MyDataModel instance or an ErrorViewModel instance, wrapped in the OneOf<MyDataModel, ErrorViewModel> type. This allows the client to handle different response types gracefully based on the specified returnType.

Here's how a potential usage of this method might look like.

// Example usage of the method
var result = GetDataByType("error");

if (result.IsT0) // Check if the result is of type MyDataModel
{
    MyDataModel data = result.AsT0; // Extract the MyDataModel value
    // Handle the data as needed
}
else if (result.IsT1) // Check if the result is of type ErrorViewModel
{
    ErrorViewModel error = result.AsT1; // Extract the ErrorViewModel value
    // Handle the error as needed
}

By using the "OneOf" library, you can easily work with discriminated unions in a type-safe and concise manner, improving the readability and maintainability of your code.