1

I'm having trouble using the HttpContext class. I can access HttpContext but can't call it's functions.

I want to use HttpContext.Authentication inside a helper class I'm writing.

I can't write anything like this (see below) inside my helper class:

private void SignInUser()
{
... Code
await HttpContext.Authentication.SignInAsync(..);
}

However, I can access HttpContext inside my controller class.

I'd appreciate any help. Thanks in advance.

tocoolforscool
  • 422
  • 1
  • 9
  • 24
  • 2
    Possible duplicate of [Access HttpContext.Current](http://stackoverflow.com/questions/31243068/access-httpcontext-current) – DavidG Mar 24 '17 at 22:46
  • Are you specifically trying to access user identity? – trevorc Mar 24 '17 at 22:57
  • @trevorc I'm specifically trying to use the SignInAsync method inside of a helper class. – tocoolforscool Mar 24 '17 at 23:01
  • @DavidG Is this answer also relevant to asp.net core? As in am I supposed to be using IHttpContextAccessor? Why can I still use HttpContext.Authentication.SignInAsync in my controller class? – tocoolforscool Mar 24 '17 at 23:03

2 Answers2

3

First create file HttpContext.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace System.Web
{
    public static class HttpContext
    {
        private static IHttpContextAccessor _contextAccessor;

        public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext;

        internal static void Configure(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    }

    public static class StaticHttpContextExtensions
    {
        public static void AddHttpContextAccessor(this IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        }

        public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
        {
            var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
            System.Web.HttpContext.Configure(httpContextAccessor);
            return app;
        }
    }
}

Next in you startup file

public void ConfigureServices(IServiceCollection services)
...
 services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
 services.AddHttpContextAccessor();
...

Finally for example out of controllers, if you need current user name

var currentUsername = !string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
            ? System.Web.HttpContext.Current.User.Identity.Name
            : "Anonymous";

I tested whit ASPNET Core 1.0 and 1.1

EDIT Sorry i forgot in your startup file in section configure add this:

public void Configure(IApplicationBuilder app)
...
app.UseStaticHttpContext();
...
  • Okay awesome I'm about to implement this. What if I was going to write a library to accomplish this same goal? I ask because there isn't a startup file in a library. I understand that you could obviously configure the startup file in the core app that the library is being used inside but what if I didn't want my users to have to do any configurations? Or is this deserving of it's own separate queston? – tocoolforscool Mar 25 '17 at 00:51
  • 1
    For more information about HttpContext recommend [http://www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/](http://www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/) – Jorge Omar Sanchez Mar 25 '17 at 01:09
  • Great answer and reference. Thank you. – tocoolforscool Mar 25 '17 at 01:23
  • Don't use static classes to store context or context accessor, this beats the idea of having a built-in dependency injection in the first place. IHttpContextAccessor should be injected in all classes which require it – Tseng Mar 25 '17 at 09:45
3

If you wannt to use a helper class which signs in a user, you should make an extension method instead, which either wraps around IHttpContextAccessor or HttpContext itself.

public static class HttpContextExtensions 
{
    public static void SignInUser(this HttpContext context)
    {
        await context.Authentication.SignInAsync(..);
    }

    public static void SignInUser(this.IHttpContextAccessor contextAccessor) 
    {
        // Calls the method from above
        contextAccessor.HttpContext.SignInUser();
    }
}

Or if you have a bigger dependency chain and require other injected services, convert it into a injectable class:

public class UserLogonService : IUserLogonService 
{
    private readonly IHttpContextAccessor contextAccessor;

    public UserLogonService(IHttpContextAccessor contextAccessor)
    {
        if(contextAccessor==null)
            throw new ArgumentNullException(nameof(contextAccessor));

        this.contextAccessor = contextAccessor;
    }

    public void SingInUser()
    {
        contextAccessor.HttpContext.SignInUser();
    }
}

and in Startup.Configure method:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IUserLogonService, UserLogonService>();

Now you can inject IUserLogonService everywhere in your project via constructor, i.e.

public class MyController
{
    private readonly IUserLogonService userLogon;

    public MyController(IUserLoggonService userLogon)
    {
        this.userLogon = userLogon;
    }

    public async Task<IActionResult> Login()
    {
        await userLogon.SignInUser();
    }
}

It's clean, decoupled and can easily be unit tested, which you can't do with a static helper class.

Tseng
  • 61,549
  • 15
  • 193
  • 205