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
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;
}
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.
I heared this should be possible, but I can not imagine how this should work.
I am using Dependency Injection (autofac) for my project. I develop a project with someone else and call the methods of his classes (I use his assembly).
Then I get an instance of an object which the other person should use for his operations.
We want to avoid passing this object instance on every method and use autofac.
Can he resolve this instance in his assembly project without passing any parameter?
I think we have to pass at least the DI-Container... But I heard that the concept of Dependency Injection should make it possible that you can resolve objects in the whole "execution context" and get the same one.
Here is an example with the asp.net web api:
This is a api controller of a asp.net webapi project:
public class DocumentsController : ApiController
{
// GET /api/documents
public HttpResponseMessage Get()
{
// Here I call the method of the other developer,
// security/authorization should be handled in
// his method!
// In this context the WebAPI provides the
// IPrincipal of the current user in this
// variable => "HttpContext.Current.User" but we
// don't want to pass it on every method call
ClassFromOtherAssembly.GetDocuments();
HttpResponseMessage response =
Request.CreateResponse<IEnumerable<Document>>(
HttpStatusCode.OK, documents);
return response;
}
}
This is the class of the other developer. He should deliver the documents and check if the user is authorized:
public class ClassFromOtherAssembly
{
public List<Documents> GetDocuments()
{
//Security check
IPrincipal principal =
DI_Container.Resolve(IPrincipal);
if(principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}
No, do not pass the container itself, you will end up with a Service Locator patter, and if you do a quick search you will understand that this pattern has a rotten smell.
public class Foo
{
private IContainer container;
private IBar bar;
public Foo( IContainer container) //no-no
{
this.container = container;
this.bar = container.Resolve<IBar>();
}
}
Instead use proper DI, like
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}
It doesn't really matter in which assembly your types are. This is the whole point of IoC and DI - to decouple parts of the application and make you depend on abstractions, rather than concrete implementations.
Edit
You misunderstood Service locator pattern with DI. "Instead of passing a parameter we want to use Dependency Injection" - passing a parameter is a DI, in contrast, resolving a type from a static container is a service locator.
public class DocumentsController : ApiController
{
public HttpResponseMessage Get()
{
ClassFromOtherAssembly.GetDocuments(); //this is Service locator
//really bad for testability and maintenance
...
}
}
DI looks like this
public class DocumentsController : ApiController
{
private IDocumentProvider;
public DocumentsController(IDocumentProvider provider)
{
this.provider = provider;
}
public HttpResponseMessage Get()
{
provider.GetDocuments(); //this is DI
...
}
}
You're using the ServiceLocator (anti-pattern) by calling Resolve directly from GetDocuments()
Use inversion of control with constructor injection to pass in the IPrinciple thus:
public class ClassFromOtherAssembly
{
private IPrincipal principal;
public ClassFromOtherAssembly(IPrincipal principal)
{
this.principal = principal;
}
public List<Documents> GetDocuments()
{
//Security check
if (principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}
I have a legacy code, and I have a problem with reconstructor it.
At start of my application I load from WCF to property on App (this is SL application) list of users.
Then every control (for sending emails, view calendar and assigning tasks) use this property as
(App.Current as App).Users
Now, I'm trying to create Unit Test for one of controls that use this lists, and I'm stuck.
Should I make a Constructor Injection(I'm using Unity) with App as parameter? Or maybe introduce some class to hold this list?
Updated with OP's implementation as the pseudocode was incomplete.
I propose create an interface for all your application services
Inject IApplicationService to your modules.
You can use this interface for all the services the application provides(probably you will need more). Mock the interface for the unit tests
OP's implemantation
public interface IApplicationService
{
List<User> Users{get;set;}
}
public class ApplicationService : IApplicationService
{
public List<User> Users
{
get { return (App.Current as App).Users; }
set { (App.Current as App).Users = value; }
}
}
public partial class MainWindow : UserControl
{
readonly IApplicationService _applicationService
public MainWindow(IApplicationService applicationService)
{
_applicationService=applicationService;
}
}
I would create a wrapper class that will expose the list of users. In production code this class will just be a wrapper around your App.Current property and it can be injected in the constructor trough Unity.
In your Unit Tests you can easily mock the App parameter and pass it when constructing a new SUT.
Something like:
public interface IUserList
{
List<User> Users { get; }
}
public class SUT
{
private IUserList UserList { get; set; }
public SUT(IUserList userList)
{
this.UserList = userList;
}
}
public class AppUserList : IUserList
{
public List<User> Users
{
get
{
return ((App)App.Current).Users;
}
}
}
For Silverlight there is an extension model called Application Extension Services.
For infrastructure purposes that might be a better alternative than adding properties to your app class and casting App.Currentback and forth.
Downside of that model is the creation of a singleton you would have to initialize for your unit tests. It would also hide the dependency on Users in your consuming classes.
Your users seem to be just data. Making that data an ambient context which can be accessed and edited everywhere in your application will bite you. You don't know who does what with that data and when he does it. This is like a session state.
So making the dependency on your data explicit would be a first step to be able to track abuse of that data.
If it makes sense to you to create a "data holder object" that has a property for Users or directly inject that data into your consumers is up to you. If there is more data than just Usersit is tempting to put all of them into the same central data store object, even if your specific consumers don't need them.
Jimmy's answer is great, but can be provide quite a bit, and some errors fixed. Differences are explained at the bottom below the code/instructions:
Create a public interface: IUserService
public interface IUserService
{
// Implemented functionality as methods where possible for better
// extendability (like IoC)
IEnumerable<User> Users();
// Add any other user service stuff as you see fit.
void AddUser(User user);
}
Write a UserService that implements IUserService
public class UserService : IUserService
{
// If you need DI for this service, follow the same pattern of using
// fields and controller injection. I left examples in comment below.
// private readonly IRepository _repository;
// Constructor is unnecessary if you do not need DI example.
public UserService(/* IRepository repository */)
{
// _repository = repository;
}
// Methods
public IEnumerable<User> Users()
{
return ((App)App.Current).Users;
}
public void AddUser(User user)
{
((App)App.Current).Users.Add(user);
}
}
Inject IUserService into classes via their Constructor
In this case your MainWindow as an example:
public partial class MainWindow : UserControl
{
private readonly IUserService _userService;
public MainWindow(IUserService userService)
{
_userService = userService;
}
// Example method consuming the service
public IEnumerable<User> GetUsers()
{
return _userService.Users();
}
}
Differences:
Separate your User Services from a central Application Service
Better modularity. In addition I use an IApplicationService for more central/global data like Api Keys, Timeouts, cleanup, DB prepping, etc.
Return IEnumerable<T> instead of List<T>
This is just a golden rule of thumb for keeping things dry and not imposing hard instantiations on your consuming classes. Refactoring is easier/safer, and your code more extensible.
Use methods instead of properties
This is preference, but I think it smart in a service layer to use methods where possible so that you can introduce filters and overloads or continue to use dependency injection - for example, you could add GetUsers(string lastName), GetUsers(string lastName, string firstName) and maintain a clean interface for your consuming classes.
Cast App.Current without the as keyword
This is a good practice because using the as keyword means when the cast fails it will return null, rather than throw an exception. I prefer the exception because 99% of the time, if your cast fails, your next operations will too. :)
Enjoy!