What type of result should be returned from the service level?

Say, for example, that I have a PostsService that creates a message:

 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; } } } 

The problem with this is that if an exception occurs during the actions of the repository, it is swallowed. Create() returns false , and all the consumer knows is that Post not been added, but does not know why.

Instead, I thought about having a ServiceResult class:

 public class ServiceResult { public bool Success { get; private set; } public Exception Exception { get; private set; } } 

Will it be a good design? Or do I even need to report these errors to the consumer? Is it enough to say "Error adding message". and then register an exception inside the service?

Any other suggestions are welcome.

+6
c # architecture domain-driven-design
source share
6 answers

I think it depends on the scope. In my opinion, some reasons for the refusal do not concern the consumer, and they must be registered in the service. On the other hand, there are times when the consumer must be informed about these reasons, so in addition to registering them, you must somehow indicate the cause of the error.

For example, suppose this is a very common use case for a user registration service. It is very likely that you will have a unique attribute that identifies the user (user descriptor, email address, etc.). This uniqueness must be performed by the service (and possibly also at the database level). Now, if the consumer is trying to register the user and he fails because the restriction has been violated, the consumer must be notified of these reasons (so that he can try another user descriptor). In most cases, failed checks fall into the same scenario.

If on the other hand there is some kind of internal problem with the database, the consumer should not be informed about the details (because it is the sole responsibility for the service, and it is not that the consumer can do anything at all).

Given this, I would say that in many cases, returning a boolean value is not enough. Therefore, having a ServiceResult type ServiceResult not seem like a bad idea. I'm not sure that I will include Exception . But perhaps you can create some kind of ServiceExpection specific to your service. Sometimes error codes are also suitable for this.

+3
source share

Yes, the ServiceResult class is a good idea, but I would not include an exception, there are times when you want to report errors, but you do not want / need to throw / throw / catch an exception, instead I would include a collection of error messages or an enum type indicating what went wrong, something like MembershipCreateStatus .

In addition, do not catch Exception , this can make it difficult to find errors.

+2
source share

(Disclaimer: In my experience, I have worked a lot with the provision / consumption of services between environments where the built-in functionality in something like WCF is not always useful and does not always have control over the client while consuming the service.)

More and more in my service projects, I switched to a request / response system. (Actually, I used agatha-rrsl library heavily in this regard.) In this design, I have a BaseRequest object and a BaseResponse object from which all types of requests and responses are inherited.

Continuing with what you were thinking, the ServiceResult class will serve well as the beginning of such a BaseResponse . This does not have to be the actual exception, but some things that I usually include:

  • A bool indicating success or failure for any request, even one that returns actual results on successful completion.
  • IList<> custom Message objects that themselves contain the type of message (Info, Warn, Error, etc.), as well as the message text (and, possibly, an additional convenient message text for the UI), a stack trace, if necessary, and etc.

Next, I would also like to add a few things to BaseRequest , such as the original user, host, etc.

The idea is that the service itself should never throw an initial exception. Anyone who consumes the service should always expect to receive a valid response, even if this answer indicates a failure of any kind. He should expect some basic information to return every time and know how to process this information.

+1
source share

Keep in mind that one of the key benefits of a service-oriented architecture is the decoupling of system components. The more calling layers need to know about the service, the more tightly connected the layers. Following this logic, it is better for the caller to know as little as possible about the error, all he needs to know is that the service call failed.

Does the caller need to know why the service did not work? What can this do to him? Only in this way can you show the user the best message? In this case, does the user really care about the details? It is easy to think that the user wants to know more, simply because you, as a developer. But developers should get error information from the logs, not from end-user messages.

+1
source share

It is a really bad idea to catch all the exceptions. You will only catch what you can reasonably manage. You cannot handle all the exceptions, so why are you catching it? To prevent stack tracing?

If you do not want your users to see a terrible stack trace, I get this, but you want it to die and die horribly so that something is not damaged.

Let's say that the service threw an OutOfMemoryException, you just caught it and you won’t know if your application is running as memory or a large distribution of large objects.

This is bad.

If you do not want your user to see what is wrong, you must change your catch to say:

 catch (Exception e) { //send it to yourself, log it. Just don't swallow it. LogErrorAndEmailDevTeam(e); throw new SaveFailedException("We're sorry. \n" + "It not your fault, but something bad happened.\n\n" + "We've been notified and will fix it as soon as possible."); } 

But it would be even better to let the application die a terrible death, and not to catch this exception so that you quickly find out when something went wrong.

You do not want your application to continue in a corrupted state, but this is what catch (Exception) does. Are you really sure you can handle what was thrown?

+1
source share

If you are using WCF, I would recommend against ServiceResult or something similar for handling exceptions at the SOA level.

You must define a FaultContract for your method. This would allow the consumer code to learn about the types of exceptions that can be thrown and handle them accordingly using traditional try/catch blocks.

This question is fooobar.com/questions/368973 / ...

You may still have your front-end just say, β€œAn error has occurred,” but using a contract with an error will improve the error handling at the user interface level of your code, if necessary in the future.

0
source share

All Articles