views:

66

answers:

2

When creating a website my pattern often is the following:

  1. Controllers (application services)
  2. Services (domain services, infrastructure services)
  3. Repositories

Controllers talk to domain services or infrastructure services, and domain services may talk to repositories, infrastructure services will wrap things like smtp etc.

Currently I handle identity as an infrastructure service, if an infrastructure service or domain service needs to find out 'who the invoker is', it will request an identity service at construction, the identity service will have methods / properties to identity the invoker, this way I have for example, a HttpIdentityService, that determines the identity by session / cookie data.

However I'm a little stuck about how to handle results of service calls, for example.. I may have a service 'ArticleService', that has a method 'CreateComment' that simply takes a string comment text, and an identifier for the target Article.

My application service (controller), calls this service perhaps like so:

public ActionResult AddComment(int articleId)
{
  string commentText = ...;
  articleService.CreateComment(articleId, commentText);
  ...
}

However, this method may fail if the current identity isn't authorized, or doesn't pass policy that the ArticleService checks (such as being able to comment every 30 seconds perhaps), throwing and catching exceptions from service calls like this seems very wrong, because my calling code has no way of checking if it can actually invoke this action successfully (bar fatal app exceptions)..

So initially I started to make the services return a 'result', the result would be uniquely identifiable so the caller would know if the comment was indeed made (and additionally I would return the comment entity in the result), the results would also identify things like 'could not post as user is not authenticated', or 'could not post as specified cool-down period has not been respected' (I don't actually return strings but you get the idea).

My reasoning behind this is that the application service shouldn't be in control of if an action should invoke, imagine say I moved all of the user identity checks and everything out of the domain service and into the application service, I'd have tons of replicated code, as well as giving the application services completely power over what can happen..

I guess my question is basically, given that domain, infrastructure services will enforce additionally policy, what is the best way to inform the calling code the action did or didn't succeed, and why.

Thanks in advance, steve.

A: 

In a similar situation I used aspects to check if the method invocation was authorized, and threw an AuthorizationException if it was not. The aspect intercepted the method calls, retrieved the user informations from the session, checked the role/permissions set and eventually threw the exception. This way the callig code can handle the exception to provide meaningful feedback to the user, log the incident, whatever.

Manrico Corazzi
Hi Manrico, yes actually I have a similar AOP pattern (which is more explicit), I actually have service implementations that are proxies, they enforce a policy before calling the 'real' service.However, instead of throwing exceptions, I return instances of specific type results...
meandmycode
... the reasoning being that I don't think exceptions are the best way to inform of domain issues, and I don't think exceptions are easy to identify.. exception types are, but the specific intent is less so.
meandmycode
I understand your point (more here: http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx), but unless you develop a mechanism to perform actions and report, another layer decoupling the caller and the performer, chosing between exceptions and "error codes" is merely a matter of taste, imho.
Manrico Corazzi
Hi Manrico, you are right, you've certainly helped me realize a solution.
meandmycode
A: 

Use Aspect Oriented Programming to check for privileges. If these fail throw an exception.

Before an Action is actually invoked, check if the necessary privileges are available. If not cancel the action.

If an Action has some optional task that need special privileges, check the necessary privileges before executing the optional task and react as your Business Rules dictate. If you forget to do the check, your aop code will do the check and throw an exception, which is ok, because it really should never come to that.

Edit: As to the question posed in the comments on how to communicate the reason why an action is not allowed: I'd use objects. If the set of possible reasons is a fixed set at compiletime use a enum. If not just create a little class, that can contain all the relevant values.

Jens Schauder
Hi Jens, I like the idea that theres a safety net as well as an explicit method for calling code to check if it could invoke the action.. one thing however, whats the best way to inform of specifically 'why' you cannot invoke the action, returning a bool wouldn't be good, currently I return classes.
meandmycode