[Windows Programming/Prism] - [Prism] 들어가며...

[Windows Programming/Prism] - [Prism] 1. Introduction


잘못 작성되어 있는 부분이나 매끄럽지 않은 부분 대해서 Feedback을 주시면 반영토록 하겠습니다. 감사합니다.


2: Initializing Applications Using the Prism Library 5.0 for WPF 


 이 주제는 WPF 응용프로그램이 동작하기 위해 Prism을 취하는데 필요한 것이 무엇인지 언급합니다. 응용프로그램의 시작시 Prism 응용프로그램은 등록과 설정을 필요로 합니다 - 이는 응용프로그램을 부트스트래핑 하는 것으로 알려져 있습니다. Prism 부트스트랩 절차는 모듈 카탈로그를 만들고 설정, Unity같은 의존성 주입 컨테이너를 생성, UI구성에 대한 기본 리전 어댑터를 구성, 쉘 뷰를 만들고 초기화, 그리고 모듈들을 초기화하는 것을 포함하고 있습니다.


부트스트래퍼란? (What Is a Bootstrapper?)

 부트스트래퍼는 Prism 라이브러리를 사용하여 구축된 응용프로그램의 초기화를 담당하는 클래스 입니다. 부트스트래퍼를 사용함으로써, Prism 라이브러리 구성요소가 당신의 응용프로그램에 연결되는 방법을 더 잘 다룰 수 있습니다. (you have more control of how the Prism Library components are wired up to your application.) Prism 라이브러리는 어느 컨테이너와도 사용하기 위해 특화 될 수 있는 기본적인 추상 부트스트래퍼 기초 클래스(abstract Bootstrapper base class)를 포함하고 있습니다. 부트스트래퍼 클래스들의 메서드들의 상당수는 가상 메서드 입니다. 당신은 사용자 정의 부트스트래퍼 구현에 적절하도록 이 메서드들을 오버라이드(override) 할 수 있습니다.



Basic stages of the bootstrapping process

[ 부트스트래핑 절차의 기본 단계 (Basic stages of the bootstrapping process) ]



 Prism 라이브러리는 부트스트래퍼로 부터 파생되어 대부분의 응용프로그램에 적합한 기본적인 구현체들 가지고 있는 몇가지 추가 기본 클래스들을 제공합니다. 당신의 응용프로그램 부트스트래퍼를 위해서 구현까지 남은 유일한 단계들은 쉘을 만들고 초기화 하는 것입니다.


의존성 주입 (Dependency Injection)

 Prism 라이브러리로 개발된 응용프로그램은 컨테이너가 제공하는 의존성 주입을 필요로 합니다. 라이브러리는 Unity Application Block (Unity) 또는 Mananged Extensibility Framework (MEF)와 동작하는 어셈블리들을 제공하며, 이는 당신이 다른 의존성 주입 컨테이너들을 사용 할 수 있도록 합니다.부트스트랩 절차의 일부는 이러한 컨테이너를 설정하고 컨테이너와 함께한 형식을 을 등록하는 것 입니다. Prism 라이브러리는 UnityBootStrapper 와 MefBootstrapper 클래스를 포함하며, 이들은 당신의 응용프로그램에서 의존성 주입 컨테이너로써 Unity나 MEF를 사용하는데 필요한 대부분의 기능이 구현되어 있습니다. 이전의 그림에서 보여주는 단계에 추가하여, 각각의 부트스트래퍼는 그것들의 컨테이너를 특정화하는 몇몇 단계들을 추가 합니다.

쉘 만들기 (Creating the Shell)

 기존의 Windows Presentation Foundation (WPF) 응용프로그램의 경우, 시작 Uniform Resource Identifiuer (URI)는 주 화면을 실행하는 App.xaml 파일에 지정되어 있습니다.


Prism 라이브러리로 만든 응용프로그램은, 쉘이나 주 화면을 만드는 것은 부트스트래퍼의 책임입니다. 쉘은 쉘이 표시되기 전에 등록되어야 하는 ,리전 관리자 같은, 서비스에 의존하기 때문입니다.


주요 결정 (Key Decisions)

응용프로그램에서 Prism 라이브러리를 사용을 결정 한후에, 추가로 결정해야할 몇가지 들이 있습니다.

    • 당신의 의존성 주입 컨테이너를 위해서 MEF, Unity, 혹은 또다른 컨테이너를 사용할지 결정해야 합니다. 이는 당신이 사용할 부트스트래퍼가 어떤것인며 당신이 다른 컨테이너에 대해 부트스트래퍼 작성여부를 결정 할 것입니다.
    • 응용프로그램에서 당신이 원하는 응용프로그램 특정 서비스에 대해서 생각해보아야 합니다. 해당 서비스는 컨테이너에 등록해야 합니다.
    • 내장 로깅 서비스가 당신의 필요에 적합한지 다른 로깅 서비스를 제작하는게 필요한지 결정하세요.
    • 응용프로그램이 어떻게 모듈을 탐색할지 결정하세요: 명시적 코드 선언, 디렉토리 검색을 통해 발견된 코드 속성, 설정, 혹은 XAML

남은 주제들은 좀더 자세한 정보를 제공합니다.


핵심 시나리오 (Core Scenarios)

시작 시퀀스를 작성하는 것은 Prism 응용프로그램 구축에 중요한 한 부분입니다.

이 섹션에서는 부트스트래퍼를 작성하고 쉘을 작성하기 위해 사용자 정의 하는 것, 의존성 주입 컨테이너를 설정,  응용프로그램 수전의 서비스들을 등록, 그리고 모듈을 불러오고 초기화하는 방법에 대해서 설명합니다.


당신의 응용프로그램을 위한 부트스트래퍼 만들기 (Creating a Bootstrapper for Your Application)

Unity나 MEF를 의존성 주입 컨테이너로써 사용을 택했다면, 응용프로그램을 위한 간단한 부트스트래퍼만드는 것은 쉽습니다. MefBootStrapperUnityBootstrapper로 부터 상속한 새로운 클래스를 만들어야 합니다. 그후, CreateShell 메서드를 구현하세요. 선택적으로, 쉘 특정 초기화를 위해 InitializeShell 메서드를 오버라이드 할 수도 있습니다.


CreateShell 메서드 구현하기 (Implementing the CreateShell Method)

CreateShell메서드는 개발자가 Prism응용프로그램의 취상위 윈도우를 지정 할수 있습니다. 쉘은 보통 MainWindowMainPage입니다.

응용프로그램의 쉘 클래스의 인스턴스를 반환하여 이 메서드를 구현하세요. Prism응용프로그램에서, 응용프로그램 요구사항에 따라서 당신은 쉘 객체를 만들거나, 컨테이너로부터 요구사항을 해결 할 수 있습니다.


아래 코드 예제에서 쉘 객체를 해결하기 위해 ServiceLocator를 사용하는 예를 보여줍니다.


protected override DependencyObject CreateShell()
{
    return ServiceLocator.Current.GetInstance<Shell>();
}


Note:

당신은 종종 ServiceLocator가 특정 의존성 주입 컨테이너대신의 타입들의 인스턴스를 해결하는데 사용되기도 하는걸 볼 수 있습니다. ServiceLocator는 컨테이너를 호출 함으로써 구현됩니다, 그래서 컨테이너 사용없는 코드에 대해서 좋은 선택입니다. 당신은 직접 참조할수 있고 ServiceLocator대신 컨테이너를 사용할 수도 있습니다.


InitializeShell 메서드 구현하기 (Implementing the InitializeShell Method)

당신은 쉘을 만든 다음에, 쉘이 표시될 준비가 되었다는 것을 확인하기 위한 초기화 단계를 실행 해야 합니다. 아래에 보이는 것처럼 (from the Modularity QuickStarts for WPF), WPF 응용프로그램을 위해, 당신은 쉘 응용프로그램 객체를 만들고 응용프로그램의 주 윈도우로써 설정할 것입니다.


protected override void InitializeShell()
{
    Application.Current.MainWindow = Shell;
    Application.Current.MainWindow.Show();
}

InitializeShell의 기본적의 구현은 아무것도 하지 않습니다. 기본 클래스 구현을 호출하지 않는 것에 안전합니다.


모듈 카탈로그 작성 및 구성하기 (Creating and Configuring the Module Catalog)

 모듈 응용프로그램을 만드는 중이라면, 모듈 카탈로그를 작성하고 설정해야합니다. Prism은 응용프로그램에 어떤 모듈이 이용가능한 지, 어떤 모듈들이 다운로드 되어야 하는지, 어느곳에 상주해야 하는지에 대한 추적을 유지 위해 구체 IModuleCatalog 인스턴스를 사용합니다. 


 부트스트래퍼는 가상 CreateModuleCatalog 메소드의 기본 구현체뿐만 아니라 카탈로그를 참조할 protected ModuleCatalog 속성을 제공합니다.

기본 구현체는 새로운  ModuleCatalog를 반환해줍니다; 하지만, 대신에 WPF의 빠른 시작을 위해 MEF의 모듈화에서 QuickStartBootstrapper 부터 다음의 코드를 보여주는 것처럼 이 메소드는 다른 IModuleCatalog 인스턴스를 제공하기 위해 재정의 할 수 있습니다.


protected override IModuleCatalog CreateModuleCatalog()
{
    // When using MEF, the existing Prism ModuleCatalog is still
    // the place to configure modules via configuration files.
    return new ConfigurationModuleCatalog()
}

UnityBootstrapper 와 MefBootstrapper class 두개 모두, Run메소드는 CreateModuleCatalog 메소드를 호출하고 반환된 값을 사용하여 클래스의 ModuleCatalog 속성을 설정합니다. (In both the UnityBootstrapper and MefBootstrapper classes, the Run method calls the CreateModuleCatalog method and then sets the class's ModuleCatalog property using the returned value.) 이 메소드를 재정의 한다면, 제공된 기능을 대체 할 것이므로 기반 클래스의 구현체를 호출할 필요가 없습니다. 모듈화에 대한 더 많은 정보는, "Modular Application Development"를 보시기 바랍니다.


컨테이너 작성 및 구성하기 (Creating and Configuring the Container)

컨테이너는 Prism 라이브러리로 만들어진 응용프로그램에서 핵심 역할을 합니다. Prism 라이브러리와 이 위에 작성된 응용프로그램들은 요구되는 의존성들 주입과 서비스들을 위한 컨테이너에따라 달라집니다. (Both the Prism Library and the applications built on top of it depend on a container for injecting required dependencies and services.) 컨테이너 구성 단계에서, 몇몇 핵심 서비스들이 등록되어 있습니다. 핵심 서비스들에 이외에, 구성요소 관한 추가적인 기능을 제공하는 응용프로그램 특정 서비스를 취할 수 있습니다.

핵심 서비스 (Core Services)

다음 표는 Prsim 라이브러리에서 핵심 비 응용프로그램 특정 서비스들을 나열합니다.


 Service Interface

 설명

 IModuleManager

 응용 프로그램의 모듈들을 검색하고 초기화하는 서비스를 위한 Interface를 정의합니다.

 IModuleCatalog 

 응용프로그램에서의 모듈에 대한 메타 데이터를 포함합니다. Prism 라이브러리는 여러가지 다른 카탈로그들을 제공합니다.

 IModuleInitializer 

 모듈들을 초기화 합니다.

 IRegionManager 

 배치를 위한 시각적 컨테이너인 리전들을 등록하고 검색합니다.

 IEventAggregator 

 발행자와 구독자사이의 느슨한 결합인 이벤트들의 모음(collection)입니다.

 ILoggerFacade 

 로깅 메카니즘에 대한 래퍼입니다. 그래서 당신이 가진 로깅 메카니즘을 선택할 수 있습니다. 당신의 로거(logger)를 사용하  는 방법의 예로써, 주식 거래 참고 구현 (Stock Trader RI)가 EnterpriseLibraryLoggerAdapter class를 통해서 Enterprise  Library Logging Application Block을 사용합니다. CreateLogger 메소드가 반환한 값을 사용하는 부트스트래퍼의 Run메소드  의해서 로깅 서비스는 컨테이너에 등록됩니다.

 컨테이너와 함께 다른 로거(logger)를 등록하는 것은 동작하지 않을 것입니다; 대신 부트스트래퍼의 CreateLogger 메소드를  재정의 하십시요.

 IServiceLocator 

 Prism 라이브러리가 컨테이너에 접근토록 합니다. 라이브러리를 사용자 정의 혹은 확장하고 싶을 경우 유용할 수 있습니다.


응용프로그램 특정 서비스 (Application-Specific Services)

 다음 표는 Stock Trader RI에서 사용되는 응용프로그램 특정 서비스들을 나열하고 있습니다. 당신의 응용프로그램에서 제공할 서비스들의 타입들을  이해하기위한 예로써 사용할수 있습니다.


 Services in the Strock Trader RI

 설명

 IMarketFeedService

 실시간 (모의) 시장 자료를 제공합니다. PositionSummaryViewModel 은 이 서비스로부터 수신한 알림에 기초하여 화면 위치를 갱신합니다.

 IMarketHistoryService

 선택한 기금에 대한 추세선을 표시하는데 사용되는 역사적인 시장 자료를 제공합니다.

 IAccountPositionService

 포트폴리오 내의 펀드 목록을 제공합니다.

 IOrdersService

 제출한 판매/구매 주문을 계속합니다.

 INewsFeedService

 선택된 펀드에 대한 새로운 항목의 목록을 제공합니다.

 IWatchListService

 새로운 아이템이 감시 목록에 추가 될 경우를 다룹니다.


 Prism에서 이용 가능한 두개의 부트스트래퍼 파생 클래스가 있습니다. UnityBootstrapper 와 MefBootstrapper 입니다. 다른 컨테이너를 작성 하고 구성하는 것은 다르게 구현된 유사한 개념을 포함하고 있습니다. (Creating and configuring the different containers involve similar concepts that are implemented differently.)


UnityBootStrapper에서 컨테이너를 작성 및 구성하기 (Creating and Configuring the Container in the UnityBootstrapper)

 UnityBootstrapper 클래스의 CreateContainer 메소드는 간단하게 UnityContainer  새로운 인스턴스를 만들고 반환 합니다. 대부분의 경우에서, 이 기능들을 바꿀 필요가 없을 것입니다; 그러나, 이 메소드는 가상이므로 유연성있게 합니다.


컨테이너가 만들어진 후, 응용프로그램을 위해 구성해야 합니다. 여기에서 보여주는 것 처럼, UnityBootstrapper 에서 ConfigureContainer 구현은 기본적으로 많은 수의 핵심 Prism서비스들 등록합니다.



Note:

이는 모듈이 초기화 메소드에서 모듈-레벨 서비스를 등록할 때의 예제 입니다.


// UnityBootstrapper.cs protected virtual void ConfigureContainer() { ... if (useDefaultConfiguration) { RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true); RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true); RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true); RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true); RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);

RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);

RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);

RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);

RegisterTypeIfMissing(typeof(IRegionNavigationJournalEntry), typeof(RegionNavigationJournalEntry), false);

RegisterTypeIfMissing(typeof(IRegionNavigationJournal), typeof(RegionNavigationJournal), false);

RegisterTypeIfMissing(typeof(IRegionNavigationService), typeof(RegionNavigationService), false);

RegisterTypeIfMissing(typeof(IRegionNavigationContentLoader), typeof(UnityRegionNavigationContentLoader), true);

} }

 부트스트래퍼의 RegisterTypeIfMissing 메소드는 서비스가 이미 등록 되어 있는지 판별합니다 - 이는 두번 등록하지 않도록 합니다. 이는 당신이 구성을 통해 기본 등록(default registration)을 재정의 할 수 있도록 합니다. 또한 기본적으로 모든 서비스를 등록 해제 할 수 있습니다; 이를 하기위해, false로 통과하는 오버로드된 Bootstrapper.Run 메소드를 사용하세요. ConfigureContainer 메소드를 재정의 하고, 이벤트 event aggregator 같이 사용을 원치 않는 서비스들을 비활성화 할 수 있습니다.



Note:

만약 기본 등록(default registration)을 해제한 경우, 수동으로 필요한 서비스들을 등록해야 합니다.


 ConfigureContainer 의 기본 행위를 확장하려면, 단순히 응용프로그램의 부트스트래퍼에 재정의를 추가하고 다음에서 보여주는 것 같이 선택적으로 기본 구현체를 호출하세요. the Modularity for WPF (with Unity) QuickStart 의 QuickStartBootstrapper 로부터 온 코드입니다.

이 구현부는 기초 클래스의 구현부를 호출하고, IModuleTracker의 구제적 구현부로서 ModuleTracker형식을 등록하고, Unity와 함께 CallbackLogger의 싱글톤 인스턴스로써 callbackLogger를 등록합니다.


protected override void ConfigureContainer()
{
    base.ConfigureContainer();

    this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true);
    this.Container.RegisterInstance<CallbackLogger>(this.callbackLogger);
}

MefBootstrapper에서 Container 작성 및 구성하기 (Creating and Configuring the Container in the MefBootstrapper)

 MefBootstrapper 클래스의 CreateContainer 메소드는 여러가지 작업을 수행합니다. 첫번째로, AssemblyCatalog 와 CatalogExportProvider를 생성합니다. The CatalogExportProvider allows the MefExtensions assembly to provide default exports for a number of Prism types and still allows you to override the default type registration. 그런다음 CreateContainerCatalogExportProvider를 사용해서 CompositionContainer의 새로운 인스턴스를 생성하고 반환합니다. 대부분의 경우, 이 기능들을 변경할 필요가 없습니다; 그러나, 이 메소드는 가상이므로, 유연성을 가집니다.


 해당 컨테이너가 생성된 후에, 응용프로그램에 대한 구성을 해야 합니다. 다음의 예제 코드에서 보여주듯이, MefBootstrapperConfigureContainer 구현부는 기본적으로 많은수의 Prism 핵심 서비스들을 등록합니다.

If you override this method, consider carefully whether you should invoke the base class's implementation to register the core Prism services, 

이 메소드를 재정의 하거나 당신의 구현부에서 Prism 핵심 서비스들을 제공할 것이라면, Prism 핵심 서비스들을 등록하는 기본 클래스의 구현부를 호출할지의 여부를 신중하게 고려해야 합니다.


protected virtual void ConfigureContainer()
{
    this.RegisterBootstrapperProvidedTypes();
}

protected virtual void RegisterBootstrapperProvidedTypes()
{
    this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
    this.Container.ComposeExportedValue<IModuleCatalog>(this.ModuleCatalog);
    this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
    this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
}


Note:

MefBootstrapper에서, Prism의 핵심 서비스들은 싱글톤들로써 컨테이너에 추가 되어 그들은 응용프로그램 전체에서 컨테이너를 통해 위치할 수 있습니다.


 CreateContainer 와 ConfigureContainer를 제공하는 것 뿐 아니라, MefBootstrapper는 MEF가 사용하는 AggregateCatalog를 작성하고 구성하기 위한 두개의 메소드역시 제공하고 있습니다. CreateAggregateCatalog는 간단히 AggregateCatalog 객체를 생성하고 반환합니다. MefBootstrapper의 다른 메소드들과 같이, CreateAggregateCatalog는 가상이며 필요하면 재정의 할 수 있습니다. ConfigureAggregateCatalog 메소드는 당신이 AggregateCatalog에 형식 등록을 추가 할수 있도록 합니다. 예를 들어, Modularity with MEF QuickStart 의 QuickStartBootstrapper는 아래에서 보는것 처럼 AggregateCatalog에 ModuleA 와 ModuleC를 명쾌하게 추가하고 있습니다.


protected override void ConfigureAggregateCatalog()
{
    base.ConfigureAggregateCatalog();
    // Add this assembly to export ModuleTracker
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(QuickStartBootstrapper).Assembly));
    // Module A is referenced in in the project and directly in code.
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleA.ModuleA).Assembly));
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleC.ModuleC).Assembly));

    // Module B and Module D are copied to a directory as part of a post-build step.
    // These modules are not referenced in the project and are discovered by inspecting a directory.
    // Both projects have a post-build step to copy themselves into that directory.
    DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules");
    this.AggregateCatalog.Catalogs.Add(catalog);
}


'Windows Programming > Prism' 카테고리의 다른 글

[Prism] 1. Introduction  (0) 2016.09.07
[Prism] 들어가며...  (0) 2016.09.07

+ Recent posts