ASP.NET Core Middleware

ASP.NET Core Middleware 는 모든 요청과 응답을 처리하는 파이프라인이다. 레거시 ASP.NET 과 ASP.NET MVC 에서는 이를 IHttpModuleIHttpHandler를 통해 구현하여 처리하거나, Global.asax.cs 에서 처리 가능하다.

IHttpModule 이 주로 사용되는 경우는 권한 처리 등과 같이 다양하게 사용된다. 모든 요청은 이 IHttpModule을 파이프라인을 통과하게 되고, 응답을 제어할 수 있기 때문이다.

이 파이프라인이 오늘에 와서 ASP.NET Core Middleware 에서 그 역할을 대신하게 된다.

- 레거시에서 파이프라인

최초 레거시 ASP.NET 은 ‘ASP.NET 파이프라인’은 최초 요청부터 마지막 응답까지 컨텍스트가 흐르는 순서가 있다. 이것이 IIS 7.0 부터 IIS 서버와 통합이 되었다.

아래 그림은 IIS 7.0의 응용 프로그램 생명주기(즉 파이프라인)이다.

Application Lifecycle
https://msdn.microsoft.com/en-us/library/bb470252.aspx

- ASP.NET Core Middleware

ASP.NET Core 는 크로스플랫폼을 지향하는데, IIS 는 마이크로소프트 윈도우에서만 실행 가능한 웹/응용프로그램 서버이다. 따라서 ASP.NET Core 를 크로스플랫폼에서 호스팅하려면 IIS 서버에서 적용되었던 파이프라인 개념을 버려야 했다. 그래서 나온 개념이 Middleware 다.

Middleware 또한 IHttpModule이 수행하는 요청과 응답을 제어하는 역할을 한다.


https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware

다만, Global.asax.cs 에서 Session 생성/소멸과 같은 이벤트를 Middleware 만으로는 세세하게 제어하지 못한다. 아마도 다른 접근 포인트가 있는지 좀 찾아봐야 겠다.

IHttpMoudle과 IHttpHandler 마이그레이션

자세한 마이그레이션 과정이 MSDN 문서에 훌륭하게 설명되어 있어서 링크로 대체하고, 간단한 샘플만 남긴다.

참고로 Middleware는 UseMvc() 메서드 이전에 남겨야 한다. 그렇지 않으면, Middleware 가 동작하지 않는다.

Startup.cs
public class Startup
{

    // 생략...

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

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseApplicationInsightsExceptionTelemetry();
        app.UseStaticFiles();

        // 미들웨어 등록
        app.UseMiddleware<FrameworkMiddleware>();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

    }
}
FrameworkMiddleware.cs
public class FrameworkMiddleware
{
    private readonly RequestDelegate next;

    public FrameworkMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        Console.WriteLine("==========================================");
        await next(context);
        Console.WriteLine("------------------------------------------");
    }
}



자세한 내용은 아래 링크를 방문하기 바란다.
https://docs.microsoft.com/en-us/aspnet/core/migration/http-modules

Posted by 땡초 POWERUMC

댓글을 달아 주세요

IControllerFactory

IControllerFactory 는 컨트롤러 객체를 반환하거나 객체 릴리즈 시키는 팩토리 인터페이스이다. ASP.NET MVC 4 까지 지원하지 않았던 DI(Dependency Injection) 기능을 사용하기 위해 이 인터페이스를 구현하여 사용하였다.

ASP.NET Core 에서는 객체 주입(Injection) 할 때 한 가지 큰 단점이 있다.

생성자 주입(Constructor Injection) 으로만 DI(Dependency Injection) 기능을 사용할 수 있다. 이 방법은 필자가 가장 좋아하지 않는 방법인데, 그 사용성이 여간 귀찮을 수 없다.

이 아티클에서는 프로퍼티 인젝션(Property Injection) 이 가능한 Unity Application Block 을 사용하기 위해 IControllerFactory 를 마이그레이션 하는 것을 목표로 한다.

- 레거시 ASP.NET MVC 에서 IControllerFactory 설정

Controller 클래스들을 IoC(Inversion of Control) 컨테이너(Container) 에 담아 놓고, 꺼내쓸 때 DI(Dependency Injection) 을 시키는 방식이다. 이렇게 하면 사용하는 입장에서는 복잡한 객체와 인스턴스 관계를 파악할 필요 없이 꺼내 쓰면 되는 것이다. 당연 단위 테스트에서도 간결하게 사용할 수 있게 된다.

global.asax.cs

ControllerBuilder 클래스를 이용하여 IControllerFactory 인스턴스를 설정한다.

// 종속성 주입 설정
Application.Lock();
{
    Container = configureContainer();
    ControllerBuilder.Current.SetControllerFactory(new FrameworkControllerFactory(Container));
}
Application.UnLock();

FrameworkControllerFactory.cs

public class FrameworkControllerFactory : DefaultControllerFactory
{
    private readonly IFrameworkContainer container;

    public FrameworkControllerFactory(IFrameworkContainer container)
    {
        this.container = container;
    }

    #region Overrides of DefaultControllerFactory

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            requestContext.HttpContext.Response.Redirect("/", true);
        }

        var controller = container.Resolve(controllerType);
        return controller as IController;
    }

    #endregion
}

- ASP.NET Core 에서 IControllerFactory 설정

ASP.NET Core 에서는 상당수 서비스 클래스와 인스턴스들이 IoC Container 에 등록되어 여기에서 객체를 불러 사용하고 있는 형태다. IServiceCollection 인터페이스에 서비스에 ASP.NET Core 가 동작하기 위한 코어 클래스들이 등록되어 있다.

IServiceCollection 에 Singleton 객체로 services.AddSingleton<IControllerFactory, FrameworkControllerFactory>(); 하게되면 IControllerFactory 가 등록된다.

그럼 IServiceCollection 에는 IControllerFactory 가 두 개 등록이 되어있는데, 나머지 하나가 DefaultControllerFactory 클래스이다. 이 때, ASP.NET Core는 가장 마지막에 등록된 IControllerFactory 클래스를 반환한다.

먼저, Nuget 을 통해 Unity Application Block 을 설치한다.

Startup.cs

public class Startup
{
    public static IUnityContainer Container = new UnityContainer();

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);
        services.AddMvc();

        // IControllerFactory 설정
        services.AddSingleton<IControllerFactory, FrameworkControllerFactory>();
    }
}

FrameworkControllerFactory.cs

public class FrameworkControllerFactory : IControllerFactory
{
    public object CreateController(ControllerContext context)
    {
        return Startup.Container.Resolve(context.ActionDescriptor.ControllerTypeInfo.AsType());
    }

    public void ReleaseController(ControllerContext context, object controller)
    {
    }
}

모든 설정이 다 되었으면, Unity Container 에서 DI(Dependency Injection) 을 수행하는 HomeController 가 정상적으로 동작하게 된다.

HomeController.cs

public class HomeController : Controller
{
    [Dependency]
    public MessageService MessageService { get; set; }

    public IActionResult Index()
    {
        MessageService.Say();

        return View();
    }
}

public class MessageService
{
    public void Say()
    {
        Console.WriteLine("MessageService Resolved. ===========================");
    }
}


Posted by 땡초 POWERUMC

댓글을 달아 주세요