Skip to content

Instantly share code, notes, and snippets.

@ivarne
Last active February 22, 2024 22:17
Show Gist options
  • Save ivarne/e12d280e7ad9936e9cff73a8c568ec08 to your computer and use it in GitHub Desktop.
Save ivarne/e12d280e7ad9936e9cff73a8c568ec08 to your computer and use it in GitHub Desktop.
Suggested ServiceResult implementation for Altinn apps
public class TestService
{
public ServiceResult<string> GetResult(bool success)
{
if (success)
{
return "Hello, World!";
}
else
{
return new ServiceError
{
Title = "An error occurred",
Details = "Something went wrong",
SuggestedStatusCode = HttpStatusCode.InternalServerError
};
}
}
public void Test()
{
ServiceResult<string> result = GetResult(true);
if (result.Success)
{
Console.WriteLine(result.Data.ToString());
}
else
{
Console.WriteLine(result.Error.Title.ToString());
}
result = GetResult(false);
if (result.Success)
{
Console.WriteLine(result.Data);
}
else
{
Console.WriteLine(result.Error.Title);
}
}
}
using System.Diagnostics.CodeAnalysis;
using System.Net;
namespace Altinn.App.Core.Helpers;
/// <summary>
/// A generic result object that can be used to wrap the result (or some error data) of a service call
/// </summary>
public sealed class ServiceResult<T>
{
private ServiceResult(bool success, T? data, ServiceError? error)
{
Success = success;
Data = data;
Error = error;
}
/// <summary>
/// Indicates if the result is successful or not
/// The private constructor ensures that it is not possible to create a ServiceResult without setting either Data or Error
/// </summary>
[MemberNotNullWhen(true, nameof(Data))]
[MemberNotNullWhen(false, nameof(Error))]
public bool Success { get; }
/// <summary>
/// The data object, if the result is successful
/// </summary>
public T? Data { get; }
/// <summary>
/// The error object, if the result is erronious
/// </summary>
public ServiceError? Error { get; }
/// <summary>
/// Because of the private constructor, this is the only way to create a new instance of ServiceResult
/// The imlicit cast makes it easy to just return an object of type T and have it wrapped in a ServiceResult
/// </summary>
public static implicit operator ServiceResult<T>(T data) => new ServiceResult<T>(true, data, null);
/// <summary>
/// Because of the private constructor, this is the only way to create a new instance of ServiceResult
/// The imlicit cast makes it easy to just return an object of type ServiceError and have it wrapped in a ServiceResult
/// </summary>
public static implicit operator ServiceResult<T>(ServiceError error) => new ServiceResult<T>(false, default, error);
}
public sealed class ServiceError
{
public required string Title { get; init; }
public required string? Details { get; init; }
public HttpStatusCode? SuggestedStatusCode { get; init; }
public Dictionary<string, object>? Extentions { get; init; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment