Okay so I have a UI layer and a BLL layer.
namespace BLL
{
public class User : IUser
{
public void DoSomething(){}
}
public interface IUser
{
void DoSomething();
}
public static class TypeRegistry
{
public static void RegisterTypes(Container container)
{
container.Register<IUser, User>(Lifestyle.Singleton);
}
}
}
namespace UI
{
public partial class Login : System.Web.UI.Page
{
private IUser user;
}
}
I can't figure how to get user to not be null. I have tried making a constructor but that caused an error
public Login(IUser user){ this.user = user;}
Compilation Error : Login does not contain a constructor that takes 0 arguments
This link helped me get the answer:
https://simpleinjector.readthedocs.org/en/latest/wpfintegration.html
Similar to #Steven's link
https://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html
If you've done all the registration appropriately as demonstrated in the Web Forms integration guide of the documentation, then I think the problem is due to you setting the IUser accessibility level in your page to private.
So private IUser user; should become public IUser user;. Since Web Forms requires you to do property injection over constructor injection, the property user should be publicly accessible to be injected.
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 Service and virtually every method requires the current user to execute. Before I started using autofac I basically created a public property like this:
private IOrderProvider _orderProvider;
public IOrderProvider OrderProvider => _orderProvider ?? (_orderProvider = new OrderProvider((ClaimsIdentity)User.Identity));
Because this was a public property on the controller, it would have access to the User. Now using autofac I register my Service in the StartupConfig. Naturally I don't have access to the User there.
Is there a way to inject the current user into the OrderProvider constructor, or another way to get at it?
The user principal can be accessed through the HttpContext.Current.User. How ever tightly coupling code to HttpContext is frowned upon as it is not very unit test friendly. so create a service that exposes what you want.
using System.Security.Principal;
public interface IPrincipalProvider
{
IPrincipal User { get; }
}
An implementation in production can look like this.
using System.Security.Principal;
public class DefaultPrincipalProvider : IPrincipalProvider
{
public IPrincipal User
{
get
{
return HttpContext.Current.User;
}
}
}
With that done update the dependent class to use the abstraction
public class OrderProvider : IOrderProvider
{
private readonly ClaimsIdentity identity;
public OrderProvider(IPrincipalProvider provider) {
identity = (ClaimsIdentity)provider.User.Identity;
}
}
and then register the provider on startup as usual
//...other code removed for brevity
builder.RegisterType<DefaultPrincipalProvider>().As<IPrincipalProvider>();
builder.RegisterType<OrderProvider>().As<IOrderProvider>();
//...other code removed for brevity
The service should get everything injected
public class Service {
private readonly IOrderProvider _orderProvider;
public Service(IOrderProvider orderProvider) {
_orderProvider = orderProvider;
}
public IOrderProvider OrderProvider => _orderProvider;
}
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
}
}
I am trying to access an object created by ninject within my layout view but I have no idea how to access them.
Here is a brief outline of what I have tried so far:-
Created by service and bound them:
public interface IService
{
void SomeMethod();
}
public class Service : IService
{
public void SomeMethod
{
}
}
Bind<IService>().To<Service>();
Created a static class and use the [Inject] attribute:
public static class MasterLayout
{
[Inject]
public static IService Service { private get; set; }
public static void CallSomeMethod();
{
Service.SomeMethod
}
}
Everytime I call MasterLayout.CallSomeMethod() from my master view or partial view, the Service field is always null.
Is this even possible or should I be creating a base Controller and getting other controllers to inherit from it where I can set those values to be used within the master view and partial views? Is there an even better way of achieving this?
Does Ninject work if used with contructor injection?
( see http://ninject.codeplex.com/wikipage?title=Injection%20Patterns )
Something like
IUnitOfWork UnitOfWork;
public AccountController(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}
Have you checked here?
bind to property always return null
When you say "on every page", you mean "on every controller"?
If yes, i think you could create a BaseController class, and all the controllers should inherit from it. I'm using this method.
You have to create a custom controller factory to have Ninject create the controllers. Once you do, this will work. There is also probably an extension for this already.
I have a class library:
public class SomeBL : ISomeBL
{
private IUser myUser;
public SomeBL(IUser user)
{
myUser = user;
}
public void TestMethod()
{
...some code using the user...
}
}
I also have a factory in this code library:
public class BLFactory
{
public static ISomeBL SomeBL
{
get { return ServiceLocator.Current.GetInstance<ISomeBL>(); }
}
}
Then I have a separate wcf application with one service that looks like this:
public class MyWcfService : IMyWcfService
{
public void TestMethod(User user)
{
BLFactory.SomeBL.TestMethod();
}
}
As you can see I am in need of IoC to properly resolve the IUser property on the SomeBL constructor level. I also don't want to pass it explicitly.
I was wondering if it's possible to configure Windsor in such a way that IUser will be resolved dynamically using value from the wcf service method's parameter ?
p.s.
Let's forget about wcf's inability to pass interfaces for a moment.
Edit#1
I solved it using Castle Project's Wcf Facility. Smooth as silk after I added it!
Based on the way you have things set up, and with your conditions I don't see how it's possible. There is no way for the container to "just know" the context by configuration.
However, I see a few options.
The first is to make your BLFactory a proper abstract factory, and pass the user to its Create method:
public class BLFactory
{
public ISomeBL Create(IUser user)
{
return new SomeBL(user);
}
}
You could also do this by calling Resolve<>() and passing the parameter there, or using Windsor's Typed Factory Facility. Referencing the container to directly resolve service in a factory class is generally not a good practice (see Three Calls Pattern).
Second option would be to pass the user as a method parameter (although you said you don't want to do this):
public class SomeBL : ISomeBL
{
public void TestMethod(IUser user)
{
...some code using the user...
}
}
This makes SomeBL more of a pure service (stateless), which IMHO is more along the lines of what DI and Windsor should be used for.
A final option assumes that the user represents the logged in user (if this is incorrect, ignore this option). Look at creating a service that returns the current logged-in user and inject that servce into your class. You would use some form of Ambient Context to store the user (on login or at some other point) and retrieve the user via this service.
public class SomeBL : ISomeBL
{
private IUser _userservice;
public SomeBL(IUserService userservice)
{
_userservice = userservice;
}
public void TestMethod()
{
IUser currentUser = _userService.GetCurrentUser();
}
}
public interface IUserService
{
IUser GetCurrentUser();
}
public class UserService : IUserService
{
public IUser GetCurrentUser
{
//pull user from Thread, HttpContext.CurrentRequest, cache, session, etc.
}
}
It can be done by the use of Typed Factory see http://stw.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx