74083

Repository and UoW pattern with service layer

Question:

I'm using Repository and UoW pattern. My services look like this:

public class MyService : IService { private readonly IUnitOfWork<MyContext> unitOfWork; private readonly IMyRepository myRepository; public MyService(IUnitOfWork<MyContext> unitOfWork, IMyRepository myRepository) { this.unitOfWork = unitOfWork; this.myRepository = myRepository; } //Methods... }

Within services, I need to use other entities (for example to check for rights, etc).

Is it recommended to use the relevant repositories in the service or use the services directly?

Also, for each user we have rights (boolean) for each CRUD action. These rights are stored in the database.

Should checking of rights be done at the controller level or at the service level?

Answer1:

Don't use your UoW to just wrap your database context. Since all your repositories are directly dependent of a given context (more or less, ofc), your repositories can be included in the UoW. Something along the lines of:

public interface IUnitOfWork<TContext> : IDisposable { } public abstract class UnitOfWork<TContext> : IUnitOfWork<TContext> { private readonly TContext _context; protected TContext Context { get{ return _context; } } protected UnitOfWork(TContext context){ _context = context; } } public interface IMyDbUnitOfWork : IUnitOfWork<MyContext>{ public ICarRepository Cars { get; } public IOwnerRepository Owners { get; } } public class MyDbUnitOfWork : UnitOfWork<MyContext>, IMyDbUnitOfWork{ public MyDbUnitOfWork():base(new MyContext()){} private ICarRepository _cars; public ICarRepository Cars { get{ return _cars ?? (_cars = new CarRepository(Context)); } } private ICarRepository _owners; public IOwnerRepository Owners { get{ return _owners ?? (_owners = new OwnerRepository(Context)); } } } public class MyService : IService { private readonly IMyDbUnitOfWork _unitOfWork; public MyService(IMyDbUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } //Methods... }

Obviously you can create this more or less generic, but I believe this should be enough to pass my point. As a note, and since I normally use IoC frameworks, my services receive an IUnitOfWorkFactory because of the diferent lifestyles.

For the permissions question, it really depends how much control you want to have and how user friendly you want your application to be. Normally is a mix of both. Your application should know if your user has access to the screen but also if you must disable buttons accordingly. Since you also must prevent that, if by any reason, the user can invoke your service method, you can't allow it. To solve this problem I don't filter by CRUD actions but by Service actions instead, intercepting every service invocation, which makes it easy to map my permissions to the user interface since normally is a 1 to 1 relation between button action and service action.

Answer2:

My golden rule is:

<blockquote>

When you get business logic in your UI create a service, otherwise use the repository directly.

</blockquote>

So if you have this code in the UI:

var user = repos.Get(1); user.FirstName = txtFirstName.Text; repos.Save(user);

You are fine in my opinion. But if you instead have something like:

var user = userRepository.Get(1); var accessChecker = authorizationRepository.GetForUser(id); if (!accessChecker.MaySendEmail(user)) throw new SecurityException("You may not send emails"); var emailSender = new EmailSenderService(); emailSender.Send(user, txtDestination.Text, txtMessage.Text); repos.Save(user);

It's likely that you should use a service instead.

Answer3:

I think using repositories is just fine. I wouldn't invent a service layer for each of the repos. Repository is used for abstracting the data access and service layer is to encapsulate business logic, however with recent trend , I find this overkill. Having service layer is fine if they act as controllers but don't try to map one to one to each entity or repo.

Answer4:

I typically use services from the UI and those services in turn use the repositories. I also find it useful to have some domain objects that encapsulate reusable logic in the services.

I do this so that rather than services calling each other and getting circular references, services use a common domain object instead. This avoids circular references and people copying and pasting the same code all over the place.This domain object may then use the repositories if necessary.

Recommend