ASP.NET Core에서도 HttpContext.Current 사용할 수 있도록 시도했습니다.

이전 이런 기사을 썼을 때 ASP.NET Core에서의 개발에서 힘든 일 중 하나로, 'HttpContext.Current 없음 했습니다!

아무튼 실제로 없어도 개인적으로는 거기까지 곤란한 일도 없었습니다만, 수요 따위 있는 것일까 하는 일을 말하면 @neuecc 선생님



AspNetCoreCurrentRequestContext



라는 이름의 라이브러리를 만들었습니다.

패키지는 NuGet, 소스는 Github에서 공개합니다.
  • NuGet - AspNetCoreCurrentRequestContext
  • Github - ttakahari/AspNetCoreCurrentRequestContext

  • 사용법



    NuGet에서 패키지를 설치합니다.
    PM > Install-Package AspNetCoreCurrentRequestContext
    

    ASP.NET Core 응용 프로그램 프로젝트에 패키지 참조를 추가한 후 Startup 클래스의 Configure 메서드에서 IApplicationBuilderCurrentRequestContextMiddleware 를 추가합니다.

    표준으로 확장 메소드를 준비하고 있으므로 그것을 사용하는 것이 편합니다.
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            // ミドルウェアを追加
            app.UseCurrentRequestContext();
        }
    }
    

    미들웨어를 추가할 수 있으면 나중에 좋아하는 부분에서 HttpContext.Current 를 부를 뿐이라고 하고 싶은 곳입니다만 현재의 .NET 언어의 기능에 정적 프로퍼티를 확장하는 기능이 없기 때문에, 새롭게 AspNetCoreHttpContext 라고 하는 클래스 를 준비하고 있습니다.

    이 클래스의 Current라는 정적 속성을 호출하여 이전 ASP.NET과 마찬가지로 현재 요청의 HttpContext를 가져올 수 있습니다.
    using AspNetCoreCurrentRequestContext; // using追加は必須!!
    
    public class Foo
    {
        public string GetRequestUrl()
        {
            // このプロパティで現在のHttpContextを取得できる
            var context = AspNetCoreHttpContext.Current;
    
            return context.Request.Path.Value;
        }
    }
    

    다만 CurrentRequestContextMiddleware 뒤에 추가된 미들웨어에서는 언제라도 AspNetCoreHttpContext.CurrentHttpContext 를 취득할 수 있습니다만, 그것보다 전에 추가된 미들웨어내에서는 취득할 수 없다는 것에 주의해 주세요.

    내부 구현



    내부 구현도 매우 간단하고 실제의 코드행수는 100행도 없습니다.

    @neuecc 님이 작성한 OWIN에서 사용할 수있는 HttpContext.Current 라이브러리CallContext 라는 같은 실행 컨텍스트를 가지는 thread간에 데이터를 공유할 수 있는 클래스를 사용해 구현하고 있었습니다만, .NET Core용 라이브러리의 corefx CallContext 가 없으므로 사용할 수 없습니다.

    대신 .NET Framework 4.6에서 추가된 AsyncLocal<T>라는 클래스를 사용하고 있습니다.

    AsyncLocal<T> 는 thread 단위의 스토리지로서 사용할 수가 있습니다.

    하위 스레드가 파생된 경우에도 상위 스레드의 저장소를 참조할 수 있으며 하위 스레드에서 값을 다시 작성한 경우 하위 스레드의 저장소만 다시 작성되어 상위 스레드의 스토리지에 영향을 미치지 않습니다.
    public class Program
    {
        public static void Main(string[] args)
        {
            var storage = new AsyncLocal<int>();
    
            storage.Value = 1;
    
            Console.WriteLine($"Parent - {storage.Value}"); // 1
    
            new Thread(_ =>
            {
                Console.WriteLine($"Child - {storage.Value}"); // 1
            }).Start();
    
            new Thread(_ =>
            {
                storage.Value = 2;
    
                Console.WriteLine($"Child - {storage.Value}"); // 2
            }).Start();
    
            Console.WriteLine($"Parent - {storage.Value}"); // 1
    
            Console.ReadLine();
        }
    }
    

    AspNetCoreCurrentRequestContext 에서는 CurrentReuqestContextMiddlewareAspNetCoreHttpContext 안에 보관 유지되고 있는 AsyncLocal<HttpContext> 의 변수에 값을 대입하고 있어 이후는 그 변수의 값을 돌려주도록 하고 있습니다.

    요약



    AspNetCoreCurrentRequestContext를 사용하면 요청의 통계 및 요청 중에 만 캐시하고 싶은 값의 상호 작용이 쉬워질 것입니다.

    지금까지 ASP.NET에서 HttpContext.Current에 의존하고 있었기 때문에 ASP.NET Core에 벽을 느끼고 있던 분들도 ASP.NET Core 애플리케이션의 신규 작성, 또는 기존의 마이그레이션의 장애물이 내려주면 무엇보다입니다.

    좋은 웹페이지 즐겨찾기