I have a service object that does some work on a particular patient.
public class PatientDxService
{
public Patient Patient { get; set; }
public PatientDxService(Patient patient)
{
this.Patient = patient;
}
}
My service takes in a Patient object as shown above.
I have a SessionManager object that has a property to get the session Patient. I want to inject the patient.
Bind<PatientDxService>().ToConstructor(x => new PatientDxService(x.Inject<ISessionManager>().Patient));
Bind<ISessionManager>().To<SessionManager>().InSingletonScope();
The above does not work for me. I don't really want to inject ISessionManager because if I wanted to use the services outside of the web scope, it wouldn't make sense.
Inject the ISessionManager into your Service instead of the Patient. then in constructor (or better yet, where you actually use the Patient), request the Patient from the session.
public class PatientDxService
{
private readonly ISessionManager _session;
public PatientDxService(ISessionManager session)
{
this._session = session;
}
public void DoStuff()
{
var patient = _session.GetPatient();
...
}
}
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.
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()
{
}
}
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.
I am creating a view that displays all the information of a product on for my website. I want to create a "Details" service class, that handles most of my querying.
I binded my session to to my data in a GeneralWebApplicationDataNinjectModule:
Bind<IContentService>().To<ContentService>().InRequestScope();
Bind<ISession>()
.ToMethod(
context =>
context.Kernel.Get<IMasterSessionSource>()
.ExposeConfiguration()
.BuildSessionFactory()
.OpenSession()
)
.WhenInjectedInto<IContentService>()
.InRequestScope();
I have a ContentService class that pull all my data in that looks like this:
public interface IContentService
{
IQueryable<Program> Programs { get; }
}
public class ContentService : IContentService
{
private readonly ISession _session;
public ContentService(ISession session)
{
_session = session;
}
public IQueryable<Program> Programs
{
get { return _session.Query<Program>(); }
}
}
...this works fine when i load it into my Controller:
public class ProgramController : Controller
{
private static IContentService _contentService;
public ProgramController (IContentService contentService)
{
_contentService = contentService;
}
public ActionResult Details(string item)
{
var ProgramDetails = DetailsService.ProgramsFind();
//this is where i want to use the service class to pull data in DetailsService.
var model = new DetailPageViewModel
{
ProgramTables = GetUpComingCourses(),
};
return View("../Shared/DetailView", model);
}
so i created a new service class to pull details trying to using ContentService:
public class DetailsService
{
private static IContentService _contentService;
public DetailsService(IContentService contentService)
{
_contentService = contentService;
}
public static IEnumerable<Programs> ProgramsFind()
{
var results =
_contentService
.Programs
.Where(
d => d.TypeId >= 16 || d.TypeId <= 18);
return results;
}
i get a System.NullReferenceException was unhandled by user code, Message=Object reference not set to an instance of an object on the line in ProgramsFind() where im calling _contentService. When i debug that it says its null.
So i realized this is because the data isnt binded to Details Service. When i enter in my InjectionDependency this:
Bind<IContentService>().To<DetailsService>().InRequestScope();
i get a lot of errors where it wants me to implement everything thats in ContentService in DetailsService but i dont want to replicate that. i just want to use the content that ContentService found in my DetailsService. Much like how the controller easily does it.
I feel like theres something im missing...
UPDATE
i think i might have figured something out. I added IDetailsService to the Controller, and it seems to be successfully pulling queries.
private static IContentService _contentService;
// new
private static IDetailsService _detailsService;
public MobileController(IContentService contentService, IDetailsService detailsService)
{
_contentService = contentService;
//new
_detailsService = detailsService;
}
Yes that was the answer!
Create Service
Bind Sessions to Service
Add Service to the Controller.
Call Service when necessary.
As always, just something overlooked!