Truy cập httpContext hiện tại trong ASP.NET Core


132

Tôi cần truy cập hiện tại HttpContexttrong một phương thức tĩnh hoặc một dịch vụ tiện ích.

Với ASP.NET MVC cổ điển và System.Web, tôi sẽ chỉ sử dụng HttpContext.Currentđể truy cập vào bối cảnh tĩnh. Nhưng làm thế nào để tôi làm điều này trong ASP.NET Core?

Câu trả lời:


149

HttpContext.Currentkhông còn tồn tại trong ASP.NET Core nhưng có một cái mới IHttpContextAccessormà bạn có thể đưa vào phần phụ thuộc của mình và sử dụng để truy xuất dòng điện HttpContext:

public class MyComponent : IMyComponent
{
    private readonly IHttpContextAccessor _contextAccessor;

    public MyComponent(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public string GetDataFromSession()
    {
        return _contextAccessor.HttpContext.Session.GetString(*KEY*);
    }
}

3
Điểm tốt! Điều đáng nói là IHttpContextAccessorsẽ chỉ khả dụng ở những nơi mà container DI đang giải quyết thể hiện.
tugberk

6
@tugberk, theo lý thuyết, bạn cũng có thể sử dụng CallContextServiceLocatorđể giải quyết một dịch vụ, ngay cả từ một trường hợp không được tiêm DI : CallContextServiceLocator.Locator.ServiceProvider.GetService<IHttpContextAccessor>(). Trong thực tế, đó là một điều tuyệt vời nếu bạn có thể tránh nó :)
Kévin Chalet

17
Không sử dụng CallContextServiceLocator
davidfowl 7/07/2015

9
@davidfowl trừ khi bạn có lý do kỹ thuật hợp lệ (tất nhiên ngoài 'thống kê là xấu xa', tôi cá là mọi người sẽ sử dụng nó nếu họ không có lựa chọn nào khác.
gỗ Kévin

7
Chắc chắn, mọi người hiếm khi có một lý do kỹ thuật hợp lệ mặc dù. Nó giống như dễ sử dụng tĩnh hơn và ai quan tâm đến khả năng kiểm tra :)
davidfowl 7/07/2015

35

Necromance.
CÓ BẠN CÓ THỂ
Mẹo bí mật cho những người di cư lớntháng sáuchunk (thở dài, trượt Freud) của mã.
Phương pháp sau đây là một kẻ tấn công độc ác của một vụ hack đang tích cực thực hiện công việc nhanh của satan (trong mắt các nhà phát triển khung .NET Core), nhưng nó hoạt động :

Trong public class Startup

thêm một tài sản

public IConfigurationRoot Configuration { get; }

Và sau đó thêm một IHttpContextAccessor vào DI trong ConfigureService.

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();

Sau đó, trong Cấu hình

    public void Configure(
              IApplicationBuilder app
             ,IHostingEnvironment env
             ,ILoggerFactory loggerFactory
    )
    {

thêm tham số DI IServiceProvider svp, vì vậy phương thức này trông như sau:

    public void Configure(
           IApplicationBuilder app
          ,IHostingEnvironment env
          ,ILoggerFactory loggerFactory
          ,IServiceProvider svp)
    {

Tiếp theo, tạo một lớp thay thế cho System.Web:

namespace System.Web
{

    namespace Hosting
    {
        public static class HostingEnvironment 
        {
            public static bool m_IsHosted;

            static HostingEnvironment()
            {
                m_IsHosted = false;
            }

            public static bool IsHosted
            {
                get
                {
                    return m_IsHosted;
                }
            }
        }
    }


    public static class HttpContext
    {
        public static IServiceProvider ServiceProvider;

        static HttpContext()
        { }


        public static Microsoft.AspNetCore.Http.HttpContext Current
        {
            get
            {
                // var factory2 = ServiceProvider.GetService<Microsoft.AspNetCore.Http.IHttpContextAccessor>();
                object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));

                // Microsoft.AspNetCore.Http.HttpContextAccessor fac =(Microsoft.AspNetCore.Http.HttpContextAccessor)factory;
                Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
                // context.Response.WriteAsync("Test");

                return context;
            }
        }


    } // End Class HttpContext 


}

Bây giờ trong Cấu hình, nơi bạn đã thêm IServiceProvider svp, lưu nhà cung cấp dịch vụ này vào biến tĩnh "ServiceProvider" trong lớp giả vừa tạo System.Web.HttpContext (System.Web.HttpContext.ServiceProvider)

và đặt HostingEn Môi trường. Lưu trữ thành đúng

System.Web.Hosting.HostingEnvironment.m_IsHosted = true;

đây thực chất là những gì System.Web đã làm, chỉ là bạn chưa bao giờ thấy nó (tôi đoán biến được khai báo là nội bộ thay vì công khai).

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    ServiceProvider = svp;
    System.Web.HttpContext.ServiceProvider = svp;
    System.Web.Hosting.HostingEnvironment.m_IsHosted = true;


    app.UseCookieAuthentication(new CookieAuthenticationOptions()
    {
        AuthenticationScheme = "MyCookieMiddlewareInstance",
        LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Unauthorized/"),
        AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("/Account/Forbidden/"),
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        CookieSecure = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest

       , CookieHttpOnly=false

    });

Giống như trong ASP.NET Web-Forms, bạn sẽ nhận được NullReference khi bạn đang cố truy cập vào một HTTPContext khi không có, chẳng hạn như nó đã từng tồn tại Application_Starttrong global.asax.

Tôi nhấn mạnh một lần nữa, điều này chỉ hoạt động nếu bạn thực sự thêm

services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();

như tôi đã viết bạn nên
Chào mừng bạn đến với mẫu ServiceLocator trong mẫu DI;)
Đối với các rủi ro và tác dụng phụ, hãy hỏi bác sĩ nội trú hoặc dược sĩ của bạn - hoặc nghiên cứu các nguồn của .NET Core tại github.com/aspnet và thực hiện một số thử nghiệm.


Có lẽ một phương pháp dễ bảo trì hơn sẽ là thêm lớp người trợ giúp này

namespace System.Web
{

    public static class HttpContext
    {
        private static Microsoft.AspNetCore.Http.IHttpContextAccessor m_httpContextAccessor;


        public static void Configure(Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor)
        {
            m_httpContextAccessor = httpContextAccessor;
        }


        public static Microsoft.AspNetCore.Http.HttpContext Current
        {
            get
            {
                return m_httpContextAccessor.HttpContext;
            }
        }


    }


}

Và sau đó gọi httpContext.Configure trong Khởi động-> Cấu hình

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();


    System.Web.HttpContext.Configure(app.ApplicationServices.
        GetRequiredService<Microsoft.AspNetCore.Http.IHttpContextAccessor>()
    );

37
ĐÂY LÀ PURE EVIL
Nghệ thuật

2
Là phiên bản với phương thức trợ giúp hoạt động đúng trong từng kịch bản. Suy nghĩ về đa luồng, không đồng bộ và với các dịch vụ trong bộ chứa IoC với tuổi thọ khác nhau?
Tamas Molnar

7
Tôi biết tất cả chúng ta phải cố gắng chỉ ra điều này thật tệ hại như thế nào ... Nhưng nếu bạn đang chuyển một dự án lớn sang Core, trong đó, HTTPContext. Hiện tại đã được sử dụng trong một số lớp tĩnh khó tiếp cận .. Điều này có lẽ sẽ khá hữu ích. Ở đó, tôi đã nói nó.
Brian MacKay

2
Đây là điều ác thuần túy ... và thích hợp là tôi sẽ thực hiện nó vào Halloween. Tôi yêu DI và IoC ... nhưng tôi đang xử lý một ứng dụng kế thừa với các Lớp tĩnh ác với các biến tĩnh ác, rằng chúng tôi cần đẩy mạnh sử dụng Kestrel và cố gắng tiêm httpContext sẽ không thể xóa được đối với chúng tôi, mà không phá vỡ mọi thứ.
Nhà của Dexter

2
Ya, đây là câu trả lời chính xác cho MIGRATION. ;)
Tom Stickel

23

Chỉ cần thêm vào các câu trả lời khác ...

Trong ASP.NET 2.1 lõi, có các AddHttpContextAccessorphương pháp khuyến nông , đó sẽ đăng ký IHttpContextAccessorvới thời gian tồn tại đúng:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpContextAccessor();

    // Other code...
}

2
Vui mừng khi thấy một sự thay thế chính thức hơn cho carbuncle Satan!
Ken Lyon

@Ken Lyon :;) khellang: Singleton là trọn đời chính xác. Phạm vi sẽ là sai. Hoặc ít nhất là tại thời điểm viết, đó là như vậy. Nhưng tất cả sẽ tốt hơn nếu AddHttpContextAccessor thực hiện chính xác mà không cần chúng tôi cần một tài liệu tham khảo cho phiên bản khung cụ thể.
Stefan Steiger

Bạn có thể vui lòng chia sẻ một ví dụ?
Bộ công cụ

@Toolkit Đã thêm một số mã ví dụ. Tuy nhiên, không chắc chắn giá trị nó cung cấp qua văn bản trên.
khellang

22

Cách hợp pháp nhất mà tôi đã đưa ra là bằng cách tiêm IHttpContextAccessor vào triển khai tĩnh của bạn như sau:

public static class HttpHelper
{
     private static IHttpContextAccessor _accessor;
     public static void Configure(IHttpContextAccessor httpContextAccessor)
     {
          _accessor = httpContextAccessor;
     }

     public static HttpContext HttpContext => _accessor.HttpContext;
}

Sau đó, việc gán IHttpContextAccessor trong Startup Configure sẽ thực hiện công việc.

HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());

Tôi đoán bạn cũng cần phải đăng ký dịch vụ singleton:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Xinh đẹp. Chỉ cần những gì bác sĩ đã ra lệnh!
ShrapNull

5

Theo bài viết này: Truy cập HTTPContext bên ngoài các thành phần khung trong ASP.NET Core

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

Sau đó:

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

Sau đó:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticHttpContext();
        app.UseMvc();
    }
}

Bạn có thể sử dụng nó như thế này:

using System.Web;

public class MyService
{
   public void DoWork()
   {
    var context = HttpContext.Current;
    // continue with context instance
   }
}

2

Khởi nghiệp

services.AddHttpContextAccessor();

Trong bộ điều khiển

public class HomeController : Controller
    {
        private readonly IHttpContextAccessor _context;

        public HomeController(IHttpContextAccessor context)
        {
            _context = context; 
        }
        public IActionResult Index()
        {
           var context = _context.HttpContext.Request.Headers.ToList();
           return View();
        }
   }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.