C#处理DAL中的WebException

时间:2019-05-17 10:27:02

标签: c# data-access-layer system.net.webexception

是否可以在数据访问层中正确处理WebException?

下面是DAL中用于与远程服务器通信的方法SendReceive,如果出现通信问题,例如无法访问端点,因此无法检索数据,我希望用户重定向到视图,通知用户请稍后重试。

private static TResult SendReceive<TResult, TPayLoad>(string method, string route, TPayLoad payload, bool post, bool authentication, string hashedPassword)
{
    var subject = "WebApplication1 - " + method + " Error";

    using (var webClient = new WebClient())
    {
        try
        {
            var uri = new Uri("http://ourdomain/ourwebapicontroller/" + route);

            webClient.Headers[HttpRequestHeader.ContentType] = "application/json";

            if (authentication)
            {
                var hashedPasswordAsBytes = Encoding.UTF8.GetBytes(hashedPassword);

                webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(hashedPasswordAsBytes));
            }

            var response = post ? webClient.UploadString(uri, JsonConvert.SerializeObject(payload)) : webClient.DownloadString(uri);

            var parsedResponse = JsonConvert.DeserializeObject<TResult>(response);

            return parsedResponse;
        }
        catch (WebException webException)
        {
            SendEmail(subject, MvcApplication.To, MvcApplication.From, "<p>WebException [" + webException.Message + "]</p>");

            // Issue with endpoint 
        }
        catch (Exception exception)
        {
            SendEmail(subject, MvcApplication.To, MvcApplication.From, "<p>Exception [" + exception.Message + "]</p>");
        }
    }

    return default(TResult);
}

public Models.WebApplication1.Test GetTest(int id)
{
    return SendReceive<Models.WebApplication1.Test, int?>("GetTest", "get-test/" + id, null, false, false, null);
}

public int SetTest(Models.WebApplication1.Test test)
{
    return SendReceive<int, Models.WebApplication1.Test>("SetTest", "set-test", test, true, false, null);
}    

由于DAL是从控制器引用的,所以我不认为可以使用throw new HttpException(),但是可以这样处理:

public ViewResult Test(int id)
{
    var test = Dal.GetTest(id);

    if (test == null)
    {
        throw new HttpException(404, "Please try again later.");
    }

    return View(test);
}

宁愿处理SendReceive中的通信问题,而不是针对引用SendReceive的每种方法在控制器级别进行处理。

1 个答案:

答案 0 :(得分:0)

一切取决于您对“句柄”甚至“异常”的理解。

控制器
在控制器内,如果客户端请求不存在的内容,您想做什么? 404是一个很好的响应。但是,如果DAL抛出异常怎么办?将完全相同的结果返回给客户端是否有意义?告诉客户出问题的500错误可能更有意义。

此处显示不匹配:

throw new HttpException(404, "Please try again later.");

如果请求引发异常(出于任何原因,包括DAL),则返回500错误并显示“稍后重试”是有意义的。您正在清楚地表明问题已经解决了。抱歉,希望不会再发生,如果我们正在处理它。

如果客户要求的东西不存在,则可能会改变,也可能永远不会改变。他们是否应该稍后再试?为什么?也许他们所要求的将永远找不到。这也不例外。有人索要不存在的东西,却一无所获意味着您的应用程序 正常工作。 404告诉他们我们的应用程序正在运行-我们只是没有他们想要的东西。

基于此,冒充控制器的实际异常可能是有道理的。 DAL不了解控制器甚至网站。知道呼叫者是否应该知道存在异常不是很合适。

DAL “处理”异常可能意味着不同的意思。 (我将保留对哪个正确的意见,因为它不相关。)

如果您的DAL引发异常,则可以做一些事情。有些也许比其他更好,但是同样,这取决于观点和需求。 - 没做什么。让异常冒出来。 -记录并重新抛出。 -记录它,然后将其包装在提供某些上下文的另一个异常中,并引发新异常。 (是否包装例外是一个完整的讨论。)

有人会说“处理”异常是与众不同的,涉及以某种方式对异常做出反应以解决问题的方式,而我们不太可能这样做。例如,如果我们的应用程序每天从API检索Chuck Norris笑话,但抛出异常,则我们可能会记录该异常,以便我们知道出了点问题,然后将其替换为备用Chuck Norris笑话。

不会要做的最重要的事情是“隐藏”异常,以便对调用者而言,异常和“未找到任何东西”看起来相同。如果出现问题,控制器需要知道这一点-即使它不了解具体细节-因此它(不是DAL)也可以确定应该传达给呼叫者的内容。

控制器和DAL之间的关系类似于浏览器客户端和控制器之间的关系。如果这不仅有效,我们将进行沟通。如果没有数据,我们会进行沟通。


我不建议将代码编写在发送电子邮件的DAL中。这是非常具体的,它将您的所有代码都与该决定以及可能的发送邮件实现相结合。

另一种方法是定义这样的接口:

public interface ILog
{
    void LogException(Exception ex);
    void LogMessage(string message);
}

...并注入DAL类。发生异常时,请致电_log.LogException(ex);。您的DAL不知道实现是什么。您可以记录它,甚至可以发送电子邮件。