【问题标题】:How to properly throw and handle exceptions with web services如何使用 Web 服务正确抛出和处理异常
【发布时间】:2015-08-11 13:03:00
【问题描述】:

我在我的应用程序服务器中遵循 MVC 模式。我试图抛出一个异常,但它没有被正确抛出。

这是控制器的代码:

[HttpPost]
public IHttpActionResult PostAddSuperUser(SuperUserViewModel SU)
{
    try
    {
        //more code
        blHandler.addSuperUser((SuperUser)SU.user, SU.Password);
        return Ok();
    }
    catch (EUserAlreadyExist ex)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
        resp.Content = new StringContent(string.Format("Already exist ", SU.user.Mail));
        resp.ReasonPhrase = "Already exist";
        throw new HttpResponseException(resp);
    }

然后客户端调用如下:

try{
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://localhost:50687/");

            HttpResponseMessage response = await client.PostAsJsonAsync<SuperUserViewModel>("/api/SuperUser/PostAddSuperUser", SUVM);

            if (response.IsSuccessStatusCode)
            {
                new SuccesPupUp("", "SuperUser " + SupUserName + " was added");
            }
            this.Close();
        }
}
catch (HttpResponseException Exc)
{
    new ErrorPopUp("", Exc.Message);
}

根据这个this,我正确地抛出了它,但是当我运行它时,我得到了这个错误

我该如何解决?

编辑:我想向客户端抛出异常,以便它可以要求用户提供新的电子邮件地址

【问题讨论】:

  • 如您所见,它会抛出您没有捕获的 HttpResponseException,只需添加第一个捕获 - catch(HttpResponseException ex)
  • 由于您询问的是“正确处理异常”,请注意使用 Exception 后缀而不是前缀“E”来命名异常是“最佳实践”。例如,EInvalidPassword 应该命名为 InvalidPasswordException,是的,它更长,但更明显的是它是什么。
  • catch() 中你必须处理HttpResponseException,而不是EUserAlredyExist,因为你不会抛出EUserAlredyExist 异常。
  • 这个问题与stackoverflow.com/questions/19287426/…有关。如果您从一个 catch 块中抛出一个异常,并且在该块之外没有 catch 块,则该异常是未处理的。
  • @DanielPetrovaliev,他的 blHandler.addSuperUser() 方法可能会抛出 EUserAlreadyExist 异常,这就是他捕捉它的原因。

标签: c# .net web-services web exception-handling


【解决方案1】:

问题出在这段代码中(看起来很明显,但请耐心等待):

  catch (EUserAlreadyExist ex)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
        resp.Content = new StringContent(string.Format("Already exist ", SU.user.Mail));
        resp.ReasonPhrase = "Already exist";
        throw new HttpResponseException(resp);
    }

发生的情况是,您从上述尝试中捕获了 EUserAlreadyExist 异常,然后抛出了一个新异常,而没有伴随的 try-catch 块。所以这意味着仅仅因为你在 catch 中抛出了一个异常,它不会自动捕捉它,你必须在你的 catch 中有一个单独的 try-catch

更进一步,对此try-catch 的客户端调用也不会捕获抛出的异常,因为它们(catch 语句)捕获的异常类型与抛出的异常类型不同。

要修复它,您需要捕获在这种情况下引发的异常 HttpResponseException 异常。所以这意味着你的代码可能看起来像这样:

  catch (EUserAlreadyExist ex)
    {
    try{
        var resp = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
        resp.Content = new StringContent(string.Format("Already exist ", SU.user.Mail));
        resp.ReasonPhrase = "Already exist";
        throw new HttpResponseException(resp);
       }
       catch(HttpResponseException ex2)
       {
         //do something here with the exception
       }
    }

【讨论】:

  • 这好像不太对劲,为什么要抛出异常然后马上捕获呢?
  • 根据@Rodrigo 的问题和代码,这个答案在技术上应该可行,但我同意以这种方式抛出异常没有多大意义。
  • @Pseudonym 我想在服务器端使用我的 try catch 所做的就是将异常抛出到客户端,那么捕获我自己的异常将如何帮助我做到这一点?如我所见,如果我添加一个新的 try-catch,我会再次捕获它,但我仍然不知道如何处理它或如何将其发送到客户端
【解决方案2】:

服务器端代码不需要捕获异常并重新抛出它 - 有什么意义?让它冒泡给客户。这就是例外的美妙和力量。问题是 MVC 想要返回一个视图或一个 HTTP 状态码,而不是丰富的强类型异常信息。

您似乎在富客户端(客户端-服务器)情况下使用 MVC 模式,这没有任何意义。 MVC 最适合瘦客户端情况,服务器提供视图,客户端只呈现它们。当你有一个富客户端时,MVVM 模式更有意义。服务器可以提供视图模型(数据),客户端可以接管所有的用户交互、视图等。

考虑使用 MVVM 方法(使用 WCF)而不是 MVC。那么客户端和服务端都会对可以抛出的异常类型有一个共同的认识。服务器可以抛出,客户端可以捕捉,很简单。

您的客户端代码将如此简单:

try
{
    c.AddSuperUser(SUVM);
}
catch (Exception e)
{
    // etc
}

其中 c 是 WCF 客户端代理。

【讨论】:

    猜你喜欢
    • 2021-01-20
    • 1970-01-01
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多