Clean Up Your Client to Business Logic Relationship With a Result Pattern (C#)

If you’ve been developing well structured and scalable code bases, you probably focus a whole lot on your “Separation of Concerns”. Maybe you implement a design pattern or code architectures like SOLID, Clean, or Onion to enforce some stricter rules around those separations.

In the .NET world, we use a lot of Inversion of Control and Dependency Injection. Especially in ASP.NET Core. However, I find that a lot of implementations are still missing one big separation – error handling.

The most common case I see in a decently structured application is:

  • Controller injects a service
  • Service runs business logic
  • On error, service throws exception
  • Controller exposes that an error happened via catching exception

One problem I have with this is that the Controller is now handling some business logic by managing the error. So what is my proposal? Handle your business logic errors / validation and expose the result of that logic, whether successful or with errors, to the controller that then determines the proper HTTP Response Code and message to return based on the type of result.

This is often just called the Result Pattern but I think it goes beyond this concept when wrapping it up into something like CLEAN or Onion. So, I often refer to it as the Service Result Pattern. I typically employ this pattern in all of my applications – back end and front end alike.

Here is what it looks like in C#. We want to create a Result object that our business logic will return to our Controller, ViewModel, View, etc. Samples here will be referring to an ASP.NET Core 2.1 RESTful API implementation, but the pattern can be applied everywhere.

So we need:
– Result classes
– A controller that returns IActionResult
– A business logic class that returns a Result
– Validation and error handling logic

The Result Model

I’ve created a NuGet package for these Result models if you want to use those, but these are the essentials duplicated here if you want to do it yourself. The package can be found here:

NuGet: https://www.nuget.org/packages/ServiceResult/
GitHub: https://github.com/SuavePirate/ServiceResult

First we want an abstract Result class that contains the data, errors, and the type. Then we can create child types that can make the typing of our results stronger.

Result.cs

public abstract class Result<T>
{
    public abstract ResultType ResultType { get; }
    public abstract List<string> Errors { get; }
    public abstract T Data { get; }
}

ResultType.cs

public enum ResultType
{
    Ok,
    Invalid,
    Unauthorized,
    PartialOk,
    NotFound,
    PermissionDenied,
    Unexpected
}

The idea is that for each one of these result types, we should have a strongly typed implementation. Here are a few examples of the most commonly used ones.

InvalidResult.cs

public class InvalidResult<T> : Result<T>
{
    private string _error;
    public InvalidResult(string error)
    {
        _error = error;
    }
    public override ResultType ResultType => ResultType.Invalid;

    public override List<string> Errors => new List<string> { _error ?? "The input was invalid." };

    public override T Data => default(T);
}

UnexpectedResult.cs

public class UnexpectedResult<T> : Result<T>
{
    public override ResultType ResultType => ResultType.Unexpected;

    public override List<string> Errors => new List<string> { "There was an unexpected problem" };

    public override T Data => default(T);
}

SuccessResult.cs

public class SuccessResult<T> : Result<T>
{
    private readonly T _data;
    public SuccessResult(T data)
    {
        _data = data;
    }
    public override ResultType ResultType => ResultType.Ok;

    public override List<string> Errors => new List<string>();

    public override T Data => _data;
}

Notice how the only one that implements Data as anything other than default(T) is the SuccessResult. This guarantees us our data is consistent based on the result type and we can instead use different error types to map the proper error messages, ResultType, etc.

Using the Result in Business Logic

Let’s take a look at a sample of how we can use these models in our business logic to house all our success and error logic.

MyService

public class MyService : IMyService
{
    private readonly IMyRepository _repository;
    private readonly IPermissionService _permissions;

    public MyService (IMyRepository repository, IPermissionService permissions)
    {
        _repository = repository;
        _permissions = permissions;
    }

    public async Task<Result<MyDTO>> GetSomethingAsync(string id)
    {
        try
        {
            if(string.IsNullOrEmpty(id))
                return new InvalidResult<MyDTO>("Invalid ID");

            var hasPermission = await _permissions.HasPermissionsToDoSomethingAsync();
            if(!hasPermission)
                return new AccessDeniedResult<MyDTO>();

            var myData = await _repository.FindAsync(id);
            if(myData == null)
                return new NotFoundResult<MyDTO>();

            return new SuccessResult<MyDTO>(new MyDTO(myData));
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex);
            return new UnexpectedResult<MyDTO>();
        }
    }
}

This shows how we can use our different Result classes to step through our business logic in a very flat easy to follow and read way while still managing errors consistently.

Build an IActionResult from a Result

Once we have a Result returned, we want to give our controller the ability to map the type and data to the proper HTTP response. Doing this ensures that our Controller is only responsible for HTTP related logic, and not for business logic.

I’ve done this in the past with either a BaseController or with an extension method. If you want a simple extension method, check out my other NuGet package for it:

NuGet: https://www.nuget.org/packages/ServiceResult.ApiExtensions/
GitHub: https://github.com/SuavePirate/ServiceResult

Here’s what that method would look like:

ControllerExtensions

public static ActionResult FromResult<T>(this ControllerBase controller, Result<T> result)
{
    switch (result.ResultType)
    {
        case ResultType.Ok:
            return controller.Ok(result.Data);
        case ResultType.NotFound:
            return controller.NotFound(result.Errors);
        case ResultType.Invalid:
            return controller.BadRequest(result.Errors);
        case ResultType.Unexpected:
            return controller.BadRequest(result.Errors);
        case ResultType.Unauthorized:
            return controller.Unauthorized();
        default:
            throw new Exception("An unhandled result has occurred as a result of a service call.");
    }
}

With this, our Controller methods can be made extremely clean. Here’s an example:

MyController.cs

public class MyController : Controller
{
    private readonly IMyService _service;
    public MyController(IMyService service)
    {
        _service = service;
    }

    [HttpGet]
    public async Task<IActionResult> GetSomethingAsync(string id)
    {
        var result = await _service.GetSomethingAsync(id);
        return this.FromResult(result);
    }
}

Assuming our _service.GetSomethingAsync() returns a Task we can keep all our endpoints clean and only responsible for being a gateway to our application logic! So clean šŸ˜€

Conclusion

All together, we are able to ensure our error logic lives within our application/business logic and that our Controllers are able to worry just about the HTTP side of things. We do a better job at separating our concerns, we keep our business logic flat and easy to follow, and we provide our consumers of our application easy to follow data and errors by ensuring we return the proper HTTP responses and structures.


If you like what you see, donā€™t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? MessageĀ @Suave_PirateĀ on twitter for details.

Advertisements

Xamarin.Tip – Mvvm Light and Dependency Injection

Inversion of Control and Dependency Injection are some design principles that help make our applications more flexible and scalable. They both help us separate our implementations and make it easy to substitute drastic changes to our implemented data or business logic whether it be for writing unit tests or product improvement.

Xamarin is a platform where IoC and DI fit extremely well. I’ve talked about this concept a few other times in both my blogs and videos about the Onion Architecture in Xamarin as well as how to call Platform Specific code from a Portable Class Library. You can find those posts and videos here:

  1. Onionizing Xamarin Part 6
  2. [VIDEO] Xamarin.Tips: Calling Platform-Specific Code from a PCL (Dependency Injection)

In this post, I want to talk about using DI with Mvvm Light at a VERY basic level.

First, let’s define an interface for a service we might use:

IUserService.cs

public interface IUserService
{
    Task<User> GetCurrentUserAsync();
}

Now let’s create two different implementations. One that will be the service used in the application and the other that will be used for testing.

UserService.cs

public class UserService : IUserService
{
    // makes a call to a web api to get a user
    public async Task<User> GetCurrentUserAsync()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetAsync("https://mywebapi.mydomain/api/currentuser");
            var content = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<User>(content);
        }
    }
}

TestUserServices.cs

public class TestUserService : IUserService
{
    public Task<User> GetCurrentUserAsync()
    {
        return Task.FromResult(new User { Name = "Test User" });
    }
}

Now we need a ViewModel that will use this service. We define a private readonly IUserService and then inject the implementation that we want in the constructor of the ViewModel.

CurrentUserViewModel.cs

public class CurrentUserViewModel : ViewModelBase
{
    // use the interface as the service and inject the implementation in the constructur
    private readonly IUserService _userService;
    private User _user;

    public User User
    {
        get
        {
            return _user;
        }
        set
        {
            Set(ref _user, value);
        }
    }

    public CurrentUserViewModel(IUserService userService)
    {
        _userService = userService;
    }

    public async Task UpdateUserAsync()
    {
        User = await _userService.GetCurrentUserAsync();
    }
}

Now let’s define an IoCConfig that handles registering dependencies and implementations.

IoCConfig.cs

public class IoCConfig
{
    public IoCConfig()
    {
        // use SimpleIoc from MvvmLight as our locator provider
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    }

    // register the real implementation
    public void RegisterServices()
    {
        SimpleIoc.Default.Register<IUserService, UserService>();
    }

    // register the test implementation
    public void RegisterTestServices()
    {
        SimpleIoc.Default.Register<IUserService, TestUserService>();
    }

    // register the view model
    public void RegisterViewModels()
    {
        SimpleIoc.Default.Register<CurrentUserViewModel>();
    }
}

Now that we can register our Services as well as our ViewModels, the dependency resolver from SimpleIoc can retrieve an instance of CurrentUserViewModel with whichever version of IUserService is registered depending on whether we call RegisterServices or RegisterTestServices.

Now we can retrieve our instance of the CurrentUserViewModel by calling

var currentUserViewModel = ServiceLocator.Current.GetInstance<CurrentUserViewModel>();

MvvmLight recommends using a ViewModelLocator to get the instance of your ViewModels:

ViewModelLocator.cs

public class ViewModelLocator
{
    private readonly IoCConfig _iocConfig;
    public CurrentUserViewModel CurrentUser
    {
        get
        {
            return ServiceLocator.Current.GetInstance<CurrentUserViewModel>();
        }
    }

    public ViewModelLocator()
    {
        _iocConfig = new IoCConfig();
        _iocConfig.RegisterServices();
        //_iocConfig.RegisterTestServices();
        _iocConfig.RegisterViewModels();
    }

}

It’s recommended to either create your ViewModelLocator at the app start up, or if you’re using Xamarin.Forms, register it as a Resource in your App.xaml

<Application ...     xmlns:locator="clr-namespace:YOUR_LOCATOR_LOCATION">
    <Application.Resources>
        <ResourceDictionary>
            <locator:ViewModelLocator x:Key="Locator"/>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Now in your XAML pages, you can automatically wire up your view model.

MainPage.xaml

<ContentPage ...     BindingContext="{Binding Source={StaticResource Locator}, Path=CurrentUser}"     Title="{Binding User.Name}">
...
</ContentPage>

In order to change to your testing data, you can just switch which call to your IoCConfig is made for registering your dependency without having to make any changes to any of your other layers or UI!

If you like what you see, donā€™t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? MessageĀ @Suave_PirateĀ on twitter for details.