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.
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'm in a situation where the classic functionality of vnext's DI container is not enough to provide me with the correct functionality. Let's say I have a DataService that gets data from a database like this:
public class DataService : IDataService, IDisposable {
public List<MyObject> GetMyObjects()
{
// do something to fetch the data...
return myObjects;
}
}
I can then register this service in the DI container during the configuration phase in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IDataService), typeof(DataService));
}
This ensures the correct lifecylce of the service (one per request scope), however, I need the service to access a different database when a different request is made. For simplicity reasons, let's say the following scenario applies:
when a request to my Web API is made, the DataService will access the currently logged in user, which contains a claim called Database which contains the information which database to use.
the DataService is then instantiated with the correct database connection.
In order to get the second step to work, I have created a constructor for the DataService like this:
public DataService(IHttpContextAccessor accessor)
{
// get the information from HttpContext
var currentUser = accessor.HttpContext.User;
var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
if (databaseClaim != null)
{
var databaseId = databaseClaim.Value;
// and use this information to create the correct database connection
this.database = new Database(databaseId);
}
}
By using the currently logged in user and his claims, I can ensure that my own authentication middleware takes care of providing the necessary information to prevent attackers from trying to access the wrong database.
Of course adding the IDisposable implementation is required to cleanup any database connections (and gets called correctly using the scope lifecycle).
I can then inject the DataService into a controller like this
public MyController : Controller
{
private IDataService dataService;
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
This all works fine so far.
My questions now are:
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Is this method really safe? Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
What you have is fine.
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Not really. You can use delegate registration but it's the same problem.
Is this method really safe?
Yes
Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
Nope. The IHttpContextAcessor uses AsyncLocal (http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to provide access to the "current" http context.
I have several services that are currently highly decoupled. Now I have to extend them and they need to depend to access each other.
Let's say I have 4 services: EmailService, HouseService, UserService, PriceService. Each user has an email address and each user belongs to a house.
I want to send an email to each user about the price of the house that they are connected to. So in the EmailService I have SendEmailToAddress(string email, string text), in PriceService I have GetHousePrice(int id), in HouseService I have GetUsersInHouse(int id) and in UserService I have GetEmailOfUser(int id).
What would be the best approach to send an email to all the users from the HouseController? Should I just init all the services in the controller action and call each one in order or should I use the Mediator pattern? If I should use it, it would probably contain only one method so it seems a bit of an overkill. Also if I use it everywhere should I create different mediators for each service connection or should it be only one class that has all my services as private properties and then in the methods use only the once I need for a specific action? If I go with the Mediator pattern should I use it in every controller or should I stick with the bare services where they don't need to interact together (e.g. if I only need a list of houses I think it's probably best to just get them directly from the service object instead of the Mediator)?
Given that your services aren't actually needing to communicate with each other, you just need to call various methods on each and use the return values to complete a higher level task, I don't think the Mediator pattern is appropriate here.
For example, its not like you need the HouseService to manipulate the state of objects managed by the PriceService...you just need data from the PriceService that the HouseService provides input for:
var houseId = houseService.GetIdOfHouse(someCriteria);
var price = priceService.GetPriceOfHouse(houseId);
Instead, I think what you need to implement is the Facade pattern, which will:
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.
Good example of Facade pattern can be found on the dofactory.com site:
http://www.dofactory.com/net/facade-design-pattern
Here's what I would consider doing:
public class NotificationFacade
{
private IPriceService _priceService;
private IHouseService _houseService;
private IUserService _userService;
private IEmailService _emailService;
public NotificationFacade(IPriceService priceService, IHouseService houseService, IUserService userService, IEmailService emailService)
{
_priceService = priceService;
_houseService = houseService;
_userService = userService;
_emailSerice = emailSerice;
}
public void NotifyUsersAboutPriceForHouse(int houseId)
{
var price = _priceService.GetHousePrice(houseId);
var users = _houseService.GetUsersInHouse(houseId);
foreach(var user in users)
{
var emailAddress = _userService.GetEmailOfUser(user);
_emailService.SendEmailToAddress(emailAddress, "Your House Price is:" + price);
}
}
}
In your controller:
public HouseController
{
private NotificationFacade _notificationFacade;
public HouseController(NotificationFacade notificationFacade)
{
_notificationFacade = notificationFacade;
}
public void SomeActionMethod(int houseId)
{
_notificationFacade.NotifyUsersAboutPriceForHouse(houseId);
}
}
The dependencies should be resolved using Dependency Injection with a container such as Unity, Ninject, StructureMap or something similar...
You could create a workflow service that contains the actual logic to look up the information and send the mail using the existing services.
This service is then called from your HouseController. You could use the service directly as a class library or expose it as a WCF service; but it depends on your requirements.
This way your entity services remain loosely coupled, and all of your cross-service logic is in a dedicated component.
As I was looking for best practices since past couple of days in ASP.Net MVC and I concluded that our services should contain all business logic ( using repositories of different domain models) and expose public methods that are accessible by controller.
In your case you should create a new service and put the whole logic of calculation and sending email in a method of that service. So that your service will work like a black box. Other developers (who work on your project) don't need to know that how thing are managed in that method. All they need to know is to call that method with required parameter and handle response.
Just create HouseServiceFacade that contains the services you need. In this facade you can put all methods for the controller.
I'm building a multi-tenant MVC app where there's a single app pool and single database. I have a Tenant table, and each of my models has a TenantId identified.
Each Tenant has a string "Url" that identifies the full URL used to access that tenant's data.
I can access this from my BaseController with the following (rough approximation):
HttpRequest request = HttpContext.Current.Request;
Uri requestUrl = request.Url;
_tenant = _tenantService.GetTenantByUrl(requestUrl);
Now, I'm at a point where I need to pass the Tenant into the service layer to perform business logic. One way I can do this is to go across every single method across all services (~200 methods) and add a Tenant parameter. I'd have to touch every call to the service layer, and every service layer method. This would work, but it's tedious and muddles the code.
For example, one of my methods before:
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = db.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
After (if I pass in the Tenant):
public void DeleteUserById(Tenant tenant, int userId)
{
using (var db = CreateContext())
{
var user = tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
What I'm trying to achieve (by setting the tenant from my BaseController, one layer up):
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = _tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
Is there any way I can use my BaseService (all other services inherit from this) or some other pattern to define the Tenant from the Controller, and have the service methods pick it up, without passing it as a parameter to each one? This way I need only touch the base controller (or maybe even global.asax), and nothing else.
Put simply: How can I make an object accessible to all services by defining it from an MVC controller, without passing it directly to the service?
I guess what you´re saying about having a base service (see Layer Supertype) makes sense. That base class will have a dependency on an interface defined in the same service layer (e.g. IUserSession, IContext or whatever) and that interface will have a method or property that will return your Tenant.
The implementation of this interface will reside in your web application and it will do something as what you described, obtaining the data from the HttpContext.
If you have a background process, console application or whatever that does not run on a web context, you will have a different implementation that will create the Tenant based on any other criteria that you want.
So to summarize, you will have in your service layer:
abstract class BaseService
{
protected IContext Context {get; private set;}
public BaseService(IContext context)
{
Context = context;
}
}
public interface IContext
{
Tenant GetTenant();
}
Then in your web layer you´ll have:
public IWebContext : IContext
{
public Tenant GetTenant()
{
//your code to return create the tenant based on the url.
}
}
Hope this helps.
I have the same 'problem' since I'm building a multi tenant app as well. However, I solved it quite simple, IMO: every repository/service has defined a TenantId property, that must be set when that service is used. TenantId is a value object and it will throw if null.
Now, the point is any of the repos/services can be used outside the request, for example in a background thread or app. I am using a message driven approach so any required info (like tenant id) is part of the message and thus available for the consumer of the service (the message handler). Another benefit is testability.
I advice against coupling your service to a request specific object like HttpContext, Session or Cache.