달력

022012  이전 다음

  •  
  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  •  
  •  
  •  
지난번 HttpHelper 클래스를 이어 이번에는 WebClient를 이용한 Downloader 클래스를 만들어 보도록 하겠습니다.

다들 아시겠지만 Downloader 클래스는 실버라이틑 1.1에는 있었지만 실버라이트 2가 나오면서 사라지고 WebClient로 대체가 되었습니다.

물론 바뀐 WebClient가 사용방법이 어려운건 아니지만 좀 더 사용하기 편하게 하기 위해서 WebClient를 이용한 Downloader 클래스를 작성해 보았습니다.

WebClient를 이용한 Downloader 클래스 만들기

1. Downloader 클래스 작성

Downloader 클래스도 HttpHelper 클래스와 마찬가지로 기본 클래스, 이벤트, 다운로드 구분자로 구성 되어 있습니다.

사용할 네임스페이스

using System.Net;
using System.IO;

다운로드 구분

public enum DownloadKind
{
    Text,
    Binary
}

다운로드 구분은 크게 2가지로 텍스트와 바이너리로 구성이 됩니다. 텍스트는 txt, xml, html, js, cs, asp, aspx 같은 순수 텍스트로만 이루어진 파일이며, 바이너리는 wmv, zip, exe 같은 동영상이나 압축파일 등등 텍스트를 제외한 모든 파일이라고 생각해도 좋을거 같습니다.

이벤트 핸들러

public delegate void DownloadCompleteEventHandler(DownloadCompleteEventArgs e);
public class DownloadCompleteEventArgs : EventArgs
{
    public Stream ResultStream { get; set; }
    public string ResultString { get; set; }
    public DownloadCompleteEventArgs(Stream result)
    {
        this.ResultStream = result;
    }
    public DownloadCompleteEventArgs(string result)
    {
        this.ResultString = result;
    }
}
public delegate void DownloadErrorEventHandler(DownloadErrorEventArgs e);
public class DownloadErrorEventArgs : EventArgs
{
    public string Error { get; set; }
    public DownloadErrorEventArgs(string error)
    {
        this.Error = error;
    }
}

이벤트 핸들러는 크게 다운로드 완료 이벤트와 다운로드 에러 이벤트로 구성됩니다.

다음은 기본 클래스의 구성 입니다.

전역

WebClient       m_WebClient;
DownloadKind m_DownloadKind;
Uri                 m_DownloadUri;
public event DownloadCompleteEventHandler DownloadComplete;
private void OnDownloadComplete(DownloadCompleteEventArgs e)
{
    if (this.DownloadComplete != null)
    {
        this.DownloadComplete(e);
    }
}
public event DownloadErrorEventHandler DownloadError;
private void OnDownloadError(DownloadErrorEventArgs e)
{
    if (this.DownloadError != null)
    {
        this.DownloadError(e);
    }
}

다운로드에 필요한 변수와 이벤트를 발생 시키기 위한 내용입니다.

생성자

public Downloader(Uri downloadUri, DownloadKind kind)
{
    m_WebClient = new WebClient();
    m_DownloadKind = kind;
    m_DownloadUri  = downloadUri;
    if (m_DownloadKind == DownloadKind.Binary)
    {
        m_WebClient.OpenReadCompleted += new OpenReadCompletedEventHandler(m_WebClient_OpenReadCompleted);
    }
    else
    {
        m_WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(m_WebClient_DownloadStringCompleted);
    }
}

다운로드 구분에 따라서 이벤트를 다르게 생성해 줍니다.

다운로드 시작 함수

public void Start()
{
    if (m_DownloadKind == DownloadKind.Binary)
    {
        m_WebClient.OpenReadAsync(m_DownloadUri);
    }
    else
    {
        m_WebClient.DownloadStringAsync(m_DownloadUri);
    }
}

역시 다운로드 구분에 따라서 Async 함수를 구분해서 실행 합니다.

바이너리 파일 다운로드 완료 이벤트

void m_WebClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if ((e.Error == null) && (e.Cancelled == false))
    {
        OnDownloadComplete(new DownloadCompleteEventArgs(e.Result));
    }
    else
    {
        OnDownloadError(new DownloadErrorEventArgs(e.Error.Message));
    }
}

텍스트 파일 다운로드 완료 이벤트

void m_WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if(e.Error == null)
    {
        OnDownloadComplete(new DownloadCompleteEventArgs(e.Result));
    }
    else
    {
        OnDownloadError(new DownloadErrorEventArgs(e.Error.Message));
    }
}

이렇게 해서 Downloader 클래스 작성을 완료 했습니다. 이 클래스에 자신이 원하는 기능을 추가해서 확장 클래스를 작성해서 사용해도 좋을 것입니다.

Downloader 클래스 다운로드



2. Downloader 클래스 사용방법

다운로드 하기

Uri uri = new Uri(http://localhost/DownloaderTest.aspx);
Downloader down = new Downloader(uri, DownloadKind.Text);
down.DownloadComplete += new DownloadCompleteEventHandler(down_DownloadComplete);
down.DownloadError += new DownloadErrorEventHandler(down_DownloadError);
down.Start();

이벤트

void down_DownloadError(DownloadErrorEventArgs e)
{
    txtResult.Text = "에러 : " + e.Error;
}
void down_DownloadComplete(DownloadCompleteEventArgs e)
{
    // 텍스트일 경우
    txtResult.Text = e.ResultString;

    // 바이너리일 경우
    MediaElement media = new MediaElement();
    media.SetSource = e.ResultStream;
    ...
}

도메인 접근시 크로스 도메인이 허용이 안된 사이트는 에러 이벤트를 발생 시킵니다.
이 경우 에러는 Download Failure 라는 에러가 나오네요!!

이것으로 다운로더 클래스 사용 방법도 마치도록 하겠습니다.
아무쪼록 이 글을 보시는 분들께 많은 도움이 되었으면 좋겠습니다.

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

실버라이트 1.1에서 2 베타1으로 버전업이 되면서 변경된 부분이 상당히 있습니다.
그래서 마이그레션하기도 쉽지 않습니다.
그래서 실버라이트 2 프로젝트를 새로 만들어서 클래스 복사하는 형식으로 마이그레이션을 하는 분들이 많을 것이라고 생각이 됩니다.
이 마이그레이션 작업을 하는 분들에게 도움이 되고자 변경된 내용을 정리해 보았습니다.

내용은 MSDN실버라이트(Silverlight) 정보공유 카페에서 참고를 하였습니다.

1. EventHandler의 변화


MouseLeftButtonUp과 MouseLeftButtonDown 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : MouseEventHandler, MouseEventArgs
- 2 beta 1 : MouseButtonEventHandler, MouseButtonEventArgs

MouseLeave 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : EventHandler, Eventargs
- 2 beta 1 : MouseEventHandler, MouseEventArgs

Loaded 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : EventHandler, Eventargs
- 2 beta 1 : RoutedEventHandler, RoutedEventArgs

KeyEvent 에서 KeyboardEventArgs의 아규먼트 값의 Key 값이 Key의 enum 타입으로 바뀌었습니다.

void onKeyUp(object sender, KeyboardEventArgs e)
{
    switch (e.Key) // e.Key가 enum 타입입니다.
    {
        ....
    }
}

2. BrowserHost 변경


이 기능은 사이즈 변경이나 전체화면을 사용할 때 많이 사용하셨을 것입니다.
네임스페이스와 클래스가 아래와 같이 변경이 되었습니다.

BrowserHost -> Application.Current.Host.Content

Resize 이벤트 처리는 아래와 같이 변경 되었습니다.

Application.Current.Host.Content.Resized += new EventHandler(Content_Resized);

void Content_Resized(object sender, EventArgs e)
{
    Width = Application.Current.Host.Content.ActualWidth;
    Height = Application.Current.Host.Content.ActualHeight;
}

IsFullScreen 속성의 위치는 아래와 같이 변경되었습니다.

// 풀스크린 여부
Application.Current.Host.Content.IsFullScreen

풀스크린 변경 이벤트 핸들러

Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);

void Content_FullScreenChanged(object sender, EventArgs e)
{
    System.Windows.Interop.Content content =  Application.Current.Host.Content;

    // 풀스크린 여부
    if (content .IsFullScreen)
    {
        double heightRatio = content.ActualHeight / this.Height;
        double widthRatio = content.ActualWidth / this.Width;
        ScaleTransform scale = new ScaleTransform();
        scale.ScaleX = widthRatio;
        scale.ScaleY = heightRatio;
        this.RenderTransform = scale;
    }
    else
    {
        this.RenderTransform = null;
    }
}

네임스페이스

using System.Windows;

3. Image.Source 사용법

1.1에서는 Uri 클래스를 바로 적용을 했지만 2에서는 Bitmap으로 변경해서 적용을 하도록 변경이 되었습니다.

Image image = new Image();
image.Source = new BitmapImage(new Uri("http://shblitz.net/shblitz.jpg", UriKind.Absolute));

BitmapImage를 사용하면서 좋은 점은 BitmapImage에 DownloadProgress 이벤트가 있어서 이미지가 다 받아졌는지 확인이 가능하다는 것입니다.

Image image = new Image();
BitmapImage bitmap = new BitmapImage(new Uri(http://shblitz.net/shblitz.jpg, UriKind.Absolute));
bitmap.DownloadProgress += new DownloadProgressEventHandler(bitmap_DownloadProgress);

// 다운로드 완료 이벤트 핸들러
void bitmap_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
    BitmapImage bitmap = sender as BitmapImage;
    // 다운로드 성공
    if (e.Progress == 1)
    {
        // 로직...
    }
}

네임스페이스

using System.Windows.Media.Imaging;

4. HtmlTimer 대신 DispatcherTimer 사용

Silverlight 2에서는 HtmlTimer가 사라졌습니다. 대신 아래와 같은 클래스를 사용하면 될것입니다.

System.Threading.Timer
System.Windows.Threading.DispatcherTimer

HtmlTimer를 사용하시던 분은 DispatcherTimer를 사용 할것을 권합니다.

사용법은 비슷하며, Interval을 TimeSpan으로 수정만 하시면 될것입니다.

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(3000); // 3초
// timer.Interval = new TimeSpan(0, 0, 0, 0, 3000); // 3초
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

void timer_Tick(object sender, EventArgs e)
{
    // 로직...
}

5. Downloader 대신 WebClient 사용

1.1에서 한글을 사용하기 위해 Downloder를 많이 사용해 보셔을 것입니다. 그러나 Silverlight 2에서 이 Downloader가 사라졌습니다. 대신 WebClient를 사용하시면 됩니다.

파일 전송을 위한 메서드로 OpenReadAsync와 DownloadStringAsync가 지원됩니다.

OpenReadAsync

받아올 파일이 wmv, zip 파일같이 이진파일일 경우 사용합니다.

WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
wc.OpenReadAsync(new Uri("song.wma", UriKind.Relative));

이벤트 아규먼트로 넘어오는 e.Result 값은 Stream으로 넘어온다.

// 다운로드 완료 이벤트 핸들러
void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    MediaElement media = new MediaElement();
    if ((e.Error == null) && (e.Cancelled == false))
    {
        media.SetSource = e.Result;
        LayoutRoot.Children.Add(media);
        media.Play();
    }
}

Zip 파일 다운로드시 사용 예제

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if ((e.Error == null) && (e.Cancelled == false))
    {
        StreamResourceInfo zipResourceInfo = new StreamResourceInfo(e.Result, null);
        StreamResourceInfo imageResourceInfo = Application.GetResourceStream(zipResourceInfo, new Uri("image1.jpg"));
        // .....
    }
}

DownloadStringAsync

받아올 파일이 xml이나 Text 형식일 경우 이 메소드를 사용합니다.

WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("data.xml", UriKind.Relative));

이벤트 아규먼트로 넘어오는 e.Result 값은 String으로 넘어온다.

// 다운로드 완료 이벤트 핸들러
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    XmlReader xr = XmlReader.Create(new StringReader(e.Result));
    //...
}

* 참고 : 실버라이트2의 루트는 1.1과는 달리 ClientBin 폴더가 루트로 인식됩니다. 그러니 다운로드할 파일은 기본적으로 ClientBin 폴더 이하에 있어야 합니다. 절대경로로 사용할 경우는 상관없습니다.

네임스페이스

using System.Net;

6. HtmlPage에서 HtmlDocument로 이동된 함수들

Submit, Cookies, QueryString, DocumentUri

예제)

System.Windows.Browser.HtmlDocument doc = new System.Windows.Browser.HtmlDocument();
string seq = doc.QueryString["ParameterName"];

7. HtmlPage에서 HtmlWindow로 이동된 함수들

CurrentBookmark, Alert/Confirm/Eval/Prompt, CreateInstance, Navigate*/NavigateToBookmark

예제)

System.Windows.Browser.HtmlWindow win = System.Windows.Browser.HtmlPage.Window;
win.Alert("경고");

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

  1. 이봉호  댓글주소 수정/삭제 댓글쓰기 2008/03/25 16:19

    감사합니다 좋은 참고 자료가 돼겠어요^^

  2. ramses8  댓글주소 수정/삭제 댓글쓰기 2008/07/31 09:42

    좋은 내용 고맙습니다~

  3. 실버라잇  댓글주소 수정/삭제 댓글쓰기 2008/09/06 23:13

    좋은 정보 감사합니다..스크랩 해 갈게요~