ASP.NET MVC에서 WebActivator를 사용해 보자

- Bootstraper 기능

 이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다.

ing™       



 WebActivator는 ASP.NET이 IIS에서 로드가 되기 전에 미리 필요한 초기화 작업을 개발자의 명시없이 진행할 수 있는 방안을 제시해 주고 있다. 더군다나 다른 개발자가 배포한 참조 DLL에서 초기화를 해야 하는 경우에도 WebActivator가 암시적으로 초기화를 할 수 있도록 할 수 있다. 우선 사용하기 위해서는 Nuget에서 WebActivator로 검색해서 설치를 하도록 하자. 아래 그림을 참고로 설치를 하자


[그림1] WebActiviator 검색

(Install 버튼을 눌러 설치를 한다.)


[그림2] WebActivator 설치



 이제 프로젝트에 WebActivator이 설치가 되었다. 이제 프로젝트 아무데서나 BootStrapper.cs(필자가 임의로 만들었다) 파일을 생성해 아래 코드와 같이 입력해 보자.


[코드1] Activator 실행 코드


 위 소스코드에서 1, 2, 3번줄을 살펴 보자. 

- [assembly: WebActivator.PreApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PreStart")] : 최초 Web Server가 실행 할 때  Application Start가 되기 전에 실행 됨

- [assembly: WebActivator.PostApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PostStart")] : 최초 Web Server가 실행 되고 나서 Application End가 되고 나서 실행 됨

- [assembly: WebActivator.ApplicationShutdownMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "Shutdown")] : Web Server가 종료되기 전에 실행 됨


 클래스 위에서 위와 같이 선언하여 사용할 수 있으며 자신이 작성한 코드의 초기화나 종료를 암시적으로 실행시킬 수 있으며 다른 개발자가 배포한 모듈에서 필요한 초기화를 WebActivator를 통해서도 초기화를 진행할 수 있다. 이 기능을 이용해서 Global.asax 파일이나 Web.Config 파일에 집중되어 있던 초기화 작업에 대해서 암시적으로 실행할 수 있는 길이 열렸다. 자세한 사용 기능을 "코드1"에 있는 주석을 읽어 보도록 하자.


소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략하도록 하겠습니다. 포스트의 내용이 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 하기 위해 노력하였습니다. 실 개발에서도 적용할 수 있도록 간단하면서도 현실적인 예제 프로그램을 통해 각 소스를 만들고 이해 시키고자 하였으며 실무에 필요한 개발요구 사항들을 해결 하는데 도움이 되고자 노력하였습니다. 그리고 소스와 같이 있는 주석을 이용해 nDoc이나 별도의 자동 Document 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다. 
※ DOC에 대한 프로그램 정보 Util link

ing™       


C# ASP.NET MVC 세션 동시 접근 테스트

http://msdn.microsoft.com/ko-kr/library/system.web.sessionstate.sessionstatebehavior.aspx


 ASP.NET MVC에서 서버 객체에서 세션 값을 동시적으로 접근 하였을 경우 처리하는 방법에 대해 알아 보자. 일반적인  컨트롤러에서 세션에 접근하면 thread unsafe 상태에서 세션의 값을 수정하게 되어 있다. 예로 "코드1"번 처럼 같은 사용자의 세션에서 접근하여 값을 수정하거나 삭제를 할 수 있다.

//세션에 저장
Session["testSerialCallValue"= "Value";

[코드1] 세션 객체 수정


 위와 같은 코드에서는 ajax를 통해 동시 다발적으로 처리를 수행 하는 케이스에서는 기대하는 수행 결과가 나오지 않을 수도 있다. 다음과 같은 코드가 오류가 발생할 수 있는 케이스이다.

Session["incValue"= ((int.Parse(Session["incValue"].ToString())) + 1).ToString();

[코드2] 세션 객체 수정 ( 오류가 발생 할 수 있는 케이스 )


 이와 같은 케이스에서는 Controller 클래스에서 아래와 같은 Attribute를 추가해 줌으로써 해결이 가능 하다.

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

[코드3] 세션 객체 컨트롤 Attribute


 이제 키워드를 알았으니 예제를 통해 전체 흐름을 알아 보자.( SessionStateBehavior 알아 보기 )



<script type="text/javascript">
    var start = '';
    $(function () {
        //ajax cache 옵션 해제
        //$.ajaxSetup({ async: false });    //ajax 1.9.1에서 fale로 지정하면 server controller에 상관 없이 순차적으로 ajax calling 진행
        start = new Date().getTime();
 
        //SessionStateBehavior.ReadOnly 
        //동시 호출 테스트 - 병렬 수행 케이스
        for (var i = 1; i <= 3; i++) {
            $.ajax('SessionConcurrentParallel/GetParallelCall' + i, {
                cache: false
            }).done(logParallel);
        }
 
        //SessionStateBehavior.Required
        //동시 호출 테스트 - 순차 수행 케이스
        for (var i = 1; i <= 3; i++) {
            $.ajax('SessionConcurrentSerial/GetSerialCall' + i, {
                cache: false
            }).done(logSerial);
        }
    });
 
    function logParallel(data, stateText, responseObject) {
        console.log(['Parallel', data, stateText, responseObject, start, new Date().getTime()]);
    }
 
    function logSerial(data, stateText, responseObject) {
        console.log(['Serial', data, stateText, responseObject, start, new Date().getTime()]);
    }
</script>

[코드4] 웹 페이지에서 ajax를 통해 동시적으로 controller 호출 하기


 "코드4"에서와 같은 코드로 첫번째 ajax 호출은 서버 컨트롤러에서 병렬로 Session 객체에 접근할 수 있는 액션을 호출 하고, 두번째 ajax 호출은 Session 객체를 순차적으로만 접근 하도록 되어 있는 컨트롤러의 액션을 호출 하도록 구성 하였다. 이제 이 코드에 상응하는 컨트롤러를 구성해 보자.

[SessionState(System.Web.SessionState.SessionStateBehavior.Required)]
[OutputCache(NoStore = trueDuration = 0VaryByParam = "*")]
public class SessionConcurrentSerialController : Controller
{
    #region Serial Call processing test
    public JsonResult GetSerialCall1()
    {
        //세션에 저장
        Session["testSerialCallValue"= "Value";
        Thread.Sleep(3000);
        return Json(new { obj = "SeriallCall1 Value #1" }, JsonRequestBehavior.AllowGet);
    }
 
    public JsonResult GetSerialCall2()
    {
        //세션에 저장
        Session["testSerialCallValue"= "Value";
        Thread.Sleep(3000);
        return Json(new { obj = "SeriallCall1 Value #2" }, JsonRequestBehavior.AllowGet);
    }
 
    public JsonResult GetSerialCall3()
    {
        //세션에 저장
        Session["testSerialCallValue"= "Value";
        Thread.Sleep(3000);
        return Json(new { obj = "SeriallCall1 Value #3" }, JsonRequestBehavior.AllowGet);
    }
    #endregion
}

[코드5] 순차적 Session 객체 접근


[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
[OutputCache(NoStore = trueDuration = 0VaryByParam = "*")]
public class SessionConcurrentParallelController : Controller
{
    //
    // GET: /SessionConcurrent/
 
    public ActionResult Index()
    {
        Session["testValue"= "TempValue";
        Session["incValue"= ((int.Parse(Session["incValue"].ToString())) + 1).ToString();
 
        return View();
    }
 
    #region Parallel Call processing test
    public JsonResult GetParallelCall1()
    {
        //세션에서 읽기
        var x = Session["testParallelCallValue"];
        Thread.Sleep(3000);
        return Json(new { obj = "GetParallelCall1 Value #1" }, JsonRequestBehavior.AllowGet);
    }
 
    public JsonResult GetParallelCall2()
    {
        //세션에서 읽기
        var x = Session["testParallelCallValue"];
        Thread.Sleep(3000);
        return Json(new { obj = "GetParallelCall1 Value #2" }, JsonRequestBehavior.AllowGet);
    }
 
    public JsonResult GetParallelCall3()
    {
        //세션에서 읽기
        var x = Session["testParallelCallValue"];
        Thread.Sleep(3000);
        return Json(new { obj = "GetParallelCall1 Value #3" }, JsonRequestBehavior.AllowGet);
    }
    #endregion
}

[코드6] 병렬로 Session 객체 접근


 컨트롤러 선언시 클래스 선언부에서 "SessionState"의 Attribute를 선언하여 Session 접근 유형을 패턴을 정의 하였으며 Index 액션과 연결된 웹 페이지에서 ajax를 통해 테스트할 수 있는 뷰 페이지를 연결 하였다.


 이제 아래 그림을 통해 결과를 확인해 보도록 하자.


[그림1] 컨트롤러의 액션 로딩 타임


 "그림1"에서와 같이 Parallel 형식으로 선언된 컨트롤러의 액션 호출은 일률적인 시간으로 완료가 되었으나 Serial 형식으로 접근하도록 선언된 컨트롤러 액션은 순차적으로 처리가 되어 총 처리 시간이 3s * 3회인 9초가 걸린 결과가 나왔다. 세션을 사용할 때 동시성 처리에 대한 처리를 Attribute를 통해서 컨트롤 할 수 있도록 해주는 방안을 ASP.NET MVC에서 제공해 주고 있는 것이다. 다만 예외적으로 "그림2"와 같은 결과가 나올 수 있다.


[그림2] 컨트롤러 액션 로딩 타임 - ajax request limit에 따른 결과


 "그림2"와 같은 결과가 나오게 되는 케이스는 브라우저마다 한번에 ajax콜을 할 수 있는 connection 수가 제한 되어 있기 때문이다. 브라우저(버전에 따라 다름) 마다 2 ~ 6개 정도를 지원하도록 되어 있어서 측정 수치는 달라질 수 있다. 필자와 같은 케이스로 결과값이 나오기를 바란다면 최신 브라우저로 테스트를 해 보기를 바란다.



 이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다.

ing™       


C# WriteSubstitution - OutputCache


웹을 개발하는데 있어서 캐시를 적절히 사용하면 웹 서버의 성능을 비약적으로 끌어 올릴 수 있다.

 

아래와 같이 특정 액션이 자원을 많이 소모하여 얻어낸 결과를 사용자가 요청할 때마다 얻어와야 하는 곳에서 OutputCache Attribute를 사용함으로써 선택적으로 캐시를 사용할 수 있다.

위와 같이 설정이 되면 10초 동안 서버에서는 캐시 된 정보를 반환하도록 되어 있다.

 

그렇지만 캐시가 되어 있는 상황에서도

일부 데이터는 갱신되어야 하는 시나리오가 있을 수 있을 것이다.

이럴 때 사용할 수 있는 방안 중에 Response.WriteSubstitution를 소개하도록 하겠다.

 

@ViewBag.Time : 서버에서 캐시 된 값을 Duration 시간 동안 출력한다.

@{ Response.WriteSubstitution((context) => DateTime.Now.ToString()); } : 캐시 된 Content에서도 요청 시 마다 새로운 값을 출력이 되도록 해주는 메소드 ( Action 메소드를 통해 delegate를 구현하였다. )

 

위와 같이 설정하고 아래 화면에서 확인해 보도록 하자.

첫번째 형광색 표시가 WriteSubstitution으로 출력된 값이고

두번째 형광색 표시가 캐시 된 값을 보여주고 있다.

C# ASP.NET MVC 4에서 CommonServiceLocator.WindsorAdapter 사용하여 IoC 세팅


이전 포스트에서 Windsor를 이용해서 IoC를 세팅하는 방법을 소개하였다.

(2013/01/25 - [ASP.NET MVC] - [IoC & DI]ASP.NET MVC 4에서 Windsor (Castle)로 IoC로 Controller 생성)

이전 방법은 Windsor IoC에 대해서 Dependency하게 세팅하는 방법으로 다른 종류의 IoC를 세팅하기 위해서는 다른 접근 전략을 세워야만 했었다.

그렇지만 CommonServiceLocator을 사용하면 아래와 같은 IoC에 상관없이 일관되게 프로젝트에서 접근하고 사용할 수 있다.

- NInject

- Windsor

- MEF

- Unity

- StructureMap

- … ( ETC )

 

우선 CommonServiceLocator의 Open Source를 알려 주도록 하겠다.

http://commonservicelocator.codeplex.com/ : CommonServiceLocator URL

다음으로 이번에 같이 소개할 WindsorAdapter ( CommonServiceLocator을 사용할 수 있도록 도와주는 Extended Adapter )

https://github.com/yellowfeather/CommonServiceLocator.WindsorAdapter

 

이번 포스트에서는 WindosrAdapter을 사용하여 ASP.NET MVC 4에서 Controller 생성하도록 하겠다.

이제 Visual Studio에서 해당 DLL을 추가하면 된다.

Tip!
다른 IoC를 CommonServiceLocator Adapter해서 구현해 놓은 라이브러리가 있다.

Castle Windsor Adapter

Spring .NET Adapter

Unity Adapter

StructureMap Adapter

Autofac Adapter

MEF Adapter now on .NET Framework 4.0

LinFu Adapter

Multi-target CSL binaries

 

Visual studio에서 Nuget을 통해 CommonServiceLocator.WindsorAdapter을 프로젝트에 추가한다.

추가하였으면

다음 클래스를 작성하기 바란다.

파일명 : CommonServiceLocatorControllerFactory.cs

/// <summary>
/// CommonServiceLocator을 이용해서 DefaultControllerFactory를 구현한다.
/// </summary>
public class CommonServiceLocatorControllerFactory : DefaultControllerFactory
{
    /// <summary>
    /// 인스턴스된 Controller를 가져온다.
    /// </summary>
    /// <param name="requestContext">Request Context</param>
    /// <param name="controllerType">Typeof Controller</param>
    /// <returns>Controller object</returns>
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        //controllerType이 있으면
        if (controllerType == null)
            return base.GetControllerInstance(requestContext, controllerType);

        //ServiceLocator에  파라메터를 넘겨서 IController를 가져오도록 한다.
        return ServiceLocator.Current.GetInstance(controllerType) as IController;
    }
}

 

이제 Global에서 수정하면 IoC가 세팅이 될 것이다.

파일명 : Global.asax

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

 

//Windosr Container을 세팅한다.
//FromAssembly.This()를 실행하면  ControllersInstaller ( IWindsorInstaller 구현 클래스 )에 정의된 범위에서 Instance시킨다.
container = new WindsorContainer().Install(FromAssembly.This());

//ServiceLocator에 Provider을 등록한다.
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));
//ASP.NET MVC Framework에 ControllerFactory를 세팅한다.
ControllerBuilder.Current.SetControllerFactory(typeof(CommonServiceLocatorControllerFactory));

        }
    }

 

위와 같이 수정하고 실행해 보도록 하자.

정상적으로 페이지가 나오는 것을 확인할 수 있을 것이다.

 

그렇지만 의문이 들 것이다.

내가 세팅한 ServiceLocator가 작동이 된 것인지 아니면 기본적인 설정으로 된 것인지 알 수 없기 때문이리라.

그리하여 직접 Debug 모드에서 확인해 보도록 하겠다.

아래와 같이 CommonServiceLocatorControllerFactory.cs파일에서 return되기 직전에 breakpoint를 걸어 보도록 하겠다.

이제 F5를 눌러 실행시켜 보자.

페이지가 호출 될 때마다 해당 Controller 찾는 시도를 한다는 것을 알 수 있을 것이다.

그래서 이제는 정상적으로 동작하고 있다는 것을 확실 할 수 있을 것이다.

 

Tip!

CommonServiceLocator을 사용하기 위해서는 Windsor이 온전하게 동작을 한 상태에서 ServiceLocator을 연결해야 한다.

예로 Windsor IoC에서 Register을 이용해 어떤 DLL(범위 확정)에서 어떤 타입의 객체를 인스턴스 시켜줘야 하는지에 대한 작업이 필요 하다

이 작업은 IWindsorInstaller을 상속하여 구현한 클래스에 정의 되어 있다.

 

2013/01/25 - [ASP.NET MVC] - [IoC & DI]ASP.NET MVC 4에서 Windsor (Castle)로 IoC로 Controller 생성



BootStrapper.cs


 

ASP.NET MVC를 실행 할 때 Global.asax 파일에서 일부 설정 파일을 적용토록 하는 작업을 해 보았을 것이다.

ASP.NET MVC 4에서는 기본적으로는 아래와 같이 간소화 되어 Global.asax의 Application_Start()로 만들어 두었다.

파일명 : Global.asax

protected void Application_Start()
{
     AreaRegistration.RegisterAllAreas();

     WebApiConfig.Register(GlobalConfiguration.Configuration);
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
     RouteConfig.RegisterRoutes(RouteTable.Routes);
     BundleConfig.RegisterBundles(BundleTable.Bundles);
     AuthConfig.RegisterAuth();

}

위에서 Web API 설정, 필터 설정, 라우트 설정 등등 여러 가지 설정을 MVC Framework에 제공하는 기능으로 대체 하여 MVC의 기본 Configuration을 지정하였다.

그리고 무엇보다 중요한 기능은 외부 라이브러리를 추가하여(DLL 참조) 사용할 때 그 라이브러리의 환경 변수를 개발자가 설정하지 않고 기본 값을 자체적으로 설정하여 Default Behavior를 갖도록 할 수 있다는 것이다.

 

그렇지만 사용자가 임의의 수정하거나 변경을 하기 위해서는 Global.asax파일이 지저분 해지도록 할 수 밖에 없지만

지금 소개하는 WebActivator 라이브러리를 이용하면 파일 구조나 깊이에 상관없이 설정 또는 Business logic을 할 수 있다.

 

이제 본격적으로 소개하도록 하겠다.

“WebAativator”를 Nuget에서 검색하여 프로젝트에 추가한다.

그런 다음 아래와 같이 소스를 추가한다.

파일명 : /App_Start/BootStrapper.cs

( 임의로 BootStrapper.cs로 명명 하였다 )
오른쪽 그림과 같이 파일 추가                                                       

[assembly: WebActivator.PreApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PreStart")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PostStart")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "Shutdown")]

namespace TDDMVCTest.App_Start
{
    public static class BootStrapper
    {
        private static IWindsorContainer container;

        /// <summary>
        /// 최초 Web Server가 실행 할 때  Application Start가 되기 전에 실행 됨
        /// </summary>
        public static void PreStart() {

            //Business logic or configuration job
            var temp = string.Empty;
        }

        /// <summary>
        /// 최초 Web Server가 실행 되고 나서 Application End가 되고 나서 실행 됨
        /// </summary>
        public static void PostStart()
        {

            //Business logic or configuration job
            var temp = string.Empty;
        }

        /// <summary>
        /// Web Server가 종료되기 전에 실행 됨
        /// </summary>
        public static void Shutdown()
        {

            //Business logic or configuration job
            var temp = string.Empty;
        }
    }
}

위 실행 순서는 IHttpModule 상속하여 구현된 ActivationManager.cs에서 실행을 하며 전체 DLL을 읽어 들여 실행이 되게 하는 구조로 되어 있다.

- 클래스 명이나

- 네임 스페이스가 다름

- 외부 라이브러리로 선언

위와 같아도 Web Server가 실행이 되면 실행이 되는 구조다.

 

Tip !

    WebActivator.ActivationManager.RunPreStartMethods();
    WebActivator.ActivationManager.Run();
    WebActivator.ActivationManager.RunPostStartMethods();
    WebActivator.ActivationManager.RunShutdownMethods();

    위 메소드 실행으로 Activator 단계를 임의로 실행 할 수 있다.

    궁금하면 한번 테스트 해보기 바란다.

 

Tip !

    바로 이전 IoC 컨테이너 속성을 Activator을 이용해 초기화를 할 수도 있을 것이다. 바로 아래에 예시를 달도록 하겠다.

   2013/01/25 - [ASP.NET MVC] - ASP.NET MVC 4에서 Windsor (Castle)로 IoC로 Controller 생성 - 참조


using System;
using System.Web.Mvc;
using TDDMVCTest.Core;
using Castle.Windsor;
using Castle.Windsor.Installer;

[assembly: WebActivator.PreApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PreStart")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "PostStart")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(TDDMVCTest.App_Start.BootStrapper), "Shutdown")]

namespace TDDMVCTest.App_Start
{
    public static class BootStrapper
    {
        private static IWindsorContainer container;

        /// <summary>
        /// 최초 Web Server가 실행 할 때  Application Start가 되기 전에 실행 됨
        /// </summary>
        public static void PreStart() {
            container = new WindsorContainer().Install(FromAssembly.This());

            var controllerFactory = new WindsorControllerFactory(container.Kernel);
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        }

 

       ……..

    }

}


ASP.NET MVC 4에서 Windsor (Castle)로 IoC로 Controller 생성


Visual studio에서 Nuget을 통해 Windsor을 프로젝트에 추가한다.

위 그림은 Online에서 ‘Windsor’로 검색한 결과다.

 

Tip! - Windsor ver 3.1.0 – 2012.08.15

 

정상적으로 References에 참조 등록이 된 것을 확인하고

아래 파일을 추가한다.

 

파일명 : WindsorControllerFactory.cs
(DefaultControllerFactory를 상속받아 Windsor을 이용해 객체를 생성하는 기능을 구현한다)

    public class WindsorControllerFactory : DefaultControllerFactory
    {
        private readonly IKernel kernel;

        public WindsorControllerFactory(IKernel kernel)
        {
            this.kernel = kernel;
        }

        public override void ReleaseController(IController controller)
        {
            kernel.ReleaseComponent(controller);
        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
            }

            return (IController)kernel.Resolve(controllerType);
        }
    }

 

파일명 : ControllersInstaller.cs
(어떤 Assembly에서 어떤 객체를 IoC 해줄지를 등록한다)

    public class ControllersInstaller : IWindsorInstaller
    {

        public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
        {
            container.Register(Classes.FromThisAssembly()
                                        .BasedOn<IController>()
                                        .LifestyleTransient());
        }
    }

 

위의 파일을 만든 다음

Global.asax 파일을 아래와 같이 수정한다.

파일명 : Global.asax.cs
( 컨테이너를 MVC Framework에 끼워 넣는다 )

    public class MvcApplication : System.Web.HttpApplication
    {
        private static IWindsorContainer container;

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

            container = new WindsorContainer().Install(FromAssembly.This());

            var controllerFactory = new WindsorControllerFactory(container.Kernel);
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        }
    }

 

위와 같이 WindsorControllerFactory를 Global.asax 파일에 연결 시켰으면 이제 실행해 보도록 하자.

 

Ctrl + F5 –> 실행

위와 같이 화면을 정상적으로 보여주고 있다.

 

이제 이 프로젝트는 IoC 컨테이너(Windsor)를 통해 Controller 객체를 생성하여 실행이 되는 구조로 바뀐 것이다.

Web API - JSONP 호출 반환


Web API는 기본적으로 JSONP를 지원하지 않는다.


JSONP를 지원하기 위해서는 Fomatter를 추가하여 아래와 같이 해결 할 수 있습니다.


설정 파일


[코드] JSONP로 변환해주도록 설정 함




Business Logic


[코드] JSONP로 변환해주는 코드



HTML 코드


[코드] HTML에서 Javascript로 호출하여 확인하는 코드




위와 같이 세팅하면

Asp.net MVC 4에서 JSONP 형식으로 리턴이 된다.




http://blogs.msdn.com/b/dancre/archive/2006/10/11/datamodel-view-viewmodel-pattern-series.aspx


http://blog.quantumbitdesigns.com/tag/dm-v-vm/



MVVM과 비슷하면서도 Data Model에 중점을 둔 패턴


말하자면 DM-V-VM



기타 Link

http://robbbloggg.blogspot.kr/search/label/DM-V-VM

http://joel.inpointform.net/software-development/mvvm-vs-mvp-vs-mvc-the-differences-explained/


MVVM, MVC과 MVP에 대한 차이점을 설명해 주고 있다.

+ Recent posts