I have a set of interfaces I need to implement, and in each implementation I need to access a value that is available in the calling context, but is not a part of the interface method. Also, the calling context receives the instance as a dependency.
To solve this, I'm looking to see if there is some way to create a scoped context of sorts, similar to HttpContext, with a limited lifespan.
This is how I envision it: The OrderProcessor class makes the userId value available to all method calls within the using scope for the instance of the UserContext class.
The question is: Is this even possible, and if so how?
public class OrderProcessor
{
private readonly IBusiness _business;
public OrderProcessor(IBusiness business)
{
_business = business; // DI is providing us with an instance of MrBusiness
}
public static void ProcessOrders(string userId)
{
using (new UserContext(userId))
{
var thisUsersOrders = _business.GetOrders();
}
}
}
public interface IBusiness
{
List<Order> GetOrders();
}
public class MrBusiness : IBusiness
{
public List<Order> GetOrders()
{
var userId = UserContextManager.Current.UserId;
// Use the userId to retrieve data from somewhere
}
}
public class UserContextManager
{
public static UserContext Current
{
get
{
// If this had been a web application I could perhaps have used the Http context, hmm?
}
}
}
public class UserContext : IDisposable
{
public string UserId { get; }
public UserContext(string userId)
{
UserId = userId;
}
public void Dispose()
{
}
}
Related
I have an ASP.NET MVC 5 Application with a SignalR 2 hub and using autofac for the DI.
The entire business logic is encapsulated in manager classes in their own layer. Some manager methods need informations about the current logged in user (UserId, TenantId, ..).
I solved this problem by injecting an AuthorizationProvider into each manager class that needs the user information.
public interface IAuthorizationProvider
{
long? GetUserId();
long? GteTenantId();
}
public class MyManager : IMyManager
{
private IAuthorizationProvider _authorizationProvider;
public MyManager(IAuthorizationProvider authorizationProvider)
{
_authorizationProvider = authorizationProvider;
}
public void MyMethod()
{
// Getting the User information here is pretty simple
long userId = _authorizationProvider.GetUserId();
}
}
Normally I can get the user information from the HttpContext and from the session. So I wrote a SessionAuthorizationProvider:
public class SessionAuthorizationProvider{
public long? GetUserId()
{
HttpContext.Current?.Session?[SessionKeys.User]?.Id;
}
public long? GteTenantId() { ... }
}
But now I have a new method in the SignalR hub that use the same mechanism.
[HubName("myHub")]
public class MyHub : Hub
{
private IMyManager _myManager;
public MyHub(IMyManager myManager)
{
_myManager = myManager;
}
[HubMethodName("myHubMethod")]
public void MyHubMethod(long userId, long tenantId)
{
_myManager.MyMethod();
}
}
The problem is that a SignalR request doesn't have a session. Therefore I have also set the required user information in the hub method as parameters postet from the client.
So I thought it is the best solution for this problem to write a new AuthorizationProvider for SignalR and adapt the depdendency resolver. But I can't get the current user in the new SignalrAuthorizationProvider.
public class SignalrAuthorizationProvider{
public long? GetUserId()
{
// How to get the user information here???
}
public long? GteTenantId() { /* and here??? */ }
}
Is there a recommended solution to this problem?
Of course, I can extend MyMethod to accept the user information as a parameter. But MyMethod calls another method from another manager and that manager also calls another method. The user information is only needed for the last method call. So I had to change at least 3 methods and many more in the future.
Here is a sketch of the problem
This is a potential solution. But it's very bad
Session is not supported by SignalR by default and you should avoid using it. See No access to the Session information through SignalR Hub. Is my design is wrong?. But you still can use cookie or querystring to get the desired value.
In both case you need to have access to the HubCallerContext of the underlying hub, the one that is accessible through the Context property of the Hub.
In a ideal word you should just have to had the dependency to the SignalAuthorizationProvider
ie :
public class SignalrAuthorizationProvider {
public SignalrAuthorizationProvider(HubCallerContext context){
this._context = context;
}
private readonly HubCallerContext _context;
public long? GetUserId() {
return this._context.Request.QueryString["UserId"]
}
}
But due to SignalR design it is not possible. Context property is assigned after construction of the Hub and AFAIK there is no way to change it.
Source code here : HubDispatcher.cs
One possible solution would be to inject a mutable dependency inside the Hub and alter the object in the OnConnected, OnReconnected methods.
public class SignalrAuthorizationProvider : IAuthorizationProvider
{
private Boolean _isInitialized;
private String _userId;
public String UserId
{
get
{
if (!_isInitialized)
{
throw new Exception("SignalR hack not initialized");
}
return this._userId;
}
}
public void OnConnected(HubCallerContext context)
{
this.Initialize(context);
}
public void OnReconnected(HubCallerContext context)
{
this.Initialize(context);
}
private void Initialize(HubCallerContext context) {
this._userId = context.QueryString["UserId"];
this._isInitialized = true;
}
}
and the Hub
public abstract class CustomHub : Hub
{
public CustomHub(IAuthorizationProvider authorizationProvider)
{
this._authorizationProvider = authorizationProvider;
}
private readonly IAuthorizationProvider _authorizationProvider;
public override Task OnConnected()
{
this._authorizationProvider.OnConnected(this.Context);
return base.OnConnected();
}
public override Task OnReconnected()
{
this._authorizationProvider.OnReconnected(this.Context);
return base.OnReconnected();
}
}
Having a mutable dependency is not the best design but I can't see any other way to have access to IRequest or HubCallerContext.
Instead of having an abstract Hub class which is not a perfect solution. You can change the RegisterHubs autofac method to use AOP with Castle.Core and let the interceptor calls the methods for you.
This question already has an answer here:
Mock HttpRequest in ASP.NET Core Controller
(1 answer)
Closed 4 years ago.
I'm having the following setup:
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
public UserDetails UserDetails => Request.GetUserDetailsFromHttpHeaders();
}
public class ExampleConcreteController : ExampleBaseController
{
// UserDetails is being used in here
// this is the class under test
I need to be able to inject UserDetails during production run and also be able to mock it during tests.
Since UserDetails depends on Request and Request is a member of Microsoft.AspNetCore.Mvc.Controller I do not know how to achieve this.
If you want to mock something, you should first allow mocking on it. If you want to mock UserDetails you should allow mocking on its getter and pass required context inside newly crafted contract:
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly IUserDetailsProvider _userDetailsProvider;
public UserDetails UserDetails => _userDetailsProvider.Get(Request);
public ExampleBaseController(IUserDetailsProvider userDetailsProvider)
{
_userDetailsProvider = userDetailsProvider;
}
}
So, in test you mock IUserDetailsProvider to return some "foobar". In production you just invoking GetUserDetailsFromHttpHeaders() method on passed inside Request.
To answer question about Request and Controller relations. Controller depends on Request, yes, and Microsoft thought that it will be good to strongly merge them together instead of passing dependency, for example like this:
public class FooBarController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly System.Web.HttpRequestBase _request;
public FooBarController(System.Web.HttpRequestBase request)
{
_request = request;
}
}
Or even like this:
public class FooBarController : Microsoft.AspNetCore.Mvc.Controller
{
public void ProcessRequest(System.Web.HttpRequestBase request)
{
//request here
}
}
They instead used Property injection, which leaves developer with no way to affect injection. This is a problem. But not unsolvable - you just pass context inside (by delegate, by interface, by reference), if you need one of those coupled together objects.
It could be not so convinient as solution, proposed by #eocron, but still:
public interface IWithUserDetails
{
UserDetails UserDetails();
}
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller, IWithUserDetails
{
public UserDetails UserDetails()
{
return Request.GetUserDetailsFromHttpHeaders();
}
}
Same name for class and method is not a best way to do, but it was like it in the example with a property
Here is another point of view:
public interface IUserDetailsProviderOptions
{
Func<UserDetails> UserDetailsProvider { get; set; }
}
public class DefaultUserDetailsProviderOptions : IUserDetailsProviderOptions
{
public Func<UserDetails> UserDetailsProvider {get; set;}
}
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly Func<UserDetails> _userDetailsProvider;
public UserDetails UserDetails => _userDetailsProvider();
public ExampleBaseController(IUserDetailsProviderOptions options)
{
_userDetailsProvider = options.UserDetailsProvider ??
Request.GetUserDetailsFromHttpHeaders;
}
}
Register in Startup.cs like this:
services.AddSingleton<IUserDetailsProviderOptions, DefaultUserDetailsProviderOptions>();
In testing you could do:
public class StubUserDetailsOption : IUserDetailsProviderOptions
{
public Func<UserDetails> UserDetailsProvider { get; set; } = () => new StubDetails();
}
var controller = new ExampleBaseController(new StubUserDetailsOption());
and do testing.
Scenario
I have a UserContext class serving as the gateway to a database.
public class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
}
I want to restrict direct access to the database (i.e. UserContext.Users), because I want to enforce audits. So far I had extra model classes that do the audit and implement interfaces that controllers use:
Controller -> Interface -> Model class -> DbContext
But there is nothing to prevent the controllers (or rather other developers creating them) from accessing a DbContext directly.
As far as I know I can't just allow access to some classes (models) and deny to others (controllers), so I need to protect UserContext from all classes.
My Solution
The only solution I can think of is to make Users private and then implement access methods inside UserContext:
public class UserContext : DbContext
{
private DbSet<User> Users { get; set; }
public changePassword(String username, String newPassword)
{
doAudit();
Users.Single(user => user.Username == username).Password = newPassword;
SaveChanges();
}
}
But if I have to implement all db access methods inside UserContext it will become pretty big and have multiple responsibilities.
Questions
Is there another way of preventing other classes from accessing db objects directly?
Is my proposed solution of putting all access methods into UserContext a violation of the Single Responsibility Principle? Or is this OK, because in this case it has only one responsibility: Allow access to the database?
Securing your code by nesting it.
You could create a class and secure your context by nesting the various classes inside of it, but it's a bit of an unusual pattern.
// sealed public class
public sealed class SecuredUserService : ISecuredUserService
{
private readonly UserContext _context;
private readonly ILogger _logger;
public SecuredUserService(ILogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger;
_context = new UserContext()
}
// expose a secure interface / method
public bool TryChangePassword(IUser user, string value)
{
_logger.Log("password was NOT changed.");
return false;
}
// secure the context
private class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
}
// secure the model
private class User : IUser
{
public int ReadOnlyInteger { get; set; }
public bool WriteOnlyBool { get; set; }
public DateTime ReadWriteDateTime { get; set; }
public string SecretString { get; set; }
}
}
These would be the public interfaces for the above.
// public exposed interfaces
public interface IUser
{
int ReadOnlyInteger { get; }
bool WriteOnlyBool { set; }
DateTime ReadWriteDateTime { get; set; }
}
// public exposed interface
public interface ISecuredUserService
{
bool TryChangePassword(IUser user, string value);
}
Note: To take it even further, you can put the class into a separate namespace.
Create a repository that will expose only the functionality you deem acceptable. This way you'll have a centralized, testable gateway to your database.
While deviating from the current solution as least as possible, consider splitting responsibilities that would otherwise be in UserContext into other classes UserContext will control and delegate to. For example, a PasswordChange class is responsible for auditing and carrying out password changes. UserContext can then delegate password changing to the PasswordChange class:
public class PasswordChange
{
private DbSet<User> Users { get; set; }
public PasswordChange(DbSet<User> users)
{
Users = users;
}
public void Execute(String username, String newPassword)
{
doAudit();
Users.Single(user => user.Username == username).Password = newPassword;
}
}
public class UserContext : DbContext
{
private DbSet<User> Users { get; set; }
public changePassword(String username, String newPassword)
{
new PasswordChange(Users).Execute(username, newPassword);
SaveChanges();
}
}
A cleaner, but more involved solution would be to define an IUserRepository interface with a ChangePassword method or a more fine-grained IPasswordChange interface with an Execute method if size is a concern. Concrete implementations of these interfaces would use UserContext to carry out database related tasks while also doing auditing. In case of going with IUserRepository:
public interface IUserRepository
{
public void ChangePassword(string username, string newPassword);
//other user related methods
}
public class SqlUserRepository : IUserRepository
{
UserContext UserContext { get; }
public SqlUserRepository(UserContext userContext)
{
UserContext = userContext;
}
public void ChangePassword(string username, string newPassword)
{
DoAudit();
UserContext.Users.Single(user => user.Username == username).Password = newPassword;
UserContext.SaveChanges();
}
//other user related methods
}
In case of going with IPasswordChange:
public interface IPasswordChange
{
public void Execute(string username, string newPassword);
}
public class SqlPasswordChange : IPasswordChange
{
UserContext UserContext { get; }
public SqlPasswordChange(UserContext userContext)
{
UserContext = userContext;
}
public void Execute(string username, string newPassword)
{
DoAudit();
UserContext.Users.Single(user => user.Username == username).Password = newPassword;
UserContext.SaveChanges();
}
}
Controllers would then accept IUserRepository or IPasswordChange interfaces through their constructors. Through these interfaces they would access concrete implementations, which ensures that auditing will always take place and that controllers cannot access the database directly.
To prevent controllers from constructing UserContext or having any references to it at all, UserContext and related database classes like SqlUserRepository or SqlPasswordChange can be moved to a separate assembly. Then the classes or just their constructors can be marked as internal to prevent accessing them from the controller.
I am working on a project with a complex business.
Consider two classes : AccountService and SchoolService
I am using Unity and the dependency resolver of the Web API to implement dependency injection in the constructor.
The school service uses the account service in some methods, also the account service uses the school service. All this is required in the business of the project. This will cause circular dependency, and it is not possible to move the methods from one class into another.
Can you please provide any idea on how to solve this ?
Here is an example:
public class SchoolBLC : ISchoolBLC
{
public School GetSchool(int schoolId)
{
...
}
public bool RenewRegistration(int accountId)
{
bool result = true;
IAccountBLC accountBLC = new AccountBLC();
// check some properties related to the account to decide if the account can be renewed
// ex : the account should not be 5 years old
// check the account created date and do renewal
return result;
}
}
public class AccountBLC : IAccountBLC
{
public void ResetAccount(int accountId)
{
ISchoolBLC schoolBLC = new SchoolBLC();
School accountSchool = schoolBLC
// get the school related to the account to send a notification
// and tell the school that the user has reset his account
// reset account and call the school notification service
}
public Account GetAccount(int accountId)
{
...
}
}
The two classes are referencing each other, this is the situation for 70% of the BLCs in the project.
If you absolutely have to do it that way you can have an interface that does your IoC logic and resolve that to an implementation that wraps Unity's resolution, e.g.
public interface ITypeResolver
{
T Resolve<T>();
}
Then you can pass that interface to both services in the constructor and use it to lazy-resolve the other service before you use it, outside the constructor.
That way when both services are initialized they will not have a direct dependency on the other service, only on ITypeResolver
I will do as suggested by #KMoussa but with some modifications:
The project is using the anemic model, so i will use a context pattern to lazy load and create any service, and the context will be passed as parameter to the service constructor.
public class SDPContext : ISDPContext
{
private ITypeResolver _typeResolver;
public Account CurrentUser { get; set; }
public IAccountService AccountService
{
get
{
// lazy load the account service
}
}
public ISchoolService SchoolService
{
get
{
// lazy load the schoolservice
}
}
public SDPContext(ITypeResolver typeResolver)
{
this._typeResolver = typeResolver;
}
}
public class ServiceBase
{
public ISDPContext CurrentContext { get; set; }
public ServiceBase(ISDPContext context)
{
this.CurrentContext = context;
}
}
public class AccountService : ServiceBase, IAccountService
{
public AccountService(ISDPContext context) : base(context)
{
}
public bool ResetAccount(int accountId)
{
// use base.Context.SchoolService to access the school business
}
}
public class SchoolService : ServiceBase, ISchoolService
{
public SchoolService(ISDPContext context) : base(context)
{
//this._accountService = accountService;
}
public void RenewRegistration(int accountId)
{
// use the base.Context.Account service to access the account service
}
}
For every page request, I need to get some current user permissions data from the database and then use this information several times in the logic
(which is made of several objects)
I want to get data from the database once per request, and reuse it where needed by injecting it.
Is the following the best way to do this?
1) define a object like this
class ApplicationUser : IApplicationUserProvider
{
private UserPermissions _userPermissions;
...
public ApplicationUser(IDatabase userService)
{
_userPermissions = userService.GetUserPermission(); // this would executed for every request once
}
UserRoles GetRoles()
{
return _userPermissions;
}
}
2) define the ioc something like this
var container1 = new Container(c =>
{
c.For<IDatabase>().Use<Database>();
c.For<IApplicationUser>().Use<ApplicationUser >();
c.For<IApplicationLogic1>().Use<ApplicationLogic1>(); // this has IApplicationUser in ctor
c.For<IApplicationLogic2>().Use<ApplicationLogic2>(); // this has IApplicationUser in ctor
});
3) the controller would be
void PageController(IApplicationLogic1 l1)
{
l1.Process();
l2.Process();
}
The UserPermissions information is runtime data, and as explained here, runtime data should not be injected or resolved during construction of the object graphs.
Instead, the call to userService.GetUserPermission() should be moved out of the constructor. For instance by delaying the call by using a Lazy<T>:
class ApplicationUser : IApplicationUserProvider
{
private Lazy<UserPermissions> _userPermissions;
public ApplicationUser(IDatabase userService) {
_userPermissions = new Lazy<UserPermissions>(userService.GetUserPermission);
}
UserRoles GetRoles() {
return _userPermissions.Value.GetRoles();
}
}
Another option is to define a decorator on IDatabase that will implement the caching:
public class PerRequestCacheDatabaseDecorator : IDatabase
{
private IDatabase _decoratee;
public PerRequestCacheDatabaseDecorator(IDatabase decoratee) {
_decoratee = decoratee;
}
public UserPermissions GetUserPermission() {
var items = HttpContext.Current.Items;
if (items["permissions"] == null)
items["permissions"] = _decoratee.GetUserPermission();
return (UserPermissions)items["permissions"];
}
}
By wrapping the real database inside the PerRequestCacheDatabaseDecorator, you can simplify the ApplicationUser to the following:
class ApplicationUser : IApplicationUserProvider
{
private IDatabase _userService;
public ApplicationUser(IDatabase userService) {
_userService = userService;
}
public UserRoles GetRoles() {
return _userService.GetUserPermission().GetRoles();
}
}
Now neither the ApplicationUser nor the Database class are concerned with this performance optimization, which is a good thing. The decorator allows us to plugin this performance optimization without having to change any of the existing classes.