.Net Core Use Session in Class - c#

I am using Session in .Net core, However i am able to set and get the Session data in Controller like
HttpContext.Session.SetString("User", "True");
var user = HttpContext.Session.GetString("User");
But when i am trying to use the same code in a concrete class i am not able to do so. It does not show GetString or SetString after HttpContext.Session.
It does not work after
HttpContext.Session
Please help
Thanks

To access session in non-controller class -
First, register the following service in Startup.ConfigureServices
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Now, register a class (example - SessionManager) where you want to access the Session in Startup.ConfigureServices.
services.AddScoped<SessionManager>();
Now, in SessionManager class, add the following code.
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ISession _session;
public SessionManager(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
_session = _httpContextAccessor.HttpContext.Session;
}
The above code is receiving IHttpContextAccessor object through dependency injection and then, it is storing Sessions in a local variable.

That's because HttpContext is a member of Controller, and outside a controller, it's a type name. See Access the current HttpContext in ASP.NET Core how to inject the IHttpContextAccessor into a class and access the session from there.
However, it's generally inadvisable to use the session in a class library. You'd better pass the particular values to your library call. So instead of accessing the settings in the library method, you do:
// controller code
var user = HttpContext.Session.GetString("User");
var libraryResult = _fooLibrary.Bar(user);
HttpContext.Session.SetString("UserResult", libraryResult);

Related

Null reference exception from object

I have an application in asp.net core 2.1. I have registered/injected HttpContextAccessor in startup.cs file as like below.
services.AddHttpContextAccessor();
Also i have created an object for the interface IHttpContextAccessor and initiated that object in the constructor of Dependency injection class "GetScopedServicesTools"
public readonly IHttpContextAccessor HttpContextAccessor;
public GetScopedServicesTools(IHttpContextAccessor _httpContextAccessor)
{
HttpContextAccessor = _httpContextAccessor;
}
I have created an object for the DI class "GetScopedServicesTools" but am not sure what value need to be passed to the constructor of that class.
private GetScopedServicesTools getScopedServices;
Could you please help me what value need to be pass to the constructor of the class "GetScopedServicesTools".
If you want to use that class with and with the DI container, you should also register GetScopedServicesTools with the service provider.
In your Startup.cs you can do services.AddScoped<GetScopedServicesTools>(); and then simply inject it in your controllers or wherever you like.
Note:
I would like to point however that the DI mechanism is already providing out-of-the-box what you're trying to achieve with your GetScopedServicesTools class. You can simply inject the IHttpContextAccessor wherever you like since you already registered it with the service provider with services.AddHttpContextAccessor();. What you're doing with your extra class is an anti-pattern and should be avoided.

Access Session Values in a AddHttpMessageHandler Method

I am trying to create a generic way to add my access token to my outgoing calls in a Razor application. I followed the documentation to add an DelegatingHandler via AddHttpMessageHandler:
services.AddHttpClient("MyName").AddHttpMessageHandler<AddAuthorizationHeaderHandler>();
My handler is called correctly, but I can't find a way to get at the session value that holds the access token (so I can add it as a header).
ASP.Net Core is storing this value in the cookie. In the "code behind" of my page, I can get at the value via HttpContext (a public member of the PageModel class). Like this:
var accessToken = await HttpContext.GetTokenAsync("access_token");
The problem I have is that I can't find a way to get access to this HttpContext in my DelegatingHandler.
How can I get at the session value of access_token in my DelegatingHandler?
Inject IHtpContextAccessor into the delegating handler
private readonly IHttpContextAccessor accessor;
public AddAuthorizationHeaderHandler(IHttpContextAccessor accessor) {
this.accessor = accessor
}
So that you can have access to the context
AddAuthorizationHeaderHandler.SendAsync
//...
var accessToken = await accessor.HttpContext.GetTokenAsync("access_token");
//...
Make sure to register it with the service collection
services.AddHttpContextAccessor();

IHttpContextAccessor contains empty User.Identity, when used outside of the controller

I am writing an app ASP.Net Core (2.2) MVC. I need to filter some the data inside the DbContext by value of certain claims of the Logged in user. I inject IHttpContextAccessor, but when I try to access HttpContext.User.Identity - all properties are null and all claims are empty.
This is how I am trying to achieve that
I wire up IHttpContextAccessor. I use a standard method like that:
public void ConfigureServices(IServiceCollection services){
services.AddHttpContextAccessor();
...
}
Then I build a custom Provider to extract claims from the User:
public class GetClaimsFromUser : IGetClaimsProvider
{
public string UserId {get; private set;}
public GetClaimsFromUser(IHttpContextAccessor accessor)
{
UserId = accessor.HttpContext?.User.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
}
}
Then I also inject it inside ConfigureServices method:
public void ConfigureServices(IServiceCollection services){
...
services.AddScoped<IGetClaimsProvider, GetClaimsFromUser>();
...
}
Afterwards I injected it inside the ApplicationDbContext and try to set the private _userId field inside the constructor:
public class ExpenseManagerDbContext: IdentityDbContext<ApplicationUser>
{
private string _userId;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IGetClaimsProvider claimsProvider) : base(options)
{
_userId = claimsProvider.UserId;
...
}
...
}
And exactly here it is empty. When I access the HttpContext inside the controller, the User.Identity is not empty and everything is fine. However, when I need to access it outside the controller, it is empty.
Thanks for any help!!!
The full code can be found here:
https://github.com/dudelis/expense-manager/blob/master/ExpenseManager.DataAccess/Concrete/EntityFramework/ExpenseManagerDbContext.cs?
You are attempting to access the user in ExpenseManagerDbContext which is the application’s IdentityDbContext. As such, it itself is a dependency of the authentication system and will get resolved when the framework performs the authentication.
So the flow is somewhat like this:
Request comes in.
Authentication middleware runs to authenticate the user.
UserManager resolves ExpenseManagerDbContext.
ExpenseManagerDbContext resolves IGetClaimsProvider.
GetClaimsProvider resolves the HttpContext and attempts to access the user’s claims.
Authentication middleware performs the authentication and sets HttpContext.User with the result.
If you look at steps 5 and 6, you will see that the HttpContext is accessed before the authentication middleware is able to actually authenticate the user and update the user object on the context. And since the authentication middleware always runs at the beginning of a request, this will always be the case.
I would recommend you to rethink your ExpenseManagerDbContext since it probably shouldn’t depend on the currently signed-in user. It should be independent of that. If you have logic there that depends on the user id, then it should probably be a separate service.
Solved!
The problem was in the sharing of the same DbContext for IdentityDbContext and ApplicationDataDbContext.
In my controller I had the following code:
[Authorize]
public class AccountController : Controller
{
[HttpGet]
public IActionResult Index()
{
var accounts = _accountService.GetAll();
var models = _mapper.Map<List<AccountDto>>(accounts);
return View(models);
}
}
And when I tried to call the controller from the browser, the app initialized DbContext first time due to [Authorize] attribute. And this was done without any HttpContext. So when the application made a call to the DbContext in '_accountService.GetAll()', the DbContext was already instantiated and the Constructor method was not called, therefore, all my private fields remained empty!
So I created a second DbContext class only for authentication/authorization purposes.
public class ApplicationDbAuthContext : IdentityDbContext
{
public ApplicationDbAuthContext(DbContextOptions<ApplicationDbAuthContext> options) : base(options)
{
}
}
Due to this, during the request inside the controller the correct DbContext was instantiated when I made a call and it contained the HttpContext.
I will update my code in the repo to show the changes.
Meanwhile, thanks for all the answers.

Using static variables in C# Web Application - Accessing Session variables in class properties

Forgive me for my lack of coding knowledge as well as ability to ask the right question.
I'm rather new to this ASP.Net Web Application thing (Core), yet I still wondered..
In my current application, I have a class that has a property in which it gets it from a static variable, set when a user requests a controller. So the flow is: User sends a request with a variable in body, if not specified in body, the StaticClass.StaticProperty (example) is then set to the variable the user specified in the body (or default = 0), data is returned based upon the variable.
Yet I wondered, since there is no thread guarantee on this variable, whether or not this could be changed or messed up when the web application gets 50,000 requests at once?
I looked into sessions and tried the following:
service.AddSession(); //Not sure this even does anything?
HttpContext.Session.SetString //Setting this works in the controller, but I cant access it elsewhere by GetString
System.Web.HttpContext.Current.Session["test"] // Cant even access System.Web.Httpcontext, doesn't seem to exist.
HttpContext.Current //doesn't exist either
Session["test"] //doesn't exist either
Can I send a session over somewhere? I'm pretty lost.
Not sure if any of this made sense, I'll try to elaborate if needed.
Thank you in advance.
EDIT: Updated info.
I have added this to my startup.cs:
services.AddSingleton();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
and
app.UseSession();
Setting the Session variable:
https://i.imgur.com/CY8rcdk.png
Using the Session variable:
https://i.imgur.com/SuLJKzV.png
Variable is always null.
Thank you for trying to help.
HttpContext is accessible only from things that are request specific, since it's a context of one and only request. And new controller instances are created by the framework for each request, with injected HttpContext. It's the developers job to pass it further if the need arises.
I recommend reading this article about it: https://dotnetcoretutorials.com/2017/01/05/accessing-httpcontext-asp-net-core/
First in your startup.cs, you need to register IHttpContextAccessor as a service like so :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
When you create a helper/service class, you can then inject in the IHttpContextAccessor and use it. It would look like something not too dissimilar to this :
public class UserService : IUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public bool IsUserLoggedIn()
{
var context = _httpContextAccessor.HttpContext;
return context.User.Identities.Any(x => x.IsAuthenticated);
}
}

How to get current user's data in Controller's constructor?

I need to use some current user's data in controller's constructor to initialize repositories, but looks like impossible to get current user's data, because all objects, which can give any data about the user (for example HttpContext or User) is nullable in constructor's area. How can I get needed data inside the constructor or any other way initialize repositories with user's data?
You can use IHttpContextAccessor to access HttpContext in constructor;
public class HomeController : Controller
{
public HomeController(IHttpContextAccessor httpContextAccessor)
{
var httpContext = httpContextAccessor.HttpContext;
}
}
If you are using ASP.NET Core 1.x register IHttpContextAccessor in configure method in startup class and for ASP.NET Core 2.0 I think it is not required.
services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
Why in the constructor?
There are four ways you can get the current user's data in MVC:
You can create a session for the current user's data (preferred)
You can store data in local storage.
Using cookies. But that depends on cookies being allowed in the user's browser.
MVC provides ViewBag. You can pass data by using it.

Categories

Resources