【问题标题】:C# should I use try catch within a try catch to handle response? is it a bad idea?C# 我应该在 try catch 中使用 try catch 来处理响应吗?这是个坏主意吗?
【发布时间】:2017-05-01 14:40:10
【问题描述】:

我的代码处理一些其他 API(GET 方法)。此 GET 方法返回如下响应:

{"error":0,"Logs":[{"LoggerIdx":"91","OfficeID":"MIA1A0955","Agent":"581A78AD"}]}

如果查询没有找到任何内容,则返回:

{"error":0,"Logs":[{"No values found"}]}

我正在使用调用此 API 来检索值并显示报告的代码是:

private string uri = "http://localhost";

    public async Task<List<T>> GetWSObjects<T>(string uriActionString)
    {
        return new List<T> { await this.GetWSObject<T>(uriActionString) };
    }

public async Task<T> GetWSObject<T>(string uriActionString)
    {
        T returnValue =
            default(T);
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(uri);                    
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage response = await client.GetAsync(uriActionString);
                response.EnsureSuccessStatusCode();

                returnValue = JsonConvert.DeserializeObject<T>(((HttpResponseMessage)response).Content.ReadAsStringAsync().Result);
            }
            return returnValue;
        }
        catch (Exception e)
        {
            throw (e);
        }
    }

returnValue 尝试用响应中的值填充我的模型。但是,当响应仅包含“未找到值”时,它会中断(显然)。我的问题是,我应该在这个 try-catch 中放置一个 try-catch 来处理这种行为吗?问题是向用户显示了整个异常,而不仅仅是“未找到值”。建议?我的模型是:

    public class BuildingReportModel
{
    public string message1 { get; set; }
    public Log[] Logs { get; set; }        
}

public class Log
{
    public string ProdLoggerIdx { get; set; }
    public string OfficeID { get; set; }     
    public string Agent { get; set; }
}

【问题讨论】:

  • 您只是重新抛出错误。你甚至可以一起摆脱外部的 try catch
  • @Steve 我想了想,但是要捕捉其他真正的错误,比如错误的输入,sql 呢?
  • 你应该看看这个answer
  • Try catch 内的 try catch 让我在嘴里吐了一点点。我工作的人把它们放在 finally 块中,所以情况可能会更糟......

标签: c# .net model try-catch


【解决方案1】:

在您的catch 块中,记录或以其他方式捕获异常,但不要throw 如果正在显示此方法的返回值(从您发布的内容看来是这样)。然后给你的模型写一条友好的消息(我假设这就是string message1 属性的用途?如果不是,你可以为它添加一个属性来达到这个目的)。这样一来,您的用户就会看到写的内容,这些内容比异常的详细信息更容易被理解。

至于再次尝试捕获 - 你可以,但这不是必需的。无论JsonConvert.DeserializeObject 抛出什么异常,最终都会是Exception 类型,并且会被你的catch 捕获。如果您想捕获特定的异常类型,请将另一个 catch 语句放在您的 Exception catch 块之前,并以相同的方式处理它。

关于如何重新抛出(这是您当前的代码所做的)的文章和意见到处都是 - 做一些研究并找到适合您情况的最佳模式。

此外,@Yaser 提供的答案也是一个好主意 - 如果您可以首先防止异常,那么剩下的就没有实际意义了。

因此,这是您发布的代码示例,我对其进行了一些修改和评论,这可能有助于澄清(还有改进的余地,但这超出了您的问题范围):

  public async Task<T> GetWSObject<T>(string uriActionString)
    {
        var returnValue = default(T);
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(uri);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                var response = await client.GetAsync(uriActionString);
                response.EnsureSuccessStatusCode();

                // this does not need a try catch, 
                // because whatever exception is thrown here 
                // will still be caught
                returnValue = JsonConvert.DeserializeObject<T>(
                    response.Content.ReadAsStringAsync().Result);
            }

        }
        catch (Exception e)
        {
            // log or otherwise capture the exception details
            // if you don't need to log/capture the e variable
            returnValue.message1 = "A user-friendly description of the problem";
        }
        //catch // could also do it this way
        //{
        //    // if you don't need to log/capture the exception,
        //    // then don't bother with the overload
        //    returnValue.message1 = "A user-friendly description of the problem";
        //}

        return returnValue;
    }

【讨论】:

  • 这里的棘手部分是我传递了一个 LIST,所以我无法直接访问 returnValue message1,如果我在 catch 中做某事,在我的情况下如何识别每个问题,即“未找到任何值”?
  • @Rolando F - 我当然可以提供一个建议,但你问“我的问题是,我应该在这个 try-catch 中放置一个 try-catch 来处理这种行为吗?问题是整个正在向用户显示异常,而不仅仅是“未找到值”。建议?”我相信我已经回答了您的问题并提供了一些建议。如果您仍然需要帮助,我可以仔细查看并提供更多反馈,但我想指出这一点。
【解决方案2】:

不确定这是否是解决问题的最佳方法,但它正在工作:

catch (Exception e)
        {                
            if (e.Message.ToString().Contains("No Logs"))
            {
                Exception e2 = (Exception)Activator.CreateInstance(e.GetType(), "No Logs Found ...", e);
                throw e2;                    
            }
            throw (e);
        }

我只是在验证异常是否包含“无日志”,如果为真,则创建一个新异常并抛出它。似乎有效,但是这样做有什么缺点吗?有什么想法吗?

【讨论】:

    【解决方案3】:

    最好的处理方法是在解析之前检查响应:

    var responseString = await ((HttpResponseMessage)response).Content.ReadAsStringAsync();
    if(response.ToLower().Contains("no values found")) {
        //do something here like returning an empty model
    }
    else
    {
        returnValue = JsonConvert.DeserializeObject<T>(responseString);
    }
    

    【讨论】:

    • .Result 是一个非常好的方法,可以让自己在脚下开枪......如果当前 SynchronizationContext 不为空,则可能出现死锁
    • 这种方式是有道理的,但是这个“响应”没有ToLower,也没有包含方法
    • 抱歉没看到,必须刷新才能看到最后一条评论
    猜你喜欢
    • 2020-02-11
    • 2019-03-24
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多