Looks to me like your issue is:
I have a thread acting on behalf of a user. I don't wish to pollute my nice clean business logic with authorisation details. But my data store needs authorisation details to enforce control of the data.
From your description it sounds pretty critical that User A does/does not have access to Client B. That sounds very much like a Business Concern. So the first answer is its pretty obvious: Your business logic should care about which user is doing what. Passing the user details through the appropriate business logic directly is the clean way to handle this. This gives many positives: its clear, its clean, its easily tested, and the API is not coupled to the Data Store.
If need be there will be a point in your Business Logic where you can translate from talking about a User
, to specifically talking about Authorised to do X
. Also there is no reason why this User information could not be made more anemic, or enriched in different parts of your Business Logic.
Pragmatically, if the thread only serves one User at a time, use Thread Local storage and shove a reference to the user there. Later in your data store (aka wherever you need it) access that reference. This is a dreadful solution. It enforces direct coupling between API and Data Store (the recipient location), the Business Concern is not in the Business Logic, and you have a non-intuitive, indirect argument, that may not be set or cleaned up properly affecting future calls on the thread. In short what you make back from tedium, you will pay back over and over again in bugs and change resistance.
Added extra answer
Possible Solutions
- Attribute with some Aspect-Orientated programming.
- an Abstract Class/interface with some Aspect-Orientated programming.
- A Generic class that wraps a lambda/interface.
- a Meta Program that constructs an Abstract class for derivation.
- a Meta Program that constructs a tailored class which wraps a lambda/interface.
Solutions 1 and 2 uses your languages aspect orientation (C# attributes) to detect the "authorisation required" functions, and intercept calls to them. It will throw an exception on unauthorised, but permit the call if authorised.
class command
{
public command(User user);
public User user {get; }
[AuthorisedFor("xyz")]
public void action(object a);
[AuthorisedFor("xyz")]
public void action(User user, object a);
}
Solution 1 requires you to directly decorate the authorisation required functions, and provide an properties/arguments for user information.
Solution 2 allows you to pre-specify the authorisation required for the standard functions, and provide the properties/arguments for user information.
Solution 3 is a decorator and captures through its constructor the knowledge about authority required, the permit and deny functions. The only issue is that the Command interface will either force you to use Object
arguments, a Generic Type and a limit on arguments, or require copies per downstream command interface.
class command<T>
{
public command(User user, Authority[] required, Action<T> permit, Action<T> deny);
public void action(T arguments);
}
class command2
{
public command(Authority[] required, SomeInterface permit, SomeInterface2 deny);
public void action();
}
Solutions 4 and 5 are just not easily achieved in C#. You would essential need to write code that JIT's a new Base Class and derivations, or decorator classes for the various interfaces. I only include them for completeness.
The run-time flexible options are 3 or 5. The other solutions 1, 2 or 4 are more reasonable for compile time.
User and Authorisation Passing
Orthogonal to which solution you pick for handling permit/deny, those solutions will need access to the user/authorisations. These could be stored in various forms of storage:
- global
- thread local
- object property
- function argument
Picking Global or thread local is going to give you the implicit user passing you desire, it will however complicate testing and be a source of non-intuitive bugs.
Picking an Object property or a function argument is going to require that you pass the user/authorisation information through your commands. It will make the information requirement explicit, simplify testing, and reduce the capacity for non-intuitive bugs. It will require more typing.
My preference is for explicitly passing the user/authorisations down. However there may be a reason that makes the implicit Global/Thread local option the better choice.
The central idea of the DIP is to eliminate any direct dependencies between higher-level modules and lower-level modules. To achieve this, an abstract, stable interface is placed between them, upon which both layers depend instead.
In the repository pattern, the interface usually references the entity for which the repository is responsible. It therefore makes the lower level implementation (CarModelRepository
) depend on a higher-level module entity (CarModel
).
Replacing the concrete CarModel
with an ICarModel
interface does not really solve this problem. After all, the CarModel
instance that we obtain through the repository implements various business rules and should therefore live in the business layer.
We could increase the separation between the business layer and the repository implementation. For example, we could provide a CarModelFactory
(implemented in the business layer) that implements ICarModelFactory
(part of the shared interface) to the repository. Alternatively, we might make the repository deal with CarData
value objects rather than actual CarModel
entities - and make the business layer instantiate the entities itself.
In most cases, this doesn't seem fruitful. Attempting to find an abstract interface between the two modules that is more stable than CarModel
itself is almost always going to be futile. That's because, fundamentally, CarModelRepository
is not intended to be a generic utility class. It's purpose is essentially to glue your specific domain model to the database.
As a result, trying to separate it from the domain model (or the database) doesn't really produce anything useful. In other words, the repository can be seen as an adapter between the domain model and the database driver - and therefore must be aware of both.
I should note that Martin's primary focus when introducing the DIP was to separate the higher level module from lower level modules, which the repository pattern achieves.
Best Answer
A good repository should abstract away the underlying database structure. An entity may have its data stored in several different tables, but your domain logic shouldn't care about that. At most, you'd have one repository for each entity in your domain, but you could also just have one repository for each aggregate root. It's up to you to decide what makes sense for your case.
For example, let's say your domain contains Order entities and OrderLineItem entities. Does it make sense in your domain to retrieve an OrderLineItem directly without the corresponding Order? If so, then you may need a repository for both entities. However, if you only access OrderLineItem entities from an Order entity, then you only need a repository for Orders. This repository would potentially query both the orders table and the order line items table to construct a complete Order with all of its OrderLineItems.