1
\$\begingroup\$

What I am wanting to do, is record the status of a HTTP call, so that I can give the user some feedback in the UI, rather than either succeeding silently, or showing a grim error.

What I have done is created a Result class. For ease, I will show the simple class, but I also have this as a generic class, so it can also contain data.

The Result class:

public class Result
    {
        public bool IsSuccess { get; set; }

        public string Error { get; set; }

        public HttpStatusCode HttpStatusCode { get; set; }

        public Result() { }

        public Result(bool isSuccess)
        {
            IsSuccess = isSuccess;
        }

        public Result(string errors, bool isSuccess)
        {
            IsSuccess = isSuccess;
            Error = errors;
        }

        public Result(string errors, bool isSuccess, HttpStatusCode statusCode)
        {
            Error = errors;
            IsSuccess = isSuccess;
            HttpStatusCode = statusCode;
        }
    }

When I make a call to the API I am using, I use the Result class, as below:

public async Task<Result> UpdateColour(GrapeColour grapeColour)
        {
            var body = new StringContent(JsonConvert.SerializeObject(grapeColour), Encoding.UTF8, "application/json");
            var client = _httpClient.CreateClient(ApiNames.WineApi);

            var response = await client.PutAsync(_grapeColourUrl, body).ConfigureAwait(false);
            if (response.IsSuccessStatusCode)
            {
                return new Result(true);
            }
            else
            {
                return await HttpResponseHandler.HandleError(response).ConfigureAwait(false);
            }
        }

Where my HttpResponseHandler does some stuff, but fundamentally writes the bool isSuccessful to false, give an error message, and set the status code.

This all lives in my Domain layer.

I then pass this over to the web side of my project, here is the controller method:

[HttpPost]
        public async Task<IActionResult> EditColour(Result<EditableGrapeColourViewModel> model)
        {
            if (!ModelState.IsValid)
            {
                return View(new Result<EditableGrapeColourViewModel>(model.Data));
            }

            var domainGrapeColour = _grapeMapper.Map<Domain.Grape.GrapeColour>(model.Data);

            var saveResult = await _grapeService.SaveColour(domainGrapeColour, SaveType.Update).ConfigureAwait(false);
            if (saveResult.IsSuccess)
            {
                return RedirectToAction("EditColour", "Grape", new { id = model.Data.Id, IsSuccess = true });
            }

            var viewModel = new Result<EditableGrapeColourViewModel>(saveResult.IsSuccess, saveResult.Error, model.Data);

            return View(viewModel);
        }

So the model I use in for the viewmodel and the view has to be the Result<T> so I can access the isSuccessful and the error message to show the user.

I use automapper to map from my domain object, to an object in the web project, but I use the domain Result.

So my question is two fold; Is what I am doing a decent solution for what I want to do? And if it is, should I be using the domain Result object as I am?

\$\endgroup\$
6
  • \$\begingroup\$ Since the "success/fail" nature of the result can be defined based on the HTTP status code alone, why separately record the two? By default, HTTP 2xx is a success and HTTP 4xx and 5xx are a failure. Is there any particular reason why you're trying to manually define a success rather than relying on the HTTP status code? \$\endgroup\$ – Flater Apr 12 at 11:34
  • \$\begingroup\$ For simplicity in the view, so I can simply check the isSuccess bool to show/hide a div which will either show save successful, or an error message. I use the HTTP status code on there, just to be helpful should something go wrong and a screen shot be sent etc. It's a fair point, maybe I could simply check to see if the status code starts with a 4/5 to determine what to show \$\endgroup\$ – Keith Apr 12 at 13:05
  • 2
    \$\begingroup\$ Please learn to use this instead of copy-pasting code between constructors: docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… \$\endgroup\$ – BCdotWEB Apr 12 at 13:27
  • \$\begingroup\$ You're also not handling exceptions. What if the URL you call is off-line, for instance? \$\endgroup\$ – BCdotWEB Apr 12 at 13:28
  • \$\begingroup\$ @BCdotWEB that is something I am going to handle with middleware. What I am wanting to know at the moment is around how I am using the Result class \$\endgroup\$ – Keith Apr 12 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.