I have implemented repository pattern and it works pretty well.
public interface IServiceRepository
{
User GetUser(int id);
User GetUser(string email);
User GetUser(string email, byte[] password);
//SkipCode
}
//Service repository where I keep extended methods for database manipulation
public class ServiceRepository : IServiceRepository
{
private readonly IRepository<User> _userRepository;
private readonly IRepository<Order> _orderRepository;
private readonly IUnitOfWork _unitOfWork;
public ServiceRepository(IRepository<User> userRepository, IRepository<Order> orderRepository, IUnitOfWork unitOfWork)
{
}
//SkipImplementation
}
When I want to access some methods from IServiceRepository in Controller I do this
public class AccountController : Controller
{
private readonly IRepository<OrderDetail> _orderDetailRepository;
private readonly IRepository<UserDetail> _userDetailRepository;
private readonly IServiceRepository _serviceRepository;
public AccountController(IRepository<OrderDetail> orderDetailRepository, IRepository<UserDetail> userDetailRepository, IServiceRepository serviceRepository)
{
_orderDetailRepository = orderDetailRepository;
_userDetailRepository = userDetailRepository;
_serviceRepository = serviceRepository;
}
}
As you see I inject IRepositories and IServiceRepository in this scenario. Sometimes I inject only IRepositories or IServiceRepository depending on a needs.
Question would be maybe I should move all IRepositories into IServiceRepository. And in all controllers embed only IServiceRepository and access IRepositories from IServiceRepository? This implementation looks more clear to me because only IServiceRepository will be injected in controllers. But to access for example one Repositorie<User> from ServiceRepository will need to build and inject all other repositories in ServiceRepository, so it may slow down the whole application. What do you think?
My answer is controversial, so please bear with me :)
To the point
Building and injecting repositories should take almost no time. I assume your repositories do not open any connections when they are created, so do not bother about micro optimisation, just get it working :)
You can merge your interfaces, as long as the result interface is small (say no more than 10 or so methods), focused and has a clear purpose.
Side comments
What is the need for the repository pattern? Do you allow (or in the nearest future plan) to easily switch between databases? For most cases repository is a massive overkill and a maintenance problem.
Consider this code
public interface IServiceRepository
{
User GetUser(int id);
User GetUser(string email);
User GetUser(string email, byte[] password);
//SkipCode
}
What does it tell me? Well, from the generic name I couldn't understand what this interface does, it is like service of a service, abstraction over abstraction. But from the method definitions I see it does something with Users.
Why do you explicitly using IUnitOfWork? Is it not already implemented by the data provider you using?
Instead of all this architecture (of course if possible), just use ORM directly, this is easy to do and maintain, reliable and fast.
Your ServiceRepository seems to be closer to a domain service in a Service Layer than a repository of its own.
A domain service typically coordinates a sequence of interactions with various data repositories, for example loading a customer from a customer repository and a list of orders from an order repository to present a unified view of a customer and all their orders. As such domain services are used to create an operational boundary around an application - abstracting the various sequences of data access.
This is a fine approach, but I think the problem you have is that you have not taken it far enough. If you decide that the operations of the application should be encapsulated into a series of domain services, then there will be no need for a Controller to access repositories. If on the other hand you decide that the Controllers will take that reposibility, and access repositories themselves, then your ServiceRepository class, and others like it, basically become utility classes.
I see that you have two options - improve your service layer to such an extent that controllers no longer need repositories:
public class AccountController
{
public AccountController(IAccountsService service)
{
_service = service;
}
public void SomeActionMethod(Foo someParams)
{
_service.SomeAction(someParams);
}
}
or call the ServiceRepository what it is, a shortcut utility for doing a fixed sequence of data accesses...
public class AccountController
{
public AccountController(ICustomerRepository customerRepo, IOrderRepository orderRep)
{
_customerRepo = customerRepo;
_orderRepo = orderRepo;
}
public void SomeActionMethod(Foo someParams)
{
var utility = new CustomerOrderBuilderUtility(_customerRepo, _orderRepo);
var customerWithOrders = utility.GetCustomerAndOrders(someParams.CustomerId);
// some domain logic...
}
}
Related
I have a three layered architecture.
I can't use constructor injection and I need to get access to a service in my business code, in which I don't have access to HttpContext.
For example, in action methods, or in filters or middleware I can get a service using:
HttpContext.RequestServices.GetRequiredService<ITranslator>();
But in my business code, I don't have access to HttpContext.
How can I get an instance of my service?
Update:
Here's my business code:
public class InvoiceBusiness
{
// for some reasons, I can't use constructor injection here
public void CalculateTranslationsInvoice(long customerId)
{
// I need to get an instance of ITranslator here, and a couple of other services.
// If this method was in a controller, I could use HttpContext.RequestServices.
// But here what should I do?
}
}
If you're needing to access HTTP concerns in the inner layers, you should abstract it to an interface.
Assume you need to access the current user. Normally, you'd use HttpContext.User. But you can't access it in the domain layer.
The solution is to define an interface in your domain layer that encapsulates what your ITranslator implementation actually needs from the HTTP context.
public interface IUserAccessor {
ClaimsPrincipal CurrentUser { get; }
}
public class Translator: ITranslator {
// inject the interface
private readonly IUserAccessor _userAccessor;
public Translator(IUserAccessor userAccessor) {
_userAccessor = userAccessor;
}
// ...
}
Keep this interface as focused as possible. Here, I'm OK with using ClaimsPrincipal and having a dependency on the standard library, but if you're not, you can just extract the user id claim if that makes sense in your application.
Then implement this interface in the application/HTTP layer.
internal class HttpUserAccessor: IUserAccessor {
IHttpContextAccessor _httpAccessor;
public HttpUserAccessor(IHttpContextAccessor httpAccessor) {
_httpAccessor = httpAccessor;
}
public ClaimsPrincipal CurrentUser => _httpAccessor.HttpContext?.User;
}
Then register this implementation:
services.AddHttpContextAccessor();
services.AddScoped<IUserAccessor, HttpUserAccessor>();
Now you can access HTTP concerns in any layer without that layer knowing where the data actually comes from.
The bottom line is: you don't have to forego dependency injection. You can define & implement interfaces in different layers.
You work on a legacy app which has a static class UserDataAccess:
public static class UserDataAccess
{
public static void AddUser(User user)
{
// Insert user into DB
}
}
which is used by a UserService class:
public class UserService
{
public bool AddUser(string firstName, string lastName)
{
User user = ...
UserDataAccess.AddUser(user);
}
}
You need to add unit tests for the UserService class, but you cannot modify the UserDataAccess (you are not allowed, you do not have access to the DB).
A good solution is to create an interface and inject into UserService:
public interface IUserDataAccess {
void AddUser(User user);
}
and add an implementation which delegates the call to the static class:
public class UserDataAccessProxyOrAdapter : IUserDataAccess
{
public void AddUser(User user) {
UserDataAccess.AddUser(user);
}
}
My question is, is this a Proxy or an Adapter?
Proxy is supposed to add some functionality. Can the access to the static resource be considered a functionality?
It looks like an Adapter because it adapts the UserDataAccess to be called through the IUserDataAccess interface
What is the correct reasoning and why?
EDIT: This is from this refactoring test, specifically at this step: https://youtu.be/U3QvTaw224o?t=944
This is neither an Adapter nor a Proxy design pattern.
Adapter can be dismissed easily because an Adapter's API differs from the API of the object it adapts. Both IUserDataAccess and UserDataAccess share the same API: AddUser(User user), which rules out the Adapter pattern.
Proxy can be dismissed for the reason mentioned in the OP: there is nothing more than a direct passthrough from UserDataAccessProxyOrAdapter to UserDataAccess. No remote call, no deferral of instantiation cost, no access control, no additional action taken at all.
We would not want to call this simple example a Proxy design pattern, because that would imply every composition is a Proxy, which would devalue the pattern entirely.
But, do note that proxy is also a general English word; so while it doesn't make sense to name this example a Proxy design pattern, calling it a proxy based on the broader dictionary definition could be valid. I'm not sure whether that was the author's intent or not.
I am developing ASP.NET Core application. To keep controllers lean, most of the data manipulation is done in ViewModels. Everything works fine - the two problems, however, are
ViewModels don't have access to ControllerContext information (or I can't figure out how to get it). For example, Session, User and whatever else Controller gets for free.
ViewModels don't accept Dependency Injection (again, or I can't figure out how to pass it along). For example, if I have constructor MyController(ApplicationDbContext db) I get db passed without any problems. However, if I have ComplexViewModel(ApplicationDbContext db) I get null passed in. Obviously, I have exactly the same services.AddDbContext<ApplicationDbContext>() in Startup
Right now I am passing whatever is required from Controller to ViewModel explicitly. But it feels that there should be a better way.
View models are supposed to be simple POCOs to transfer data between the views and action methods. I think it is a bad idea to mix all your business logic (or even data access) to view models. You may consider doing that in services. You can inject this services to your controllers.
For example.
Yo get a User information, you may consider creating a service
public interface IUserService
{
UserDto GetUser(int id);
}
public class UserService : IUserService
{
IUserDataAccess userDataAccess;
public UserService(IUserDataAccess userDataAccess)
{
this.userDataAccess=userDataAccess;
}
public UserDto GetUser(int id)
{
// with this.userDataAccess, get a User and map to UserDto
// to do : return something
}
}
So your controllers will stay lean
public class UserController : Controller
{
private readonly IUserService userService;
public UserController(IUserService userService)
{
this.userService = userService;
}
public ActionResult Details(int id)
{
var userDto= this.userService.GetUser(id);
return View(userDto);
}
}
Now you can have a UserDataAccess which query your data and inject that to the UserService class.
With this approach your view model does not have any idea what data access technology you are using. Imagine tomorrow you decided to ditch EF for performance reason and want to switch to Dapper, you simply need to create a new implementation of your IUserDataAccess called "DapperUserDataAccess" and udpate your DI config registration to use that. No other code change :)
What is recommended architectural approach for defining dependencies in a service class ?
Is this OK, when another class, ex. OrderService has dependencies to repository class ex. CartRepository instead of CartService? Should I always create one repository and one service per domain object ?
public class CartService : ICartService
{
private IBuyerRepository _buyerRepository;
private ICartRepository _cartRepository;
private IConfigService _configService;
private ISimpleDataService _simpleDataService;
public CartService(IBuyerRepository buyerRepository,
ICartRepository cartRepository,
IConfigService configService)
{
_buyerRepository = buyerRepository;
_cartRepository = cartRepository;
_configService = configService;
}
public void Save(Cart cart)
{
_cartRepository.Save(cart);
}
}
OrderService file:
public class OrderService : IOrderService
{
public OrderService(ICartRepository cartRepository)
{
}
}
Your implementation is good as a first step, and in a simple, not too big, domain.
A such implementation has avantages:
While just one service per http resquest manages all the repositories it needs, there is no difficulty to manage the sql transaction to maintain integrity.
It has too disadvantages:
You could write two times, or more, the same business rules... We all are lazy so it's a problem. But a major failure will come when someone, or you, 6 months later, will call the repository for the third time in its service implementation and forget a business rule... bye bye lovely domain...
My recommendation would be that a service just call its repository, and calls the other services that encapsulate their own logic, when needed.
The only trick to remember is to propagate the transaction to avoid odd things to happen.
Hope it helps,
Julien
Hi there i am new to the repository pattern. I would like to have feedback on the approach i am following.
Requirement : Build the menu for the user that is currently logged in.
My Solution :
I created a Service, that will be called by the controller to get the menu items.
public interface IApplicationHelperService
{
List<Menu> GetMenuForRoles();
}
The implementation for the service
public class ApplicationHelperService : IApplicationHelperService
{
private readonly IMenuRepository _menuRepository; //this fecthes the entire menu from the datastore
private readonly ICommonService _commonService; //this is a Service that contained common items eg. UserDetails, ApplicationName etc.
public ApplicationHelperService(IMenuRepository menuRepository,ICommonService commonService)
{
this._menuRepository = menuRepository;
this._commonService = commonService;
}
public List<Menu> ApplicationMenu
{
get
{
return _menuRepository.GetMenu(_commonService.ApplicationName);
}
}
List<Menu> IApplicationHelperService.GetMenuForRoles()
{
return ApplicationMenu.Where(p => p.ParentID == null && p.IsInRole(_commonService.CurrentUser.Roles)).OrderBy(p => p.MenuOrder).ToList();
}
}
Then the CommonService (used for common items needed in the Services eg. CurrentUser
public interface ICommonService
{
IUser CurrentUser { get; }
string ApplicationName { get; }
}
On the class the implements the ICommonService, i get the current user using the context, in other words my service layer does not know about the HttpContext, since there is a possibility that this might by used for another type of application in the future. So this way i can handle by Current User differently for all applications, but my Service Layer will not mind.
So what you should give feedback on is, is this approach to inject this kind of common service into all services a good approach or is there another way of doing this, the reason i ask, is at a later stage i will need the current user's details for auditing purposes or whatever reason presents itself.
Hope this makes sense to someone. :-)
We are using a similar approach. The difference is that, we do not have a CommonService object injected into each service.
We are using WCF and we have written an extension to OperationContext to store Username etc. The properties defined in this extension can be accessed using static method calls. It has an advantage over CommonService implementation; since you are employing IOC, there is not direct way to pass parameters into CommonService in each service call. For instance, if you are sending the username on the WCF calls, you need to set the value of CurrentUser in each constructor.
I do not know whether you are planning to use WCF; but the point is that: if you need to pass variables to your CommonService, you will endup with populating this values inside each constructor. If you are not planning to pass variables, then you can just create a base class for your services and force the developers to use this base class.
Also, you should set the lifetime manager of CommonService as UnityPerResolveLifeTimeManager, in order not to create a new instance in each constructor.Otherwise, you may endup with having different instances in each Service.