Autofac Getting the current identity - c#

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;
}

Related

How to create a response from a generic class containing HttpContext data in .Net 5 Web API

I've started a new project using .Net 5 (my previous was .Net Framework 4.7). I'm writing a web API project and I want all my controllers/action responses to be of a certain type. This allows me to put some info I want included in every response, such as the current user info (and more stuff too).
My generic response looks like this (I've only left the relevant code):
public class MyResponse<T>
{
public T data { get; set; }
public User user { get; set; }
public MyResponse(T inputData)
{
data = inputData;
}
}
And I set the response on a controller's action this way:
public IActionResult Get()
{
var response = new MyResponse<string>("Hello");
return Ok(response);
}
So the idea is that the response always contains a "data" property with the actual data, and a bunch of other properties with metadata.
The problem is how to include information on the logged in user in .Net 5. In .Net 4.x you could just access HttpContext from anywhere, so you could just populate the User property. But this is not possible in .Net 5
I'm going crazy trying to understand how to achieve this in .Net 5.
The first thing I've tried is DI (which I'm new to, so I might not be understanding this properly).
The first thing I tried is to make my User class depend on IHttpContextAccessor as most documentation points to:
public class User : IIdentity
{
private readonly IHttpContextAccessor _httpContextAccessor;
public User(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
and register it this way on startup.cs:
services.AddHttpContextAccessor();
services.AddTransient<User>();
But that doesn't work well, since when I try to create my User class within MyResponse class:
var user = new User(); // This doesn't work, as the constructor requires one argument
So the constructor requires one argument so I can't create the class like that. I (believe) I would need to create the User from the DI container, but I don't have access to that on MyResponse class (or at least I couldn't really understand how to do it or if possible at all).
I could pass the HttpContext from the controller to MyResponse, but that seems plain wrong (plus, there might be other people writing controllers, so I think it's better if they don't explicitly need to pass that to the response, should be handled transparently)
My concrete questions:
Any thoughts of how can I get hold of the HttpContext within my custom response class?
Should I be looking for an alternative option (such as a Middleware or Filter) to generate my response?
Thank you very much.
You could use a factory along with dependency injection.
Create your user class:
using Microsoft.AspNetCore.Http;
using System.Security.Principal;
public class User : IIdentity
{
private IHttpContextAccessor HttpContextAccessor { get; }
public User(IHttpContextAccessor httpContextAccessor)
{
this.HttpContextAccessor = httpContextAccessor;
}
public string AuthenticationType => this.HttpContextAccessor.HttpContext.User.Identity.AuthenticationType;
public bool IsAuthenticated => this.HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated;
public string Name => this.HttpContextAccessor.HttpContext.User.Identity.Name;
}
Use DI to inject factories with the types you want:
services.AddHttpContextAccessor();
services.AddSingleton(a => GetResponse<string>(a));
services.AddSingleton(a => GetResponse<int>(a));
services.AddSingleton(a => GetResponse<decimal>(a));
Func<T, MyResponse<T>> GetResponse<T>(IServiceProvider serviceProvider)
{
var contextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
var user = new User(contextAccessor);
return (data) => new MyResponse<T>(user, data);
}
Then inject it where you want:
namespace WebAppFiles.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private Func<int, MyResponse<int>> ResponseFactory { get; }
public MyController(Func<int, MyResponse<int>> responseFactory)
{
this.ResponseFactory = responseFactory;
}
[HttpGet]
public IActionResult Get([FromQuery] int value)
{
return Ok(this.ResponseFactory(value));
}
}
}

Provide user information from signalr request in business logic layer using autofac

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.

Circular reference between the services using the Anemic domain model

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
}
}

How to use FluentValidation with LightInject in asp.net web-api project

I'm trying to inject a service using the IoC container into a Validation class. See the example below:
[Validator(typeof(UserPayloadValidator))]
public class UserPayload
{
public int UserId { get; set; }
}
public class UserPayloadValidator : AbstractValidator<UserPayload>
{
private IUserService _userService;
public UserPayloadValidator(IUserService userService)
{
_userService = userService;
RuleFor(x => x.UserId).Must(BeUnique).WithMessage("This user already exists");
}
private bool BeUnique(int userId)
{
var user = _userService.GetUser(userId);
return user == null;
}
}
At this point I was hoping everything would auto-magically work and the userService would be injected into the validation class. Instead, I get an exception complaining about a parameter-less constructor not being found.
After some reasearch I've attempted to create a ValidationFactory as in the example linked.
public class LightInjectValidationFactory : ValidatorFactoryBase
{
private readonly ServiceContainer _serviceContainer;
public LightInjectValidationFactory(ServiceContainer serviceContainer)
{
_serviceContainer = serviceContainer;
}
public override IValidator CreateInstance(Type validatorType)
{
return _serviceContainer.TryGetInstance(validatorType) as IValidator;
}
}
and in the LightInject configuration
//Set up fluent validation
FluentValidationModelValidatorProvider.Configure(httpConfiguration, provider =>
{
provider.ValidatorFactory = new LightInjectValidationFactory(container);
});
This results in an exception:
Unable to resolve type: FluentValidation.IValidator`1
I guess the IoC container doesn't know how to resolve the correct instance for the validator.
Any ideas are much appreciated.
Thanks to the comment above I realized I wasn't actually registering the validator in container. This can be done like this for all the validators:
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
Please note that UserPayloadValidator needs to be just one of your validators. Based on this type, FindValidatorsInAssembly can infer all the other available validators.
Also, in the validation factory you should use TryGetInstance instead of GetInstance in case the factory tries to instantiate non existant validators (parameter in the controller for which validators do not exist)
I have found solution for all validation classes use injected service.
Replace below code
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
With
FluentValidation.AssemblyScanner findValidatorsInAssembly = FluentValidation.AssemblyScanner.FindValidatorsInAssembly(typeof(UserPayloadValidator).Assembly);
foreach (FluentValidation.AssemblyScanner.AssemblyScanResult item in findValidatorsInAssembly)
{
container.Register(item.InterfaceType, item.ValidatorType);
}
Using this your all validator classes use injected service.

Castle.Windsor and dynamic injection using calling method parameters values

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

Categories