是否可以在数据访问层中正确处理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
的每种方法在控制器级别进行处理。
答案 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不知道实现是什么。您可以记录它,甚至可以发送电子邮件。