ü  WCF Service의 개념

1.     닷넷의 여러 분산 기술들을 하나로 통합하여 SOA기반의 애플리케이션을 쉽게 개발해 줄 수 있게 지원해주는 기술이며, 기존의 복잡했던 각각의 개발 방식을 일관된 방식으로 프로그래밍할 수 있게 제공해줍니다.

2.     보안이나 트랜잭션과 같은 기능을 구현할 수 있는 높은 생산성을 제공해주고 있고, 기존의 닷넷 분산 기술과 웹 서비스 확장 스펙(WS-*)과의 높은 상호 운용성을 제공해 주고 있습니다. , 닷넷 웹 서비스를 포함하여 좀 더 포괄적인 분산 기술을 지원한 닷넷 기술이라고 보시면 됩니다.

     참고 사이트

MSDN - WCF(Windows Communication Foundation) 서비스 구축

ü  Silverlight에서 WCF Service를 사용하는 경우

1.     DB에 접근할 때

-       Silverlight에서는 .NET의 데이터 처리(DataSet)가 지원하지 않습니다. 웹 서비스 및 WCF 서비스를 통해 데이터를 가져와야 합니다.

2.    다른 플랫폼과 소통을 위한 경우

3.     기타 외부에서 필요한 인자를 읽어오려 할 때

ü  Silverlight를 위한 WCF Service 만들기

1.     WCF의 가장 기본이 되는 개념인 엔드포인트(EndPoint)의 개념

-       WCF서비스와 클라이언트가 엔드포인트를 통해 메시지를 주고 받게 됩니다..

-      엔드포인트는 주소(Address), 바인딩(Binding), 계약(Contact) 3가지 요소로 구성되어 있습니다. , 어디에서(Where) 무엇을(What) 어떻게(How) 통신할 것인지에 대한 개념입니다.

2.   웹사이트에 WCF Service 만들기 방법

-       새로 만들기에 웹사이트를 새로 만듭니다.

-       WCF 서비스를 선택하고, 폴더 경로를 선택하여 프로젝트를 생성합니다.

-       App_Code폴더에 IService.cs Service.cs 두개의 파일이 생성되어 있는 것을 볼 수 있으며, 파일에 작성되어 있는 샘플 코드를 지우고 아래와 같이 작성합니다.

Code

IService.cs

[ServiceContract]

public interface IService

{

    [OperationContract]

    DateTime GetNowDate();

}

 

Service.cs

public class Service : IService

{

    public DateTime GetNowDate()

    {

        return DateTime.Now;

    }

}

-       Web.config을 열어보시면, EndPoint binding 속성을 basicHttpBinding으로 변경합니다.

Code

<!-- 중략 -->

<system.serviceModel>

    <services>

      <service name="Service" behaviorConfiguration="ServiceBehavior">

        <!-- Service Endpoints -->

        <endpoint address="" binding="basicHttpBinding" contract="IService">

          <!--

              배포 시 다음 identity 요소는 배포된 서비스를 실행할 때 사용하는 ID를 반영하도록

              제거되거나 대체되어야 합니다. 해당 요소가 제거되면 WCF에서는 적합한 ID

              자동으로 유추합니다.

          -->

          <identity>

            <dns value="localhost"/>

          </identity>

        </endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="ServiceBehavior">

          <!-- 메타데이터 정보를 공개하지 않으려면 배포하기 전에 아래의 값을 false로 설정하고 위의 메타데이터 끝점을 제거하십시오. -->

          <serviceMetadata httpGetEnabled="true"/>

          <!-- 디버깅 목적으로 오류에서 예외 정보를 받으려면 아래의 값을 true로 설정하십시오. 예외 정보를 공개하지 않으려면 배포하기 전에 false로 설정하십시오. -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Description

ð  Silverlight Web에 종속된 기술이기 떄문에 기본적인 바인딩인 basicHttpBinding만 지원합니다.

-      컴파일 후, Service.svc 파일을 브라우저에서 보기 하면 다음과 같은 화면이 나타나며, 제대로 작동하고 있다는 것을 알 수 있습니다. 이 서비스는 WCF 서비스이자 웹 서비스라 할 수 있습니다.

3.     Silverlight 에서 WCF Service 참조하기

-       Silverlight 응용 프로그램을 선택한 후, 새 프로젝트를 추가합니다.

-       WCF 서비스 프로젝트에서 결과를 확인할 수 있게 기존 웹 사이트에 연결합니다.

-       Silverlight 응용 프로젝트가 생성이 되면, 프로젝트 참조 부분에 오른쪽 마우스를 눌러 서비스 참조를 선택합니다. (이하, ASP.NET에 웹 서비스 참조 하는 방식과 유사합니다.)

-       좀전에 Service.svc URL를 주소에 넣고, 이동을 누르면 해당 서비스 목록이 나타나며, 서비스 네임스페이스명을 지정합니다.

-       서비스 참조된 것을 볼 수 있으며, 서비스 설정 파일(ServcieReferences.ClientConfig)이 생성된 것을 볼 수 있으며, ServcieReferences.ClientConfig 파일을 열어보면 WCF 서비스 설정이 생성된 것을 볼 수 있습니다.

Code

ServcieReferences.ClientConfig

<configuration>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="BasicHttpBinding_IService" maxBufferSize="2147483647"

                    maxReceivedMessageSize="2147483647">

                    <security mode="None" />

                </binding>

            </basicHttpBinding>

        </bindings>

        <client>

            <endpoint address="http://localhost:8553/WCFService1/Service.svc"

                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"

                contract="WCFService.IService" name="BasicHttpBinding_IService" />

        </client>

    </system.serviceModel>

</configuration>

ð  basicHttpBinding전송수준에서의 보안이나 메시지자체의 보안기능은 제공하지만, 트랙젼선이나 세션과 같은 기능은 제공하지 않습니다.

4.    WCF Service 호출하여 Silverlight에 데이터 결과를 보여주기

-       Page.xaml 파일에 데이터를 받기 위한 텍스트블록 컨트롤을 추가하고, 페이지 로드시, 서비스 호출하여 화면에 보여줍니다.

Code

Page.xaml

<TextBlock x:Name="txtDateNow"></TextBlock>

 

Page.xaml.cs

public partial class Page : UserControl

{

    public Page()

    {

        InitializeComponent();

 

        this.Loaded += new RoutedEventHandler(Page_Loaded);

    }

 

    void Page_Loaded(object sender, RoutedEventArgs e)

    {

        //WCF 서비스 객체 생성

        WCFService.ServiceClient service = new WCFBinding.WCFService.ServiceClient();

        //GetDateNow 메서드 결과를 리턴받는 이벤트

        service.GetDateNowCompleted += new EventHandler<WCFBinding.WCFService.GetDateNowCompletedEventArgs>(service_GetDateNowCompleted);

        //비동기 호출

        service.GetDateNowAsync();

    }      

 

    //서비스로부터 호출결과를 반환받을 경우

    void service_GetDateNowCompleted(object sender, WCFBinding.WCFService.GetDateNowCompletedEventArgs e)

    {

        txtDateNow.Text = e.Result.ToShortDateString();

    }

}

Result

-       Microsoft Silverlight

http://silverlight.net/

-       실버라이트 정보 공유 카페

http://cafe.naver.com/mssilverlight.cafe

-       ScottGu's Blog

http://weblogs.asp.net/scottgu/pages/silverlight-posts.aspx

-       MSDN Library (Silverlight)

http://msdn.microsoft.com/ko-kr/library/cc838158(VS.95).aspx

ü  Silverlight 배포하는 방법

1.     Object 태그를 이용한 방법

-       Naver에서 보면 퍼가기와 같은 기능 구현이 가능하며, 특정 웹 서버의 제약 없이 구동 할 수 있어 Silverlight 배포 추천 방법이라 할 수 있습니다.

2.     Silverlight.js의 함수를 이용한 방법

3.     ASP.NET Silverlight 컨트롤을 이용한 방법

-       3번과 배포 방법은 웹사이트가 닷넷 환경이어야 한다는 제약이 있습니다.

ü  Object 태그를 이용한 방법 (알아두면 좋은 것)

1.     Object 태그의 필수적인 속성

속성

내용

Id

HTML 안에 포함될 실버라이트 플러그인의 이름

Data

실버라이트를 어떻게 로드할지에 대한 MIME 타입

Type

실버라이트의 버전

Height

실버라이트를 나타낼 높이(픽셀, %, 둘 다 지정가능)

Width

실버라이트를 나타낼 넓이(픽셀, %, 둘 다 지정가능)

2.     속성과 이벤트의 주요 파라미터

파라미터

내용

Source

URI형식으로 나타낸 실버라이트 파일의 주소이고, 기본 값은 null입니다.

onError

실버라이트에서 에러가 발생할 경우 그 에러 내용을 Javascript로 전달하여 보여줍니다.

onResize

실버라이트의 ActalHeight, ActualWidth 속성이 변경될 때 발생하는 이벤트이며, 처음 로드할 때도 발생하지만 Full-Screen 모드로 변경될 때는 발생하지 않습니다.

3.     선택적인 파라미터

파라미터

내용

background

실버라이트가 로드될 때의 배경색으로 기본값은 null입니다.

enableHtmlAccess

HTML DOM에서 실버라이트 개체로의 접근이나 실버라이트에서 HTML 컨텐트로의 접근을 허용할지에 대한 여부로 기본값은 false입니다.

initParams

실버라이트 런타임으로 전달할 초기 설정 문자열로 콤마(,)을 이용해서 여러 개의 문자열을 구분하여 전달 할 수 있습니다.(key1=value1,key2=value2,key3=value3)

maxFrmaerate

1초간 보여줄 프레임 수의 최대치로 기본값은 60입니다. 이 값은 높을수록 사용자 브라우저의 성능을 늦출 수 있고, 또한 낮을수록 애니메이션이 상당히 부자연스러울 수 있습니다.

splashScreenSource

Source 파라미터에서 지정한 파일이 다운로드 되는 동안의 로딩을 보여줄지에 대한 여부입니다.

windowless

HTML과 혼합되어 사용할 수 있는 Windowless 모드를 설정할 지에 대한 여부로 기본 값은 fasle입니다. 이 속성은 MS 원도우에서 동작되는 브라우저에만 작동됩니다.

*음영 처리된 부분은 기억해 두시는 겟 좋습니다.

4.     추가적인 이벤트 파라미터

파라미터

내용

onLoad

실버라이트가 에러없이 로드되고 모든 내용이 표시될 때 발생하는 이벤트입니다.

onSourceDownloadComplete

Source 파라미터에서 지정한 파일의 다운로드가 완료될 때 발생하는 이벤트입니다.

onSourceDownloadProgressChanged

Source 파라미터에서 지정한 파일의 다운로드가 진행될 떄 발생하는 이벤트입니다.

5.     애니메이션의 진단을 위한 추가 파라미터

-       설정한 속성 외에도 프레임 속도를 브라우저에 보여주거나 렌더링되는 위치를 진단해 보고 싶을 경우 사용합니다. 이 부분에 대해서는 자세히 정리 하지 않겠지만 도움이 될 만한 사이트 주소를 걸어두도록 하겠습니다. (링크)

 

 

ü  Sample Code

1.     initParams을 이용한 데이터 전달하기

-       Silverlight 응용 프로그램 빌드 시, 생성되는 TestPage.html object태그에 파라미터 추가합니다.

Code

TestPage.html

<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">

             <param name="source" value="DemoSample4.xap"/>

             <param name="onerror" value="onSilverlightError" />

             <param name="background" value="white" />

             <param name="minRuntimeVersion" value="2.0.31005.0" />

             <param name="autoUpgrade" value="true" />

             <param name="initParams" value="message1=demo1,message2=demo2" />

             <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                           <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

             </a>

</object>

-       App.xaml.cs에서 Application_Startup 이벤트에서 해당 값을 가져와서 Page.xaml에서 값 전달 받아, 메시지창 띄우기

Code

App.xaml.cs

private void Application_Startup(object sender, StartupEventArgs e)

{

    string strMessage = e.InitParams["message1"] + e.InitParams["message2"];

    this.RootVisual = new Page(strMessage);

}

Page.xaml.cs

public Page(string strMessage)

{

    InitializeComponent();

 

    MessageBox.Show(strMessage);

}

2.     Silverlight에서 HTML 개체에 접근하기

-       Silverlight 역시 DOM 방식을 이용하여 HTML 엘리먼트에 접근할 수 있습니다.

-       TestPage.html Silverlight div 영역 상단에 우선 HTML 개체인 input 엘리먼트를 추가합니다.

Code

TestPage.html

<input type="text" id="txtDemo" value="demo" />

<div id="silverlightControlHost">

             <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">

                           <param name="source" value="DemoSample4.xap"/>

                           <param name="onerror" value="onSilverlightError" />

                           <param name="background" value="white" />

                           <param name="minRuntimeVersion" value="2.0.31005.0" />

                           <param name="autoUpgrade" value="true" />

                           <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

                           </a>

             </object>

             <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

</div>

-       Page.xaml에서 텍스트 박스와 버튼 컨트롤 추가하고, 버튼 클릭 이벤트에 텍스트 박스의 값을 HTML개체인 input value에 넣은 로직을 구현해보겠습니다.

Code

Page.xaml

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal">

        <TextBox x:Name="TextBox1"  Width="150" Height="20"></TextBox>

        <Button x:Name="Button1" Width="100" Height="20" Content="클릭" Click="Button1_Click"></Button>

    </StackPanel>

</UserControl>

Page.xaml.cs

//추가 네임스페이스

using System.Windows.Browser;

 

private void Button1_Click(object sender, RoutedEventArgs e)

{

    //현재 HTML 페이지의 Document 가져오기

    HtmlDocument document = HtmlPage.Document;

 

    //GetElementById input 개체 접근

    HtmlElement element = document.GetElementById("txtDemo");

 

    //GetAttribute value 값 가져오기

    //element.GetAttribute("value");

 

    //SetAttribute value 값 설정하기

    element.SetAttribute("value", TextBox1.Text);

}

Result

  =>

ð  상단 영역은 HTML 개체이고, 아래는 Silverlight 영역입니다.

ð  Silverlight 영역의 텍스트박스에 텍스트 입력 후, 클릭 하시면, HTML 개체의 값이 변경되는 것을 볼 수 있습니다.

3.     HTML 엘리먼트의 이벤트 구독하기

-       테스트 페이지에 2번과 같이 Silverlight 영역 상단에 텍스트박스와 버튼 개체를 추가합니다.

Code

TestPage.html

<input type="text" id="txtDemo" value="demo" />

<input type="button" id="btnDemo" value="메시지 보이기" />

-       Page.xaml.cs에서 Page() 생성자에 HTML 개체 이벤트를 로직을 추가합니다.

Code

Page.xaml.cs

public Page()

{

    InitializeComponent();

 

    //이벤트 구독

    HtmlElement btnElement = HtmlPage.Document.GetElementById("btnDemo");

    btnElement.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this.OnBtnDemoClicked));

}

 

private void OnBtnDemoClicked(object sender, EventArgs e)

{

    HtmlElement txtElement = HtmlPage.Document.GetElementById("txtDemo");

    MessageBox.Show(txtElement.GetAttribute("value"));

}

Result

4.     Silverlight Javascript의 연동

-       Silverlight에서 Scriptable 어트리뷰트를 제공해 주며, 어트리뷰트를 선언함으로써 자바스크립트로의 접근을 허용할 수 있습니다.

-       Silverlight 응용 프로젝트 생성 후, TestPage.html 파일에 input 엘리먼트를 추가하고, Silverlight Object 태그에 id가 지정되어 있지 않는다면, id를 지정합니다.

Code

<body>

    메시지 입력 : <input type="text" id="txtMessage" /><br />

    <input type="button" id="btnReg" onclick="RegMessage()" value="등록" />

 

    <div id="silverlightControlHost">

                           <object id="silverlightObject" data="data:application/x-silverlight-2,"  type="application/x-silverlight-2" width="100%" height="100%">

                                        <param name="source" value="ClientBin/DemoSample4.xap"/>

                                        <param name="onerror" value="onSilverlightError" />

                                        <param name="background" value="white" />

                                        <param name="minRuntimeVersion" value="2.0.31005.0" />

                                        <param name="autoUpgrade" value="true" />

                                        <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                                       <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

                                        </a>

                           </object>

                           <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

    </div>

</body>

-       Page.xaml에서 받은 텍스트를 보여줄 TextBlock를 선언하고, Page.xaml.cs에서 HTML의 자바스크립트에서 접근할 수 있는 속성과 메서드를 만들겠습니다.

Code

Page.xaml

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock x:Name="txtMessage" Text="메시지 : " ></TextBlock>

    </Grid>

</UserControl>

 

Page.xaml.cs

[ScriptableType]

public partial class Page : UserControl

{

    public string message;

 

    public Page()

    {

        InitializeComponent();

        HtmlPage.RegisterScriptableObject("MessageInfo", this);

    }

 

    [ScriptableMember()]

    public void AlertMessage()

    {

        txtMessage.Text = "메시지 : " + this.Message;

 

        //자바스크립트 함수 호출하기

        //MessageBox.Show("등록되었습니다."); 와 동일함.

        HtmlElement alertScript = HtmlPage.Document.CreateElement("script");

        alertScript.SetAttribute("text", "alert('등록되었습니다.');");

        HtmlPage.Document.DocumentElement.AppendChild(alertScript);

    }

  

    [ScriptableMember()]

    public string Message

    {

        get { return message; }

        set { message = value; }

    }

}

Description

ð  클래스 속성에 [ScriptableType]를 선언하면, HtmlPage.RegisterScriptableOjbect() 메소드를 통해 모든 공용 속성, 메서드 및 이벤트를 JavaScript 코드에서 사용할 수 있으며, Javascript에서의 접근을 위해 반드시 선언하여야 합니다.

ð  각각의 속성에 선언한 [ScriptableMember()] 어트리뷰트는 HTML스크립트에서 해당 코드에 접근할 수 있도록 허용하기 위해 선언해 주어야 합니다.

-       TestPage.html 에서 RegMessage() 스크립트를 작성합니다.

Code

<script type="text/javascript">

    function RegMessage() {

 

        //실버라이트 객체

        var host = document.getElementById("silverlightObject");

 

        //사용자 정보 등록

        host.content.MessageInfo.Message = document.getElementById("txtMessage").value;

 

        //사용자 메서드 호출

        host.content.MessageInfo.AlertMessage();

    }

</script>

ð  HtmlPage.RegisterScriptableOjbect()에서 선언하였던 Script Key를 통해 JavaScript 코드에서 접근이 가능합니다.

Result

=>

ü  Understand ControlTemplate

1.     템플릿을 활용하면 컨트롤의 전체 모양을 바꿀 수 있을 뿐만 아니라, 컨트롤의 컨텐트 영역만도 바꿀 수 있으며, 컨트롤이 가지고 있는 애니메이션 역시도 바꿀 수 있습니다

2.     대부분의 컨트롤들은 컨트롤 클래스를 상속하고 있는데, 템플릿은 이 컨트롤 클래스의 Template 속성을 사용하게 됩니다. 리소스 형태 또는 컨트롤에 속성 엘리먼트로 Template 속성 값을 설정하게 됩니다.

3.     템플릿 속성 지정 방법

-       컨트롤 속성 엘리먼트로 지정하는 방법

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" >

        <Button.Template>

            <ControlTemplate>

                <Grid>

                    <!-- 중략 -->

                </Grid>

            </ControlTemplate>

        </Button.Template>

    </Button>

</Grid>

ð  가장 쉽고 명백하지만, 다른 컨트롤과 공유되지 않기 때문에 매우 제한된 경우에 주로 사용합니다.

-       컨트롤 템플릿 리소스로 값 설정하는 방법

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.Resources>

        <ControlTemplate x:Key="buttonTemplate">

            <Grid>

                <!-- 중략 -->

            </Grid>

        </ControlTemplate>

    </Grid.Resources>

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" Template="{StaticResource buttonTemplate}" ></Button>

</Grid>

ð  템플릿을 리소스에서 정의하며, x:Key 속성을 설정하여 각 컨트롤들이 바인딩을 통해 값을 설정하게 됩니다.

-       스타일 리소스로 값 설정하는 방법(스타일의 Setter를 통해 템플릿 속성값을 변경)

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.Resources>

        <Style x:Key="buttonStyle" TargetType="Button">

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="Button">

                        <Grid>

                            <!-- 중략 -->

                        </Grid>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

    </Grid.Resources>

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" Style="{StaticResource buttonStyle}" ></Button>

</Grid>

ð  가장 많이 쓰이는 방식으로, Setter를 통해 설정된 속성값에 템플릿을 정의하는데 바인딩 표현식을 사용할 수 있어, 유연하게 활용할 수 있습니다.

 

ü  Sample Code

1.     버튼 컨트롤 모양 바꾸기

-       템플릿에 그라디언트가 적용된 타원 버튼을 만들어보겠습니다.

Code

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.Resources>

            <Style x:Key="buttonStyle" TargetType="Button">

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate>

                            <Grid>

                                <Ellipse>

                                    <Ellipse.Fill>

                                        <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                                            <GradientStop Color="#FF000000" Offset="1" />

                                            <GradientStop Color="#FFFFFFFF" Offset="0" />

                                        </LinearGradientBrush>

                                    </Ellipse.Fill>

                                </Ellipse>

                            </Grid>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

        </Grid.Resources>

       

        <Button Width="100" Height="50" Content="버튼1" Style="{StaticResource buttonStyle}"></Button>

    </Grid>

</UserControl>

 

Result


Description

ð  버튼 컨트롤 모양을 바꾸는데는 성공하였지만, “버튼1”이라는 컨트롤의 텍스트 즉, 컨텐트 내용이 표시되지 않았습니다.

-       ContentPresenter을 통한 컨트롤의 컨텐트 영역을 표시합니다.

Code

<!-- 생략 -->

<Grid.Resources>

    <Style x:Key="buttonStyle" TargetType="Button">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate>

                    <Grid>

                        <Ellipse>

                            <Ellipse.Fill>

                                <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                                    <GradientStop Color="#FF000000" Offset="1" />

                                    <GradientStop Color="#FFFFFFFF" Offset="0" />

                                </LinearGradientBrush>

                            </Ellipse.Fill>

                        </Ellipse>

                        <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>

                    </Grid>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

</Grid.Resources> <!-- 생략 -->

Result

Description

ð  ContentPresenter의 컨텐트 속성을 이 템플릿이 설정된 컨트롤의 컨텐트 속성과 바인딩을 통해서 동일한 값을 설정할 수 있도록 선언하고 있습니다. (TemplateBinding 사용)

 

ü  Sample Code

1.     ListBox 컨트롤의 SelectionChanged 이벤트를 이용한 DetailView Dialog를 구현

-       DetailView를 위해 DetailView명으로 UserControl(Silverlight 사용자 정의 컨트롤)을 추가합니다.

-       UI 화면 만들고, 닫기 버튼 이벤트를 작성합니다.

Code

DetailView.xaml

<UserControl x:Class="DemoSample3.DetailView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="OrangeRed"></Rectangle>           

       

        <Button x:Name="btnClose" Content="닫기" Width="100" Height="50" Click="btnClose_Click"></Button>

    </Grid>

</UserControl>

 

DetailView.xaml.cs

// 닫기 버튼 이벤트를 추가

private void btnClose_Click(object sender, RoutedEventArgs e)

{

    Visibility = Visibility.Collapsed;

}

-       초기 페이지 Page.xaml ListBox 컨트롤 Item 선택 이벤트를 작성합니다.

Code

Page.xaml

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="DemoSample3.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:detailview="clr-namespace:DemoSample3"

    >

    <Grid x:Name="LayoutRoot" Background="DarkOrange" >

        <!-- 중략 -->

        ………

        <ListBox x:Name="lbResult" Grid.Row="1"  SelectionChanged="lbResult_SelectionChanged">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <!-- 중략 -->

………

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

       

        <!-- Modal Detail View UserControl 추가 -->

        <detailview:DetailView x:Name="DetailView" Grid.Row="1" Visibility="Collapsed"></detailview:DetailView>

    </Grid>

</UserControl>

Page.xaml.cs

private void lbResult_SelectionChanged(object sender, SelectionChangedEventArgs e)

{

    DetailView.Visibility = Visibility.Visible;

}

Description

ð  Silverlight 초기 페이지 Page.xaml 상단에 DetailView UserControl을 추가하기 위해 태그를 추가합니다. (ASP.NET 에서 UserControl 추가하는 것과 유사합니다.)

ð  DetailView 컨트롤 추가 한 후, Visiblity 속성을 Collapsed를 지정하여, 기본적으로 화면에 보이지 않게 하고, ListBox 컨트롤의 Item 선택 이벤트에 DetailView 컨트롤 Visible 처리 합니다.

Result
     

     

2.     DataContext 를 이용하여 DetailView 상세 화면 구현하기

-       DetailView에 상세 데이터를 표현하기 위해 UI를 변경하였습니다.

(데이터 표현하기 위한 TextBlock 추가)

Code

DetailView.xaml

<UserControl x:Class="DemoSample3.DetailView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="OrangeRed"></Rectangle>

 

        <StackPanel Orientation="Vertical">

            <StackPanel  Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 이름 :</TextBlock>

                <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 소개 :</TextBlock>

                <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">작성자 :</TextBlock>

                <TextBlock x:Name="txtBookAuthor" Margin="5" Text="{Binding Author}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 가격 :</TextBlock>

                <TextBlock x:Name="txtBookPrice" Margin="5" Text="{Binding Price}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">발행사 :</TextBlock>

                <TextBlock x:Name="txtBookPublisher" Margin="5" Text="{Binding Publisher}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">발행일 :</TextBlock>

                <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

            </StackPanel>

            <Button x:Name="btnClose" Content="닫기" Width="100" Height="50" Click="btnClose_Click"></Button>

        </StackPanel>

       

    </Grid>

</UserControl>

-       ListBox 컨트롤의 Item 선택시 DetailView 컨트롤에 DataContext를 이용하여 데이터 전송

Code

Page.xaml

private void lbResult_SelectionChanged(object sender, SelectionChangedEventArgs e)

{

    Book book = (Book)lbResult.SelectedItem;

 

    DetailView.DataContext = book;

    DetailView.Visibility = Visibility.Visible;

}

Result


Description

ð  DetailView UserControl과 같이 FrameworkElement가 데이터 바인딩에 참여하는 경우, 해당 DataContext를 가져오거나 설정할 수 있으며, DataContext는 특정 컨텍스트가 다른 컨텍스트에 바인딩될 수 있는 시나리오의 작업을 원활하게 수행할 수 있도록 바인딩 가능한 속성입니다.

 

u  Understand DataBinding

1.    데이터 바인딩의 개념

-      우선, UI 엘레먼트와 데이터 개체와의 연결을 만드는 과정이라고 보시면 됩니다.

-      바인딩 원본 개체의 특정 속성이 바인딩대상 엘리먼트의 의존 속성과 다르거나 원본 개체 속성의 값이 가공해야 할 경우 변환기(ValueConverter)를 통해 변경해야 합니다.

-      데이터 바인딩 기본 개념도

    데이터 바인딩의 장점  

-      모든 개체들의 속성(Property)이 바인딩을 지원합니다.

-      데이터 템플릿과 스타일을 통해 데이터표현이 자유롭고 유연합니다.

-      UI로 부터 비즈니스 로직을 완벽히 분리할 수 있습니다.

2.    데이터 흐름

-      BindingMode열거형

속성

설명

OneWay

바인딩이 만들어지거나 바인딩 원본 개체 속성이 변경되었을 때 바인딩 대상 개체의 속성 값을 변경합니다.

OneTime

바인딩이 만들어질 때만 바인딩 대상 개체의 속성 값을 변경합니다.

TwoWay

바인딩 원본과 대상 개체의 속성 중 하나가 변경되면 나머지 하나의 속성 값을 변경합니다.

-      OneWay, TwoWay와 같이 바인딩 원본 개체의 속성값이 변경되었을 때 대상 개체의 속성값을 변경하기 위해서는 INotifyPropertyChanged 인터페이스를 구현해야만 합니다.

3.    데이터 바인딩 표현식

<object Property=”{Binding}” …/>

<object Property=”{Binding propertyPath}” …/>

<object Property=”{Binding oneOrMoreBindingProperties}” …/>

<object Property=”{Binding propertyPath , oneOrMoreBindingProperties }” …/>

 

u  Sample Code

1.    마우스 왼쪽 버튼 클릭 이벤트로 TextBlock 색깔 바꾸기

-      텍스트 블록에 Foreground 데이터 바인딩하기

Code

Page.xaml

<UserControl x:Class="DemoSample2.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White" >

        <TextBlock x:Name="TextBlock1" Margin="10" Foreground="{Binding ChangingColor}">DataBinding Sample Code</TextBlock>

    </Grid>

</UserControl>

 

Page.xaml.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace DemoSample2

{

    public partial class Page : UserControl

    {

 MyColors myColor = new MyColors();

 

        public Page()

        {

            InitializeComponent();

 

            myColor.ChangingColor = new SolidColorBrush(Colors.Red);

            this.TextBlock1.DataContext = myColor;

        }

    }

 

    public class MyColors

    {

        private SolidColorBrush changingColor;

 

        public SolidColorBrush ChangingColor

        {

            get { return changingColor; }

            set { changingColor = value; }

        }

    }

}

Description

ð  Page.xaml 텍스트 블록의 Foreground 속성에 바인딩합니다.

ð  데이터 바인딩을 위한 원본 개체를 만들기 위해 MyColors 클래스를선언하였습니다.

ð  Page()에서 Object 개체에 데이터 바인딩을 지정하였습니다.

Result

 

-      마우스 왼쪽 버튼 클릭 이벤트 추가

Code

Page.xaml

<TextBlock x:Name="TextBlock1" Margin="10" Foreground="{Binding ChangingColor}" MouseLeftButtonDown="TextBlock1_MouseLeftButtonDown">DataBinding Sample Code</TextBlock>

 

Page.xaml.cs

private void TextBlock1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

    myColor.ChangingColor = new SolidColorBrush(Colors.Black);

}

Description

ð  마우스 왼쪽 버튼 클릭 이벤트를 추가하였습니다. 빌드 후, 결과 화면을 보시면, 상단 이미지와 동일하게 텍스트 블록 색깔 변화가없는 것을 볼 수 있습니다.

ð  속성 값 변경을 감지해서 대상 속성의 값을 변경하기 위해서는INotifyPropertyChanged 인터페이스를 반드시 구현해 주어야 합니다.

-      INotifyPropertyChanged인터페이스 구현

Code

public class MyColors : INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;

 

    private SolidColorBrush changingColor;

    public SolidColorBrush ChangingColor

    {

        get { return changingColor; }

        set

        {

            changingColor = value;

            NotifyPropertyChaged("ChangingColor");

        }

    }

 

    private void NotifyPropertyChaged(string propertyName)

    {

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

}

2.    ListBox컨트롤에 DataBinding 하기

-      Part3.“Naver OpenAPI 를 이용한 Book검색코드에서 DataGrid 컨트롤를 삭제하고, ListBox 컨트롤로 변경한 후, 데이터 보여주기

Code

Page.xaml

// DataGrid 컨트롤 삭제하고, ListBox 컨트롤 로 대체함.

<ListBox x:Name="lbResult" Grid.Row="1"></ListBox>

 

Page.xaml.cs

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        //Using LINQ to XML to Parse NaverOpenAPI XML Items into Book Class

        XDocument xmlBooks = XDocument.Parse(e.Result);

 

        var books = from book in xmlBooks.Descendants("item")

                    select new Book

                    {

                        BookName = (string)book.Element("title"),

                        LinkUrl = new Uri((string)book.Element("link")),

                        ImageUrl = new Uri((string)book.Element("image")),

                        Author = (string)book.Element("author"),

                        Price = (int)book.Element("price"),

                        Publisher = (string)book.Element("publisher"),

                        PubDate = (string)book.Element("pubdate"),

                        ISBN = (string)book.Element("isbn"),

                        Description = (string)book.Element("description")

                    };

 

        // XML Parse 한 데이터 바인딩하기

        lbResult.ItemsSource = books;

    }

}

Result

Description

ð  검색 버튼 클릭 시, ListBox 에 해당 데이터 영역에바인딩된 컬렉션명이 나타나는데, ListBox 컨트롤 부분에 <ListBox x:Name="lbResult" DisplayMemberPath="BookName" Grid.Row="1"></ListBox> 어떤 데이터를보여줄지 매핑을 하지 않았기 때문입니다. 위와 같이 DisplayMemberPath를 지정해 주시면,아래와 같이 원하는 데이터를 화면에 보여줍니다.


-      ListBox.ItemTemplate를 이용한 DataTemplate 구현하기

Code

Page.xaml

<ListBox x:Name="lbResult" Grid.Row="1">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이름 : </TextBlock>

                    <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 소개 :</TextBlock>

                    <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 발행일 :</TextBlock>

                    <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

                </StackPanel>

            </StackPanel>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>

Result


Description

ð  ListBox 1개 이상의 정보를 보여줄 경우, ListBox 컨트롤의 ItemTemplate안에 DateTemplate를 정의하여 표현하고자하는 UI를 표현할 수 있습니다.

ð  DataTemplate 안에는 한 개의 컨트롤만 사용 가능하나, 여러 개의 컨트롤을 사용할 경우, StackPanel를 감싸줘서 사용할 수 있습니다.

3.     Tooltips (중요)

-      Part3“Silverlight Network 이해하기 에서 Silverlight Application보안을 위한 URL 접근이 제약되어 있고, 보안 정책 파일을 통해 특정 클라이언트의 접근을허용할 수 있다고 설명 드렸습니다. 우선 샘플 코드를 통해 자세한 설명을 이어가겠습니다.

-      ListBox컨트롤의 ItemTempalte 에검색한 책 이미지를 넣어보겠습니다.

Code

Page.xaml

<ListBox x:Name="lbResult" Grid.Row="1" >

    <ListBox.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이미지 :</TextBlock>

                    <Image Source="{Binding ImageUrl}" Width="16" Height="10"></Image>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이름 :</TextBlock>

                    <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 소개 :</TextBlock>

                    <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 발행일 :</TextBlock>

                    <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

                </StackPanel>

            </StackPanel>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>

Result


Description

ð  결과 화면처럼 에러 코드 : 4001 , 범주 : ImageError , 메시지 : AG_E_NETWORK_ERROR 가 발생하는 것을 볼 수 있습니다. 좀 더 자세히 알아보기 위해 HttpWatch, Fildder IE 개발 툴을 사용하여 요청한기록(아래 이미지)을 보면 요청한 도메인 최상위 루트에 clientaccesspolicy.xml 파일과 crossdomain.xml를먼저 요청하는 것을 볼 수 있습니다. 크로스 도메인 접근시 자동으로 요청하는 2개의 파일입니다.

ð  Clientaccesspolicy.xml 파일은 Silverlight에서 사용하는 보안 정책 파일이고, Crossdomain.xml 파일은 기존에 어드비 플래시에서 사용하는 정책 파일로, 어떤 파일과 어떤 디렉토리를 접근 허용할지를 설정해 놓은 규약서라고 보시면 됩니다.

-      보안 정책 파일 작성하고 배포하기

ð  이 사이트의 모든 경로나 파일의 접근이 가능하도록 작성하였습니다.

Code

Clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

  <cross-domain-access>

    <policy>

      <allow-from http-request-headers="*">

        <domain uri="*"/>

      </allow-from>

      <grant-to>

        <resource path="/" include-subpaths="true"/>

      </grant-to>

    </policy>

  </cross-domain-access>

</access-policy>

추가 설명 (예시)

<resource path="/demo" include-subpaths="false"/> 로 지정시,

허용되는 접근

demo#intro

/demo?bar=true#intro

허용되지 않는 접근

/demo

/demo.txt

/demo/sample

/demo/sample.txt

/demo/sample?bar=true

/sample

 

<resource path="/demo" include-subpaths="true"/> 로 지정시,

허용되는 접근

/demo/sample

/demo/sample.txt

/demo/sample?bar=true

/demo#intro

허용되지 않는 접근

/sample

Crossdomain.xml

<?xml version="1.0"?>

 

<!DOCTYPE cross-domain-policy SYSTEM

"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">

 

<cross-domain-policy>

  <allow-access-from domain="*"/>

  <allow-http-request-headers-from domain="* " headers="*" />

</cross-domain-policy>

ð  위 코드와 같이 작성한 후, 사이트 최상위 루트에 배포하시면 됩니다.

 

u  Understand Style

1.     Setter를 통해 속성의 값을 설정할 수 있으며, 이렇게 설정된 속성값들은 하나의 스타일로 묶이게 되며, 여러 컨트롤에 적용이 가능합니다. HTML페이지에 정의한 스타일시트(.CSS) 개념과 유사하다고 보시면 됩니다.

-       스타일 선언은 리소스에 해야 하며, 리소스는 Silverlight특정 레이아웃 컨트롤 또는 페이지 단위로 그 적용 범위를 제어 할 수 있습니다.

-       선언된 스타일 리소스가 여러 개의 페이지에 공통으로 적용될 경우는 Application의 리소스를 사용하시면 됩니다.

u  Sample Code

1.     스타일 정의 하지 않고 일반적인 UI (컨트롤에 스타일 정의)

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

<Button x:Name="Button1" Width="100" Height="50" Margin="10" Content="버튼1" Background=" Red "></Button>

        <Button x:Name="Button2" Width="100" Height="50" Margin="10" Content="버튼2" Background=" Red "></Button>

    </StackPanel>

</UserControl>

2.     스타일 정의 후, 적용한 UI (레이아웃의 리소스에 스타일 정의)

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <StackPanel.Resources>

            <Style TargetType="Button" x:Key="buttonStyle">

                <Setter Property="Width" Value="100"></Setter>

                <Setter Property="Height" Value="50"></Setter>

                <Setter Property="Margin" Value="10"></Setter>

                <Setter Property="Background" Value="Red"></Setter>

            </Style>

        </StackPanel.Resources>

       

        <Button x:Name="Button1" Style="{StaticResource buttonStyle}" Content="버튼1"></Button>

        <Button x:Name="Button2" Style="{StaticResource buttonStyle}" Content="버튼2"></Button>

    </StackPanel>

</UserControl>

ð  1번과 2번의 결과 화면은 동일하며, 아래 이미지와 같습니다.

Result

3.     Setter.Value 속성 엘리먼트 사용

-       1번과 2번의 경우는, 컨트롤의 너비나 색과 같이 어트리뷰트 형태로 속성값을 지정하였지만, 그라디언트와 같이 복잡한 형태의 속성값을 지정하기 위해서는 Setter Value 속성 엘리먼트를 통해 지정할 수 있습니다.

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <StackPanel.Resources>

            <Style TargetType="Button" x:Key="buttonStyle">

                <Setter Property="Width" Value="100"></Setter>

                <Setter Property="Height" Value="50"></Setter>

                <Setter Property="Margin" Value="10"></Setter>

                <Setter Property="Background">

                    <Setter.Value>

                        <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                            <GradientStop Color="White" Offset="0"></GradientStop>

                            <GradientStop Color="Black" Offset="1"></GradientStop>

                        </LinearGradientBrush>

                    </Setter.Value>

                </Setter>

            </Style>

        </StackPanel.Resources>

       

        <Button x:Name="Button1" Style="{StaticResource buttonStyle}" Content="버튼1"></Button>

        <Button x:Name="Button2" Style="{StaticResource buttonStyle}" Content="버튼2"></Button>

    </StackPanel>

</UserControl>

Result
               

4.     코드 비하인드에서 스타일 정의

Code

public partial class Page : UserControl

{

    public Page()

    {

        InitializeComponent();

 

        Style style = new Style(typeof(Button));

        style.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Red)));

        style.Setters.Add(new Setter(WidthProperty, 100));

        style.Setters.Add(new Setter(HeightProperty, 50));

        style.Setters.Add(new Setter(MarginProperty, 10));

 

        this.Button1.Style = style;

    }

}

 

u  Understand Silverlight Networking

1.     다양한 네트워크 통신을 지원합니다.

-       HTTP 통신 뿐만 아니라 TCP 통신을 위한 Socket 또한 지원합니다.

-       웹 서비스나 WCF 서비스로 데이터를 교환 할 수 있으며, RSS와 같은 Feed를 쉽게 가져올 수도 있습니다.

2.     네트워크 통신을 위한 클래스

-       WebClient (System.Net) 클래스

ð  일반 XML과 같은 데이터를 가져오기 위해 사용합니다.

-       SyndicationFeed (System.ServiceModel.Syndication) 클래스

ð  RSS ATOM과 같은 Feed 데이터를 해당 클래스를 활용하여 보다 쉽게 Feed 데이터를 가져올 수 있습니다.

ð  TCP 프로토콜의 통신을 지원하는 Socket 클래스를 제공하고, Socket의 경우 양방향으로 데이터를 주고 받을 수 있고, 비동기 이벤트와 메서드들을 제공합니다.

3.     보안을 위한 URL 접근 제약

-       Silverlight는 기본적으로 크로스 도메인의 통신을 지원하지 않습니다.

ð  demosample1.kr에서 제공하는 서비스를 demosample2.kr이라는 곳에서 호출하여 사용할 수 없습니다. 하지만, 보안 정책 파일을 통해서 특정 클라이언트의 접근을 허용할 수 있습니다. 추후에 샘플 코드를 통해 자세히 소개하겠습니다.

클래스명

WebClient HTTP클래스

Image클래스와 MediaElement 클래스(프로그레시브)

XAML 소스 파일

Font 파일

미디어 스트리밍

허용된 스키마

HTTP, HTTPS

HTTP, HTTPS, FILE

HTTP, HTTPS, FILE

HTTP, HTTPS, FILE

HTTP

크로스 스키마 접근

허용되지 않음

허용되지 않음

허용되지 않음

안됨

HTTP에서는 허용되지 않음

크로스 도메인 접근

보안정책 파일에서 필요 HTTPS에서 HTTPS라면 허용되지 않음

HTTPS에서 HTTPS가 아닐 경우 허용

HTTPS에서 HTTPS가 아닐 경우 허용

허용되지 않음

HTTPS에서 HTTPS가 아닐 경우 허용

 

u  Sameple Code

1.     Naver OpenAPI 를 이용한 Book Search (WebClient 클래스 이용)

-       UI 만들기

Code

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    >

    <Grid x:Name="LayoutRoot" Background="DarkOrange" >

        <Grid.RowDefinitions>

            <RowDefinition Height="60"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>

       

        <Grid Grid.Row="0">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="*"></ColumnDefinition>

                <ColumnDefinition Width="300"></ColumnDefinition>

                <ColumnDefinition Width="100"></ColumnDefinition>

            </Grid.ColumnDefinitions>

           

            <Border CornerRadius="10" Background="Beige" Margin="10">

                <TextBlock Text="Naver OpenAPI를 이용한 책 검색" Margin="10" FontSize="16"></TextBlock>

            </Border>

            <TextBox x:Name="txtSearhWord" Width="700" Height="40" Grid.Column="1" HorizontalAlignment="Left" FontSize="20"  ></TextBox>

            <Button x:Name="btnSearch" Grid.Column="2" Content="검색" Width="90" Height="50" Click="btnSearch_Click" ></Button>

           

        </Grid>

       

       <data:DataGrid x:Name="dgResult" Grid.Row="1"></data:DataGrid>

    </Grid>

</UserControl>

Result

-       WebClient 클래스를 이용하여 검색 데이터(XML) 가져온 후, DataGrid에 데이터 바인딩 시키기

Code

private void btnSearch_Click(object sender, RoutedEventArgs e)

{

    string strSearchWord = txtSearhWord.Text;

    string strSearchUrl = string.Format("http://openapi.naver.com/search?key=acb8d10036417f370d5db98b94f3be49&target=book&query={0}&display=5&start=1&sort=sim", strSearchWord);

 

    WebClient webClient = new WebClient();

    webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);

    webClient.DownloadStringAsync(new Uri(strSearchUrl));

}

 

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        // 검색 XML 데이터 바인딩하기

        dgResult.ItemsSource = e.Result;

    }

}

Result

Description

ð  검색 클릭 시, XML 구조가 한 열에 그려지는 것을 확인 할 수 있습니다. 데이터 그리드에 알맞게 나타내 주기 위해, LINQ를 이용하여 보여주고자 UI에 맞게 XML 데이터를 Parse 하겠습니다.

-       LINQ를 사용하여 검색 XML 데이터 Parse하여 데이터 바인딩 하기

Code

1.     Book 클래스

ð  XML 데이터를 맵핑하기 위해 “Book” 클래스를 정의한 후, 데이터에 알맞은 타입으로 프로퍼티를 생성해보겠습니다.

public class Book

{

    public string BookName { get; set; }

    public Uri LinkUrl { get; set; }

    public Uri ImageUrl { get; set; }

    public string Author { get; set; }

    public int Price { get; set; }

    public string Publisher { get; set; }

    public string PubDate { get; set; }

    public string ISBN { get; set; }

    public string Description { get; set; }

}

2.     Page.xaml 클래스

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        //Using LINQ to XML to Parse NaverOpenAPI XML Items into Book Class

        XDocument xmlBooks = XDocument.Parse(e.Result);

 

        var books = from book in xmlBooks.Descendants("item")

                    select new Book

                    {

                        BookName = (string)book.Element("title"),

                        LinkUrl = new Uri((string)book.Element("link")),

                        ImageUrl = new Uri((string)book.Element("image")),

                        Author = (string)book.Element("author"),

                        Price = (int)book.Element("price"),

                        Publisher = (string)book.Element("publisher"),

                        PubDate = (string)book.Element("pubdate"),

                        ISBN = (string)book.Element("isbn"),

                        Description = (string)book.Element("description")

                    };

 

        // XML Parse 한 데이터 바인딩하기

dgResult.ItemsSource = books;

    }

}

Result



 

u  Understand Layouts Controls

1.     Canvas

-       컨트롤 내부에 자식 컨트롤들을 가질 수 있으며, 자식 컨트롤들은 부모 컨트롤의 왼쪽 상단의 시작점을 기준으로 자신의 위치를 고정합니다.

-       Canvas 컨트롤 역시도 또 다른 Canvas 컨트롤을 자식으로 가질 수 있습니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Canvas x:Name="LayoutRoot" Background="DarkOrange">

<Button Content="Button1" Width="100" Height="50"  Canvas.Top="80" Canvas.Left="50" Canvas.ZIndex="1"  ></Button>

<Button Content="Button2" Width="100" Height="50"  Canvas.Top="120" Canvas.Left="110"  Canvas.ZIndex="0" ></Button>

    </Canvas>

</UserControl>

Result


Description

ð  Canvas.Top는 해당 Canvas 영역의 상단 시작점 좌표를 나타내며, Canvas.Left는 해당 Canvas 영역의 왼쪽 시작점 좌표를 나타냅니다.

ð  Canvas.ZIndex는 해당 Canvas 영역의 렌더링 순서를 나타내며, 숫자가 높을수록, 영역의 상단에 나타납니다.

2.     StackPanel

-       Canvas와 같이, 자식 컨트롤을 가질 수 있습니다. 하지만, 절대 위치를 지정하지 않고, StackPanel에 속한 자식들을 순서대로 표시합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="DarkOrange" Orientation="Horizontal">

        <Button Width="100" Height="50" Content="Button1"></Button>

        <Button Width="100" Height="50" Content="Button2"></Button>

        <Button Width="100" Height="50" Content="Button3"></Button>

    </StackPanel>

</UserControl>

Result

Description

ð  Orientation 속성에 Horizontal(수평), Vertical(수직) 지정으로 자식 컨트롤의 정렬 방향 지정을 합니다.

3.     Grid

-       Grid 컨트롤 역시 자식 컨트롤을 가질 수 있으며, HTML의 테이블과 흡사하지만, 해당 셀에 직접 컨트롤을 위치하지 못합니다.

-       RowDefinitions ColumnDefinitions 속성을 이용하여 그리드의 열과 행을 정의해야 합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="DarkOrange" ShowGridLines="True">

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="100"></ColumnDefinition>

            <ColumnDefinition Width="200"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition Height="100"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="100"></RowDefinition>

        </Grid.RowDefinitions>

        <Button Width="100" Height="50" Content="Button1" Grid.Row="0"></Button>

        <Button Width="100" Height="50" Content="Button2"  Grid.Row="2" Grid.Column="2"></Button>

        <Button Width="100" Height="50" Content="Button3"  Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"></Button>

    </Grid>

</UserControl>

Result


Description

ð  코드의 음영 부분을 보시면 3 3열로 정의해 보았습니다. 이때, 행과 열의 Width Height 를 지정해 주셔야 합니다. 유심히 보시면, 정의 부분의 Width, Height * 로 지정한 부분이 있는데, 열과 행 크기를 비율로 설정할 수 있습니다.

ð  아래 코드로 설명하자면, 3열로 각각 *, *, 2* Height를 지정하였습니다.

이 같은 경우는 그리드 영역를 비율로 설정합니다. 따라서 아래 코드는 Grid 높이가 300이므로, 첫번째 열 높이 100, 두번째 열 높이 200, 세번째 열 높이 100으로 자동 지정됩니다.

<Grid x:Name="LayoutRoot" Background="DarkOrange" ShowGridLines="True" Height="300">

        <Grid.RowDefinitions>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="2*"></RowDefinition>

</Grid.RowDefinitions>

<Button Width="100" Height="50" Content="Button1" Grid.Row="0"></Button>

        <Button Width="100" Height="50" Content="Button2"  Grid.Row="2"></Button>

        <Button Width="100" Height="50" Content="Button3"  Grid.Row="1"></Button>

</Grid>

 

u  Visual Studio 2008을 이용한 Silverlight 기반 솔루션 만들기

1.     파일/새로 만들기에서 프로젝트를 선택합니다.

2.     새 프로젝트 대화 상자에서 개발 언어 선택 후, Silverlight 를 선택합니다. (Microsoft Silverlight Tools for Visual Studio 2008 SP1이 설치되어 있어야 Silverlight 프로젝트 형식이 나타납니다.)

3.     템플릿 항목에서 Silverlight 응용 프로그램을 선택 한 후, 프로젝트 이름 입력 후, 확인합니다. (대상 플렛폼이 .NET Framework 3.5 로 선택되어 있어야 합니다.)

         

4.     Silverlight 응용 프로그램 추가 대화상자에서 Silverlight 응용 프로그램 호스팅 방법을 선택합니다.

-       Silverlight 응용 프로그램과 Silverlight 컨트롤을 호스팅하는 ASP.NET 기반의 웹 사이트를 구분하여 프로젝트를 구성하는 경우 "솔루션에 Silverlight를 호스팅할 새 ASP.NET 웹 프로젝트 추가"를 선택하고, 웹 프로젝트의 타입과 이름을 추가로 입력합니다.

-       솔루션에 Silverlight 기반 응용프로그램 프로젝트만을 구성하는 경우, “빌드할 때 Silverlight를 호스팅할 테스트 페이지를 자동으로 생성항목을 선택합니다.


u  Silverlight 응용 프로그램 이해하기

1.     XAML 파일

-       Silverlight WPF 응용 프로그램의 UI를 지정하기 위하여 이용 될 수 있는 XML 기반의 파일입니다.

2.     App.xaml 파일

-       Sivlerlight 응용 프로그램의 시동과 구동을 위한 메인 클래스입니다. 이 클래스는 패키지 파일(.xap)이 다운로드 되면 Silverlight 플러그-인에 의하여 관리됩니다.

3.     Page.xaml 파일

-       Page 클래스는 응용프로그램에서 메인 UI를 표시하는 역할을 하며, UserControl로 부터 상속을 받고 XAML 마크업 파일과 .cs, .vb의 코드비하인드 파일의 쌍으로 구성되어 있습니다.

4.     Xap 파일

-       Silverlight 응용 프로그램의 패키지 파일로, 표준 .zip compression 압축 산법을 극소화하기 위하여 클라이언트 다운로드 크기를 이용합니다.

5.     Silverlight 응용 프로그램을 호스팅하는 웹사이트의 구성 요소

-       .aspx, .html 로 구성된 두 개의 페이지로 구성되어 있으며, Silverlight 응용 프로그램 프로젝트 이름에 TestPage라는 이름이 붙어 있습니다.

-       .html 페이지는 Silverlight 응용프로그램을 호스팅하기 위해 <object> 태그를 사용합니다.

-       .aspx 페이지는 .html 과 유사한 결과물을 얻기 위해 ASP.NET Silverlight 서버 컨트롤을 사용합니다.

               


u  Sample Code

1.     기본 컨트롤(버튼) 추가

-       버튼 컨트롤을 아래와 같은 코드를 추가합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="DarkOrange">

        <Button x:Name="MyButton" Content="버튼" Width="100" Height="50"></Button>

    </Grid>

</UserControl>

Description

Button 컨트롤을 보시면 x:Name라는 Attribute 값에 MyButton이라고 지정하였고, Content버튼이라는 텍스트를 넣었습니다.

ð  x:Name를 설명드리자면 코드 숨김 또는 일반 코드에서 인스턴스화된 개체에 액세스하기 위해 개체 요소를 고유하게 식별할 때 쓰입니다. (ASP.NET으로 보시면 개체 ID로 보시면 됩니다.)

ð  Content ASP.NET 버튼컨트롤의 Text 라고 보시면 됩니다. (컨트롤의 속성은 ASP.NET 컨트롤과 비슷하므로 금방 이해할 수 있습니다.)

Result

2.     이벤트 핸들러 추가

-       Click 이벤트를 추가해 보겠습니다. Click=” 입력시, 아래 이미지와 같이 나타납니다.

엔터 키 또는 Tab 키를 누르면, Click 이벤트 핸들러 함수명을 x:Name에 해당 이벤트명이 붙어 자동 지정되며, Code Behide 클래스에도 이벤트 핸들러 함수가 자동으로 추가됩니다. (ASP.NET 과 유사함)

-       버튼 클릭시, 버튼 컨트롤 Text“Hello World” 로 변경하는 이벤트 추가해 보겠습니다.


3.     ToolTips

-       xaml 파일에서 Code Behide 클래스로 가는 단축키 : F7

-       Code Behide 클래스에서 xaml 파일로 가는 단축키 : Shift + F7

ASP.NET 에서 우리가 사용한 서버 컨트롤 영역을 클릭 후 ENTER KEY를 누르면

해당 페이지가 다시 로드되는 현상을 많이 봤을 것이다.

 

이 부분은 개발하는 나도 사용하는 사용자도 상당히 신경쓰이고 짜증 나는 일이 아닐 수 없다.

ENTER키를 안먹게 하는 방법이 없을까?

 

그 해결 방법으로 아래와 같은 Javascript 함수로 ENTER 키를 모두 막아 버렸다.

 

function CheckEnter() {

try {

if (!e) var e = window.event;

if (document.all) var key = e.keyCode;

else var key = e.which;

 

if( key == 13 ) {

var tag = e.srcElement ? e.srcElement.tagName : e.target.nodeName ;

var tagId = e.srcElement ? e.srcElement.id : "" ;

 

/*** 1. 원하는 컨트롤 아이디만 등록 ***/

if( tagId == "InputLogin" ) {

CheckLogin();

return false;

}

/*** 2. 원하는 컨트롤만 엔터키 반응 (여기서는 TEXTAREA만) ***/

if( tag == "TEXTAREA") {

return true;

}

return false;

}

}

catch(e) { return true; }

}

document.onkeydown = CheckEnter;

 

여기서 중요한 것은 document.onkeydown = CheckEnter;

함수 내부에 있어서는 안되며 함수 밖에 등록되어 전체 HTML 문서에서의 KEYDOWN 이벤트를 체크 해야 한다.

 

주석 부분의

1. 원하는 컨트롤 아이디만 등록 

웹사이트에서 로그인 부분에서만 ENTER KEY를 사용할 수 있게 하여 로그인체크 함수를 실행 할 수 있게 했다.

 

2. 원하는 컨트롤만 엔터키 반응

이건 사이트 전체의 TEXTAREA에서만 ENTER KEY를 사용할 수 있게 했다.

 

만약 검색 INPUT 에서 ENTER KEY를 사용하려면 검색 INPUT ID를 위의 함수에 추가로 등록하여 사용할 수 있다.

예)

검색 INPUT 박스 <input type="text" id="InputSearch" name="InputSearch" size="20" /> 라면

 

if( tagId == "InputSearch" ) {

CheckSearch();

return false;

}

 

다르게 체크 할 수 있는 방법이 더 있겠지만 일단 -0-;;

Html에 특수문자를 표기하고 싶을 경우 정말이지 가끔 까먹어서 찾기 귀찮을 때가 상당히 많다;;

 

특수문자 표기는 아래의 표에서 왼쪽 회색 문자 앞뒤로 & ;를 붙이면 우측 문자가 된다.

 

quot

"

sect

§

amp

&

uml

¨

apos

'

copy

©

lt

< 

ordf

ª

nbsp

 

laquo

«

iexcl

¡

not

¬

cent

¢

shy

­

pound

£

reg

®

yen

¥

macr

¯

brvbar

¦

deg

°

plusmn

±

raquo

»

sup2

²

frac14

¼

sup3

³

frac12

½

acute

´

frac34

¾

micro

µ

iquest

¿

para

Agrave

À

middot

·

Aacute

Á

cedil

¸

Acirc

Â

sup1

¹

Atilde

Ã

ordm

º

Auml

Ä

Aring

Å

Iuml

Ï

AElig

Æ

ETH

Ð

Ccedil

Ç

Ntilde

Ñ

Egrave

È

Ograve

Ò

Eacute

É

Oacute

Ó

Ecirc

Ê

Ocirc

Ô

Euml

Ë

Otilde

Õ

Igrave

Ì

Ouml

Ö

Iacute

Í

times

×

Icirc

Î

Oslash

Ø

Ugrave

Ù

atilde

ã

Uacute

Ú

auml

ä

Ucirc

Û

aring

å

Uuml

Ü

aelig

æ

Yacute

Ý

ccedil

ç

THORN

Þ

egrave

è

szlig

ß

eacute

é

agrave

à

ecirc

ê

aacute

á

euml

ë

acirc

â

igrave

ì

iacute

í

divide

÷

icirc

î

oslash

ø

iuml

ï

ugrave

ù

eth

ð

uacute

ú

ntilde

ñ

ucirc

û

ograve

ò

uuml

ü

oacute

ó

yacute

ý

ocirc

ô

thorn

þ

otilde

õ

yuml

ÿ

ouml

ö

>

> 

 


Web Service를 이용한 파일 업로드 ( Web Site )

 

먼저 D:\SaveImage 아까 웹 서비스를 만들 때 저장 폴더를 설정했는데 그 경로로 upload 라는 가상 디렉토리를 설정한다. 이 설정은 http://local.image.co.kr 에 설정해야 한다.

 

이제 웹 사이트를 만들어보자

 

 

새 프로젝트에서 ASP.NET 웹 응용프로그램을 선택 후 UploadTestWeb이름을 생성하자.

 

FileUpload.aspx 생성하기

이 파일은 업로드를 테스트 하는 .aspx 파일이다.

 

FileUpload.aspx

<br /><br /><br />

   

   

    새이름으로 : <asp:FileUpload ID="files" runat="server" /> <asp:Button ID="Upload" runat="server" Text="업로드" OnClick="Upload_OnClick" />

    <br /><br />

   

    업로드이름으로 : <asp:FileUpload ID="files2" runat="server" /> <asp:Button ID="Upload2" runat="server" Text="업로드" OnClick="Upload2_OnClick" />

   

    <br /><br /><br />

 

 

    <img src="http://local.images.co.kr/upload/hi2/01.png" border=1 /> 01.png - <asp:Button ID="btnDel" runat="server" Text="삭제" OnClick="btnDel_OnClick" />

       

    <br /><br /><br />

   

    <img src="http://local.images.co.kr/upload/hi2/02.png" border=1 /> 02.png - <asp:Button ID="btnDel2" runat="server" Text="삭제" OnClick="btnDel2_OnClick" />

 

    <br /><br /><br />

   

    <img src="http://local.images.co.kr/upload/hi2/03.png" border=1 /> 03.png - <asp:Button ID="btnDel3" runat="server" Text="삭제" OnClick="btnDel3_OnClick" />

 

   

    <br /><br /><br />

    <br /><br /><br />

    <br /><br /><br />

 

    다중 업로드(새이름)<br />

    <asp:FileUpload ID="file1" runat="server" /><br />

    <asp:FileUpload ID="file2" runat="server" /><br />

    <asp:FileUpload ID="file3" runat="server" /> <asp:Button ID="Upload3" runat="server" Text="업로드" OnClick="Upload3_OnClick" />

 

 

    <br /><br /><br />

 

    다중 업로드(기존이름)<br />

    <asp:FileUpload ID="file4" runat="server" /><br />

    <asp:FileUpload ID="file5" runat="server" /><br />

    <asp:FileUpload ID="file6" runat="server" /> <asp:Button ID="Upload4" runat="server" Text="업로드" OnClick="Upload4_OnClick" />

 

 

    <br /><br /><br />

소스 중간의 이미지 출력 부분은 이미지가 잘 업로드가 되었는지를 보기 위해서 이다.

 

새 이름으로 업로드 하기

#region 다중 새이름으로 업로드

/// <summary>

/// 다중 새이름으로 업로드

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Upload3_OnClick(object sender, EventArgs e)

{

    List<System.Web.UI.WebControls.FileUpload> listFile = new List<System.Web.UI.WebControls.FileUpload>();

    listFile.Add(file1);

    listFile.Add(file2);

    listFile.Add(file3);

 

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.MultiNewFileUpload(listFile, "HI2")[2][0]);

 

    Response.Write(statusMessage);

 

}

#endregion

위에서 설정한 아이디와 키 값이 맞지 않으면 에러가 발생한다. 따로 try catch문을 설정하지 않아 에러로 보이니 설정 값을 서로 잘 맞춰야 한다.

 

기존 이름으로 덮어 씌우기

#region 기존 이름 덮어씌우기

/// <summary>

/// 기존 이름 덮어씌우기

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Upload2_OnClick(object sender, EventArgs e)

{

    SiteUpload sUpload = new SiteUpload();

 

    Response.Write("Len : " + files2.PostedFile.ContentLength + "<br />");

 

    /*

    상태 변수

    READY : 준비

    NOEXT : 지원되지 않는 확장자

    NOFNM : 잘못된 파일명

    FAILD : 서버에서 실패

    SUCES : 성공

    NOSEL : 파일선택안함

     */

    string statusMessage = sUpload.SatausMessage(sUpload.SameFileUpload(files2, "HI2")[0]);

 

 

    Response.Write(statusMessage);

}

#endregion

 

다중 새 이름으로 업로드

#region 다중 새이름으로 업로드

/// <summary>

/// 다중 새이름으로 업로드

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Upload3_OnClick(object sender, EventArgs e)

{

    List<System.Web.UI.WebControls.FileUpload> listFile = new List<System.Web.UI.WebControls.FileUpload>();

    listFile.Add(file1);

    listFile.Add(file2);

    listFile.Add(file3);

 

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.MultiNewFileUpload(listFile, "HI2")[2][0]);

 

    Response.Write(statusMessage);

 

}

#endregion

 

다중 기존 이름으로 덮어씌우기

#region 다중 기존이름으로 덮어씌우기

/// <summary>

/// 다중 기존이름으로 덮어씌우기

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Upload4_OnClick(object sender, EventArgs e)

{

    List<System.Web.UI.WebControls.FileUpload> listFile = new List<System.Web.UI.WebControls.FileUpload>();

    listFile.Add(file4);

    listFile.Add(file5);

    listFile.Add(file6);

 

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.MultiSameFileUpload(listFile, "HI2")[2][0]);

 

    Response.Write(statusMessage);

}

#endregion

 

파일 삭제

#region 파일 삭제

/// <summary>

/// 파일 삭제

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnDel_OnClick(object sender, EventArgs e)

{

    /*

    상태 변수

    FAILD : 서버에서 실패

    SUCES : 성공

     */

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.DeleteFile("HI2", "01.png"));

 

    Response.Write(statusMessage);

 

}

 

 

/// <summary>

/// 파일 삭제

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnDel2_OnClick(object sender, EventArgs e)

{

    /*

    상태 변수

    FAILD : 서버에서 실패

    SUCES : 성공

     */

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.DeleteFile("HI2", "02.png"));

 

    Response.Write(statusMessage);

 

}

 

/// <summary>

/// 파일 삭제

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnDel3_OnClick(object sender, EventArgs e)

{

    /*

    상태 변수

    FAILD : 서버에서 실패

    SUCES : 성공

     */

    SiteUpload sUpload = new SiteUpload();

 

    string statusMessage = sUpload.SatausMessage(sUpload.DeleteFile("HI2", "03.png"));

 

    Response.Write(statusMessage);

 

}

#endregion

 

이렇게 해서 웹 서비스를 통해 업로드 하는 과정을 모두 완료했다.

Web Service를 이용한 파일 업로드 ( DLL )

 

DLL 만들기

웹사이트에서만 사용하지 않고 Console App, Win App, ASP.NET에서 모두 이용하기 위해

클래스 라이브러리 프로젝트로 DLL을 만들 것이다.

 

 

새 프로젝트에 클래스 라이브러리를 선택하자

 

이제 프로젝트에서 웹 서비스의 자원을 사용해야 하는데 어떻게 사용해야 할까?

웹 서비스의 자원을 사용하는 것을 다음과 같다.

 

 

DLL 이나 EXE 프로젝트에서 웹서비스 사용하기

 

우리가 DLL이나 Exe에서 사용할 시 WDSL 규약에 맞게 코딩을 해주어야 한다.

이 부분은 Visual Studio에서 제공을 해준다.

 

Visual Studio 명령 프롬프트에서

wsdl /l:CS <webservice URL>을 하면 명령 프롬프트 폴더데 .cs파일 자동적으로 생성이 된다.

이것을 프로젝트에 추가하면 된다.

 

참조에는 System.Web.Service, System.Web를 추가

using System.IO;를 추가

 

wsdl 명령어에 대해 자세히 알고 싶다면 wsdl /? 하면 자세한 도움말이 나온다.

 

아까 Web Service를 만든 경로를 입력하자.

wsdl /l:CS http://local.images.co.kr/SvcFileUpload.asmx

  

 

생성된 SvcFileUpload.cs 파일을 프로젝트에 추가하면 이제부터 웹 서비스의 자원을 사용할 수 있다.

 

이제 변수와 메소드를 만들어보자

변수는 다음과 같다.

#region 변수

/// <summary>

/// 아이디 변수

/// </summary>

private string id = string.Empty;

/// <summary>

/// 아이디 세팅

/// </summary>

public string Id

{

    get { return id; }

    set { id = value; }

}

 

/// <summary>

/// 키 변수

/// </summary>

private string kno = string.Empty;

/// <summary>

/// 키 세팅

/// </summary>

public string Kno

{

    get { return kno; }

    set { kno = value; }

}

 

/// <summary>

/// 최대 업로드 용량

/// </summary>

private int maxLength = 102400 * 5; // 5MB

/// <summary>

/// 최대 업로드 용량

/// </summary>

public int MaxLength

{

    get { return maxLength; }

    set { maxLength = value; }

}

 

/// <summary>

/// 지원 확장자

/// </summary>

//private string[] ext = {"GIF", "PNG", "JPG", "JEPG", "BMP" };

public List<string> listExt = new List<string>();

 

/// <summary>

/// 상태 변수

/// READY : 준비

/// NOEXT : 지원되지 않는 확장자

/// NOFNM : 잘못된 파일명

/// FAILD : 서버에서 실패

/// SUCES : 성공

/// NOSEL : 파일선택안함

/// </summary>

private string RTN_STATUS = string.Empty;

 

#endregion

 

생성자에서는 역시나 초기화를 했다.

#region 생성자

/// <summary>

/// 생성자

/// </summary>

public SiteUpload()

{

    // 기본 세팅

    Id = " website1";

    Kno = " website1111";

 

    // 지원되는 파일 확장자

    listExt.Add("GIF");

    listExt.Add("PNG");

    listExt.Add("JPG");

    listExt.Add("JEPG");

    listExt.Add("BMP");

   

    // 초기 상태

    RTN_STATUS = "READY";

}

#endregion

 

DLL에서 사용할 메소드는 다음과 같다.

1.     디렉토리 생성

2.     새 파일로 저장

3.     기존 파일로 저장

4.     다중 새 파일로 저장

5.     다중 기존 파일로 저장

6.     파일 삭제

7.     상태 메시지

 

디렉토리 생성

#region 디렉토리 생성

/// <summary>

/// 디렉토리 생성

/// </summary>

/// <param name="dir">생성할 디렉토리</param>

/// <param name="id">사이트아이디</param>

/// <param name="kno">사이트키</param>

public void CreateDirectory(string dir, string id, string kno)

{

    // 웹서비스 자원 사용하기

    SvcFileUpload sfile = new SvcFileUpload();

    sfile.CreateDirectory(dir, id, kno);

}

#endregion

 

새 파일로 저장

#region 새 파일로 저장

/// <summary>

/// 새 파일 저장 - 같은 파일일 경우 새 이름으로 저장한다.

/// [0] 상태값

/// [1] 파일명

/// </summary>

/// <param name="files">FileUpload컨트롤</param>

/// <param name="dir">저장경로</param>

/// <returns></returns>

public List<string> NewFileUpload(System.Web.UI.WebControls.FileUpload files, string dir)

{

    string filename = string.Empty;

    string ext = string.Empty;

 

    int fileLength = files.PostedFile.ContentLength;

    int fnStart = -1;

    int fnLen = 0;

   

    // 리턴변수

    List<string> Rtn = new List<string>();

    Rtn.Add(string.Empty); //[0] : 상태값

    Rtn.Add(string.Empty); //[1] : 파일명

 

   

    filename = files.PostedFile.FileName;

    fnLen = filename.Length;

    fnStart = filename.LastIndexOf('\\') + 1;

   

    // 파일 유무 체크

    if (fnLen > 0)

    {

        if (fnStart > 0 && (fnLen - fnStart) > 0)

        {

            Stream strm;

 

            // 파일명만 추출하기

            int extStart = -1;

            int extLen = 0;

            bool chkExt = false;

 

            filename = filename.Substring(fnStart, fnLen - fnStart); // 파일명

 

            // 파일명에서 확장자 추출하기

            extLen = filename.Length;

            extStart = filename.LastIndexOf('.') + 1;

            if (extStart > 0 && (extLen - extStart) > 0)

                ext = filename.Substring(extStart, extLen - extStart); // 확장자

 

            // 확장자 체크

            foreach (string s in listExt)

                if (ext.ToUpper() == s)

                    chkExt = true;

 

            if (chkExt)

            {

                byte[] send = new byte[fileLength];

 

                strm = files.PostedFile.InputStream;

                strm.Read(send, 0, fileLength);

 

                // 웹서비스 자원 사용하기

                SvcFileUpload sfile = new SvcFileUpload();

                // 파일명만 넘겨주세요.

                filename = sfile.NewFileSaveFile(send, dir, filename, Id, Kno);

 

                strm.Close();

 

                if (!filename.Equals(string.Empty))

                    RTN_STATUS = "SUCES";

                else

                    RTN_STATUS = "FAILD";

            }

            else

                RTN_STATUS = "NOEXT";

        }

        else

            RTN_STATUS = "NOFNM";

    }

    else

        RTN_STATUS = "NOSEL";

 

    Rtn[0] = RTN_STATUS;

    Rtn[1] = filename;

 

    return Rtn;

}

#endregion

엄청난 if ;; 급하게 만드느라 생각을 많이 못하고 붙이다 보니 이렇게 많은 if문이 생겼네요.

 

기존파일명으로 파일 저장

#region 기존파일명으로 파일 저장

/// <summary>

/// 기존파일명으로 파일 저장 : 같은 이름일 경우 덮어씌운다.

/// [0] 상태값

/// [1] 파일명

/// </summary>

/// <param name="files">FileUpload컨트롤</param>

/// <param name="dir">저장경로</param>

/// <returns></returns>

public List<string> SameFileUpload(System.Web.UI.WebControls.FileUpload files, string dir)

{

    string filename = string.Empty;

    string ext = string.Empty;

 

    int fileLength = files.PostedFile.ContentLength;

    int fnStart = -1;

    int fnLen = 0;

 

    // 리턴변수

    List<string> Rtn = new List<string>();

    Rtn.Add(string.Empty); //[0] : 상태값

    Rtn.Add(string.Empty); //[1] : 파일명

 

    filename = files.PostedFile.FileName;

    fnLen = filename.Length;

    fnStart = filename.LastIndexOf('\\') + 1;

 

    // 파일 유무 체크

    if (fnLen > 0)

    {

        if (fnStart > 0 && (fnLen - fnStart) > 0)

        {

           

 

            // 파일명만 추출하기

            int extStart = -1;

            int extLen = 0;

            bool chkExt = false;

 

            filename = filename.Substring(fnStart, fnLen - fnStart); // 파일명

 

            // 파일명에서 확장자 추출하기

            extLen = filename.Length;

            extStart = filename.LastIndexOf('.') + 1;

            if (extStart > 0 && (extLen - extStart) > 0)

                ext = filename.Substring(extStart, extLen - extStart); // 확장자

 

            // 확장자 체크

            foreach (string s in listExt)

                if (ext.ToUpper() == s)

                    chkExt = true;

 

            if (chkExt)

            {

                Stream strm;

                byte[] send = new byte[fileLength];

 

                strm = files.PostedFile.InputStream;

                strm.Read(send, 0, fileLength);

 

                // 웹서비스 자원 사용하기

                SvcFileUpload sfile = new SvcFileUpload();

                // 파일명만 넘겨주세요.

                filename = sfile.SameFileSaveFile(send, dir, filename, Id, Kno);

 

                strm.Close();

 

                if (!filename.Equals(string.Empty))

                    RTN_STATUS = "SUCES";

                else

                    RTN_STATUS = "FAILD";

            }

            else

                RTN_STATUS = "NOEXT";

        }

        else

            RTN_STATUS = "NOFNM";

    }

    else

        RTN_STATUS = "NOSEL";

 

    Rtn[0] = RTN_STATUS;

    Rtn[1] = filename;

 

    return Rtn;

}

#endregion

마찬가리로 많은 if문을 볼 수 있습니다. ^^;;

 

다중 새 파일로 저장

#region 다중 새 파일로 저장

/// <summary>

/// 다중 새 파일 저장 - 같은 파일일 경우 새 이름으로 저장한다.

/// [2][0] 전체 상태값

/// </summary>

/// <param name="files"></param>

/// <param name="dir"></param>

/// <returns></returns>

public List<List<string>> MultiNewFileUpload(List<System.Web.UI.WebControls.FileUpload> files, string dir)

{

    string CHK_STATUS = "FAILD";

 

    // 리턴변수

    List<List<string>> Rtn = new List<List<string>>();

 

    List<string> RtnFile = new List<string>();

    List<string> RtnStatus = new List<string>();

    List<string> RtnFullStatus = new List<string>();

    RtnFullStatus.Add(string.Empty);

 

    List<string> svcRtn = new List<string>();

 

    foreach (System.Web.UI.WebControls.FileUpload f in files)

    {

        svcRtn = NewFileUpload(f, dir);

 

        RtnStatus.Add(svcRtn[0]); // 상태값

        RtnFile.Add(svcRtn[1]); // 파일명

    }

 

    foreach (string s in RtnStatus)

    {

        if (s == "SUCES" || s == "NOSEL")

            CHK_STATUS = "SUCES";

    }

    RtnFullStatus[0] = CHK_STATUS;

 

    Rtn.Add(RtnStatus); // 각 업로드 상태

    Rtn.Add(RtnFile); // 각 업로드 파일명

    Rtn.Add(RtnFullStatus); // 전체 상태

 

    return Rtn;

}

#endregion

하나씩 파일 업로드만 있길래 메소드는 나중에 추가하여 다중으로도 업로드를 지원했습니다.

 

다중 기존 파일로 저장

#region 다중 기존 파일로 저장

/// <summary>

/// 다중 기존 파일로 저장 - 같은 이름일 경우 덮어씌운다.

/// [2][0] 전체 상태값

/// </summary>

/// <param name="files"></param>

/// <param name="dir"></param>

/// <returns></returns>

public List<List<string>> MultiSameFileUpload(List<System.Web.UI.WebControls.FileUpload> files, string dir)

{

    string CHK_STATUS = "FAILD";

 

    // 리턴변수

    List<List<string>> Rtn = new List<List<string>>();

 

    List<string> RtnFile = new List<string>();

    List<string> RtnStatus = new List<string>();

    List<string> RtnFullStatus = new List<string>();

    RtnFullStatus.Add(string.Empty);

 

    List<string> svcRtn = new List<string>();

 

    foreach (System.Web.UI.WebControls.FileUpload f in files)

    {

        svcRtn = SameFileUpload(f, dir);

 

        RtnStatus.Add(svcRtn[0]); // 상태값

        RtnFile.Add(svcRtn[1]); // 파일명

    }

 

    foreach (string s in RtnStatus)

    {

        if (s == "SUCES" || s == "NOSEL")

            CHK_STATUS = "SUCES";

    }

    RtnFullStatus[0] = CHK_STATUS;

 

 

    Rtn.Add(RtnStatus); // 각 업로드 상태

    Rtn.Add(RtnFile); // 각 업로드 파일명

    Rtn.Add(RtnFullStatus); // 전체 상태

 

    return Rtn;

}

#endregion

마찬가지의 이유로 추가했습니다.

 

파일 삭제

#region 파일 삭제

/// <summary>

/// 파일 삭제

/// </summary>

/// <param name="dir">디렉토리</param>

/// <param name="filename">파일명</param>

public string DeleteFile(string dir, string filename)

{

    bool delCheck = false;

    string RTN_STATUS = string.Empty;

 

    // 웹서비스 자원 사용하기

    SvcFileUpload sfile = new SvcFileUpload();

    delCheck = sfile.DeleteFile(dir, filename, Id, Kno);

 

    if (delCheck)

        RTN_STATUS = "SUCES";

    else

        RTN_STATUS = "FAILD";

 

    return RTN_STATUS;

}

#endregion

 

상태 메시지

#region 상태 메세지

/// <summary>

/// 상태 메세지

/// </summary>

/// <param name="status">상태코드 5자리</param>

/// <returns></returns>

public string SatausMessage(string status)

{

    /*

    상태 변수

   

    READY : 준비

    NOEXT : 지원되지 않는 확장자

    NOFNM : 잘못된 파일명

    FAILD : 서버에서 실패

   

    SUCES : 성공

    NOSEL : 파일선택안함

     */

    string rtnMessage = string.Empty;

 

    switch (status)

    {

        case "READY":

            rtnMessage = "업로드 대기중입니다.";

            break;

        case "NOEXT":

            rtnMessage = "지원되지 않는 확장자입니다.";

            break;

        case "NOFNM":

            rtnMessage = "파일명이 잘못되었습니다.";

            break;

        case "FAILD":

            rtnMessage = "업로드가 실패했습니다.";

            break;

        case "SUCES":

            rtnMessage = "성공적으로 업로드 되었습니다.";

            break;

        case "NOSEL":

            rtnMessage = "";

            break;

    }

    return rtnMessage;

}

#endregion

업로드의 각 상태 메시지를 리턴해 주는 메소드 입니다. 급하게 만들었다고 생각해주세요;;

 

자 이렇게 해서 DLL에서 필요한 변수 및 메소드를 모두 만들었다.

빌드를 하여 dll을 만들자.

 

 

다음 장에서는 마지막으로 웹 사이트를 통해 파일 업로드 테스트 하는 페이지에 대해 알아 보겠다.

 

Web Service를 이용한 파일 업로드 ( Web Service )

 

준비하기

1.     웹사이트 만들기 ( : http://local.images.co.kr )

2.     호스트 파일에 등록 : 127.0.0.1      local.images.co.kr

3.     Visual Studio -> 파일 -> 새로 만들기 -> 새 웹사이트

4.     HTTP 선택 후 http://local.images.co.kr 을 입력 후 언어는 Visual C# 선택 후 확인

5.     웹 사이트로 프로젝트 생성 완료

 

이제 웹서비스를 생성할 준비가 완료 되었다.

 

웹 서비스 만들기

1.     프로젝트에서 새 항목 추가를 클릭

2.     템플릿에서 웹 서비스 선택 후 이름은 SvcFileUpload.asmx로 생성

 

이제 웹 서비스가 완성되었다.

기본 적으로 HelloWorld() 메소드가 추가되고

이 메소드는 http://local.images.co.kr/SvcFileUpload.asmx 에서 확인 할 수 있다.

 

 

파일 업로드를 위한 웹 서비스 계획

현재 만들어진 웹 서비스가 있는 사이트를 업로드용 파일 서버로 사용할 경우로 가정한다.

1.     간단하게 아이디와 키 값을 부여

2.     아이디와 키 값이 일치 할 경우 디렉토리 생성 및 파일 업로드

3.     아이디와 키 값이 일치 할 경우 디렉토리 삭제 및 파일 삭제

 

웹 서비스에 필요한 변수

1.     아이디와 키 값 저장 변수

2.     아이디와 키 값 비교 변수

3.     저장 할 경로의 디렉토리 변수

 

웹 서비스에 필요한 메소드

1.     아이디와 키 값 비교 메소드

2.     디렉토리 생성 메소드

3.     파일 여부 체크 메소드

4.     파일 저장 메소드 새 이름으로 저장

5.     파일 저장 메소드 기존 파일 덮어 씌우기

6.     파일 삭제 메소드

 

구조는 웹사이트에서 DLL을 참조해서 웹서비스의 메소드를 호출하여 처리하는 것이다.

 

그럼 이제부터 SvcFileUpload.asmx 을 만들어 보겠다.

 

/// <summary>

/// SvcFileUpload의 요약 설명입니다.

/// </summary>

[WebService(Namespace = "http://local.images.co.kr", Name = "SvcFileUpload", Description = "파일 업로드를 처리")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class SvcFileUpload : System.Web.Services.WebService

{

XML Web Service를 위한 기본 네임스페이스를 설정하고 XML Web Service의 명을 정하는 것이다.

 

여러 사이트에서 하나의 업로드 서버를 사용할 수 있으므로 사이트 마다 아이디와 키를 부여하고업로드 서버 저장 경로 변수 설정

/// <summary>

/// 사이트키

/// </summary>

private Dictionary<string, string> site = new Dictionary<string, string>();

/// <summary>

/// 저장할 경로 변수

/// </summary>

private string saveDir = string.Empty;

 

/// <summary>

/// 아이디, 키값 비교 변수

/// </summary>

private bool equValue = false;

 

생성자에서 위의 변수 초기화

/// <summary>

/// 생성자

/// </summary>

public SvcFileUpload () {

 

    //디자인된 구성 요소를 사용하는 경우 다음 줄의 주석 처리를 제거합니다.

    //InitializeComponent();

 

    // 저장할 기본 경로 ( 루트 )

    saveDir = "D:\\SaveImage";

    // Key : 사이트 아이디, Value : 사이트 키 번호

    site.Add("website1", "website1111");

}

 

SvcFileUpload 웹서비스는 다음과 같이 8가지의 메소드로 구성이 된다.

1.     아이디와 키 번호 체크

2.     저장 경로 반환

3.     디렉토리 생성

4.     파일 여부 체크

5.     새로운 파일명을 생성 ( 파일명 중복 방지 )

6.     파일명이 같을 경우 같은 이름으로 저장

7.     파일명이 같을 경우 새 파일명으로 저장

8.     파일 삭제

 

아이디와 키 번호 체크 메소드

/// <summary>

/// 아이디와 키번호 체크

/// </summary>

/// <param name="id"></param>

/// <param name="kno"></param>

/// <returns></returns>

[WebMethod(Description = "아이디와 키번호 체크")]

private bool EqualsIdKno(string id, string kno)

{

    string sno = site[id];

 

    if (sno == kno)

        equValue = true;

    else

        equValue = false;

 

    return equValue;

}

 

저장 경로 반환

/// <summary>dkdle

/// 저장 경로 반환

/// </summary>

/// <returns></returns>

[WebMethod(Description = "저장 경로를 반환")]

public string ReturnDirectory()

{

    return saveDir;

}

 

디렉토리 생성

/// <summary>

/// 디렉토리를 생성

/// </summary>

/// <param name="dir"></param>

[WebMethod(Description = "디렉토리를 생성")]

public bool CreateDirectory(string dir, string id, string kno)

{

    bool createDir = false;

 

    if (EqualsIdKno(id, kno))

    {

        string strDir = string.Empty;

 

        strDir = ReturnDirectory() + "\\" + dir;

 

        //디렉토리 생성

        if (!Directory.Exists(strDir))

        {

            Directory.CreateDirectory(strDir);

        }

        createDir = true;

    }

    else

    {

        createDir = false;

    }

 

    return createDir;

}

 

파일 여부 체크

/// <summary>

/// 파일 여부 체크

/// </summary>

/// <param name="fname">저장폴더와 함께 파일명</param>

/// <returns></returns>

[WebMethod(Description = "파일 여부 체크")]

public bool EqualsFile(string fname)

{

    string strFile = ReturnDirectory() + "\\" + fname;

   

    return File.Exists(strFile);

}

 

새로운 파일명 생성

/// <summary>

/// 새로운 파일명 생성

/// </summary>

/// <param name="folderPath"></param>

/// <param name="filename"></param>

/// <returns></returns>

private string GetAvailablePathname(string folderPath, string filename)

{

    int invalidChar = 0;

    do

    {

        // 파일명에서 사용할 수 없는 문자가 들어 있는 배열을 가져온다.

        invalidChar = filename.IndexOfAny(Path.GetInvalidFileNameChars());

 

        // 사용할 수 없는 문자 제거

        if (invalidChar != -1)

            filename = filename.Remove(invalidChar, 1);

    }

    while (invalidChar != -1);

 

 

    string fullPath = Path.Combine(folderPath, filename);

    string filenameWithoutExtention = Path.GetFileNameWithoutExtension(filename);

    string extension = Path.GetExtension(filename);

 

 

 

    while (File.Exists(fullPath))

    {

        Regex rg = new Regex(@".*\((?<Num>\d*)\)");

        Match mt = rg.Match(fullPath);

 

        if (mt.Success)

        {

            string numberOfCopy = mt.Groups["Num"].Value;

            int nextNumberOfCopy = int.Parse(numberOfCopy) + 1;

            int posStart = fullPath.LastIndexOf("(" + numberOfCopy + ")");

 

            fullPath = string.Format("{0}({1}){2}", fullPath.Substring(0, posStart), nextNumberOfCopy, extension);

        }

        else

        {

            fullPath = folderPath + filenameWithoutExtention + " (2)" + extension;

        }

    }

    return fullPath;

}

웹 사이트 검색을 통해 이 부분을 다른 분이 작성한 코드를 사용했다.

이 코드의 내용은 다음의 주소에 자세히 나와 있다.

http://chaoskcuf.com/entry/C-파일명이-중복일--자동으로-이름을-생성하는-코드

 

파일명이 같을 경우 같은 이름으로 저장

/// <summary>

/// 파일을 저장 - 파일이 있을 경우 같은 이름으로 저장

/// </summary>

/// <param name="httpFile"></param>

/// <param name="dir"></param>

/// <param name="id"></param>

/// <param name="kno"></param>

/// <returns></returns>

[WebMethod(Description = "파일을 저장 - 파일이 있을 경우 같은 이름으로 저장")]

public string SameFileSaveFile(byte[] fileInfo, string dir, string fileName, string id, string kno)

{

    string checkSave = string.Empty;

    string filePath = string.Empty;

 

    // 아이디와 키 값 비교

    if (EqualsIdKno(id, kno))

    {

        // 저장할 경로

        string dirpath = ReturnDirectory() + "\\" + dir + "\\";

        filePath = dirpath + fileName;

           

        if (CreateDirectory(dir, id, kno))

        {

            try

            {

                //파일처리

                using (MemoryStream ms = new MemoryStream(fileInfo))

                {

                    using (FileStream fs = new FileStream(filePath, FileMode.Create))

                    {

                        ms.WriteTo(fs);

 

                        ms.Close();

                        fs.Close();

                    }

                }

                checkSave = fileName; // 파일명

            }

            catch

            {

                checkSave = "";

            }

        }

        else

        {

            checkSave = "";

        }

    }

    return checkSave;

}

 

파일명이 같을 경우 새 파일명으로 저장

/// <summary>

/// 파일을 저장 - 파일이 있을 경우 새이름으로

/// </summary>

/// <param name="httpFile"></param>

/// <param name="dir"></param>

/// <param name="id"></param>

/// <param name="kno"></param>

/// <returns></returns>

[WebMethod(Description = "파일을 저장 - 파일이 있을 경우 새 이름으로")]

public string NewFileSaveFile(byte[] fileInfo, string dir, string fileName, string id, string kno)

{

    string checkSave = string.Empty;

    string filePath = string.Empty;

 

    // 아이디와 키 값 비교

    if (EqualsIdKno(id, kno))

    {

        // 저장할 경로

        string dirpath = ReturnDirectory() + "\\" + dir + "\\";

 

        if (CreateDirectory(dir, id, kno))

        {

            try

            {

                // 중복되지 않는 파일명 생성

                filePath = GetAvailablePathname(dirpath, fileName);

 

                //파일처리

                using (MemoryStream ms = new MemoryStream(fileInfo))

                {

                    using (FileStream fs = new FileStream(filePath, FileMode.Create))

                    {

                        ms.WriteTo(fs);

 

                        ms.Close();

                        fs.Close();

                    }

                }

                int fnLen = filePath.Length;

                int fnStart = filePath.LastIndexOf('\\') + 1;

 

                checkSave = filePath.Substring(fnStart, fnLen - fnStart); // 파일명

            }

            catch

            {

                checkSave = "";

            }

        }

        else

        {

            checkSave = "";

        }

    }

 

    return checkSave;

}

 

파일 삭제

/// <summary>

/// 파일을 삭제한다.

/// </summary>

/// <param name="DirPath">디렉토리 절대경로</param>

/// <param name="FileName">파일명</param>

/// <returns></returns>

[WebMethod(Description = "파일을 삭제한다.")]

public bool DeleteFile(string dir, string filename, string id, string kno)

{

    bool checkDel = false;

   

    // 아이디와 키 값 비교

    if (EqualsIdKno(id, kno))

    {

        try

        {

            string strDir = string.Empty;

 

            strDir = ReturnDirectory() + "\\" + dir + "\\";

 

            //파일삭제

            if (File.Exists(strDir + filename))

            {

                File.Delete(strDir + filename);

            }

            checkDel = true;

        }

        catch

        {

            checkDel = false;

        }

    }

    else

        checkDel = false;

 

    return checkDel;

}

 

위의 소스에서 아이디와 키값이 일치 하지 않으면 디렉토리 생성이나 파일 업로드 그리도 삭제 모두 되지 않는 것을 볼 수 있다.

 

이와 같이 파일 업로드에 필요한 대부분의 메소드를 생성했다.

 

다음 장에서는 DLL 만들어 웹 서비스 자원을 어떻게 사용하는지를 알아보겠다.

+ Recent posts