UWP

Prism으로 시작하는 UWP app 개발 part1

 

 

https://www.youtube.com/watch?v=5ysX1LTaF_s&list=PLC3dVya3Ez_dtw9AVyUgvjMI8Gca4N5UM&index=1

 

 

Prism으로 시작하는 UWP app 개발 Part1-14.pdf

 

https://github.com/kaki104/PrismSample2019

 


 

 

  1. Prism으로 시작하는 UWP app 개발 part1
  2. Prism으로 시작하는 UWP app 개발 part2
  3. Prism으로 시작하는 UWP app part3 – 데이터 조회
  4. Prism으로 시작하는 UWP app Part4 – DataGrid
  5. Prism으로 시작하는 UWP app Part5 – View에서 ViewModel로
  6. Prism으로 시작하는 UWP app Part6 – 상세 페이지 구현
  7. Prism으로 시작하는 UWP app Part7 – 검색과 CommandBar 구현
  8. Prism으로 시작하는 UWP app Part8 – Prism 화면 레이어와 Popup
  9. Part9 – Visual Studio 2019로 업그레이드 & WebView
  10. WebView에서 JavaScript 연동
  11. WebView – Async, EventAggregator
  12. UWP에서 Script 직접 호출과 팝업 처리
  13. Cookie 관리, Prism으로 시작하는 UWP app Part13
  14. UnityContainer – Prism으로 시작하는 UWP app part 14
  15. UnityContainer Detail & Examples – Prism으로 시작하는 UWP app part 15 – 1
  16. UnityContainer Detail & Examples – Prism으로 시작하는 UWP app part15-2

 

# 단축키
prop 탭 탭     // 프로퍼티 자동 생성
Ctrl + K + F      // 들여쓰기와 라인 자동 맞춤

 

# 마이크로소프트 스토어에서 다운
Windows Community Toolkit Sample App

 


 

# Windows Template Studio 를 이용하지 않고 새 페이지 만들기.

 

  1. Constants/PageTokens.cs -> 페이지 이름 추가
  2. Strings/en-US/Resources.resw -> Shell_페이지이름.Content : 페이지 이름 추가
  3. 새로 만든 페이지의 xaml 파일에 네임스페이스 추가

xmlns:prismMvvm=”using:Prism.Windows.Mvvm”
prismMvvm:ViewModelLocator.AutoWireViewModel=”True”

 

 


 

1강. Prism으로 시작하는 UWP app 개발 part1

 

# Windows Template Stuio 설치
Extensions – Manage Extensions -> Windows Template Studio

# New Project – Windows Template Studio
– Navigation Pane
– Pages – Master/Detail and Web View

 


 

2강. Prism으로 시작하는 UWP app 개발 part2

 

# 페이지 추가 2가지 방법
Views 폴더 – Add – New Item – XAML – Blank Page
오른쪽 프로젝트 패널 – Windows Template Studio – New Page

# Deploy 먼저 하라는 메시지가 뜰 때
Build – Configuration Manager 에서 Build와 Deploy 를 체크해준다.

# ShellPage.xaml 에 네비게이션 뷰 컨트롤이 있다.

 


 

# 프로젝트명- Windows Template Studio – New Page – Blank Page

 

<Grid Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}">
    <TextBlock Text="{Binding HelloText}" FontSize="50" HorizontalAlignment="Center" VerticalAlignment="Top"/>
    <Button Content="Click me!" FontSize="40" HorizontalAlignment="Center" VerticalAlignment="Bottom" Command="{Binding ClickMeCommand}"/>
</Grid>

 

 

public class SampleViewModel : ViewModelBase
{
    private string _helloText;

    public SampleViewModel()
    {
        Init();
    }

    private void Init()
    {
        ClickMeCommand = new DelegateCommand(OnClickMeCommand);
        HelloText = "Hello UWP World!!";
    }

    private void OnClickMeCommand()
    {
        HelloText = "UWP 세계에 오신것을 환영 합니다.";
    }

    public ICommand ClickMeCommand { get; set; }

    public string HelloText
    {
        get => _helloText;
        set => SetProperty(ref _helloText, value);
    }
}

 

 


 

3. Prism으로 시작하는 UWP app part3 – 데이터 조회

 

 

# omdb api 키 받아오기

https://www.omdbapi.com/

 

# 사용법

http://www.omdbapi.com/?s=batman&apikey={apikey}

 

# 프로젝트명.Core 프로젝트 -> Models 폴더에 클래스 파일 하나 만들기

1. 위에서 나온 결과를 복사하기
2. Edit – Paste Special – Paste JSON as Classes
3. JSON 이 클래스로 붙여넣기 되는데 아래와 같이 잘 정리한다.

 

 

// Core 프로젝트의 Rootobject.cs
using Newtonsoft.Json;
namespace UwpApp3.Core.Models
{
    public class SearchRoot
    {
        public Search[] Search { get; set; }
        [JsonProperty(PropertyName = "totalResults")]  // 실제로는 totalResults 이나 C# 네이밍 규칙 맞추기 위해서..
        public string TotalResults { get; set; }
        public string Response { get; set; }
    }

}

// Core 프로젝트의 Search.cs
using Newtonsoft.Json;
namespace UwpApp3.Core.Models
{
    public class Search
    {
        public string Title { get; set; }
        public string Year { get; set; }
        [JsonProperty(PropertyName = "imdbID")] 
        public string ImdbID { get; set; }
        public string Type { get; set; }
        public string Poster { get; set; }
    }

}

 

 

# DataGrid 페이지 추가
프로젝트명 – Windows Template Studio – New Page
DataGrid (이름: Movie)

# Settings Storage 기능 추가
프로젝트명 – Windows Template Studio – New feature
Settings Storage 추가   // JSON 기능이 추가됨

 

 

public class MovieViewModel : ViewModelBase
{
    public MovieViewModel()
    {
    }

    public override async void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
    {
        await GetMoviesAsync();
    }

    private async Task GetMoviesAsync()
    {
        using (var client = new HttpClient())
        {
            var result = await client.GetStringAsync("http://www.omdbapi.com/?s=batman&apikey={apikey}");
            if (string.IsNullOrEmpty(result)) return;

            var search = await Json.ToObjectAsync<SearchRoot>(result);
            if (search == null) return;
        }
    }
}

 

 


Json 데이터 클래스로 만들기

Edit – Paste Special – Paste JSON As Classes

Windows Template Studio – Add – New Feature – Settings Storage   // Json 을 Async 파싱 기능 추가

메인 페이지에서 무비 페이지로 이동하면 NavigationTo 이벤트 발생


 

 

// Settings Storage 기능   // Json 을 Async 파싱 기능 추가
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace MyUWPApp1.Core.Helpers
{
    public static class Json
    {
        public static async Task<T> ToObjectAsync<T>(string value)
        {
            return await Task.Run(() =>
            {
                return JsonConvert.DeserializeObject<T>(value);
            });
        }

        public static async Task<string> StringifyAsync(object value)
        {
            return await Task.Run(() =>
            {
                return JsonConvert.SerializeObject(value);
            });
        }
    }
}

 

 

 

 

 

 


 

4. Prism으로 시작하는 UWP app Part4 – DataGrid

 

# Movie 페이지 (ViewModel  설정)

namespace MyUWPApp1.ViewModels
{
    public class MovieViewModel : ViewModelBase
    {
        private SearchRoot _searchResult;
        private IList<Search> _searches;

        public MovieViewModel()
        {
        }

        public override async void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
        {
            await GetMoviesAsync();
        }

        private async Task GetMoviesAsync()
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetStringAsync("http://www.omdbapi.com/?s=batman&apikey=a4661588");
                if (string.IsNullOrEmpty(result)) return;

                var searchRoot = await Json.ToObjectAsync<SearchRoot>(result);
                if (searchRoot == null) return;
                _searchResult = searchRoot;
                Searches = _searchResult.Search.ToList();
            }
        }

        public IList<Search> Searches
        {
            get => _searches;
            set => SetProperty(ref _searches, value);
        }
    }
}

 

# Movie 페이지 (XAML 설정) // DataGrid 설정

<controls:DataGrid
    AutoGenerateColumns="False"
    GridLinesVisibility="Horizontal"
    ItemsSource="{Binding Searches}">
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Binding="{Binding Title}" Header="Title" />
        <controls:DataGridTextColumn Binding="{Binding Year}" Header="Year" />
        <controls:DataGridTextColumn Binding="{Binding ImdbID}" Header="ImdbID" />
        <controls:DataGridTextColumn Binding="{Binding Type}" Header="Type" />
        <!--<controls:DataGridTextColumn Binding="{Binding Poster}" Header="Poster" />-->                    
        <controls:DataGridTemplateColumn Header="Symbol">
            <controls:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image Source="{Binding Poster}" Height="30"></Image>
                </DataTemplate>
            </controls:DataGridTemplateColumn.CellTemplate>
        </controls:DataGridTemplateColumn>
    </controls:DataGrid.Columns>
</controls:DataGrid>

 

 


 

4.Prism으로 시작하는 UWP app Part5 – View에서 ViewModel로

 

# 프로젝트명 – Windows Template Studio – New Page – Blank Page (이름 : MovieDetail)

namespace MyUWPApp1.ViewModels
{
    public class MovieDetailViewModel : ViewModelBase
    {
        private readonly INavigationService _navigationService;

        public MovieDetailViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
        }

        public override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)  // 페이지가 이동되었을 때 발생되는 이벤트
        {
            if (e.NavigationMode == NavigationMode.New)   // 새로 열렸을 때
            {
                Debug.WriteLine(e.Parameter);
            }
        }
    }
}

# MovieDetailPage.xaml 루트에 추가 // DataContext 와 ViewModel 자동으로 연결해줌.

xmlns:prismMvvm=”using:Prism.Windows.Mvvm”
prismMvvm:ViewModelLocator.AutoWireViewModel=”True”

 

 

# Movie 페이지에서 MovieDetail 로 이동하기 구현

// MovieViewModel
using MyUWPApp1.Core.Helpers;
using MyUWPApp1.Core.Models;
using Prism.Commands;
using Prism.Windows.Mvvm;
using Prism.Windows.Navigation;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.ApplicationModel;

namespace MyUWPApp1.ViewModels
{
    public class MovieViewModel : ViewModelBase
    {
        private SearchRoot _searchResult;
        private IList<Search> _searches;
        private Search _selectedMovie;
        private readonly INavigationService _navigationService;

        public Search SelectedMovie {
            get => _selectedMovie;
            set => SetProperty(ref _selectedMovie, value);
        }

        public ICommand BeginningEditCommand { get; set; }
        public ICommand SelectionChangedCommand { get; set; }

        public MovieViewModel(INavigationService navigationService)            
        {
            _navigationService = navigationService;
            Init();
        }

        private void Init()
        {
            if (DesignMode.DesignMode2Enabled) return;
            BeginningEditCommand = new DelegateCommand(OnBeginningEditCommand);
            SelectionChangedCommand = new DelegateCommand<object>(OnSelectionChangedCommand);
            PropertyChanged += MovieViewModel_PropertyChanged;
        }

        private void OnSelectionChangedCommand(object obj)
        {
            var list = obj as IList;
            if (list == null) return;
            Debug.WriteLine($"SelectionChanged {list.Count}");
        }

        private void OnBeginningEditCommand()
        {
            throw new NotImplementedException();
        }

        private void MovieViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case nameof(SelectedMovie):
                    Debug.WriteLine($"SelectedMovie Changed!!! {SelectedMovie.Title}");
                    if (SelectedMovie == null) return;
                    _navigationService.Navigate(PageTokens.MovieDetailPage, SelectedMovie.ImdbID);   // 상세 페이지로 이동
                    break;
            }
        }

        public override async void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
        {
            await GetMoviesAsync();
        }

        private async Task GetMoviesAsync()
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetStringAsync("http://www.omdbapi.com/?s=batman&apikey=a4661588");
                if (string.IsNullOrEmpty(result)) return;

                var searchRoot = await Json.ToObjectAsync<SearchRoot>(result);
                if (searchRoot == null) return;
                _searchResult = searchRoot;
                Searches = _searchResult.Search.ToList();


            }
        }

        public IList<Search> Searches
        {
            get => _searches;
            set => SetProperty(ref _searches, value);
        }
    }
}

 

 

<controls:DataGrid x:Name="DataGrid" Grid.Row="1"
        AutoGenerateColumns="False"
        GridLinesVisibility="Horizontal"
        ItemsSource="{Binding Searches}"
        SelectedItem="{Binding SelectedMovie, Mode=TwoWay}"
        SelectionMode="Extended">
    <i:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="BeginningEdit">
            <core:InvokeCommandAction Command="{Binding BeginningEditCommand}" />
        </core:EventTriggerBehavior>
        <core:EventTriggerBehavior EventName="SelectionChanged">
            <core:InvokeCommandAction Command="{Binding SelectionChangedCommand}"
                                          CommandParameter="{Binding ElementName=DataGrid, Path=SelectedItems}" />
        </core:EventTriggerBehavior>
    </i:Interaction.Behaviors>
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Binding="{Binding Title}" Header="Title" />
        <controls:DataGridTextColumn Binding="{Binding Year}" Header="Year" />
        <controls:DataGridTextColumn Binding="{Binding ImdbID}" Header="ImdbID" />
        <controls:DataGridTextColumn Binding="{Binding Type}" Header="Type" />
        <!--<controls:DataGridTextColumn Binding="{Binding Poster}" Header="Poster" />-->
        <controls:DataGridTemplateColumn Header="Symbol">
            <controls:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image Source="{Binding Poster}" Height="30"></Image>
                </DataTemplate>
            </controls:DataGridTemplateColumn.CellTemplate>
        </controls:DataGridTemplateColumn>
    </controls:DataGrid.Columns>
</controls:DataGrid>

 

 

 


 

5. Prism으로 시작하는 UWP app Part6 – 상세 페이지 구현

 

// MovieDetailPage.xaml
<Page
    ...    
    xmlns:prismMvvm="using:Prism.Windows.Mvvm" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
    prismMvvm:ViewModelLocator.AutoWireViewModel="True" 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid x:Name="ContentArea" Margin="{StaticResource SmallLeftRightMargin}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Image Source="{Binding CurrentMovieDetail.Poster}" Width="200" VerticalAlignment="Top" Margin="0, 0, 20, 0" />
        <StackPanel Grid.Column="1">
            <TextBlock Text="{Binding CurrentMovieDetail.Title}" FontSize="20" />
            <TextBlock Text="{Binding CurrentMovieDetail.Runtime}" />
            <TextBlock Text="{Binding CurrentMovieDetail.imdbRating}" />
            <TextBlock Text="{Binding CurrentMovieDetail.Genre}" />
            <TextBlock Text="{Binding CurrentMovieDetail.Released}" />
            <TextBlock />
            <TextBlock Text="{Binding CurrentMovieDetail.Rated}" />
            <controls:HeaderedContentControl Header="Director" Content="{Binding CurrentMovieDetail.Director}" />
            <controls:HeaderedContentControl Header="Writer" Content="{Binding CurrentMovieDetail.Writer}" />
            <controls:HeaderedContentControl Header="Actors" Content="{Binding CurrentMovieDetail.Actors}" />
            <TextBlock Text="{Binding CurrentMovieDetail.BoxOffice}" />
        </StackPanel>
    </Grid>
</Page>

 

 

// MovieDetailViewModel.cs

namespace MyUWPApp1.ViewModels
{
    public class MovieDetailViewModel : ViewModelBase
    {
        private readonly INavigationService _navigationService;
        private string _movieId;
        private MovieDetail _currentMovieDetail;

        public MovieDetailViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
        }

        public override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
        {
            if (e.NavigationMode == NavigationMode.New)
            {
                Debug.WriteLine(e.Parameter);
                _movieId = e.Parameter as string;

                GetMovieDetail();
            }
        }

        private async void GetMovieDetail()
        {
            if (string.IsNullOrEmpty(_movieId)) return;

            using (var client = new HttpClient())
            {
                var url = $"http://www.omdbapi.com/?i={_movieId}&apikey={apikey}";
                var result = await client.GetStringAsync(url);
                if (result == null) return;


                var movieDetail = await Json.ToObjectAsync<MovieDetail>(result);
                if (movieDetail == null) return;
                CurrentMovieDetail = movieDetail;
            }
        }

        public MovieDetail CurrentMovieDetail
        {
            get => _currentMovieDetail;
            set => SetProperty(ref _currentMovieDetail, value); }
    }
}

 

 


 

7. Prism으로 시작하는 UWP app Part7 – 검색과 CommandBar 구현

 

// MoviePage.xaml
<Grid x:Name="ContentArea" Margin="{StaticResource SmallLeftRightMargin}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <CommandBar HorizontalAlignment="Right" DefaultLabelPosition="Collapsed">
            <AppBarElementContainer VerticalContentAlignment="Center" Margin="4,0,0,0">
                <AutoSuggestBox QueryIcon="Find" MinWidth="200" Text="{Binding InputMovieTitle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                    <i:Interaction.Behaviors>
                        <core:EventTriggerBehavior EventName="QuerySubmitted">
                            <core:InvokeCommandAction Command="{Binding QuerySubmittedCommand}" />
                        </core:EventTriggerBehavior>
                    </i:Interaction.Behaviors>
                </AutoSuggestBox>                
            </AppBarElementContainer>
            <AppBarButton Label="Help" Icon="Help" Margin="4,0,0,0" Command="{Binding HelpCommand}"/>  // Help 버튼
        </CommandBar>
        <controls:DataGrid x:Name="DataGrid" Grid.Row="1"
        ...

 

 

// MovieViewMode.cs
using MyUWPApp1.Core.Helpers;
using MyUWPApp1.Core.Models;
using Prism.Commands;
using Prism.Windows.Mvvm;
using Prism.Windows.Navigation;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.ApplicationModel;
using Windows.UI.Popups;

namespace MyUWPApp1.ViewModels
{
    public class MovieViewModel : ViewModelBase
    {
        private SearchRoot _searchResult;
        private IList<Search> _searches;
        private Search _selectedMovie;
        private readonly INavigationService _navigationService;

        public Search SelectedMovie {
            get => _selectedMovie;
            set => SetProperty(ref _selectedMovie, value);
        }

        public ICommand BeginningEditCommand { get; set; }
        public ICommand SelectionChangedCommand { get; set; }
        public ICommand QuerySubmittedCommand { get; set; }  // 검색 버튼
        public ICommand HelpCommand { get; set; }  // 도움말 버튼

        public MovieViewModel(INavigationService navigationService)            
        {
            _navigationService = navigationService;
            Init();
        }

        private void Init()
        {
            if (DesignMode.DesignMode2Enabled) return;
            BeginningEditCommand = new DelegateCommand(OnBeginningEditCommand);
            SelectionChangedCommand = new DelegateCommand<object>(OnSelectionChangedCommand);
            QuerySubmittedCommand = new DelegateCommand(OnQuerySubmittedCommand);
            HelpCommand = new DelegateCommand(OnHelpCommand);
            PropertyChanged += MovieViewModel_PropertyChanged;
        }

        private async void OnHelpCommand()  // 도움말 버튼
        {
            var message = new MessageDialog("Help me!!");
            await message.ShowAsync();
        }

        private async void OnQuerySubmittedCommand()  // 검색 버튼
        {
            await GetMoviesAsync(InputMovieTitle);
        }

        public string InputMovieTitle { get; set; }  // 검색박스 텍스트

        private void OnSelectionChangedCommand(object obj)
        {
            var list = obj as IList;
            if (list == null) return;
            Debug.WriteLine($"SelectionChanged {list.Count}");
        }

        private void OnBeginningEditCommand()
        {
            throw new NotImplementedException();
        }

        private void MovieViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case nameof(SelectedMovie):
                    Debug.WriteLine($"SelectedMovie Changed!!! {SelectedMovie.Title}");
                    if (SelectedMovie == null) return;
                    _navigationService.Navigate(PageTokens.MovieDetailPage, SelectedMovie.ImdbID);
                    break;
            }
        }

        public override async void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
        {
            // await GetMoviesAsync();
        }

        private async Task GetMoviesAsync(string movieTitle)
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetStringAsync($"http://www.omdbapi.com/?s={movieTitle}&apikey=a4661588");
                if (string.IsNullOrEmpty(result)) return;

                var searchRoot = await Json.ToObjectAsync<SearchRoot>(result);
                if (searchRoot == null) return;
                _searchResult = searchRoot;
                Searches = _searchResult.Search?.ToList();
            }
        }

        public IList<Search> Searches
        {
            get => _searches;
            set => SetProperty(ref _searches, value);
        }
    }
}

 

 

 


 

8. Prism으로 시작하는 UWP app Part8 – Prism 화면 레이어와 Popup

 

 

private void OnHelpCommand()
{
    var popup = PrismUnityApplication.Current.Container.TryResolve<Popup>();
    var stackPanel = PrismUnityApplication.Current.Container.TryResolve<StackPanel>();
    stackPanel.Background = new SolidColorBrush(Colors.DarkGray);
    stackPanel.Width = 1024;
    stackPanel.Height = 768;
    stackPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
    stackPanel.VerticalAlignment = VerticalAlignment.Stretch;
    var textBlock = PrismUnityApplication.Current.Container.TryResolve<TextBlock>();
    textBlock.Text = "Popup!!!";
    var button = PrismUnityApplication.Current.Container.TryResolve<Button>();
    button.Content = "Close";
    button.Click += (s, e) => { popup.IsOpen = false; };  // 이벤트 해제를 안하면 Dispose가 안될 수 있음. 조심해서 사용하라.
    stackPanel.Children.Add(textBlock);
    stackPanel.Children.Add(button);
    popup.Child = stackPanel;
    popup.IsOpen = true;
}

 

# Live Visual Tree 를 확인하라.

팝업을 만들면 최상위 루트인 PopupRoot 에 생성된다.

 


 

9. Part9 – Visual Studio 2019로 업그레이드 & WebView

 

# Core 프로젝트의 Helpers 폴더에 UserAgentHelper 클래스 만들기

namespace MyUWPApp1.Core.Helpers
{
    public class UserAgentHelper
    {
        const int URLMON_OPTION_USERAGENT = 0x10000001;

        [DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
        private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);
        

        public static void SetDefaultUserAgent(string userAgent)
        {
            if (string.IsNullOrEmpty(userAgent))
            {
                return;
            }
            UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, userAgent, userAgent.Length, 0);
        }
    }
}

 

// WebViewViewMode 에서 디폴트URL 변경
private const string DefaultUrl = "https://www.naver.com";

 

// App 생성자에 모바일 UserAgent 를 적용해서 모바일 버전으로 보기
public App()
{
    InitializeComponent();

    UserAgentHelper.SetDefaultUserAgent("Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Mobile Safari/537.36 Edge/15.14900");
}

 

 

# 깃헙 클론하기 : Clone or check out code

https://github.com/kaki104/PrismSample2019

# 솔루션 보기 – Toggle between Solution and Folder views 아이콘 선택

# Configuration Manager 에서 Build 와 Deploy 선택

# 마크다운 뷰어 설치 권장

# 코드 정리 Ctrl + K + E

 


 

 

10. WebView에서 JavaScript 연동

 

# 프로젝트 추가 – ASP.NET Core Web App
Configure for HTTPS // 체크 해제

# Solution 에서 Properies 클릭
Multiple startup projects 체크
– Uwp 앱 – Start
– Asp.net 앱 – Start without debuggin
// 앱과 웹서버 두 개를 동시에 실행해야 한다.

# ASP.NET 프로젝트 properties
debug – Launch browser – 체크 해제

# 프로젝트 추가 – Windows Runtime Component (Universal Windows)
이름은 UWP앱.RT (.RT를 뒤에 붙인다.)

# Uwp 앱 에서 Add – Reference – 방금 만든 Windows Runtime Component 체크

 

// ASP.NET 프로젝트
// Pages/index.cshtml

<script>
    function basics1() {
        document.getElementById('output').innerHTML = interface.getAnswer();
    }
    function basics2(answer) {
        interface.setAnswer(answer);
        document.getElementById('output').innerHTML = "Done.";
    }
</script>

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <div id="buttons">
        <button id="button1" onclick="basics1()">Basic 1</button>
        <button id="button2" onclick="basics2('Microsoft')">Basic 2</button>
    </div>
    <div id="output"></div>
</div>

 

 

// UWP 앱
// Services/WebViewService.cs

public class WebViewService : IWebViewService
{
    private WebView _webView;

    public WebViewService(WebView webViewInstance)
    {
        _webView = webViewInstance;
        _webView.NavigationCompleted += WebView_NavigationCompleted;
        _webView.NavigationFailed += WebView_NavigationFailed;
        _webView.NavigationStarting += _webView_NavigationStarting;  // 추가
    }

    private void _webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
    {
        var component = PrismUnityApplication.Current.Container.TryResolve<InterfaceComponent>();  // Windows Runtime Component 인스턴스화
        _webView.AddWebAllowedObject("interface", component);  // 웹페이지에 삽입
    }

    public void Detatch()
    {
        if (_webView != null)
        {
            _webView.NavigationCompleted -= WebView_NavigationCompleted;
            _webView.NavigationFailed -= WebView_NavigationFailed;   // +를 -로 수정하라
            _webView.NavigationStarting -= _webView_NavigationStarting;  // 제거
        }
    }
...

 

 

 


 

Add a new project
ASP .NET Core Web Application
프로퍼티 – 멀티플 시작
ProsmSample2019.Web    – Start without debugging
ProsmSample2019         – Start
ProsmSample2019.Core   – None
ProsmSample2019.Web – 속성 – Debug 탭 – Launch browser 체크 해제
Add a new project
Windows Runtime Component 추가
추가된 Windows Runtime Component 를 Reference 를 add 한다.

 


 

Windows Runtime Component

1. C#, VB, JavaScript, C++ 를 비롯한 모든 언어 및 플랫폼에서 인스턴스화하고 사용할 수 있는 개체입니다.
2. Public methods, properties and event 를 정의해서 사용할 수  있으나 몇가지 제약사항이 있습니다. 예) generic 타입
3. Windows 가 아닌 네임스페이스를 가져야 합니다.
4. Public structures 는 public fields 만 가질 수 있으며 value types 이거나 string 여야 합니다.
5. Public classes는 반드시 sealed 여야 합니다.

 


 

11. WebView – Async, EventAggregator

 

# IEventAggregator
Prism Library 는 응용 프로그램에서 느슨하게 결합 된 구성 요소 간의 통신을 가능하게 하는 이벤트 메커니즘을 제공합니다.
이벤트 수집자 서비스를 기반으로하는 이 메커니즘을 통해 게시자와 구독자는 이벤트를 통해 통신할 수 있으며, 여전히 서로에 대한 직접적인 참조가 없습니다.

 

 

// Core 프로젝트에 Models 폴더
// NavigateEventArgs.cs 클래스 추가
namespace MyUWPApp1.Core.Models
{
    public class NavigateEventArgs
    {
        public NavigateEventAction NavigateEventAction { get; set; }
        public string NavigatePageName { get; set; }
        public object NavigateParameter { get; set; }
        public Action CallBack { get; set; }
    }
}

 

// Core 프로젝트에 Enums 폴더를 만든다.
// NavigateEventAction.cs

namespace MyUWPApp1.Core.Enums
{
    public enum NavigateEventAction
    {
        None,
        Navigate,
        GoHome,
        GoBack,
        GoForward            
    }
}

 

// Prism.Core 6.3.0 필요 (PubSubEvent 클래스)
// Core 프로젝트에 Events 폴더를 만든다.
// NavigateEvent.cs

namespace MyUWPApp1.Core.Events
{
    public class NavigateEvent : PubSubEvent<NavigateEventArgs>
    {
    }
}

 

// Windows Runtime Component
// Prism.Unity 6.3.0 필요 (PrismUnityApplication 클래스)

using MyUWPApp1.Core.Enums;
using MyUWPApp1.Core.Events;
using MyUWPApp1.Core.Models;
using Prism.Events;
using Prism.Unity.Windows;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Metadata;

namespace RuntimeComponent1
{
    [AllowForWeb]
    public sealed class InterfaceComponent
    {
        private string _answer;
        private readonly IEventAggregator _eventAggregator;

        public InterfaceComponent()
        {
            _eventAggregator = PrismUnityApplication.Current.Container.TryResolve<IEventAggregator>();  // 프리즘 ViewModel 처럼 생성자 인젝션이 없으므로 수동으로 해줘야 한다.
        }

        public string GetAnswer()
        {
            var answer = _answer ?? "null";
            return $"The answer is {answer}";
        }

        public void SetAnswer(string answer)
        {
            _answer = answer;
        }

        // Runtime Component 에서는 public 과 async Task 를 쓸 수 없으므로 IAsyncOperation를 사용해야한다.
        // private Task는 가능. 그래서 한번 더 거친다.        
        public IAsyncOperation<string> GetUriContentAsync(string uri)
        { 
            return GetUriContentHelperAsync(uri).AsAsyncOperation();
        }

        private async Task<string> GetUriContentHelperAsync(string uri)
        {
            var httpClient = new HttpClient();
            var content = await httpClient.GetStringAsync(uri);
            return content;
        }
        public void GoHome()
        {
            _eventAggregator.GetEvent<NavigateEvent>()
                .Publish(new NavigateEventArgs
                {
                    NavigateEventAction = NavigateEventAction.GoHome
                });
        }

        public void GoMovie()
        {
            _eventAggregator.GetEvent<NavigateEvent>()
                .Publish(new NavigateEventArgs
                {
                    NavigateEventAction = NavigateEventAction.Navigate,
                    NavigatePageName = "Movie"
                }); ;
        }
    }
}

 

// ASP.NET 의 Pages/index.html 파일
<script>
    function basics1() {
        document.getElementById('output').innerHTML = interface.getAnswer();
    }
    function basics2(answer) {
        interface.setAnswer(answer);
        document.getElementById('output').innerHTML = "Done.";
    }
    function getContent() {   
        var result = interface.getUriContentAsync("https://kaki104.tistory.com/m/625").then(
            function (content) {
                document.getElementById('output').innerHTML = content;
            },
            function() {
                document.getElementById('output').innerHTML = "canceled";
            }
        );
    }

    function navigate(location) {
        switch (location) {
            case 'home':
                interface.goHome();  // 자바스크립트에서는 앞글자를 소문자로 써야한다.
                break;
            case 'movie':
                interface.goMovie();  // 자바스크립트에서는 앞글자를 소문자로 써야한다.
                break;
        }
    }
</script>

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <div id="buttons">
        <button id="button1" onclick="basics1()">Basic 1</button>
        <button id="button2" onclick="basics2('Microsoft')">Basic 2</button>
        <button id="button3" onclick="getContent()">Get Content</button>
        <button id="button4" onclick="navigate('home')">Go Home</button>
        <button id="button5" onclick="navigate('movie')">Go Movie</button>
    </div>
    <div id="output"></div>
</div>

 

// ShellViewModel 에서 네비게이션 동작을 담당하므로 여기에 작성한다.
// IEventAggregator 이벤트 수신을 여기서 받는다.
private readonly IEventAggregator _eventAggregator;

public ShellViewModel(INavigationService navigationServiceInstance, IEventAggregator eventAggregator)  // 생성자가 존재한다.
{
    _navigationService = navigationServiceInstance;
    ItemInvokedCommand = new DelegateCommand<WinUI.NavigationViewItemInvokedEventArgs>(OnItemInvoked);
    _eventAggregator = eventAggregator;
}

public void Initialize(Frame frame, WinUI.NavigationView navigationView)
{
    ...
    _eventAggregator.GetEvent<NavigateEvent>().Subscribe(ReceiveNavigateEvent);
}

private void ReceiveNavigateEvent(NavigateEventArgs obj)
{
    switch (obj.NavigateEventAction)
    {
        case NavigateEventAction.None:
            break;

        case NavigateEventAction.Navigate:
            _navigationService.Navigate(obj.NavigatePageName, obj.NavigateParameter);
            break;

        case NavigateEventAction.GoHome:
            _navigationService.Navigate(PageTokens.MainPage, obj.NavigateParameter);
            _navigationService.RemoveAllPages();
            break;

        case NavigateEventAction.GoBack:
            break;

        case NavigateEventAction.GoForward:
            break;
    }
}

 

 


 

12. UWP에서 Script 직접 호출과 팝업 처리

 

// ASP.NET // index.cshtml

<script>
    function basics1() {
        document.getElementById('output').innerHTML = interface.getAnswer();
    }
    function basics2(answer) {
        interface.setAnswer(answer);
        document.getElementById('output').innerHTML = "Done.";
    }
    function getContent() {   
        var result = interface.getUriContentAsync("https://kaki104.tistory.com/m/625").then(
            function (content) {
                document.getElementById('output').innerHTML = content;
            },
            function() {
                document.getElementById('output').innerHTML = "canceled";
            }
        );
    }

    function navigate(location) {
        switch (location) {
            case 'home':
                interface.goHome();  // 자바스크립트에서는 앞글자를 소문자로 써야한다.
                break;
            case 'movie':
                interface.goMovie();  // 자바스크립트에서는 앞글자를 소문자로 써야한다.
                break;
        }
    }

    function setText(text) {
        document.getElementById('output').innerHTML = text;
    }

    function getText() {
        return "Hi nice meet you!!";
    }

    // alertBox 를 호출하면 UWP MessageDialog 호출
    function alertBox(message) {
        window.external.notify('alert:' + message);
    }

    // confirmBox 를 호출하면 UWP MessageDialog 호출
    function confirmBox(message) {
        window.external.notify('confirm:' + message);
    }
    // confirmBox 에서 yes 또는 no 의 결과를 출력
    function confirmBoxResult(result) {
        document.getElementById('output').innerHTML = result;
    }

</script>

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <div id="buttons">
        <button id="button1" onclick="basics1()">Basic 1</button>
        <button id="button2" onclick="basics2('Microsoft')">Basic 2</button>
        <button id="button3" onclick="getContent()">Get Content</button>
        <button id="button4" onclick="navigate('home')">Go Home</button>
        <button id="button5" onclick="navigate('movie')">Go Movie</button>
        <button id="button6" onclick="alertBox('Everything is ok!')">Alert</button>  // 추가
        <button id="button7" onclick="confirmBox('Are you sure?')">Confirm</button>  // 추가
    </div>
    <div id="output"></div>
</div>

 

 

// WebViewPage.xaml
// 하단 왼쪽 화살표 오른쪽 화살표 오른쪽에 배치.
<StackPanel Orientation="Horizontal">
    // <Button>왼쪽 화살표</Button>
    // <Button>오른쪽 화살표</Button>
    <Button Content="setText()" Command="{Binding RunScriptCommand}" CommandParameter="javascript:setText('Run setText script successed');"/>
    <Button Content="getText()" Command="{Binding RunScriptCommand}" CommandParameter="javascript:getText();"/>
</StackPanel >

 

 

// WebViewViewModel.cs

public ICommand RunScriptCommand { get; set; }

public WebViewViewModel(IEventAggregator eventAggregator)
{
    _eventAggregator = eventAggregator;

    RunScriptCommand = new DelegateCommand<string>(OnRunScriptCommand);
}

private void OnRunScriptCommand(string script)
{
    _eventAggregator.GetEvent<RunScriptEvent>().Publish(new RunScriptEventArgs
    {
        Scripts = new string[] { script }
    });
}

 

 

 

// WebViewPage 코드 비하인드
// 생성자 인자가 달라서 오류가 나므로 아래체럼 인스턴스를 생성하도록 바꿔준다.
public WebViewPage()
{
    InitializeComponent();

    //ViewModel.WebViewService = new WebViewService(webView);
    var service = PrismUnityApplication.Current.Container.Resolve(typeof(IWebViewService), "", new ParameterOverride("webViewInstance", webView)) as IWebViewService;
    ViewModel.WebViewService = service;
}

 

public class WebViewService : IWebViewService
{
    private WebView _webView;
    private readonly IEventAggregator _eventAggregator;

    public WebViewService(WebView webViewInstance, IEventAggregator eventAggregator)
    {
        _webView = webViewInstance;
        _webView.NavigationCompleted += WebView_NavigationCompleted;
        _webView.NavigationFailed += WebView_NavigationFailed;
        _webView.NavigationStarting += _webView_NavigationStarting;

        _eventAggregator = eventAggregator;
        _eventAggregator.GetEvent<RunScriptEvent>().Subscribe(ReceiveRunScriptEventAsync);
        _webView.ScriptNotify += _webView_ScriptNotifyAsync;  // 자바스크립트에서 notify 함수호출했을때 호출
    }

    private async void _webView_ScriptNotifyAsync(object sender, NotifyEventArgs e)
    {
        var paras = e.Value.Split(':');
        if (paras.Length < 2) return;
        var messageDialog = new MessageDialog(paras.LastOrDefault());
        if (paras.FirstOrDefault() == "confirm")
        {
            messageDialog.Commands.Add(new UICommand("Yes"));
            messageDialog.Commands.Add(new UICommand("No"));
            messageDialog.DefaultCommandIndex = 1;
            messageDialog.CancelCommandIndex = 1;
        }

        var restul = await messageDialog.ShowAsync();
        if (paras.FirstOrDefault() != "confirm") return;
        if (restul.Label.Equals("Yes"))
        {
            ReceiveRunScriptEventAsync(new RunScriptEventArgs
            {
                Scripts = new string[] { "javascript:confirmBoxResult('yes')" }
            });
        }
        else
        {
            ReceiveRunScriptEventAsync(new RunScriptEventArgs
            {
                Scripts = new string[] { "javascript:confirmBoxResult('no')" }
            });
        }
    }

    private async void ReceiveRunScriptEventAsync(RunScriptEventArgs obj)
    {
        var result = await _webView.InvokeScriptAsync("eval", obj.Scripts);
        if (string.IsNullOrEmpty(result)) return;
        var messageDialog = new MessageDialog(result);
        await messageDialog.ShowAsync();
    }

    private void _webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
    {
        var component = PrismUnityApplication.Current.Container.TryResolve<InterfaceComponent>();
        _webView.AddWebAllowedObject("interface", component);
    }

    public void Detatch()
    {
        if (_webView != null)
        {
            _webView.NavigationCompleted -= WebView_NavigationCompleted;
            _webView.NavigationFailed -= WebView_NavigationFailed;   // + 를 -로 수정하라
            _webView.NavigationStarting -= _webView_NavigationStarting;
            _eventAggregator.GetEvent<RunScriptEvent>().Unsubscribe(ReceiveRunScriptEventAsync);  // 반드시 구독해제도 해준다.
            _webView.ScriptNotify -= _webView_ScriptNotifyAsync;  // 이벤트도 해제해준다.
        }
    }

 

// 웹뷰에서 ScriptNotify 이벤트를 받으려면 Package.appxmanifest 에 Content URIs 에 주소를 넣어라.

예) http://localhost:11520

 

// Core 프로젝트의 Events 폴더에 클래스 생성
namespace MyUWPApp1.Core.Events
{
    public class RunScriptEvent : PubSubEvent<RunScriptEventArgs>
    {
    }
}


// Core 프로젝트의 Models 폴더에 클래스 생성
namespace MyUWPApp1.Core.Models
{
    public class RunScriptEventArgs
    {
        public IList<string> Scripts { get; set; }
    }
}

 


 

13. Cookie 관리, Prism으로 시작하는 UWP app Part13

 

# HttpBaseProtocolFilter (쿠키 처리 위해서)
HttpClient 와 WebView 필터 클래스

 

# API 컨트롤러 추가
ASP.NET 프로젝트에 Apis 폴더 만들기 (또는 Controllers 폴더)
Add – Controller – API Controller with read/write actions (또는 Api Controller – Empty)
파일명 : ValuesController.cs

 

 

// Program.cs

app.MapRazorPages();

app.MapControllers();  // 추가

app.Run();

 

 

// ASP.NET 컨틀롤러
// http://localhost/api/values 이런식으로 요청

using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

namespace WebApplication1.Apis
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        [HttpGet]
        public IEnumerable<string> Get()
        {
            var blog = Request.Cookies["custom_blog"];
            var youtube = Request.Cookies["custom_youtube"];
            Debug.WriteLine($"Request custom_blog: {blog}");
            Debug.WriteLine($"Request custom_youtube: {youtube}");

            return new string[] { blog, youtube };
        }

        // 서버단에서 쿠키 수정
        [HttpPost]
        public void Post([FromBody] IList<string> values)
        {
            if (values.Any() == false || values.Count != 2) return;

            Debug.WriteLine($"Request custom_blog: {Request.Cookies["custom_blog"]}");
            Debug.WriteLine($"Request custom_youtube: {Request.Cookies["custom_youtube"]}");

            var option = new CookieOptions
            {
                Expires = DateTime.Now.AddMinutes(10)
            };

            Response.Cookies.Append("custom_blog", values.First(), option);
            Response.Cookies.Append("custom_youtube", values.Last(), option);
        }
    }
}

 

 

// App.xaml.cs
protected override void ConfigureContainer()
{
    // register a singleton using Container.RegisterType<IInterface, Type>(new ContainerControlledLifetimeManager());
    base.ConfigureContainer();
    Container.RegisterInstance<IResourceLoader>(new ResourceLoaderAdapter(new ResourceLoader()));
    Container.RegisterType<ISampleDataService, SampleDataService>();
    Container.RegisterType<IWebViewService, WebViewService>();

    //HttpBaseProtocolFilter 인스턴스 만들고, 컨테이너에 인스턴스 등록
    var httpFilter = Container.Resolve<HttpBaseProtocolFilter>();  // HttpBaseProtocolFilter 인스턴스를 하나 만든다.
    httpFilter.AllowAutoRedirect = true;
    httpFilter.CacheControl.ReadBehavior = HttpCacheReadBehavior.Default;
    httpFilter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.Default;
    Container.RegisterInstance(typeof(HttpBaseProtocolFilter), "httpFilter", httpFilter);  // 위에서 만든 인스턴스를 컨테이너에 등록한다. (다른 곳에서 꺼내서 사용 위해)
}

 

 

private const string DefaultUrl = "http://localhost:5021/";
private const string DefaultApiUrl = "http://localhost:5021/api/";

public DelegateCommand GetValuesCommand { get; set; }
public DelegateCommand SetValuesCommand { get; set; }

private readonly IUnityContainer _unityContainer;
private readonly HttpBaseProtocolFilter _httpFilter;

public HttpCookieCollection Cookies
{
    get => _cookies;
    private set => SetProperty(ref _cookies, value);
}

public WebViewViewModel(IEventAggregator eventAggregator, IUnityContainer unityContainer)
{
    ...
    GetValuesCommand = new DelegateCommand(OnGetValuesCommand);
    SetValuesCommand = new DelegateCommand(OnSetValuesCommand);

    _unityContainer = unityContainer;

    // app.xaml.cs 에서 등록한 httpFilter 인스턴스를 꺼낸다. 이름을 안적으면 새로 만들기 때문에 이름을 적어라.
    _httpFilter = _unityContainer.Resolve(typeof(HttpBaseProtocolFilter), "httpFilter") as HttpBaseProtocolFilter;
    if (_httpFilter == null) return;
}

private void NavCompleted(WebViewNavigationCompletedEventArgs e)
{
    var manager = _httpFilter.CookieManager;
    var cookies = manager.GetCookies(e.Uri);
    foreach (var item in cookies)
    {
        item.Value = Uri.UnescapeDataString(item.Value);
    }
    Cookies = cookies;
    ...
}

private async void OnSetValuesCommand()

{

    var uri = $"{DefaultApiUrl}values";

    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders
        .Accept
        .Add(new Windows.Web.Http.Headers.HttpMediaTypeWithQualityHeaderValue("application/json")); //ACCEPT header
        var list = new string[] { "http://kakisoft.com", "https://www.youtube.com/FutureOfDotNET" };
        var content = new HttpStringContent(await Json.StringifyAsync(list), Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");
        HttpResponseMessage response = await client.PostAsync(new Uri(uri), content);
        if (response.IsSuccessStatusCode == false)
        {
            return;
        }
    }
}

private async void OnGetValuesCommand()
{
    string uri = $"{DefaultApiUrl}values";
    HttpCookie blog = Cookies.FirstOrDefault(c => c.Name == "custom_blog"); // 쿠키가 존재하는지 검색
    if (blog != null)
    {
        blog.Value = "http://kaki104.tistory.com";
        _httpFilter.CookieManager.SetCookie(blog);
    }
    else
    {
        var existCookie = Cookies.FirstOrDefault();
        if (existCookie == null) return;
        var cookie = new HttpCookie("custom_blog", existCookie.Domain, existCookie.Path)
        {
            Value = "http://kakisoft.com"
        };

        _httpFilter.CookieManager.SetCookie(cookie);
    }
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync(new Uri(uri));
        if (response.IsSuccessStatusCode == false)
        {
            return;
        }
        string result = await response.Content.ReadAsStringAsync();
        Debug.WriteLine(result);
    }
}

 

 

// WebViewpage.xaml 하단 StackPanel에 추가 (왼쪽 오른쪽 화살표 오른쪽에)

<Button Content="GetValues" Command="{Binding GetValuesCommand}" Margin="4,0,0,0" />
<Button Content="SetValues" Command="{Binding SetValuesCommand}" Margin="4,0,0,0" />
   <ListBox ItemsSource="{Binding Cookies}" Margin="4,0">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock>
                    <Run Text="{Binding Name}"/>
                    <Run Text=" : "/>
                    <Run Text="{Binding Value}"/>
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

 

 

 


 

# Cookie

클라이언트 컴퓨터에 저장된 작은 정보입니다.

클라이언트 컴퓨터에 Username, Password, City, PhoneNo 등의 사용자 환경 설정 정보를 저장하는 데 사용됩니다.

Persist Cookie : 만료되는 시간이 없는 지속형 쿠키

Non-Persist Cookie : 만료시간이 존재하는 비 지속형 쿠키

* HttpBaseProtocolFilter

Sharing Sessions Between HttpClient and WebViews on Windows Phones

HttpBaseProtocolFilter 클래스는 HttpClient 인스턴스에서 사용하는 기본 필터 또는 처리기를 제공합니다. 추가 필터가 HttpClient 인스턴스에 추가되지 않으면 HttpBaseProtocolFilter 개체가 유일한 필터가됩니다.

HttpBaseProtocolFilter 클래스는 여러 가지 저수준 HTTP 스택 동작을 전환하기위한 속성 집합을 제공합니다.

 


 

14. UnityContainer – Prism으로 시작하는 UWP app part 14

 

 

// Type 을 Resolve 하기 위해서는 먼저 등록을 해야 한다.
unityContainer.RegisterType<T>();
unityContainer.RegisterType<AddPersonControl>();
unityContainer.RegisterType<interface, T>();
unityContainer.RegisterType<interface, TargetPropertyPath>(string);
unityContainer.RegisterType<IAddPerson, AddpersonControl>("Control");
unityContainer.RegisterType<IAddPerson, AddPersonPage>("Page");

// 컨테이너로부터 Type을 인스턴스 시켜주는 메소드
var t = unityContainer.Resolve<T>();
var t = unityContainer.Resolve<AddPersonControl>();
var t = unityContainer.Resolve<I>();
var t = unityContainer.Resolve<IAddPerson>();
var t = unityContainer.Resolve<I>(string);
var t = unityContainer.Resolve<IAddPerson>("Page");

 

public interface ICar
{
    int Run();
}

public interface IDriver
{
    Task RunCarAsync();
}

public class Audi : ICar
{
    private int _miles = 0;
    public int Run()
    {
        return ++_miles;
    }
}

public class BMW : ICar
{
    private int _miles = 0;
    public int Run()
    {
        return ++_miles;
    }
}

public class UWPDriver : IDriver
{
    private readonly ICar _car;

    public UWPDriver(ICar car)
    {
        _car = car;
    }

    public async Task RunCarAsync()
    {
        var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
        var dialog = new MessageDialog(message);
        await dialog.ShowAsync();
    }
}

unityContainer.RegisterType<ICar, BMW>();  // ICar 와 BMW 를 매핑시켜서 등록
var driver = _unityContainer.Resolve<UWPDriver>();  // UWPDriver 생성자에서 ICar를 BMW로 인식
await driver.RunCarAsync();

// 결과
Running BMW - 1 Mile

 

 

 

 

 

 

 

 


 

14. UnityContainer – Prism으로 시작하는 UWP app part 14

 

1. IoC, DIP, DI, IoC Container

IoC(Inversion of Control)

– 클래스간의 느슨한 결합(loose coupling)을 만들기 위해 OOP에서 제어를 뒤집을 것을 권장하는 디자인 원칙(principle)

 

DIP(Dependency Inversion Principle)

클래스간의 느슨한 결합(loose coupling)을 만들기 위한 원칙(principle) 중 하나
고수준 모듈(High-level)이 저수준 모듈(Low-level)에 의존해서는 안된다는 원칙. 둘다 추상화(예: interface)에 의존해야 함

 

DI(Dependency Injection)

IoC 원칙을 구현하는 디자인 패턴
종속 객체를 주입

 

IoC Container
어플리케이션 전체에서 자동 종속성 주입을 관리하는 프레임워크
Unity, Ninject, StructureMap, Autofac 등
위의 내용들을 관통하는 핵심
가능한 모든 클래스는 Interface를 이용해서 추상화하고 Container를 이용해서 Injection 해서 사용한다.

 

2. Prism Framework features

EventAggregator
응용 프로그램에서 느슨하게 결합된 (loosely coupled) 구성 요소 간의 통신을 가능하게하는 이벤트 메커니즘(PubSubEvent)을 제공합니다.

UnityContainer
가볍고 확장 가능한 종속성 주입 컨테이너 (Dependency Injection Container)

Region
런타임에 느슨하게 결합된 (loosely coupled) UI로 구성된 레이아웃을 만들기 위한 방법

Modules
관련된 기능이나 UI를 내포한 클래스 라이브러리들을 느슨하게 결합 (loosely coupled) 하기 위한 방법

UWP에서 사용가능한 버전
Prism.Unity 6.3, Prism.Core 6.3
UWP에서는 Region 기능 사용 못함

 

3. UnityContainer Overview
가볍고 확장 가능한 종속성 주입(Dependency Injection) 컨테이너

특징
Interface Type이나 기본 Type에 대한 단순 맵핑 등록
기존 인스턴스 등록 지원
디자인 타임 등록은 물론 코드 등록 지원
생성자, 속성 또는 메서드를 통해 등록된 Type을 자동으로 주입
지연(deferred) 솔루션 지원
중첩 컨테이너 지원
수명 관리자를 이용해서 인스턴스를 자동으로 disposing
서비스 위치 기능 지원
Type 차단 및 인스턴스 차단을 지원

 

4. UnityContainer 사용하기(RegisterType)

UnityContainer.RegisterType Method
Type 맵핑을 위한 메소드
대표적인 Type등록 방법 및 예제

 

5. UnityContainer 사용하기(Resolve)

UnityContainer.Resolve Method
컨테이너로부터 Type을 인스턴스 시켜주는 메소드

 


 

15. UnityContainer Detail & Examples – Prism으로 시작하는 UWP app part 15 – 1

 

// 1. 2개 연달아 생성 하면 다른 인스턴스가 생성된다.
_unityContainer.RegisterType<ICar, BMW>();
var driver1 = _unityContainer.Resolve<UWPDriver>();
await driver1.RunCarAsync();

var driver2 = _unityContainer.Resolve<UWPDriver>();
await driver2.RunCarAsync();

// 결과
Running BMW - 1 Mile
Running BMW - 1 Mile

---------------------------------------------------------------------------------------

// 2. 인터페이스를 2개 등록해 놓으면 나중에 등록한 인터페이스가 나온다.
_unityContainer.RegisterType<ICar, BMW>();
_unityContainer.RegisterType<ICar, Audi>();
var driver1 = _unityContainer.Resolve<UWPDriver>();
await driver1.RunCarAsync();

// 결과
Running Audi - 1 Mile

---------------------------------------------------------------------------------------

// 3. 매핑된 이름으로 Resolve 하기
var bmw = _unityContainer.Resolve<ICar>();  // BMW
var driver1 = new UWPDriver(bmw);            
await driver1.RunCarAsync();

var audi = _unityContainer.Resolve<ICar>("OpenCar");  // Audi (매핑된 이름으로 Resolve)
var driver2 = new UWPDriver(audi);
await driver2.RunCarAsync();

// 결과
Running BMW - 1 Mile
Running Audi - 1 Mile

---------------------------------------------------------------------------------------

// 4. Register Driver Type
_unityContainer.RegisterType<ICar, BMW>();
_unityContainer.RegisterType<ICar, Audi>("OpenCar");  // 매핑 이름

_unityContainer.RegisterType<IDriver, UWPDriver>();
_unityContainer.RegisterType<IDriver, UWPDriver>("OpenCarDriver",
    new InjectionConstructor(_unityContainer.Resolve<ICar>("OpenCar"))); // 생성자에서 ICar 를 만나면 이렇게 이용하라.

var driver1 = _unityContainer.Resolve<IDriver>();            
await driver1.RunCarAsync();

var driver2 = _unityContainer.Resolve<IDriver>("OpenCarDriver");
await driver2.RunCarAsync();  

// 결과
Running BMW - 1 Mile
Running Audi - 1 Mile

---------------------------------------------------------------------------------------

// 5. Register Instance
_unityContainer.RegisterType<ICar, Audi>();
var car = _unityContainer.Resolve<ICar>();
_unityContainer.RegisterInstance(car); // 만들어진 car 인스턴스를 싱글톤처럼 사용

var driver1 = _unityContainer.Resolve<UWPDriver>();            
await driver1.RunCarAsync();
await driver1.RunCarAsync();

var driver2 = _unityContainer.Resolve<UWPDriver>();
await driver2.RunCarAsync();   

// 결과
Running Audi - 1 Mile
Running Audi - 2 Mile
Running Audi - 3 Mile

---------------------------------------------------------------------------------------

 

# Constructor Injection (생성자 주입)

1. Resolve 시에 기본으로 사용하는 방식
2. private readonly T _instance; 를 이용해서 내부에서 사용
3. Multiple Parameters
– public Driver(ICar car, ICarKey key)
– private readonly ICar _car;
4. Multiple Constructors.
– [InjectionConstructor]public Driver(ICar car)
– public Driver(string name)
5. Primitive Type Parameter
– public Driver(ICar car, string driverName)

 

 

public interface ICar
{
    int Run();
}

public interface IDriver
{
    Task RunCarAsync();
}

public class Audi : ICar
{
    private int _miles = 0;
    public int Run()
    {
        return ++_miles;
    }
}

public class BMW : ICar
{
    private int _miles = 0;
    public int Run()
    {
        return ++_miles;
    }
}

public class UWPDriver : IDriver
{
    private readonly ICar _car;

    public UWPDriver(ICar car)
    {
        _car = car;
    }

    public async Task RunCarAsync()
    {
        var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
        var dialog = new MessageDialog(message);
        await dialog.ShowAsync();
        Debug.WriteLine(message);
    }
}

public interface ICarKey
{
}

public class AudiKey : ICarKey
{
}

public class BMWKey : ICarKey
{
}


public class UWPDriverWithKey : IDriver
{
    private readonly ICar _car;
    private readonly ICarKey _key;

    public UWPDriverWithKey(ICar car, ICarKey key)
    {
        _car = car;
        _key = key;
    }

    public async Task RunCarAsync()
    {
        var message = $"Running {_car.GetType().Name} with {_key.GetType().Name} - {_car.Run()} Mile";
        var dialog = new MessageDialog(message);
        _ = await dialog.ShowAsync();
        Debug.WriteLine(message);
    }
}

public class UWPDriverMultiConstructor : IDriver
{
    private readonly ICar _car;

    [InjectionConstructor]
    public UWPDriverMultiConstructor(ICar car)
    {
        _car = car;
    }

    public UWPDriverMultiConstructor(string name)
    {
    }

    public UWPDriverMultiConstructor()
    {
    }

    public async Task RunCarAsync()
    {
        var message = $"Running {_car?.GetType().Name} - {_car?.Run()} Mile";
        var dialog = new MessageDialog(message);
        _ = await dialog.ShowAsync();
        Debug.WriteLine(message);
    }
}

public class UWPDriverPrimitiveType : IDriver
{
    private readonly ICar _car;
    private readonly string _driverName;

    public UWPDriverPrimitiveType(ICar car, string driverName)
    {
        _car = car;
        _driverName = driverName;
    }
    public async Task RunCarAsync()
    {
        var message = $"{_driverName} is running {_car?.GetType().Name} - {_car?.Run()} Mile";
        var dialog = new MessageDialog(message);
        _ = await dialog.ShowAsync();
    }
}


----------------------------------------------------------------------------------------

        // 1. Multiple Parameters

        _unityContainer.RegisterType<ICar, Audi>();
        _unityContainer.RegisterType<ICarKey, AudiKey>();

        _unityContainer.RegisterType<IDriver, UWPDriverWithKey>();            

        var driver = _unityContainer.Resolve<IDriver>();
        await driver.RunCarAsync();
  
        // 결과
        Running Audi with AudiKey - 1 Mile

----------------------------------------------------------------------------------------

        // 2. Multiple Constructors

        _unityContainer.RegisterType<ICar, BMW>();
        _unityContainer.RegisterType<IDriver, UWPDriverMultiConstructor>();            

        var driver = _unityContainer.Resolve<IDriver>();
        await driver.RunCarAsync();

        var driver2 = new UWPDriverMultiConstructor("Empty");
        await driver2.RunCarAsync();

        // 결과
        Running BMW - 1 Mile
        Running  -  Mile

----------------------------------------------------------------------------------------

        // 3. Primitive Type Parameter

        _unityContainer.RegisterType<ICar, Audi>();            

        _unityContainer.RegisterType<IDriver, UWPDriverPrimitiveType>(
            new InjectionConstructor(new object[] {_unityContainer.Resolve<ICar>(), "Kaki"}));            

        var driver = _unityContainer.Resolve<IDriver>();
        await driver.RunCarAsync();

        // 결과 
        Kaki is running Audi - 1 Mile

 

 


 

16. UnityContainer Detail & Examples – Prism으로 시작하는 UWP app part15-2

 

# Property Injection

1. Attribute를 이용해서 Injection
2. public T Instance { get ; set; } 을 이용
3. Dependency Attribute
– [Dependency] public ICar Car { get; set; }
4. Named Mapping
– [Dependency(“MyCar”)] protected ICar Car { get; set; } // public, protected 까지 가능
5. Run-Time Configuration
– public ICar MyCar { get; set; }
– unityContainer.RegisterType<IDriver, UWPDriverRuntime>(new InjectionProperty(“MyCar”, new BMW()));

 

 

    public interface ICar
    {
        int Run();
    }

    public interface IDriver
    {
        Task RunCarAsync();
    }

    public class Audi : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class BMW : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class UWPDriver : IDriver
    {
        private readonly ICar _car;

        public UWPDriver(ICar car)
        {
            _car = car;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public interface ICarKey
    {
    }

    public class AudiKey : ICarKey
    {
    }

    public class BMWKey : ICarKey
    {
    }


    public class UWPDriverWithKey : IDriver
    {
        private readonly ICar _car;
        private readonly ICarKey _key;

        public UWPDriverWithKey(ICar car, ICarKey key)
        {
            _car = car;
            _key = key;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} with {_key.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverMultiConstructor : IDriver
    {
        private readonly ICar _car;

        [InjectionConstructor]
        public UWPDriverMultiConstructor(ICar car)
        {
            _car = car;
        }

        public UWPDriverMultiConstructor(string name)
        {
        }

        public UWPDriverMultiConstructor()
        {
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car?.GetType().Name} - {_car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverPrimitiveType : IDriver
    {
        private readonly ICar _car;
        private readonly string _driverName;

        public UWPDriverPrimitiveType(ICar car, string driverName)
        {
            _car = car;
            _driverName = driverName;
        }
        public async Task RunCarAsync()
        {
            var message = $"{_driverName} is running {_car?.GetType().Name} - {_car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverDependencyAttribute : IDriver
    {
        public UWPDriverDependencyAttribute()
        {
        }

        [Dependency]
        public ICar Car { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {Car?.GetType().Name} - {Car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverNamedMapping : IDriver
    {
        /// <summary>
        /// private, readonly, private set (3개는 안됨) public, proteced 까지 됨
        /// </summary>
        [Dependency("MyCar")]
        protected ICar Car { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {Car?.GetType().Name} - {Car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverRuntime : IDriver
    {
        public ICar MyCar { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {MyCar?.GetType().Name} - {MyCar?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

----------------------------------------------------------------------------------
             
             // 1. Dependency Attribute

            _unityContainer.RegisterType<ICar, BMW>();

            _unityContainer.RegisterType<IDriver, UWPDriverDependencyAttribute>();

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

            // 결과
            Running BMW - 1 Mile

----------------------------------------------------------------------------------

           // 2. Named Mapping

            _unityContainer.RegisterType<ICar, BMW>();
            _unityContainer.RegisterType<ICar, Audi>("MyCar");

            _unityContainer.RegisterType<IDriver, UWPDriverNamedMapping>();

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

           // 결과
           Running Audi - 1 Mile

----------------------------------------------------------------------------------

           // 3. Run-time Configuration

            _unityContainer.RegisterType<IDriver, UWPDriverRuntime>(
                new InjectionProperty("MyCar", new BMW()));

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

            // 결과
            Running BMW - 1 Mile
 








 

 

# Method Injection

 

1. Attribute를 이용해서 Injection
2. private readonly T _instance; 를 이용해서 내부에서 사용 // readonly 안됨
3. 생성자를 이용할 수 없는 경우 사용
4. InjectionMethod Attribute
– [InjectionMethod] public void UseCar(ICar car) { _car = car; } // Resolve 하면 자동으로 실행됨
5. Run-time Configuration
public void MyCar(ICar car) { _car = car; }
unityContainer.RegisterType IDriver, UWPDriverRuntimeMethod (new InjectionMethod(“MyCar”, new Audi())); // MyCar 메소드에 Audi 인스턴스를 만들어 넣어라.

 

 

    public interface ICar
    {
        int Run();
    }

    public interface IDriver
    {
        Task RunCarAsync();
    }

    public class Audi : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class BMW : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class UWPDriver : IDriver
    {
        private readonly ICar _car;

        public UWPDriver(ICar car)
        {
            _car = car;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public interface ICarKey
    {
    }

    public class AudiKey : ICarKey
    {
    }

    public class BMWKey : ICarKey
    {
    }


    public class UWPDriverWithKey : IDriver
    {
        private readonly ICar _car;
        private readonly ICarKey _key;

        public UWPDriverWithKey(ICar car, ICarKey key)
        {
            _car = car;
            _key = key;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} with {_key.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverMultiConstructor : IDriver
    {
        private readonly ICar _car;

        [InjectionConstructor]
        public UWPDriverMultiConstructor(ICar car)
        {
            _car = car;
        }

        public UWPDriverMultiConstructor(string name)
        {
        }

        public UWPDriverMultiConstructor()
        {
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car?.GetType().Name} - {_car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverPrimitiveType : IDriver
    {
        private readonly ICar _car;
        private readonly string _driverName;

        public UWPDriverPrimitiveType(ICar car, string driverName)
        {
            _car = car;
            _driverName = driverName;
        }
        public async Task RunCarAsync()
        {
            var message = $"{_driverName} is running {_car?.GetType().Name} - {_car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverDependencyAttribute : IDriver
    {
        public UWPDriverDependencyAttribute()
        {
        }

        [Dependency]
        public ICar Car { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {Car?.GetType().Name} - {Car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverNamedMapping : IDriver
    {
        /// <summary>
        /// private, readonly, private set X
        /// </summary>
        [Dependency("MyCar")]
        protected ICar Car { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {Car?.GetType().Name} - {Car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverRuntime : IDriver
    {
        public ICar MyCar { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {MyCar?.GetType().Name} - {MyCar?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }


    public class UWPDriverInjectionMethod : IDriver
    {
        private ICar _car;

        [InjectionMethod]  // Resolve 하면 자동으로 실행됨
        public void UseCar(ICar car)
        {
            _car = car;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car?.GetType().Name} - {_car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public class UWPDriverRuntimeMethod : IDriver
    {
        private ICar _car;
        private ICarKey _key;

        public void MyCar(ICar car)
        {
            _car = car;
        }

        public void MyCarKey(ICarKey key)
        {
            _key = key;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} with {_key.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }


-------------------------------------------------------------------------------

            // 1. Method Injection

            _unityContainer.RegisterType<ICar, Audi>();

            _unityContainer.RegisterType<IDriver, UWPDriverInjectionMethod>();

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

            // 결과
            Running Audi - 1 Mile

-------------------------------------------------------------------------------

            // 2. Run-time Configuration Method Injection

            _unityContainer.RegisterType<IDriver, UWPDriverRuntimeMethod>(
                new InjectionMethod("MyCar", new Audi()),        // MyCar 메소드에는 Audi 인스턴스를 만들어 넣어라.
                new InjectionMethod("MyCarKey", new BMWKey()));    // MyCarKey 메소드에는 BMWKey 인스턴스를 만들어 넣어라.

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

            // 결과
            Running Audi with BMWKey - 1 Mile

 

 

# Overrides

1. 등록된 Type 이외의 Type을 Injection 시키는 방법
2. ResolverOverride를 이용해서 등록된 Type을 재정의 할 수 있음
3. ParameterOverride
unityContainer.Resolve IDriver(
new ParameterOverride(“car”, new BMW()));
4. Override Multiple Parameters
new ParameterOverrides { { “car1”, new Audi() },
{ “carKey1”, new AudiKey() },
{ “car2”, new BMW() },
{ “carKey2”, new BMWKey() }}
5. PropertyOverride
unityContainer.Resolve IDriver (new PropertyOverride(“Car”, new BMW()));
6. DependencyOverride // Type 으로도 가능
unityContainer.Resolve IDriver (new DependencyOverride(typeof(ICar), new BMW()));

 

 

    public interface ICar
    {
        int Run();
    }

    public interface IDriver
    {
        Task RunCarAsync();
    }

    public class Audi : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class BMW : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class UWPDriver : IDriver
    {
        private readonly ICar _car;

        public UWPDriver(ICar car)
        {
            _car = car;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }

    public interface ICarKey
    {
    }

    public class AudiKey : ICarKey
    {
    }

    public class BMWKey : ICarKey
    {
    }

    public class UWPDriverMultiOverride : IDriver
    {
        private readonly ICar _car1;
        private readonly ICarKey _carKey1;
        private readonly ICar _car2;
        private readonly ICarKey _carKey2;

        public UWPDriverMultiOverride(ICar car1, ICarKey carKey1, ICar car2, ICarKey carKey2)
        {
            _car1 = car1;
            _carKey1 = carKey1;
            _car2 = car2;
            _carKey2 = carKey2;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car1?.GetType().Name} with {_carKey1.GetType().Name} - {_car1?.Run()} Mile";
            message += $"\n\rRunning {_car2?.GetType().Name} with {_carKey2.GetType().Name} - {_car2?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
        }
    }

    public class UWPDriverDependencyAttribute : IDriver
    {
        public UWPDriverDependencyAttribute()
        {
        }

        [Dependency]
        public ICar Car { get; set; }

        public async Task RunCarAsync()
        {
            var message = $"Running {Car?.GetType().Name} - {Car?.Run()} Mile";
            var dialog = new MessageDialog(message);
            _ = await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }



------------------------------------------------------------------------------

            // 1. ParameterOverride
            _unityContainer.RegisterType<ICar, Audi>();
            _unityContainer.RegisterType<IDriver, UWPDriver>();

            var driver = _unityContainer.Resolve<IDriver>();
            await driver.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>(
                new ParameterOverride("car", new BMW()));  // BMW 는 등록되지 않았지만 이렇게 등록
            await driver2.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running BMW - 1 Mile

------------------------------------------------------------------------------

            // 2. Override Multiple Parameters

            _unityContainer.RegisterType<IDriver, UWPDriverMultiOverride>();

            var p = new ParameterOverrides
            {
                { "car1", new Audi() },
                { "carKey1", new AudiKey() },
                { "car2", new BMW() },
                { "carKey2", new BMWKey() }
            };
            var driver = _unityContainer.Resolve<IDriver>(p);
            await driver.RunCarAsync();

            // 결과
            Running Audi with AudiKey - 1 Mile

            Running BMW with BMWKey - 1 Mile


------------------------------------------------------------------------------

            // 3. PropertyOverride

            _unityContainer.RegisterType<ICar, Audi>();
            _unityContainer.RegisterType<IDriver, UWPDriverDependencyAttribute>();

            var driver1 = _unityContainer.Resolve<IDriver>();
            await driver1.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>(
                new PropertyOverride("Car", new BMW()));
            await driver2.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running BMW - 1 Mile

------------------------------------------------------------------------------

             // 4. DependencyOverride     // Type 으로도 가능

            _unityContainer.RegisterType<ICar, Audi>();
            _unityContainer.RegisterType<IDriver, UWPDriver>();

            var driver1 = _unityContainer.Resolve<IDriver>();
            await driver1.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>(
                new DependencyOverride(typeof(ICar), new BMW()));
            await driver2.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running BMW - 1 Mile


 

# Lifetime Manager

 

– UnityContainer에 등록된 객체에 대한 수명을 관리하는 방법을 지정할 수 있음

1. TransientLifetimeManager          // 기본이므로 생략 가능
기본 수명 관리 방법, Resolve호출시 새로운 객체를 생성해서 반환

2. ContainerControlledLifetimeManager          // 싱글톤
처음 Resolve시 싱글톤 객체를 생성하고, 이후 Resolve할 때마다 반환

3. HierarchicalLifetimeManager          // 싱글톤이지만 상위 컨테이너와 하위 컨테이너가 따로 관리
2 항목과 동일, 추가로 하위 컨테이너가 자체 단일 객체를 만들어 반환 – 상위 컨테이너와 하위 컨테이너가 서로 다른 객체 관리

4. PerResolveLifetimeManager
1 항목과 동일, 재귀호출시 생성된 객체는 재사용함

5. PerThreadLifetimeManager
스래드당 단일 객체를 생성

6. ExternallyControlledLifetimeManager
생성된 객체에 대한 약한 참조만 유지. 사용자 정의 수명관리자를 만들어서 사용할 수 있음

 

    public interface ICar
    {
        int Run();
    }

    public interface IDriver
    {
        Task RunCarAsync();
    }

    public class Audi : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class BMW : ICar
    {
        private int _miles = 0;
        public int Run()
        {
            return ++_miles;
        }
    }

    public class UWPDriver : IDriver
    {
        private readonly ICar _car;

        public UWPDriver(ICar car)
        {
            _car = car;
        }

        public async Task RunCarAsync()
        {
            var message = $"Running {_car.GetType().Name} - {_car.Run()} Mile";
            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
            Debug.WriteLine(message);
        }
    }


------------------------------------------------------------------------------------

            // 1. TransientLifetimeManager         // 기본, 생략 가능

            _unityContainer.RegisterType<ICar, Audi>(new TransientLifetimeManager());
            _unityContainer.RegisterType<IDriver, UWPDriver>();

            var driver1 = _unityContainer.Resolve<IDriver>();
            await driver1.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>();
            await driver2.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running Audi - 1 Mile

------------------------------------------------------------------------------------

            2. ContainerControlledLifetimeManager   // 싱글톤

            _unityContainer.RegisterType<ICar, Audi>(new ContainerControlledLifetimeManager());
            _unityContainer.RegisterType<IDriver, UWPDriver>();

            var driver1 = _unityContainer.Resolve<IDriver>();
            await driver1.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>();
            await driver2.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running Audi - 2 Mile

------------------------------------------------------------------------------------

            3. HierarchicalLifetimeManager      // 싱글톤, 상위 컨테이너, 자식 컨테이너

            _unityContainer.RegisterType<ICar, Audi>(new HierarchicalLifetimeManager());
            _unityContainer.RegisterType<IDriver, UWPDriver>();

            var childContainer = _unityContainer.CreateChildContainer();  // 자식 컨테이너 생성

            var driver1 = _unityContainer.Resolve<IDriver>();    // 상위 컨테이너
            await driver1.RunCarAsync();

            var driver2 = _unityContainer.Resolve<IDriver>();
            await driver2.RunCarAsync();

            var driver3 = childContainer.Resolve<IDriver>();    // 자식 컨테이너
            await driver3.RunCarAsync();

            var driver4 = childContainer.Resolve<IDriver>();
            await driver4.RunCarAsync();

            // 결과
            Running Audi - 1 Mile
            Running Audi - 2 Mile
            Running Audi - 1 Mile
            Running Audi - 2 Mile

 

 

Related posts

Leave a Comment