lundi 19 décembre 2016

Wrapping IHttpActionResult - Generic solution

I'd like to wrap IHttpActionResult because I need some extra data to be consumed by the client app.

My first approach was to create and return simple DTO, wrapping result object if succeeded:

Response DTO:

 public class Response<T>
{
    public string ErrorMessage { get; set; }
    public bool Success { get; set; }
    public string CodeStatus { get; set; }
    public T Result { get; set; }

    public Response(bool isSuccess, [Optional] T result, [Optional] string codeStatus, [Optional] string errorMessage)
    {
        Success = isSuccess;
        Result = result;
        CodeStatus = codeStatus;
        ErrorMessage = errorMessage;
    }
}

Controller:

    public IHttpActionResult Get(int id)
    {
        return BadRequest(new Response<MyObjectClass>(false, null,"Invalid Id",400));
        ...
        return Ok(new Response<MyObjectClass>(true, result);

    }

I've found it very ineffective way to deal with wrapping. I dont find it very elegant way. I've tried to figured out some generic solution and ended up with the following:

Example Controller Action:

    public IHttpActionResult GetById(int id)
    {
        var result = _someService.Get(id);

        if (result == null)
            return NotFound().WithError("Invalid Id");

        return Ok().WithSuccess(result);
    }

This still returns Response DTO.

I've wrapped IHttpActionResult to deal with creating Response DTO:

public class HttpActionResult : IHttpActionResult
{
    private readonly string _errorMessage;
    private readonly IHttpActionResult _innerResult;
    private readonly object _result;
    private readonly bool _isSuccess;

    public HttpActionResult(IHttpActionResult inner, bool isSuccess, object result,string errorMessage)
    {
        _errorMessage = errorMessage;
        _innerResult = inner;
        _result = result;
        _isSuccess = isSuccess;            
    }


    public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await _innerResult.ExecuteAsync(cancellationToken);
        response.Content = new ObjectContent(typeof(Response), new Response(_isSuccess, _result, ((int)response.StatusCode).ToString(), _errorMessage), new JsonMediaTypeFormatter());
        return response;
    }
}

Finally I've added extension methods to IHttpActionResult to easier use in controller:

public static class IHttpActionResultExtensions
    {
        public static IHttpActionResult WithSuccess(this IHttpActionResult inner, object result = null, string message = null)
        {
            return new HttpActionResult(inner, true, result, message);
        }

        public static IHttpActionResult WithError(this IHttpActionResult inner,  string message = null)
        {
            return new HttpActionResult(inner, false,null, message);
        }
    }

What are the alternatives to deal with wrapping http messages in API Controller? What weak points do you see in my solution?

Aucun commentaire:

Enregistrer un commentaire