3

I have a MVVM app with DataServices (using mvvmlight).

Right now, i'm using it like

var answer = await myDataService.PullList(categoryId);
if (answer.Status == Ok)
    ObservableListOfItems.ReplaceWith(answer.Collection); // Show results
if (answer.Status == ConnectionLost)
    // Handle connection lost state, show msg window or something
if (answer.Status == ParsingError)
    // Handle parsing problem

where

async Task<MyAnswer> PullList(int id)
{
    // Just a wrapper around HttpWebRequest, returns String.Empty if something happened
    var resultString = await NetworkManager.GetAsync(UrlGenerator.GenerateCategoryRequest(id));  

    if (String.IsNullOrEmpty(resultString))
        return new MyAnswer {Status = ConnectionLost);

    try
    {
        var parsedResult = JsonConvert.DeserializeObject<PocoProducts>();

        return new MyAnswer {Status = Ok, Collection = parsedResult.List);
    }
    catch (Exception)
    {
         return new MyAnswer {Status = ParsingError; }
    } 

and

public class MyAnswer()
{
    public List<Items> {get; set;}
    public EnumStatuses Statuc {get; set;}
}

public enum EnumStatuses
{
    Ok = 0,
    ConnectionLost,
    ParsingError
}

So I'm curious, did i just re-invented an exceptions, didn't i?

PS: wrote a code just here, typos are possible, but general idea should be clear

2 Answers2

3

I guess my main issue with this is

What happens if an exception occurs during parsing. How will you diagnose it or know what has occurred?

The reason I ask this is that the exception itself is ignored and you are simply returning a new MyAnswer. I don't necessarily have any issues with this if you are logging the exception however this does not appear to be the case here.

Included in this, you are catching a general Exception? Does DeserializeObject throw specific exceptions? I'm not 100% on that but where possible catch the most specific exception you know about and leave the rest to bubble up. A reason for this is that your code is then easier to follow as you know exactly what you are dealing with in the method and can code accordingly.

So in summary. In general I like to at the very least do something with the exception whether it's re-throwing, including it in the response or logging it. I also like to catch the most specific exception I can at the point of interest to ensure the code is easier to follow and in the long term help provide a more robust solution.

dreza
  • 3,474
  • 4
  • 34
  • 39
1

I have a some apps which use code like your code. I use HttpClient and have a few types errors. For example MyWebException.

It is enough to keep the user informed. For example, if the Web server is not available, we will get response.StatusCode != HttpStatusCode.OK and throw the MyWebException. And if we got json but could not parse it, then throw Exception.

If we get MyWebException then we show message "Sorry, we have troubles with web server or bad signal". If Exception then "Sorry, something wrong".

You can even specify the error, if it is necessary.

Here's how it works:

API:

 public async static Task<CPParkingZones> GetZones()
        {           
            return await CPRequestService.Get<CPParkingZones>(string.Format("objects?types=zone"));        
        }

RequestService:

public async static Task<T> Get<T>(string url) where T : CPBase, new()
        {
            try
            {                
                using (var httpClient = new HttpClient())
                {
                    var response = await httpClient.GetAsync(CPConfig.APIServer + url);
                    var responseObject = new T();
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        responseObject.Error = new MyWebException();
                        return responseObject;
                    }
                    response.EnsureSuccessStatusCode();
                    string jsonResponse = await response.Content.ReadAsStringAsync();
                    responseObject = JsonConvert.DeserializeObject<T>(jsonResponse);
                    responseObject.Status = response.StatusCode;
                    return responseObject;
                }
            }
            catch (Exception ex)
            {
                var responseObject = new T();
                responseObject.Error = ex;
                return responseObject;
            }
        }

Base class

public class CPBase 
{                    
        public Exception Error { get; set; }
}

Using

var zones = await CPMapObjectsAPI.GetZones();

if (zones.Error != null)
{   
    if (zones.Error is WebException)
    {  
       DialogService.ShowMessage("Sorry, we have troubles with web server or bad signal");    
    }  
    else
    {
       DialogService.ShowMessage("Sorry, something wrong");    
    }         
}

This is just an example, "IF constructs" design looks awkward, especially If you need many types of errors, you can use many options to write this code better.

Alexandr
  • 111