C# 应该从服务层返回什么类型的结果?
例如,假设我有一个C# 应该从服务层返回什么类型的结果?,c#,architecture,domain-driven-design,C#,Architecture,Domain Driven Design,例如,假设我有一个PostsService,它创建了一个post: public class PostsService : IPostsService { public bool Create(Post post) { if(!this.Validate(post)) { return false; } try { this.repository.Ad
PostsService
,它创建了一个post:
public class PostsService : IPostsService
{
public bool Create(Post post)
{
if(!this.Validate(post))
{
return false;
}
try
{
this.repository.Add(post);
this.repository.Save();
}
catch(Exception e)
{
return false;
}
}
}
这样做的问题是,如果在存储库操作期间抛出异常,它就会被吞没Create()
返回false
,消费者只知道没有添加Post
,但不知道原因
相反,我想到了一个servicesult
类:
public class ServiceResult
{
public bool Success { get; private set; }
public Exception Exception { get; private set; }
}
这是一个好的设计吗?或者我甚至需要向消费者报告这些错误吗?只说“添加帖子时发生错误”,然后将异常记录在服务内部,这样就足够了吗
任何其他建议都非常感谢。如果您使用的是WCF,我建议您不要使用
ServiceResult
,或任何类似的方法来处理SOA层中的异常
您应该为您的方法定义一个FaultContract
。这将允许消费代码了解可以抛出的异常类型,并使用传统的try/catch
块相应地处理它们
这个
您仍然可以让前端简单地说“发生了错误”,但如果将来需要,使用错误契约将允许在代码的UI层上更好地处理错误。我认为这取决于原因的范围。在我看来,一些故障原因不应该与消费者有关,这些应该记录在服务中。另一方面,在某些情况下,应该将这些原因告知消费者,因此除了记录这些原因外,还应该以某种方式指出错误的原因 例如,假设一个非常常见的用户注册服务用例。很可能您有一个唯一的属性来标识用户(用户句柄、电子邮件等)。这种唯一性必须由服务强制执行(也可能是在数据库级别)。现在,如果使用者尝试注册用户,但由于违反了约束而失败,则应将此原因通知使用者(以便它可以尝试其他用户句柄)。大多数情况下,失败的验证属于同一场景 另一方面,如果存在某种内部DB问题,则不应将细节告知消费者(因为这是服务的专属责任;而消费者无论如何也不能对此做任何事情) 考虑到这一点,我认为在很多情况下返回布尔值是不够的。因此,使用某种
servicesult
类型听起来不是个坏主意。不过,我不确定是否会包含异常。但也许您可以创建某种特定于您的服务的ServiceExpection。有时,错误代码也适用于此。(免责声明:根据我的经验,我在环境间公开/使用服务方面做了很多工作,在这些环境中,WCF之类的内置功能并不总是有用的,也不总是能够控制使用服务的客户端。)
在我的服务设计中,我越来越多地转向请求/响应系统。(实际上,我在这方面大量使用了库。)在该设计中,我有一个BaseRequest
对象和一个BaseResponse
对象,所有请求和响应类型都从中继承
继续您的想法,servicesult
类将作为这样一个BaseResponse
的开始。它不一定需要实际的异常,但我倾向于包括以下几点:
表示任何请求成功或失败的bool
,即使是成功返回实际结果的请求
自定义消息
对象的IList
,这些对象本身包含某种类型的消息(信息、警告、错误等)以及消息文本(可能还有一个用于UI显示需要的附加用户友好消息文本)、堆栈跟踪(如果相关)等
更进一步,我还希望在BaseRequest
中包含一些内容,例如原始用户、主机等
其思想是服务本身不应该抛出原始异常。无论是谁在使用该服务,都应该始终期望得到有效的响应,即使该响应指示某种类型的故障。它应该期望每次都会返回一些基本信息,并知道如何处理这些信息。是的,ServiceResult类是个好主意,但我不会包含异常,有时您希望报告错误,但不希望/需要创建/抛出/捕获异常,相反,我会包含一组错误消息或一个枚举类型,指示出了什么地方出了问题,比如
另外,不要捕捉,它会使bug难以发现。请记住,面向服务的体系结构的一个关键好处是将系统的组件解耦。调用层对服务的了解越多,层之间的耦合就越紧密。按照这个逻辑,最好让调用层尽可能少地了解错误,它需要知道的只是服务调用失败
调用层真的需要知道服务失败的原因吗?它到底能做些什么呢?这只是为了向用户显示更好的消息吗?在这种情况下,用户真的关心细节吗?很容易认为用户想知道更多,只是因为你是开发人员。但是开发人员应该从日志中获取有关错误消息的信息,而不是从最终用户消息中获取信息。捕获所有异常是一个非常糟糕的主意。你只能抓住你能合理处理的东西。你不能处理所有的异常,为什么要捕获它?防止堆栈跟踪
如果你不想让你的用户看到一个可怕的堆栈跟踪,我明白了,但你确实希望它死掉,死掉得可怕,所以
catch (Exception e)
{
//send it to yourself, log it. Just don't swallow it.
LogErrorAndEmailDevTeam(e);
throw new SaveFailedException("We're sorry. \n" +
"It's not your fault, but something bad happened.\n\n" +
"We've been notified and will fix it as soon as possible.");
}