REST 서비스 템플릿

WCF 2011. 5. 2. 09:00 Posted by 알 수 없는 사용자

이번 포스트에선 REST 서비스를 만들 수 있는 간단한 방법~ REST 서비스 템플릿에 대해 얘기를 해볼까 합니다.
이 주제로 세미나(Your Smarter Visual Studio 2010)를 한번 했었는데, 그 때 시간이 짧아 많은 얘기를 전달하지 못한 것 같아 그 때 차마 하지 못했던 얘기들을 이번 포스팅에서 한번 주절거려 보겠습니다. 
세미나를 한 지가 꽤 오래됐는데 이제서야 포스팅을 하네요~ ^^;;;


그럼 시작합니다~ ^^

REST 서비스에 대한 자세한 설명은 과감하게 생략하도록 하겠습니다. 최근엔 REST에 대한 정보가 많아서 글 솜씨가 부족한 제가 굳이 설명하지 않아도 REST에 대해 알기 쉽게 설명한 글들을 큰 힘 들이지 않아도 찾을 수 있으실 겁니다 ㅎ

그래서, 이번 포스팅의 시작은 REST 서비스 템플릿을 다운받는 것부터 시작하겠습니다.

Visual Studio 프로젝트 템플릿을 다운 받는 방법은 크게 두 가지가 있습니다. 첫째는 Visual Studio를 통해서 다운 받는 것이고, 둘째는 직접 템플릿 다운 사이트(Visual Studio 갤러리 사이트)를 방문하여 다운 받는 것입니다.
두 방법 모두 절대 어렵지 않습니다. 여기선 Visual Studio를 사용하는 방법에 대해 알아보겠습니다.

우선,Visual Studio를 열고, 새 프로젝트를 만들기 위한 창을 띄웁니다. 그리고 좌측 메뉴에서 "온라인 템플릿"을 선택합니다. 그러면 잠깐 동안의 검색 이미지가 나타났다가, 아래 그림과 같은 화면이 나타나는데, 우측 리스트에 보면 "WCF REST Service Template 40(CS)" 아이템이 보입니다. 

 
이 아이템을 선택하고 프로젝트를 생성할 이름과 위치를 지정한 후에 확인 버튼을 클릭하면, 해당하는 템플릿을 다운받고, 바로 새로운 프로젝트를 생성해줍니다. 너무 쉽습니다~ 그죠? ㅎ 

REST 서비스 프로젝트가 생성되면 기본 파일들이 함께 생성되는데, 이 파일 중에 Service1.cs 파일이 실제 REST 서비스를 구현하기 위한 파일입니다. 이 파일을 보면 Service1 이라는 이름의 클래스 밑에 다음과 같은 메서드들이 정의되어 있는 것을 보실 수 있으실 겁니다. 

[WebGet(UriTemplate = "")]
public List<SampleItem> GetCollection() { … }

[WebInvoke(UriTemplate = "", Method = "POST")]
public SampleItem Create(SampleItem instance) { … }

[WebGet(UriTemplate = "{id}")]
public SampleItem Get(string id) {… }

[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
public SampleItem Update(string id, SampleItem instance) { … } 

[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
 
public void Delete(string id) { … }

 
REST 서비스에서 각 작업과의 상호 작용은 고유한 URI와 HTTP 표준 동사(GET, POST, PUT, DELETE) 를 통해 이루어 집니다. 기본적으로 만들어지는 위와 같은 메서드는 각 HTTP 표준 동사에 대한 메서드 특성 설정에 대한 예시를 보여줍니다.

WebGetAttribute 와 WebInvokeAttribute

WCF REST 서비스는 위와 같이 정의 된 메서드에 접근하기 위해 URI와 HTTP 동사를 메서드에 매핑해 주는데 이때 필요한 것이 WebGetAttribute 와 WebInvokeAttribute 입니다.

WebGetAttribute는 메서드가 HTTP GET 요청에 대해 응답한다는 것을 알려줍니다. WebInvokeAttribute는 기본적으로POST 요청에 응답하지만, PUT 과 DELETE 요청에 대한 응답도 지원합니다. PUT 및 DELETE 요청에 대해 응답하는 메서드를 정의하기 위해서는 WebInvokeAttribute.Method 속성을 설정해주면 됩니다. 설명이 좀 어려워 보이지만 위 코드를 보면 쉽게 이해할 수 있으실 겁니다. ^^


REST 서비스 구현

기본적인 부분은 모두 언급이 된 것 같습니다. 이제는 이를 이용하여 간단한 REST 서비스를 만들어보겠습니다.
만들려는 서비스는 회원 관리에 대한 것으로 새로운 회원의 입력, 회원 정보 조회, 회원 정보 수정 및 삭제를 할 수 있는 서비스를 구현해보도록 하겠습니다.

우선, 서비스에서 사용할 Member 클래스를 다음과 같이 정의하였습니다.

[DataContract]
public class Member
{
    [
DataMember(Order=0)]
    
public string Id { getset; }
    [
DataMember(Order=1)]
    
public string Name { getset; }
    [
DataMember(Order=2)]
    
public string Job { getset; }
    [
DataMember(Name="PhoneNumber", Order=3)]
    
public string Phone { getset; }
    [
DataMember(Order=4)]
    
public string Address { getset; }
}

 
그리고, 실제 서비스의 구현은 다음과 같습니다.

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MemberService
{
    [WebGet(UriTemplate = "GetAll")]
    public MemberList GetCollection()
    {
        BizMember bizMember = new BizMember();
        return bizMember.GetAll();
    }

 
    [WebInvoke(UriTemplate = "Add", Method = "POST")]
    public void Create(Member instance)
    {
        BizMember bizMember = new BizMember();
        bizMember.Add(instance);
    }

 

    [WebGet(UriTemplate = "{id}", ResponseFormat=WebMessageFormat.Json)]
 
   public Member Get(string id)
    {
        BizMember bizMember = new BizMember();
        return bizMember.Get(id);
    }

 

    [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
 
   public void Update(string id, Member instance)
    {
        BizMember bizMember = new BizMember();
        bizMember.Update(id, instance);
    }
 

    [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
    public void Delete(string id)
    {
        BizMember bizMember = new BizMember();
        bizMember.Delete(id);
    }
}


코드는 보시면 아시겠지만 그리 어렵지 않습니다. BizMember 라는 클래스에서 여러가지 작업이 이루어지는데 이 클래스 역시 그렇게 어려운 내용이 없기에 자세한 설명은 생략하겠습니다. 대신에 소스를 첨부시켜 놓을 테니 잠깐만 살펴보시면 알 수 있으실 겁니다. ^^;; BizMember 클래스에 대한 설명까지 하려면 내용이 너무 길어질 것 같아 그러니 양해 부탁드립니다~ 흠흠;;; 

앞에서 설명을 하지 않았는데 위 코드를 보면 WebGetAttribute와 WebInvokeAttribute에 UriTemplate 이라는 속성이 보이실겁니다. 이 속성은 서비스로 들어온 요청의 URI와 매핑을 시키는 속성이라고 생각하시면 됩니다.
예를 들어, 위의 코드에서 Create 메서드의 경우 UriTemplate 속성의 값이 "Add" 로 되어 있는데, 만약 이 서비스의 기본 주소가 "http://localhost:2853/MemberService"이라고 할 때, 요청 들어온 URI가 "http://localhost:2853/MemberService/Add" 일 때 Create 메서드를 호출 한다는 것입니다. 물론, Create 메소드의 WebInvokeAttribute에 정의되어 있듯이 "POST" 방식의 요청이어야 하겠죠~?

또한, 위 코드의 Get 메서드처럼 UriTemplate 속성의 값이 "{id}"인 경우가 있는데, 이는 메서드의 파라미터인 id의 값이 URI에 들어가는 형태가 되는 것입니다. 예를 들면, HTTP "GET" 방식으로 "http://localhost:2853/MemberService/ruaa" 의 주소로 요청이 들어오면, 위 코드에서의 Get 메서드가 호출되면서 Get 메서드의 id 파라미터 값으로 ruaa가 입력되는 것입니다.
 
그럼, 서비스의 기본 주소는 어떻게 설정할 수 있을까요? 궁금하지 않으신가요? ㅎ
기존 WCF 서비스에서는 web.config 파일을 사용했었는데, REST 서비스 템플릿은 조금 다릅니다. 
global.asax 파일을 열어보시면 그 답을 찾을 수 있으실 겁니다.

private void RegisterRoutes()
{
    // Edit the base address of Service1 by replacing the "Service1" string below
    RouteTable.Routes.Add(new ServiceRoute("MemberService"new WebServiceHostFactory(),
                                            typeof(MemberService)));
}

 
위 코드를 보니 어디서 많이 봤다~ 싶으네요~ ㅎ
ASP.NET 4.0과 ASP.NET MVC 프로젝트를 한 번이라도 구현해보신 분들이라면 저랑 같은 생각을 하셨을겁니다. ASP.NET MVC 때 부터 사용한 라우팅 방법과 같은 방식을 사용하고 있네요~

아무튼, 위 코드 처럼 구현을 할 경우 서비스의 기본 주소는 "http://{서비스가 배포된 기본 주소}/MemberService"가 됩니다.


Help 페이지

이렇게 REST 서비스 템플릿을 이용하여 서비스를 구현하고, 빌드를 하면 기본적으로 서비스에 대한 help 페이지를 만날 수 있습니다. help 페이지의 주소는 서비스의 기본주소에 "/help" 가 붙는 형식입니다.
저 같은 경우, Visual Studio 개발 서버로 돌렸기 때문에 다음 그림에서 보듯이 help 페이지의 경로는 "http://localhost:2853/MemberService/Help" 가 되는 것입니다.


위 그림을 보시면 알겠지만, 각 서비스 끝점에 대한 간단한 설명을 볼 수 있고, 각 서비스 끝점의 메서드를 클릭하면 자세한 내용을 확인할 수 있습니다. 이는 WCF 서비스의 헬프 페이지와 아주 유사하죠~? 

자~ 이제 슬 마무리 지어 볼까요? ^^

이번 포스팅을 통해 REST 서비스의 많은 부분에 대해 알려드리진 못했지만 기본적인 부분은 모두 설명이 된 듯 합니다. 그리고 REST 서비스 템플릿을 이용하면 정말 쉽게 WCF를 이용한 RESTful 서비스를 구현할 수 있다는 것도 알게 되었습니다. 

혹시나 추가적인 설명이 필요한 부분이나 질문이 있으신 분들은 댓글 남겨주시면 성심성의껏(?) 답변 해드리겠습니다.
그리고, 첨부한 소스 코드를 참조하시어 테스트 해보시면 이번 포스팅에서 설명한 많은 부분이 이해가 되실 것 같습니다. 

WCF Troubleshooting (3) - Error Handler

WCF 2011. 3. 3. 09:00 Posted by 알 수 없는 사용자
오랜만에 인사 드립니다~
해가 바뀌고, 벌써 두 달이 거의 지나가고 있는 시점에 이제야 다시 글을 올리게 되었습니다.
참, 부끄럽기 그지 없군요~ ^^;;
부끄럽긴 하지만 인사는 드려야죠!! 새해 복!! 많이 받으쌉싸리와용~

두어 달 만에 포스팅을 이어가려니 정말 난감하기도 하고, 민망하기도 하고... 
하지만, 이 민망함 그냥 얼굴에 철판 깔고, 시작 해 보렵니다. 어차피 포스팅 기다린 사람도 없었을 테니깐,, ㅋㅋ

이번 포스팅은 Troubleshooting 의 세 번째 포스팅으로, Error Handler 에 대해 알아볼까 합니다.

서비스를 개발할 때, 서비스에서 예외가 발생하는 경우, 이 예외에 대해 어떤 공통적인 동작을 취하게끔 코드를 만들고 싶을 때가 있습니다. 예를 들면, 발생하는 모든 예외에 대한 정보를 로그로 남긴다거나, 클라이언트로 전송되는 fault message의 내용을 동일하게 한다거나, 등등등... 

이럴 때 사용할 수 있는 것이 바로 Error Handler 입니다.
명칭을 봐도 딱! 감이 오지 않습니까? "에러 핸들러!!!" ㅋ

그럼, Error Handler 를 사용하는 방법을 차근 차근 적어내려 가보겠습니다.

WCF의 에러 핸들러를 사용하기 위해 가장 먼저 해야하는 것은 IErrorHandler 인터페이스를 구현하는 서브 클래스를 만드는 것입니다.

IErrorHandler 인터페이스는 다음과 같은 두 개의 메서드를 제공합니다.
 Method  Description 
 HandleError  예외에 대해 어떤 공통적인 동작을 취할 수 있는 메서드입니다.
 (예 : 예외 정보 로깅)
 ProvideFault  클라이언트로 보내질 fault message 를 정의할 수 있는 메서드입니다. 

아하~ 그리 어렵지 않죠? ㅎ

그럼, 직접 한번 구현 해보겠습니다.

namespace ErrorHandler

{

    [DataContract]

    public class MyErrorInfo

    {

        [DataMember]

        public string Message { get; set; }

        [DataMember]

        public string ExceptionInfo { get; set; }

    }

}



public class SampleErrorHandler : IErrorHandler

{

    public bool HandleError(Exception error)

    {
        // 이곳에 발생한 예외에 대한 공통적인 작업을 구현할 수 있습니다.

        return true;

    }

 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)

    {

        FaultReason reason = new FaultReason("내맘대로 무조건 예외");

        FaultException<MyErrorInfo> faultException = new FaultException<MyErrorInfo>(

                                                  new MyErrorInfo

                                                  {

                                                      Message = error.Message,

                                                      ExceptionInfo = error.ToString()

                                                  },

                                                  reason);

 

        MessageFault messageFault = faultException.CreateMessageFault();

 

        fault = Message.CreateMessage(

            version,

            messageFault,

            faultException.Action);

    }

}


이 예제에서는 HandleError 메서드에 별 다른 코드를 넣지 않았습니다. 앞에서 언급을 했었지만 HandleError 메서드에서는 발생한 예외에 대한 어떤 공통적인 행동에 대한 코드를 구현 해주시면 됩니다.

그리고, HandleError 메서드에서는  bool 형의 값을 반환 해주는 것이 보이네요~ 이 bool 형의 값은 예외가 적절하게 처리되었는지 여부를 나타내준다고 생각하시면 됩니다. 만약, false를 반환하게되면, 예외가 처리되지 않은 것으로 간주하고, 기본 응답이 사용됩니다. 이 경우 디스패처가 모든 세션을 중단하고, InstanceContext를 중단합니다.

MSDN의 HandleError 메서드 설명 페이지에도 나와 있지만, HandleError 메서드는 여러 다른 위치에서 호출될 수 있기 때문에 이 메서드에서 예외를 제대로 처리하지 못했다고 false를 반환하게 되면, 모든 상태가 손상된 것으로 간주되고, 서비스에 존재하는 모든 세션이 중단된다고 생각하시면 됩니다.

따라서, 예외가 발생했을 때 모든 세션이 중단되길 원치 않는다면 위 예제 코드처럼 true를 반환하는 것이 나을 것입니다.

ProvideFault 메서드의 코드도 그리 어려워 보이지 않는군요. 이 전 저의 포스팅을 보셨던 분이라면 같은 생각을 하실 것 같네요~ ^^

ProvideFault의 매개 변수에 대한 설명은 다음과 같습니다.

 Parameter  Description 
 error  서비스 작업 중에 던져지는 Exception 개체입니다.
 version  메시지의 SOAP 버전입니다. 
 fault  클라이언트로 보내지는 Message 개체입니다. 

위 예제 코드에선 ProvideFault 메서드 안에서 매개 변수로 받은 예외 개체(error)를 이용하여 사용자 정의 된 예외 메시지를 정의합니다. 이렇게 정의 된 예외 메시지를 매개 변수 fault에 할당만 해주면 이 메시지는 클라이언트로 전달 됩니다.
FaultException 와 FaultReason 에 관한 내용은 이 전 포스트를 확인 해주세요~ ^^

이제 ErrorHandler 구현은 끝이 났습니다.
이렇게 만든 ErrorHandler를 사용하기 위해서 다음으로 해야 할 것은 WCF 서비스에 사용할 수 있는 새로운 Behavior 를 만드는 것입니다. 
Custom Behavior 를 만들어 WCF를 확장하는 방법에 대해선 이 곳을 참고하시면 좋을 것 같습니다.

그럼 새로운 Behavior를 만들어 볼까요?


public sealed class ErrorBehaviorAttribute : Attribute, IServiceBehavior

{

    private List<Type> _errorHandler;

 

    public List<Type> ErrorHandlerType

    {

        get { return _errorHandler; }

    }

 

    public ErrorBehaviorAttribute(params Type[] errorHandler)

    {

        this._errorHandler = new List<Type>();

        foreach (var item in errorHandler)

        {

            _errorHandler.Add(item);

        }

    }

 

    public void AddBindingParameters(ServiceDescription serviceDescription,

                                        ServiceHostBase serviceHostBase,

                                        Collection<ServiceEndpoint> endpoints,

                                        BindingParameterCollection bindingParameters)

    {           

    }

 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription,

                                        ServiceHostBase serviceHostBase)

    {

        List<IErrorHandler> errorHandler = new List<IErrorHandler>();

 

        ErrorHandlerType.ForEach(

            (item) =>

            {

                errorHandler.Add((IErrorHandler)Activator.CreateInstance(item));

            });

 

        foreach (ChannelDispatcherBase dispatcherBase in
                                                     serviceHostBase.ChannelDispatchers)

        {

            ChannelDispatcher dsp = dispatcherBase as ChannelDispatcher;

            errorHandler.ForEach(

                (item) =>

                {

                    dsp.ErrorHandlers.Add(item);

                });

        }

    }

 

    public void Validate(ServiceDescription serviceDescription,

                            ServiceHostBase serviceHostBase)

    {           

    }

}

이 코드를 보면 조금 복잡해 보일 것 같습니다. Behavior의 경우 설정파일(.config)에서 설정을 하거나 코드 상에서 설정을 할 수 있는데 서비스 클래스의 Attribute 특성을 사용하여 설정합니다.
그래서 이 클래스는 Attribute 시스템 클래스를 상속합니다. 또한, IServiceBehavior 인터페이스를 상속하여 Behavior 로 사용할 수 있는 클래스를 만듭니다.

위 클래스의 생성자를 보면 하나 이상의 클래스 타입을 매개 변수로 받습니다. 이렇게 받은 타입들을 List<Type> 인스턴스의 전역 변수에 저장을 합니다. 따로 예외 처리를 하진 않았지만 생성자에 매개변수로 넘겨주는 클래스 타입은 반드시 IErrorHandler 인터페이스를 구현한 타입이어야 합니다.

그리고, IServiceBehavior 인터페이스 메서드 중에 ApplyDispatchBehavior 메서드를 구현합니다. 이 메서드에서는 서비스에 존재하는 모든 channel dispatcher 에게 생성자에서 받았던 IErrorHandler 타입들의 인스턴스를 추가시켜줍니다.

말이 조금 어렵나요? ^^;;

참고로, channel dispatcher 는 WCF 서비스를 구현할 때 어떤 Binding을 사용하는냐에 따라 달라집니다. 물론 사용하는 Binding 의 수에 따라 disptcher의 수도 늘어가게 됩니다.
dispatcher에 대해 잘 알지 못하는 분들이 있을 것 같습니다. 정확한 설명을 이 포스팅에서 하기에는 이것 만으로도 내용이 길어질 것 같아 설명하긴 힘들지만, 이 곳(디스패처 확장)의 내용을 확인하시면 이해는 가시리라 생각합니다. ^^

이제 준비 작업은 모두 끝이 났습니다. 앞에서 만든 ErrorHandler 를 사용할 수 있을 것 같네요

ErrorHandler를 사용하기 위해 다음과 같이 간단한 서비스를 만들고 서비스 클래스에 ErrorBehavior 특성을 설정하였습니다.

// Service Contract
[
ServiceContract]

public interface ICalc

{

    [OperationContract]

    [FaultContract(typeof(MyErrorInfo))]

    int Add(int a, int b);

 

    [OperationContract]

    [FaultContract(typeof(MyErrorInfo))]

    int Sub(int a, int b);

 

    [OperationContract]

    [FaultContract(typeof(MyErrorInfo))]

    int Mul(int a, int b);

 

    [OperationContract]

    [FaultContract(typeof(MyErrorInfo))]

    int Div(int a, int b);

}


// Service 구현 클래스
[ErrorBehavior(typeof(SampleErrorHandler))]

public class Calculator : ICalc

{

    public int Add(int a, int b)

    {

        throw new InvalidOperationException("잘못된 Add 메서드 호출입니다.");

    }

 

    public int Sub(int a, int b)

    {

        throw new InvalidOperationException("잘못된 Sub 메서드 호출입니다.");

    }

 

    public int Mul(int a, int b)

    {

        throw new InvalidOperationException("잘못된 Mul 메서드 호출입니다.");

    }

 

    public int Div(int a, int b)

    {

        throw new InvalidOperationException("잘못된 Div 메서드 호출입니다.");

    }

}

모든 메서드를 호출하면 아~무 이유없이 예외를 던지고 있군요~!! ㅎ

이제 이 서비스를 빌드하고 테스트를 해보야겠죠.
이번에는 따로 Console 어플리케이션을 만들지 않고 WcfTestClient.exe를 사용해보도록 하겠습니다.
이 간단한 프로그램은 WCF 서비스를 테스트하기 위한 클라이언트 툴입니다.

Visual Studio 명령 프롬프트를 실행시키고 "WcfTestClient"를 치고 엔터를 클릭하면 실행시킬 수 있습니다. 또는 Visual Studio 에서 WCF 서비스 프로젝트를 F5 를 이용하여 실행해도 역시 이 툴을 사용할 수 있습니다.

이 툴을 실행시키면 다음과 같은 모습을 하고 있죠.


여기에서 간단히 호출하고자 하는 메서드를 왼쪽 창에서 마우스로 더블 클릭 "톡! 톡!" 해주시면 실행할 수 있습니다. 이건 너무 직관적인거라 자세한 설명을 하지 않더라도 모두 사용하실 수 있으실겁니다 ^^

아무 메서드를 하나 실행시키면 예외가 발생했다는 내용을 담고 있는 창이 뜨는 것을 보실 수 있습니다. 여기서 오류정보를 보면 위에 SampleErrorHandler 의 ProvideFault 메서드에서 정의한 내용들이 들어가 있는 것을 확인할 수 있습니다.

더 자세한 내용을 보고 싶다면, 예외 창을 닫고 오른쪽 창 밑에 있는 "XML" 탭을 클릭해보세요~ 그럼 다음과 같은 화면을 보실 수 있으실 겁니다.


응답에 있는 XML을 다시 보여드려볼까요?

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">

  <s:Header />

  <s:Body>

    <s:Fault>

      <faultcode>s:Client</faultcode>

      <faultstring xml:lang="ko-KR">내맘대로 무조건 예외</faultstring>

      <detail>

        <MyErrorInfo xmlns="http://schemas.datacontract.org/2004/07/ErrorHandler" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

          <ExceptionInfo>

            System.InvalidOperationException: 잘못된 Sub 메서드 호출입니다.

            위치: ErrorHandler.Calculator.Sub(Int32 a, Int32 b) 파일 D:\Dev\Learning\WCF\ErrorHandler\ErrorHandler\Service1.svc.cs: 21

            위치: SyncInvokeSub(Object , Object[] , Object[] )

            위치: System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)

            위치: System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)

            위치: System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

          </ExceptionInfo>

          <Message>잘못된 Sub 메서드 호출입니다.</Message>

        </MyErrorInfo>

      </detail>

    </s:Fault>

  </s:Body>

</s:Envelope>



네~ XML 내용을 확인하니 좀 더 확실해 졌네요. 클라이언트가 받은 메시지에 ProvideFault 메서드에서 정의한 내용들이 들어가 있다는 것을요~ ㅎ

자~ 그럼 마무리 하겠습니다!!

이번 내용은 뭔가 조금 복잡했던 것 같지만 사실 그렇게 복잡하지 않습니다. 이 포스트를 찬찬히 되새기면서, 그리고 인터넷을 통해 다른 부가적인 내용들도 알아가면서 학습을 하시면 그리 어렵지 않다는 것을 느끼게 되실겁니다.
예외를 처리하는 방법은 실무에 꽤 많이 쓰일 수 있는 내용이니깐 제대로 알고 가는건 좋을 것 같습니다.

다음 포스팅에선 계속해서 Troubleshooting 에 관한 내용으로 찾아 뵙도록 하겠습니다.
WCF에서 제공하는 몇 가지 툴들이 있는데 이런 툴들에 대한 설명이 될 것 같습니다.

그럼 다음 포스팅때까지 안녕히~ ^^

'WCF' 카테고리의 다른 글

REST 서비스 템플릿  (3) 2011.05.02
WCF Troubleshooting (2)  (2) 2010.11.29
WCF Service Configuration Editor  (0) 2010.11.24
WCF Troubleshooting (1)  (0) 2010.11.19
WCF Security (2) - 전송 계층에서의 메세지 인증 (사용자 지정 인증)  (0) 2010.09.06

2011년 .NET 개발자의 생존전략

VSTS 2010 팀 블로그 2011. 1. 10. 08:30 Posted by POWERUMC

최근 2년 동안 다양한 개발 분야의 기술들이 물망에 오르는 굉장히 뜻 깊은 해였습니다. 2년 전이면 Microsoft 강성재 차장과 함께 처음으로 "Visual Studio 한국 공식 팀"을 창설하면서 http://vsts2010.net 이 탄생한 시기이군요. 2008년 12월에 팀이 창설되고, 2009년 1월 5일이 팀 블로그 2주년이 되는 날이었군요.

바로 저희 "Visual Studio 한국 공식 팀" 블로그에서 한홀 한홀 정성스럽게 작성된 포스트들이 2년 여간의 기술 흐름을 대변해 주고 있으며, 그리고 2011년의 기술도 짐작해 볼 수 있는 짧지만 굵은 변화의 흐름과 함께 여기까지 온 것 같습니다.

우리 팀이 함께 해왔던 핵심 키워드의 태그는 무엇이었을까요?

  • Visual Studio 2010
  • .NET 4.0, .NET Framework 4.0
  • ASP.NET MVC
  • C# 4.0
  • C++0x, C++/CLI
  • Parallel Computing
  • WCF
  • Cloud
  • Application Lifecycle Management

   

그리고 위의 태그들에 대해 더 자세히 살펴보더라도 생소한 기술과 이름, 아키텍처, 환경 등이 2년 동안 격변을 일으키며 변화를 해왔다는 사실입니다.

2011년 이전까지는 여러분들에게 선택권이었던 것들이, 이제는 필수가 되어야 한다고 해도 과언이 아닐 겁니다. 비즈니스 요구사항의 단면을 보면 업무적인 요인, 시대적인 배경 등인데, 이 시대적인 배경에는 트랜드+시장+기술+… 이 있을테고요. 그리고 '우리가 이 시대적인 배경 중 '기술'에 한 배를 타고 흐르고 있는가…?' 에 다시 한번 생각해 볼만 합니다.

예전 2010년 6월 1일 REMIX10 세미나에서 여러분에게 말씀 드린 마지막 문구가 다시금 생각이 나네요.

http://www.techdays.co.kr/2010spring/remix10/session3_1.html

   

여러분의 생존전력은 바로 아래에 해답이 있습니다. 여러분들에게 필요한 것, 그리고 그 가능성이 있다고 판단하시면 2011년 생존을 위하여 달려보는 것은 매우 멋진 2011년 한 해가 될 것입니다.

   

.NET 프레임워크

.NET Framework .NET 의 과거와 현재, 그리고 미래
.NET Framework .NET Framework 4.0 의 특징
.NET Framework .NET Framework 4.0 마이그레이션 이슈
.NET Framework .NET 스마트클라이언트 한계 극복 [1]
.NET Framework .NET 스마트클라이언트 한계 극복 [2]
CLR 1. Hello 世界
CLR 2. CLR! CLR! CLR!
CLR 3. MSCorLib & Metadata
CLR 4. Assembly
CLR 5. Assembly - Strongly named assemblies
CLR 6. Assembly - GAC(Global Assembly Cache)
CLR 7. System.Object
CLR 8. System.Object (2)
CLR 닷넷4.0에서 네이티브코드와 매나지드코드의 동거 part 1.
CLR 닷넷4.0에서 네이티브코드와 매나지드코드의 동거 part 2-1.
CLR 닷넷4.0에서 네이티브코드와 매나지드코드의 동거 part 2-2. 네이티브 랩퍼 만들기
Managed Extensibility Framework [MEF] 1. Managed Extensibility Framework 이란?
Managed Extensibility Framework [MEF] 2. Parts 와 Contracts 선언
Managed Extensibility Framework [MEF] 3. Export 선언
Managed Extensibility Framework [MEF] 4. Import 선언
Managed Extensibility Framework [MEF] 5. Catalog 사용
Managed Extensibility Framework [MEF] 6. Lazy Exports
Managed Extensibility Framework [MEF] 7. Exports and Metadata
Managed Extensibility Framework [MEF] 8. Strongly Typed Metadata
Managed Extensibility Framework [MEF] 9. Recomposition
Managed Extensibility Framework [MEF] 10. Querying the CompositionContainer
Managed Extensibility Framework MEF Preview 6 공개
Managed Extensibility Framework MEF 는 Generic Type 을 지원하지 않는다!
Managed Extensibility Framework MEF 에 Generic Type 을 지원하기 위해서..?
Managed Extensibility Framework MEFGeneric 코드 플랙스에 공개합니다.

   

애자일 개발

Agile Development [Better Code]TDD의 개념이 완벽히 녹아 들어간 VSTS 2010
Agile Development [Better Code]Visual Studio 2010 Code Analysis Enhancements - 1.개요
Agile Development [Better Code]Visual Studio 2010 Code Analysis Enhancements - 2. Rule Sets Feature
Agile Development [Better Code]PEX, Automated Whitebox Testing for .NET - 1. 개요
Agile Development [Better Code]Visualize Code Relationships
Agile Development [Testing] TDD (Test-Driven Development-테스트 주도 개발)
Agile Development [Testing] BDD (Behavior-Driven Development?행위 주도 개발)
Agile Development [Testing] Moq.NET (T/B Driven Development)
Agile Development [Better Code]Visual Studio Code Analysis Enhancements - 3. Data Flow Rules and Phoenix Engine
Agile Development 애자일에 대한 고찰
Agile Development [ALM-Test] 1. 왜 단위 테스트를 해야 하는가?
Agile Development [ALM-Test] 2. 한국적인 애자일 모델의 필요성
Agile Development [협업 1] 협업 도구의 통일성과 협업 인프라 관리
Agile Development [ALM-Test] 3. 테스터에 대한 오해와 진실
Agile Development [ALM-Test] 4. 테스터(SDET) 의 역할
Agile Development [ALM-Test] 5. 테스트 계획
Agile Development [ALM-Test] 6. Load Runner vs Visual Studio 2010 테스팅 비교 분석 - http://willstory.tistory.com/4 제공
Agile Development [ALM-Test] 7. TDD vs 계약기반 테스트
Architect Development Architect Development ?
Architect Development 몽당연필과 함께하는 VSTS 2010 모델링 0/4
Architect Development 몽당연필과 함께 하는 VSTS 2010 모델링 1/4
Architect Development Windows Server AppFabric - Velocity 란?
Architect Development WCF=SOA 에 대한 고찰

   

ASP.NET 4.0

ASP.NET 4.0 [ASP.NET 4.0] 1. Core Service - Extensible Output Caching
ASP.NET 4.0 [ASP.NET 4.0] 2. AJAX - Declarative Client Template Rendering
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Dynamic Data(1)
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Dynamic Data(2)
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Designer & Deployment
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Core Services
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - New Features in the Microsoft Ajax Library
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Forms(1)
ASP.NET 4.0 Razor in WebMatrix
ASP.NET 4.0 Razor in WebMatrix(2) 코드의 재 사용
ASP.NET 4.0 Razor in WebMatrix(3) ? WebMatrix Helper
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Forms(2)
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Forms(3)
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Forms(4)
ASP.NET 4.0 ASP.NET 4 와 Visual Studio 2010 Web Development Beta 2 Overview - Web Forms(5)
ASP.NET MVC M, V 그리고 C의 각방생활(1) - ASP.NET MVC vs ASP.NET WEB FORM
ASP.NET MVC M, V 그리고 C의 각방생활(2) - ASP.NET MVC와 인사나누기
ASP.NET MVC M, V 그리고 C의 각방생활(3) - 초간단 사이트 만들기(1)
ASP.NET MVC M, V 그리고 C의 각방생활(4) - 유효성 검사
ASP.NET MVC M, V 그리고 C의 각방생활(5) - 초간단 사이트 만들기(2)
ASP.NET MVC M, V 그리고 C의 각방생활(6) - 유효성 검사(2)
ASP.NET MVC M, V 그리고 C의 각방생활(7) - 함께 즐겨요~ jQuery
ASP.NET MVC M, V 그리고 C의 각방생활(8) - jQuery와 탭메뉴 그리고 파샬뷰
ASP.NET MVC M, V 그리고 C의 각방생활(9) - jqGrid 사용해보자
ASP.NET MVC M, V 그리고 C의 각방생활(10) - jqGrid를 이용한 paging과 sorting
ASP.NET MVC ASP.NET MVC 3 Preview 1 이 릴리즈 되었습니다.
ASP.NET MVC M, V 그리고 C의 각방생활(11) - jqGrid로 데이터 추가,편집,삭제해보기
ASP.NET MVC M, V 그리고 C의 각방생활(12) - 테스팅 그거, 아무나 하나?
ASP.NET MVC JailBreak From Controllers and Actions
ASP.NET MVC VSTS2010 에서 Razor 코드 하이라이팅 지원하기

   

C# 4.0

C# [C# 4.0] Named and Optional Parameters
C# [C# 4.0] Duck Typing
C# [C# 4.0] New Extension Method "Zip"
C# [C# 4.0] Generic Covariance And Contra Variance
C# Welcome to Dynamic C#(1) - 첫만남.
C# Welcome to Dynamic C#(2) - Wanna be a polyglot.
C# Welcome to Dynamic C#(3) - 마음이 넒어진 C#
C# Welcome to Dynamic C#(4) - 극과극 비교체험.
C# Welcome to Dynamic C#(5) - Return to Dynamic.
C# Welcome to Dynamic C#(6) - Return to Dynamic (2)
C# Welcome to Dynamic C#(7) - 아낌없이 표현해 주는 나무
C# Welcome to Dynamic C#(8) - DLR이 나무를 사랑하는 이유
C# Welcome to dynamic C# 외전(1) - Generate From Usage.
C# Welcome to dynamic C# 외전(2) - Generic Method.
C# Welcome to dynamic C# 외전(3) - 감시하는 자와 감시당하는 자.
C# Welcome to Dynamic C#(9) - Dynamic Returns Again.
C# Welcome to Dynamic C#(10) - Dynamic Returns Again.(2)
C# Welcome to Dynamic C#(11) - The Phantom of The Dynamic
C# Welcome to Dynamic C#(12) - dynamic은 외로운 아이.
C# Welcome to Dynamic C#(13) - 아직도 가야할 길.
C# Welcome to Dynamic C#(14) - 철지난 만우절에 낚여서 파닥파닥.
C# Welcome to Dynamic C#(15) - A/S for dynamic.
C# Welcome to Dynamic C#(16) - dynamic이라도 이건 안되는 거임.
C# Welcome to Dynamic C#(17) - 필요한 말만 하고 삽시다.
C# Welcome to Dynamic C#(18) - 이름을 붙이면서 벌어진 일들.
C# Welcome to Dynamic C#(19) - 위너 고르기.
C# Welcome to Dynamic C#(20) - 어르신과 대화하는 법.
C# Welcome to Dynamic C#(21) - 인덱스의 힘.
C# Welcome to Asynchronous C#(0) - C#의 전설.
C# Parallel Programming [C# 4.0] Parallel Extension - [1] 병렬 처리
C# Parallel Programming [C# 4.0] Parallel Extension - [2] 병렬 처리 아키텍처
C# Parallel Programming [C# 4.0] Parallel Extension - [3] TPL(Task Parallel Library)
C# Parallel Programming Welcome to Parellel world(1) - Here comes a new challenger!
C# Parallel Programming Welcome to Parallel C#(1) - 굿바이, 그리고 안녕~~?
C# Parallel Programming Welcome to Parallel C#(2) - 계속 되는 개념 찾기.
C# Parallel Programming Welcome to Parallel C#(3) - 작업의 기본.
C# Parallel Programming Welcome to Parallel C#(4) - 작업의 기본 Part 2.
C# Parallel Programming Welcome to Parallel C#(5) - 병렬작업에서 예외가 생기면 어케...?
C# Parallel Programming Welcome to Parallel C#(6) - To be continue...
C# Parallel Programming Welcome to Parallel C#(7) - Excuse me.
C# Parallel Programming Welcome to Parallel C#(8) - 취소 쉽게 하기.
C# Parallel Programming Welcome to Parallel C#(9) - 백지장은 맞들지 말엉.
C# Parallel Programming Welcome to Parallel C#(10) - 이보게, 잠깐 뒤를 돌아보지 않겠나.

   

C++/CLI

C++/CLI C++/CLI는 미운 오리새끼 or 백조
C++/CLI .NET에서의 C++/CLI의 의미
C++/CLI [Step 01] 'C++/CLI가 뭐야?'에 답하기 && 가장 많은 프로그래밍 언어로 만드는 프로그램 만들기
C++/CLI [Step 02-1] 클래스(class), 핸들(^), 그리고 구조체(struct)
C++/CLI [Step.02-2] 클래스(class), 핸들(^), 그리고 구조체(struct)
C++/CLI [step.03] 배열
C++/CLI [Step. 04] nullptr, interior_ptr, pin_ptr
C++/CLI [Step. 05] 관리 코드의 array를 비관리 코드에 포인터로 전달
C++/CLI [Step. 06-1] 관리코드의 문자열과 비관리코드의 문자열 변환
C++/CLI [Step. 06-2] 관리코드의 문자열과 비관리코드의 문자열 변환
C++/CLI [Step. 07] 비관리 클래스에서 관리 클래스를 멤버로, 관리 클래스에서 비관리 클래스를 멤버로
C++/CLI [Step. 08] 프로퍼티 ( property )
C++/CLI [Step. 09] 델리게이트 (delegate)
C++/CLI [Step. 10] 이벤트 ( event )
C++/CLI [Step. 11] 열거형( enum )
C++/CLI [Step. 12] for each
C++/CLI [Step. 13] parameter array
C++/CLI [Step. 15] static 생성자, initonly, literal
C++/CLI [Step. 14] 인터페이스 ( interface )
C++/CLI [Step. 16] array 클래스에 non-CLI 오브젝트 사용
C++/CLI [Step. 17] 델리게이트에 비관리 함수를 할당하기 그리고 다음 예고
C++/CLI [Step. 18] 순수 가상 함수
C++/CLI [Step. 19] char* -> 관리코드, 관리코드 -> char*
C++/CLI [Step. 20] 닷넷에서 HalfNetwork를 사용하자 - 1
C++/CLI [Step. 21] 닷넷에서 HalfNetwork를 사용하자 - 2
C++/CLI [Step. 22] 닷넷에서 HalfNetwork를 사용하자 ? 3
C++/CLI [Step. 23] 닷넷에서 HalfNetwork를 사용하자 ? 4
C++/CLI [Step. 24] 닷넷에서 HalfNetwork를 사용하자 ? 5
C++/CLI [Step. 25] 닷넷에서 HalfNetwork를 사용하자 ? 6(마지막)

   

C++0x

C++0x [VC++] 1. 큰 변화가 기대되는 Visual C++( VC++ )
C++0x [VC++] 2. C++0x의 auto
C++0x [VC++] 3. static_assert
C++0x [VC++] 4. 우측 값 참조( RValue Reference ) - 첫 번째
C++0x [VC++] 5. 우측 값 참조( RValue Reference ) ? 두 번째
C++0x [VC++] 6. 우측 값 참조( RValue Reference ) - 세 번째
C++0x [VC++] 7. 우측 값 참조( RValue Reference ) - 네 번째
C++0x [VC++] 8. 우측 값 참조( RValue Reference ) ? 다섯 번째
C++0x [VC++] 9. Lambda ( 람다 ) - 첫 번째
C++0x [VC++] 11. Lambda - 두 번째
C++0x [VC++] 12. Lambda - 세 번째
C++0x [VC++] 13. Lambda - 네 번째
C++0x [VC++] 14. decltype
C++0x 대용량 파일 조작을 위한 C++0x의 변화
C++0x nullptr
C++0x VC++ 10에 구현된 C++0x의 코어 언어 기능들
C++0x C++0x 관련 책 "Visual C++ 10과 C++0x"
C++0x "Visual C++ 10과 C++0x" pdf 파일
C++0x [Plus C++0x] 람다(Lambda) 이야기 (1)
C++0x [Plus C++0x] 람다(Lambda) 이야기 (2)
C++0x [Plus C++0x] 람다(Lambda) 이야기 (3)
C++0x [Plus C++0x] 람다(Lambda) 이야기 (마지막회)
C++0x [STL] 1. What's new in VC++ 2010?
C++0x [STL] 2. unique_ptr (1/2)
C++0x [STL] 3. unique_ptr (2/2)
C++0x [STL] 4. make_shared
C++0x [STL] 5. 에 추가된 새로운 함수들 (1/5)
C++0x [STL] 6. 에 추가된 새로운 함수들 all_of, any_of, none_of (2/5)
C++0x VS2010에서 nullptr의 알려진 버그
C++0x RValue Reference에 의한 STL의 성능향상 테스트
C++0x [STL] 7. 에 추가된 새로운 함수들 copy_if, copy_n, find_if_not (3/5)
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [0]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [1]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [2]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [3]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [4]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [5]
VC++ 10 Concurrency Runtime C++ 개발자를 위한 병렬 프로그래밍 동영상 [6/7] 완결!
VC++ 10 Concurrency Runtime PPL task를 이용한 피보나치 수 계산
VC++ 10 Concurrency Runtime 인사 및 Multi Core, Multi Thread...그리고 VC++ 10
VC++ 10 Concurrency Runtime Concurrency Runtime
VC++ 10 Concurrency Runtime Parallel Patterns Library (PPL)
VC++ 10 Concurrency Runtime 양보할 줄 아는 Concurrency Runtime의 event
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - Task
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - 병렬 알고리즘
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - parallel_for 알고리즘
VC++ 10 Concurrency Runtime Asynchronous Agents Library로 Dining Philosophers 문제 해결하기 - 1
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - parallel_for_each 알고리즘
VC++ 10 Concurrency Runtime Asynchronous Agents Library로 Dining Philosophers 문제 해결하기 - 2
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - parallel_invoke
VC++ 10 Concurrency Runtime Asynchronous Agents Library로 Dining Philosophers 문제 해결하기 - 마지막회
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - combinable
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - task group에서의 병렬 작업 취소 - 1
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - task group에서의 병렬 작업 취소 - 2
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - concurrent_vector - 1
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - concurrent_vector - 2
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - concurrent_queue - 1
VC++ 10 Concurrency Runtime Parallel Patterns Library(PPL) - concurrent_queue - 2
VC++ 10 Concurrency Runtime Concurrency Runtime(ConcRT)의 디버그 모드에서 메모리 leak 문제
VC++ 10 Concurrency Runtime Asynchronous Agents Library 소개
VC++ 10 Concurrency Runtime Asynchronous Agents Library - agent. 1 ( 상태 )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? agent. 2 ( 기능 )
VC++ 10 Concurrency Runtime Asynchronous Agents Library - message 전달 함수. 1 ( 전송 )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message 전달 함수. 2 ( 수신 )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 1. ( 인터페이스 )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 2. ( unbounded_buffer )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 3. ( overwrite_buffer & single_assignment )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 4. ( call )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 5. ( transformer )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 6. ( choice )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 7. ( join & multitype_join )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 8. ( timer )
VC++ 10 Concurrency Runtime Concurrency Runtime ? 동기화 객체 1. ( critical_section & reader_writer_lock )
VC++ 10 Concurrency Runtime Concurrency Runtime ? 동기화 객체 2. ( event )
VC++ 10 Concurrency Runtime Asynchronous Agents Library ? message block 9. ( custom )
VC++ 10 Concurrency Runtime Concurrency Runtime - 만델브로트 프랙탈 ( Mandelbrot Fractal ) 예제
VC++ 10 Concurrency Runtime Concurrency Runtime ? Task Scheduler 1. ( Scheduler )
VC++ 10 Concurrency Runtime Concurrency Runtime ? Task Scheduler 2. ( SchedulerPolicy )
VC++ 10 Concurrency Runtime Concurrency Runtime ? Task Scheduler 3. ( ScheduleGroup )
VC++ 10 Concurrency Runtime Concurrency Runtime ? Task Scheduler 4. ( ScheduleTask )
VC++ 10 Concurrency Runtime Concurrency Runtime ? Task Scheduler 5. ( Context blocking )
Visual C++ 10 About Visual C++ 10
Visual C++ 10 디버깅 모드에서 역어셈블리 코드 보기
Visual C++ 10 Visual C++ 10의 변화
Visual C++ 10 [Upgrade to VC++ 10] _WIN32_WINNT 버전 문제
Visual C++ 10 VS2010 C++ 프로젝트의 디렉토리 설정

   

클라우드 컴퓨팅

Cloud 구름 속의 미래 : Windows® Azure™ Platform [1]
Cloud SQL Azure - CTP1
Cloud SQL Azure 알아보기 (1) - 데이터베이스 개체 생성
Cloud SQL Azure 알아보기(2) ? 데이터베이스 스키마 마이그레이션, 데이터 전송
Cloud 구름 속의 미래 : Windows® Azure™ Platform [2]
Cloud SQL Azure 사용 시 주의점(1) - 방화벽 설정
Cloud SQL Azure 알아보기(3) ?SQL Server 2008 R2 Nov CTP
Cloud SQL Azure 알아보기(4) ? SQL Azure Cloud App
Cloud SQL Azure 알아보기 (5)- SQL Azure 이점과 T-SQL 지원
Cloud [MS@클라우드컨퍼런스] MS 클라우드 기술과 플랫폼
Cloud 클라우드 기반 분산 컴퓨팅을 위한 AppFabric (1) : 아하! App 분산!
Cloud Hello Windows Azure / Windows Azure Platform의 이해
Cloud Hello Windows Azure / Gallery of 'Powered by Windows Azure Platform'
Cloud Hello Windows Azure / Windows Azure 개발 환경의 구축
Cloud Hello Windows Azure / Understanding Windows Azure Development Process
Cloud Hello Windows Azure / Windows Azure Tools for Visual Studio 1.2 출시
Cloud Hello Windows Azure / Windows Azure Platform 최신 소식 업데이트 (종합) [수정]
Cloud Hello Windows Azure / Twitter 스타일 방명록 만들기 #1
Cloud Windows Azure Update: Microsoft Project Code-Named "Houston" CTP 1
Cloud SQL Azure와 Excel 2010의 PowerPivot
Cloud Hello Windows Azure / Twitter 스타일 방명록 만들기 #2
Cloud Windows Azure Update: CloudStorageAccount 클래스 사용 시 주의 사항
Cloud SQL Azure Update: Dynamic Management View
Cloud Hello Windows Azure / Twitter 스타일 방명록 만들기 #3
Cloud Windows Azure Update: myAzureStorage
Cloud SQL Azure 와 SQL Reporting Service
Cloud Windows Azure Update: Windows Azure CDN의 활용
Cloud [작업 중] Windows Azure Update: Adaptive Smooth Streaming with Windows Azure Storage

   

게임 개발

Direct3d Mobile [d3dm 기초] 1. wm6.x 개발환경 세팅
Direct3d Mobile .NET 기반에서 공개소스 게임엔진 포팅하기
DirectX 11 [JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서...
DirectX 11 [JumpToDX11-2]DeviceContext...넌 누구냣!!
DirectX 11 [JumpToDX11-3] Feature Level
DirectX 11 [JumpToDX11-4] ID3D11View
DirectX 11 [DX11_#1]D3D Buffer( 1 / 2 )
DirectX 11 [DX11_#2]D3D Buffer( 2 / 2 )
DirectX 11 [DX11_#3]기본적인 설정
DirectX 11 [JumpToDX11-5] 새로운 시대를 여는 DirectX11...
DirectX 11 [JumpToDX11-6] 커맨드(Command)...
DirectX 11 [DX11_#4]텍스트, 버튼 출력
DirectX 11 [JumpToDX11-7] 간편해진 리소스 처리.
DirectX 11 [JumpToDX11-8] Deferred Contexts
DirectX 11 [JumpToDX11-9] Multi-threaded Rendering 을 위한 API.
DirectX 11 [JumpToDX11-10] GPGPU 를 위한 DirectCompute.
DirectX 11 [JumpToDX11-11] DirectCompute 를 위한 한걸음!
DirectX 11 [JumpToDX11-12] DirectCompute 의 절차.
DirectX 11 [JumpToDX11-13] Tessellation 등장.
DirectX 11 [DX11_#5]DirectX11의 활용 사례(1/3)
DirectX 11 [JumpToDX11-14] DirectX9 세대의 테셀레이션( ID3DXPatchMesh 편 )
DirectX 11 [JumpToDX11-15] DirectX9 세대의 테셀레이션( IDirect3DDevice9::DrawXXXPatch편 )
DirectX 11 [알콜코더의 미리 배워보는 DirectX 11 - 입문편] 0. 누구를 위한 연재인가
DirectX 11 [알콜코더의 미리 배워보는 DirectX11-입문편] 1.튜터리얼 01 : 다이렉트 3D 기초 #1
DirectX 11 [알콜코더의 미리 배워보는 DirectX11-입문편] 1.튜터리얼 01 : 다이렉트 3D 기초 #2
DirectX 11 [JumpToDX11-16] DirectX9 세대의 테셀레이션( D3DXTessellateNPatches편 )
DirectX 11 [알콜코더의 미리 배워보는 DX11 ? 입문편] DX11에서 무엇이 추가되었나?
DirectX 11 [JumpToDX11-17] DirectX9 세대의 테셀레이션( ATI 라이브러리편 )
DirectX 11 [발표자료] 예제로 느껴보는 다이렉트X 11의 매력
DirectX 11 [JumpToDX11-18] DirectX11의 테셀레이션 ( 테셀레이션을 위한 하드웨어의 등장편 )
DirectX 11 [알콜코더의 미리 배워보는DX11 입문편] DirectX 11의 특징들
DirectX 11 [알콜코더의 미리배워보는 DX11-입문편] 1. 튜터리얼01 : 디바이스와 스왑체인의 생성

   

F#

F# Welcome to F#(1) - 첫만남.
F# Welcome to F#(2) - 두번째 만남.
F# Welcome to F#(3) - 사소한 탐색전.
F# Welcome to F#(4) - 과거와 배경을 좀 더 알고싶어.
F# Welcome to F#(5) - 아주 조금씩 심화되는 탐색전.
F# Welcome to F#(6) - 비교본능.
F# Welcome to F#(7) - 클리프 행어.
F# Welcome to F#(8) - 은총알과 엄친아.
F# Welcome to F#(9) - 메이져 데뷰.
F# Welcome to F#(10) - 인도음식 카레.....?
F# Welcome to F#(11) - 차별을 권장하는 언어인거임?!?!
F# Welcome to F#(12) - 공동작업 좋치아니항가

   

MFC

MFC [MFC] 리스타트 매니저(Restart Manager) - (1/3) : 기능 소개
MFC [MFC] 리스타트 매니저(Restart Manager) - (2/3) : 사용하기
MFC [MFC] 리스타트 매니저(Restart Manager) - (3/3) : 활용하기
MFC [MFC] 태스크 대화상자(Task Dialog) - (1/3) : 기능 소개
MFC [MFC] 태스크 대화상자(Task Dialog) - (2/3) : 사용하기
MFC [MFC] 태스크 대화상자(Task Dialog) - (3/3) : 활용하기
MFC [MFC] 태스크 대화상자(Task Dialog) - 예제 코드 올립니다.
MFC [MFC/윈도우 7 멀티터치] #2 : 제스처(gesture)를 이용한 구현()
MFC [MFC/윈도우 7 멀티터치] #3 : 제스처(gesture)를 이용한 구현()
MFC [MFC/윈도우 7 멀티터치] #4 : WM_TOUCH 메세지를 이용한 구현()
MFC [MFC/윈도우 7 멀티터치] #5 : WM_TOUCH 메세지를 이용한 구현()
MFC [MFC/윈도우 7 멀티터치] #6 : 예제 코드 올립니다

   

RIA

RIA Expression Blend3 preview - 1.인터페이스
RIA Expression Blend3 preview - 2. Photoshop import
RIA Silverlight 3 & Blend 3 RC 공개!!!
RIA Silverlight 4 Beta 공개
RIA .Net Ria Service + IIS6 + Silverlight 4 Troubleshooting!!
RIA 실버라이트 비하인드 코드에서 바인딩하기.
RIA .Net Ria Service 와 Entities 그리고 Stored Procedure 하다가 생긴일..
RIA 실버라이트 프로그래머가 할 수 있는 최소한의 블랜드 디자이너를 위한 배려

   

SharePoint 2010

SharePoint 2010 Visual Studio 2010 에게 바란다 - SharePoint 14 Development
SharePoint 2010 SharePoint 2010 Overview
SharePoint 2010 SharePoint 2010 개발 환경 구성
SharePoint 2010 SharePoint 2010 개발 환경- Hello World 웹 파트 생성 및 배포하기
SharePoint 2010 SharePoint 2010 Web Part 생성
SharePoint 2010 SharePoint 2010 Visual Web Part
SharePoint 2010 SharePoint 2010 Feature
SharePoint 2010 SharePoint 2010 Event Receiver
SharePoint 2010 SharePoint 2010 데이터 기술
SharePoint 2010 SharePoint 2010 Server Object Model
SharePoint 2010 Visual Studio 2010 출시에 따른 SharePoint Developer Tools
SharePoint 2010 SharePoint 2010 LINQ to SharePoint
SharePoint 2010 Client Object Model - .NET
SharePoint 2010 Client Object Model ? Silverlight (1)
SharePoint 2010 Client Object Model ? Silverlight (2)
SharePoint 2010 Client Object Model - Javascript(1)
SharePoint 2010 Client Object Model - Javascript(2)
SharePoint 2010 Client Object Model ? 정리
SharePoint 2010 SharePoint 2010 개발환경 구축 가이드
SharePoint 2010 REST -.NET
SharePoint 2010 REST ? Silverlight
SharePoint 2010 REST - jQuery
SharePoint 2010 SharePoint 2010 프로젝트 디버깅
SharePoint 2010 SharePoint 2010 Developer Dashboard

   

Team Foundation Server

Team Foundation Server Visual Studio Team System 2010 (CTP10) - 작업 항목 링크
Team Foundation Server TFS 2010 설치 하기
Team Foundation Server TFS 2010 Build Service 설치
Team Foundation Server TFS 2010 설치 과정 중에 TF255040 문제
Team Foundation Server Visual Studio 2010을 활용한 ALM (1-5) - ALM 이란 무엇인가
Team Foundation Server Team Foundation 트러블 슈팅 가이드
Team Foundation Server Visual Studio Team Foundation Server 2010 를 설치해보자
Team Foundation Server Visual Studio Team Foundation Server 2010 설치 전 할일
Team Foundation Server VS TFS 2010 설치편 - 설치전 IIS, .NET 설치
Team Foundation Server VS TFS 2010 설치편 - 설치 시작
Team Foundation Server VS TFS 2010 구성편 - 설치 후 TFS 구성으로 점심 얻어먹기 편
Team Foundation Server VS TFS 2010 사용편 - SourceSafe? 버려~
Team Foundation Server [HowTo] Team Foundation Server 의 로컬 매핑 캐시 제거하기
Team Foundation Server [HowTo] SharePoint 2010 Beta 깨끗하게 제거하기
Team Foundation Server [HowTo] SCVMM 의 Install Virtual Guest Service 작업 중 2941 오류
Team Foundation Server [HowTo] TFS2010 의 Tfs_Analysis 웨어하우스 데이터베이스가 망가졌을 경우
Team Foundation Server [PPT] 테스트와 가상화의 만남 - 테스트 가상화(Lab Management)
Team Foundation Server Team Foundation Server 2010으로 업그레이드, 마이그레이션, 동기화
Team Foundation Server Visual Source Safe 사용자를 위한 TFS2010 시리즈

   

Visual Studio 2010

Visual Studio 2010 Visual Studio Team System 2010 CTP 만료 해결하기
Visual Studio 2010 Visual Studio 2010 의 특징
Visual Studio 2010 Visual Studio 2010 내부 빌드 최신 동영상: C# 4.0 Language + IDE + WPF Shell + Editor
Visual Studio 2010 Visual Studio 2010 & .NET 4.0 참고 자료들
Visual Studio 2010 Visual Studio 2010 Beta 1 설치부터 살펴보기
Visual Studio 2010 멀티 모니터 사용
Visual Studio 2010 Visual Studio 2010 Beta 2 출시
Visual Studio 2010 Visual Studio 2010 Beta 2 설치 미리 보기
Visual Studio 2010 VS 2010 Beta 2 설치 과정에서 Silverlight SDK 문제
Visual Studio 2010 VS2010 베타2의 WPF & Silverlight 디자이너 성능 향상 팁
Visual Studio 2010 VS 2010 기능 소개 01 인텔리 센스 기능의 변화
Visual Studio 2010 Visual Studio 2010과 Blend Preview for .NET 4 통합 문제
Visual Studio 2010 VS 2010 기능 소개 02 - IDE의 기능 추가
Visual Studio 2010 VS 2010 기능 소개 03 - IDE의 변화
Visual Studio 2010 Visual Studio 2010 출시 일정
Visual Studio 2010 VS 2010 기능소개 04 - Visual C#&VB 개발자 IDE Tips & Tricks 첫번째
Visual Studio 2010 VS 2010 기능소개 05 - Visual C#&VB 개발자 IDE Tips & Tricks 두번째
Visual Studio 2010 Visual Studio 2010 RC 공개 임박!
Visual Studio 2010 Visual Studio 2010 RC 공개
Visual Studio 2010 C#에서 IntelliSense가 동작하지 않을 때 문제 해결 방법
Visual Studio 2010 똑똑한 검색을 지원하는 VSTS 2010의 "Navigate To" 검색
Visual Studio 2010 실버라이트4 RC와 블렌드 4 베타 공개
Visual Studio 2010 윈도우폰 7 개발환경 공개
Visual Studio 2010 Visual Studio 2010! 나랑 놀아보자 ? 기본편 (2회) - VS IDE
Visual Studio 2010 Visual Studio 2010! 나랑 놀아보자 ? 기본편 (3회) - Box Selection
Visual Studio 2010 Visual Studio 2010! 나랑 놀아보자 ? 기본편 (4회) - Call Hierarchy
Visual Studio 2010 Visual Studio 2010 출시와 완소 정보 총 정리
Visual Studio 2010 Visual Studio 2010 e-book 무료로 다운로드 하세요
Visual Studio 2010 Visual Studio 2010! 나랑 놀아보자 ? 기본편 (5회) - Navigate To
Visual Studio 2010 Visual Studio 2010 RTM 추가 완소 정보
Visual Studio 2010 Visual Studio 2010! 나랑 놀아보자 ? 기본편 (6회) - Generate from Usage
Visual Studio 2010 VS 2010 기능소개 05 - Visual C#&VB 개발자 IDE Tips & Tricks 두번째
Visual Studio 2010 Visual Studio 2010, 2008, 2005 에서 .NET Framework 1.1 개발하기
Visual Studio 2010 Visual Studio 2010, 2008, 2005 에서 .NET Framework 1.1 개발하기
Visual Studio 2010 Just for fun! / Visual Studio Express Edition
Visual Studio 2010 왜 Visual Studio 2010 이여야 하는가?
Visual Studio 2010 Visual Studio 2010 최신 PDF 자료를 MSDN 에서 다운로드 받으세요
Visual Studio 2010 Just for fun! / DreamSpark는 대학생 여러분을 위한 솔루션입니다.
Visual Studio 2010 VS2008 을 VS2010 에서 동시에 개발하기
Visual Studio 2010 VS2008 과 VS2010 동시에 개발하기 : 테스트 프로젝트가 포함 될 경우
Visual Studio 2010 Introducing Visual Studio LightSwitch! - Enjoy your development
Visual Studio 2010 Visual Studio Hotfix List
Visual Studio 2010 곧 다가올 기술, Microsoft Research [1/2]
Visual Studio 2010 곧 다가올 기술, Microsoft Research [2/2]
Visual Studio 2010 Visual Studio 31 (1) - 시작, 그리고 Intellisense
Visual Studio 2010 Visual Studio 31 (2) - Startpage
Visual Studio 2010 Visual Studio 31 (3) - Temp Project
Visual Studio 2010 Visual Studio 31 (4.1) - Visual Studio 2010 Productivity Power Tools, Part 1
VIsual Studio Extensibility [Blueprints] S+S Blueprints
VIsual Studio Extensibility Visual Studio 2010 SDK 와 Readme
VIsual Studio Extensibility Visual Studio 2010 Extension Manager
VIsual Studio Extensibility [VSIX] 1. What is different from before version?
VIsual Studio Extensibility [VSIX] 2-1. How to start VSIX programming
VIsual Studio Extensibility [VSIX] 2-2. How to start VSIX programming
VIsual Studio Extensibility MousePresentationTracker - MEF 세미나 예제
VIsual Studio Extensibility [VSX] 1. Visual Studio Extensibility,, 그 시작
VIsual Studio Extensibility Visual Studio 2010 확장 모델인 VSIX 버그
VIsual Studio Extensibility VSGesture v2.0 for VS2010 is now available for download

   

우리 블로그 소식

VSTS 2010 팀 블로그 Visual Studio Team System 2010 공식 팀 블로그 맴버소개
VSTS 2010 팀 블로그 Visual Studio Team System 2010 팀 블로그 소개
VSTS 2010 팀 블로그 VSTS 2010 팀 블로그/스터디 맴버를 모집합니다.
VSTS 2010 팀 블로그 VSTS 2010 팀 맴버 지원을 마감합니다
VSTS 2010 팀 블로그 Visual Studio Team System 2010 Beta 1 공개
VSTS 2010 팀 블로그 [MSDN 주간 세미나] 발표자료 / .NET Framework와 Visual Studio : 현재와 미래 1, 2
VSTS 2010 팀 블로그 VSTS 2010 팀 3분기 맴버 모집
VSTS 2010 팀 블로그 VSTS 2010 팀 세미나 동영상 - 6월 10일
VSTS 2010 팀 블로그 VSTS 2010 팀 맴버 추가 모집
VSTS 2010 팀 블로그 VSTS 2010 팀 트위터를 오픈하였습니다.
VSTS 2010 팀 블로그 TECH DAY 2009 행사 오픈!!!
VSTS 2010 팀 블로그 VSTS 2010 공식 블로그 Viva 2010팀 멤버 추가 모집 공고
VSTS 2010 팀 블로그 [세미나] 차세대 응용 프로그램 구축 방법 및 사례 소개 세미나
VSTS 2010 팀 블로그 Visual Studio 2010 팀에서 팀원 모집합니다.
VSTS 2010 팀 블로그 한국 Visual Studio 2010 사용자를 위한 트위터 커뮤니케이션
VSTS 2010 팀 블로그 C++ 개발자와 함께하는 Visual Studio 2010
VSTS 2010 팀 블로그 [무료 세미나] ReMIX 10
VSTS 2010 팀 블로그 6월 1일, 대한민국 웹 컨퍼런스의 지존 ReMIX 10가 개최됩니다!
VSTS 2010 팀 블로그 REMIX10 의 VS2010 팀 후기
VSTS 2010 팀 블로그 6월 1일, REMIX10 세미나 세션 공개
VSTS 2010 팀 블로그 [세미나] Visual Studio Camp #1
VSTS 2010 팀 블로그 [세미나 후기] Visual Studio Camp #1
VSTS 2010 팀 블로그 [세미나 발표 자료] Visual Studio Camp #1
VSTS 2010 팀 블로그 [세미나] Visual Studio Seminar #1 / 2010년 9월 28일
VSTS 2010 팀 블로그 9월 13일에 개최하는 KGC에서 강연을 합니다.
VSTS 2010 팀 블로그 KGC10에서의 VS2010 스터디 팀의 활약 모습
VSTS 2010 팀 블로그 [VSKOREA] Visual Studio 2010 정보가 한 눈에…
VSTS 2010 팀 블로그 [세미나 후기] Visual Studio Seminar #1
VSTS 2010 팀 블로그 [세미나 발표 자료] Visual Studio Seminar #1
VSTS 2010 팀 블로그 [후기] C++ & 게임 개발자를 위한 개발 생산성 및 퍼포먼스 향상 전략 세미나

   

WCF

WCF WCF란 무엇인가?
WCF 기본 WCF 프로그래밍 - 첫 WCF 서비스 만들기
WCF 기본 WCF 프로그래밍 - 첫 WCF 서비스 만들기 2
WCF WCF의 기본 - Service Contract
WCF WCF의 기본 - Data Contract
WCF WCF 서비스의 동시성(Concurrency) - 1
WCF WCF 서비스의 동시성(Concurrency) - 2
WCF WCF - Serialization
WCF WCF Hosting - WAS를 이용한 Hosting
WCF 도메인을 여러개 등록했을때 WCF 서비스를 호스팅 할수 없어요 ㅠㅠ
WCF WCF Hosting(2) - ASP.NET 호환성(Compatibility)
WCF WCF Hosting (3) - Windows Service를 이용한 Hosting
WCF WCF Security (1) - SSL을 이용한 전송계층에서의 보안 설정
WCF WCF Security (2) - 전송 계층에서의 메세지 인증 (사용자 지정 인증)
WCF WCF Troubleshooting (1)
WCF WCF Service Configuration Editor
WCF WCF Troubleshooting (2)


WCF Troubleshooting (2)

WCF 2010. 11. 29. 09:00 Posted by 알 수 없는 사용자
일주일 만에 돌아온 RuAA 입니다. 하핫~
이제 곧 올해의 마지막인 12월이네요~ 어느새,, 벌써,, ㅡㅠ
나이만 먹는 것 같아 참 슬퍼지려 합니다.
12월엔 술자리도 많고, 행사도 많아 바빠지는데, 모두 건강 챙기시길 바랍니다.


다른 설명 없이 바로~ 지난 포스트에 이어서, 진행해보도록 하겠습니다~

이번 포스팅에서는 FaultContractAttribute 대해서 잠깐 알아보고, 이를 이용하여 에러 메시지를 직접 정의해보도록 하겠습니다.

그럼, FaultContractAttribute 무엇이냐~? 간단하게아주 간단하게직접 정의한 에러 메시지를 클라이언트로 전달하기 위한 서비스 메서드의 속성이라고 생각하면 됩니다.

닷넷에는 기본적으로 제공하는 여러 종류의 예외 클래스가 존재합니다. 지난 포스트에서 봤듯이 이러한 예외가 발생하였을 때는 그에 맞는 예외 클래스에 정의되어 있는 메시지들이 클라이언트로 전달되었습니다
.
하지만, 이러한 메시지들 이외에
서비스 정책에 맞는 메시지를 따로 정의하고, 이를 클라이언트에 노출하고 싶을 , FaultContractAttribute 사용할 있습니다.

그럼, 이를 이용해,  특정 에러 메시지를 정의하고, 메시지를 클라이언트에 전달하는 예제를 한번 보도록 하겠습니다. 예제 한번 보고 나면 이해가 되실겁니다. 하하

우선, WCF 서비스에서 사용할 있는 새로운 클래스를 정의합니다. 물론, DataContractAttribute 이용해서요~


[
DataContract]

public class ErrorInfo

{
    [
DataMember]

    public string Info { get; set; }

 

    [DataMember]

    public ErrorCode Code { get; set; }

}

 

[DataContract]

public enum ErrorCode

{

    [EnumMember]

    WrongName,

    [EnumMember]

    NotExist

}

 


ErrorInfo 라는 이름의 클래스를 정의 하였습니다. 클래스에는 에러의 정보를 담을 있는 Info 라는 프로퍼티가 있고, 에러의 종류를 나타내는 Code 라는 프로퍼티가 정의되어 있습니다. 또한, 덤으로 에러 종류를 쉽게 분류하기 위하여 ErrorCode 라는 이름의 열거형을 정의하였습니다.

그럼, FaultContractAttribute 어디에 정의하는 걸까요? 다음 코드를 보시면 바로 있습니다~


[
ServiceContract]

public interface IService1

{

[OperationContract]

int Divide(int numerator, int denominator);

 

    [OperationContract]

    [FaultContract(typeof(ErrorInfo))]

    int FindEmployee(string employeeId);

}

 


보이시죠? ~ 바로 OperationContractAttribute 같은 위치에 선언됩니다. 예제에서 FindEmployee 오퍼레이션은 ErrorInfo 타입의 에러 메시지가 발생할 있다는 것을 나타냅니다.

이제, 직접 ErrorInfo 클래스에 에러 메시지를 정의하고, 클라이언트로 전달하는 코드를 보셔야죠~
다음 예제를 보겠습니다.


public
class Service1 : IService1

{

    public int Divide(int numerator, int denominator)

    {

        return numerator / denominator;

    }

 

    public int FindEmployee(string employeeId)

    {

        // 사용자 정의 에러 발생

        FaultReason reason = new FaultReason(string.Format("{0} employee is not exist", employeeId));

        ErrorInfo error = new ErrorInfo

        {

            Info = string.Format("Not Exist Employee, ID : {0}", employeeId),

            Code = ErrorCode.NotExist

        };

 

        throw new FaultException<ErrorInfo>(error, reason);

    }

}

 


FindEmployee 메소드는 무조건 예외를 발생하도록 되어 있습니다. 사실, 에러 메시지를 클라이언트로 전달하는 것이 목적이니깐 다른 코드는 예제에서 생략이 되어도 상관없겠죠~ ^^

FaultReason 이라는 새로운 클래스도 눈에 띄는군요~ 클래스는 해당하는 오류의 간단한 메시지를 작성하기 위한 클래스라고 생각하시면 됩니다.

그리고, 방금 만들었던 ErrorInfo 인스턴스를 생성하고, Info, Code 프로퍼티에 클라이언트로 전달하고 싶은 오류 메시지를 입력하였습니다.
마지막으로 FaultException<T> 이용하여 ErrorInfo 포함한 예외를 발생시켰습니다
.
FaultException
클래스는 SOAP 오류로 변환될 있는 예외 클래스입니다.

이제, 클라이언트에서 에러메시지를 낚아채어(?) 보여주는 예제를 보겠습니다.
콘솔 어플리케이션을 생성하고, 서비스 참조를 후에 다음과 같이 코드를 작성 해보았습니다.


static
void Main(string[] args)

{

    Service1Client proxy = new Service1Client();

 

    try

    {

        proxy.Divide(5, 0);

    }

    catch (FaultException ex)

    {

        Console.WriteLine("Reason : {0}", ex.Reason.ToString());

        Console.WriteLine("Message : {0}", ex.Message);

        Console.WriteLine();

    }

 

    try

    {

        proxy.FindEmployee("RuAA");

    }

    catch (FaultException<ErrorInfo> ex)

    {

        Console.WriteLine("Reason : {0}", ex.Reason.ToString());

        Console.WriteLine("Message : {0}", ex.Message);

        Console.WriteLine("\n<< Detail Info >>");

        Console.WriteLine("Code : {0}", ex.Detail.Code);

        Console.WriteLine("Info : {0}", ex.Detail.Info);

    }

}

 


처음엔 Divide 오퍼레이션을 호출하여 닷넷에서 기본적으로 제공하는 예외를 발생시켰고, 번째 try, catch 문에서 FindEmployee 오퍼레이션을 호출 하였습니다.

위의 코드에서 보듯이, 클라이언트에서 서비스의 예외를 낚아채기(?) 위해선 FaultException 클래스를 사용합니다. FaultException 클래스에 제네릭 형식이 정의되어 있지 않은 경우엔 닷넷에서 제공하는 기본적인 예외 메시지를 catch 있으며, 서비스에 정의 특정 예외 메시지를 catch 하고자 , FaultExcepton 클래스에 제네릭 형식을 지정해주면 됩니다.

그리고, 가지 주목할 점은, ErrorInfo 인스턴스가 FaultException 인스턴스의 Detail 프로퍼티에 입력된다는 것입니다. 이는, 뒤에 보여줄 SOAP Fault 메시지를 확인하면 아마 이해가 쉬우실겁니다.
때문에, (서비스 오퍼레이션에서 정의했던
) ErrorInfo 클래스의 Info, Code 프로퍼티에 입력된 값을 가져오기 위해선 ex.Detail.Code(또는 ex.Detail.Info) 같이 접근 하여야 합니다.

이렇게 처리를 하면, 다음과 같은 클라이언트 결과를 확인할 있습니다.


마지막으로, 서비스에서 클라이언트로 전달되는 SOAP 메시지를 확인해 보겠습니다.

 

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">

  <s:Header>

    <a:Action s:mustUnderstand="1">http://tempuri.org/IService1/FindEmployeeErrorInfoFault</a:Action>

    <a:RelatesTo>urn:uuid:c67dd581-4b6d-4a02-aa35-fba3515a0ccf</a:RelatesTo>

  </s:Header>

  <s:Body>

    <s:Fault>

      <s:Code>

        <s:Value>s:Sender</s:Value>

      </s:Code>

      <s:Reason>

        <s:Text xml:lang="en-US">RuAA employee is not exist</s:Text>

      </s:Reason>

      <s:Detail>

        <ErrorInfo xmlns="http://schemas.datacontract.org/2004/07/Wcf_TroubleShooting"

                   xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

          <Code>NotExist</Code>

          <Info>Not Exist Employee, ID : RuAA</Info>

        </ErrorInfo>

      </s:Detail>

    </s:Fault>

  </s:Body>

</s:Envelope>

 


SOAP 메시지를 확인해 보면 ErrorInfo 라는 엘리먼트가 눈에 ~!! 띄는군요. 하하
이렇게 SOAP 메시지의 내용과 앞의 예제 코드, 그리고 클라이언트의 결과 화면을 비교해보면 이번 포스팅의 내용이 이해하기 쉬울 같습니다. ^^

아직 얘기가 많지만, 다음 포스팅을 기약하면서, 마무리 하도록 하겠습니다.

WCF Troubleshooting (1)

WCF 2010. 11. 19. 09:00 Posted by 알 수 없는 사용자
 
와우~ 정말 오랜만에 포스팅을 하네요 ^^;;
여러 가지 일 때문에 포스팅을 하지 못했는데 이제 다시 힘을 내서 그 동안 못했던 포스팅을 해보도록 하겠습니다.
어느새 계절은 겨울이 되어 날씨가 많이 추워졌는데, 모두 건강 주의 하시길 바랍니다.

이번 포스팅 부터는 WCF 를 이용하여 서비스를 구현하는데 있어 발생할 수 있는 여러 가지 예외나 에러를 어떻게 처리할 수 있는지에 대한 얘기를 해 볼까 합니다.

WCF 서비스와 같이 분산 어플리케이션을 개발할 때는 항상 에러나 예외의 원인을 찾거나 디버깅하기가 조금 애매하죠. 로컬에서 개발할 때에는 문제가 없다가도 실제 서버에 배포를 하고 나면 발생하는 예외나 에러는 개발자를 난감하게 만들기도 합니다.

그래서~ 이번 포스팅 부터는 WCF 에서 발생하는 예외를 어떻게 핸들링 할 수 있는지, 그리고 에러에 대한 진단을 하기 위해 어떤 방법을 사용할 수 있는지에 대한 내용으로 진행을 해볼까 합니다.


Fault Message 와 Exception

.NET 어플리케이션은 에러가 발생했을 때, 에러에 대한 내용을 알리기 위해 Exception 클래스를 사용합니다. 이는 물론, WCF에서도 예외가 아닙니다. 다만, 이러한 에러의 내용을 클라이언트에 전달하기 위해서 Fault Message 를 사용한다는 것이 조금 다르긴 하죠.
쉽게 얘기해서, 서비스에서 클라이언트로 어떤 데이터를 넘겨줄 때 직렬화를 사용하는 것처럼, 에러 메시지,, 그러니깐 Exception 오브젝트도 직렬화를 한 후에 클라이언트로 전달한다고 생각하면 된다는 것입니다.

Fault Message는 다음과 같은 XML 형태로 클라이언트로 전달되는데, 이는 표준 SOAP Fault 메시지(Ver 1.2)의 스키마와 같습니다.

<Body>
   <Fault>
      <Code>
         <Value>s:Sender</Value>
      </Code>
      <Reason>
         <Text xml:lang="en-US">…</Text>
      </Reason>
      <Detail>
         <ErrorInfo xmlns="http://Service1">
            <Info>…</Info>
         </ErrorInfo>
      </Detail>
   </Fault>
</Body>


각 element에 대한 자세한 설명은 다음의 링크에서 확인하시면 될 것 같습니다. (http://www.w3.org/TR/soap12-part1/#soapfault) 근데, 자료가 영문이라 보기 싫으신 분들 있으실 겁니다. 저도 그렇지만~ 일단, 글이 너무 많으면 부담되서…(그것도 영문… OTL)

그래서, 다음과 같이 간단하게 정리를 해보았습니다.

Element

설명

Fault

Fault 메시지의 root element

Code

예외가 발생한 원인을 나타낸다.

Reason

예외의 자세한 내용을 보여준다.

Detail

예외의 추가적인 정보를 나타낸다.


이 정도만 체크하고, 다음으로 넘어가기로 하죠~ 엣헴~ ;;;;

기본적으로 WCF 서비스에서 예외가 발생하면, 자세한 정보가 담겨있는 Fault 메시지가 전달되는 대신에 다음과 같이 Detail element가 빠져있는 Fault 메시지를 전달합니다.

<s:Fault>
   <s:Code>
      <s:Value>s:Receiver</s:Value>
      <s:Subcode>
         <s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault
         </s:Value>
      </s:Subcode>
   </s:Code>
   <s:Reason>
   <s:Text xml:lang="en-US">The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.</s:Text>
   </s:Reason>
</s:Fault>


Text element의 내용을 자세히 보면, WCF 서비스 개발을 하면서 한번쯤 봤을 법 한 메시지가 적혀있는 것을 확인 할 수 있습니다. 이 Fault 메시지는 닷넷에서 처리할 수 없는 범주의 예외가 발생했거나, 예외 정보를 공개하지 않도록 설정되어 있는 경우에 생성되는 메시지 입니다.

기본적으로 WCF 서비스는 예외 정보를 공개하지 않도록 설정되어 있으므로, 개발을 하는 동안 자세한 예외 정보를 받기를 원한다면 이 설정 값을 바꿔주어야 합니다.

서비스의 환경 설정 파일(web.config/app.config) 에서 behavior element 밑에 있는 serviceDebug element 의 includeExceptionDetailInFaults의 속성값을 true로 바꿔주면 되는 것이죠.

<behaviors>
   <serviceBehaviors>
      <behavior name="MyBehavior">
         <serviceMetadata httpGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
   </serviceBehaviors>
</behaviors>

 
이와 같이 설정을 한 후에 예외를 발생시켜 볼까요? 서비스에 두 숫자를 받아 나눗셈을 한 결과를 리턴하는 "Divide" 라는 메서드를 만들었습니다. 그리고, 간단하게 예외를 발생시키기 위해서, 0으로 다른 숫자를 나누도록 파라미터를 넘겨주었습니다. 그러면, 당연히 DivideByZeroException 이 발생하겠죠~

그랬더니~ 다음과 같은 Fault Message 를 클라이언트로 전송해 주는 것을 볼 수 있었습니다.
아~ 참고로 이 메시지를 확인하기 위해서 저는 Fiddler(피들러)를 사용했습니다.

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
      <a:Action s:mustUnderstand="1">
         http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/
dispatcher/fault
      </a:Action>
      <a:RelatesTo>urn:uuid:8e5a89f4-b765-45e3-b343-26c07fde57dd</a:RelatesTo>
   </s:Header>
   <s:Body>
      <s:Fault>
         <s:Code>
            <s:Value>s:Receiver</s:Value>
            <s:Subcode>
               <s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">
                 
a:InternalServiceFault
               </s:Value>
           
</s:Subcode>
         </s:Code>
         <s:Reason>
            <s:Text xml:lang="en-US">Attempted to divide by zero.</s:Text>
         </s:Reason>
         <s:Detail>
            <ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
               <HelpLink i:nil="true"/>
               <InnerException i:nil="true"/>
               <Message>Attempted to divide by zero.</Message>
               <StackTrace>
at Wcf_TroubleShooting.Service1.Divide(Int32 numerator, Int32 denominator) in C:\Users\RuAA\documents\visual studio 2010\Projects\Wcf-TroubleShooting\Wcf-TroubleShooting\Service1.svc.cs:line 19&#xD;
at SyncInvokeDivide(Object , Object[] , Object[] )&#xD;
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)&#xD;
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)&#xD;
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
               </StackTrace>
               <Type>System.DivideByZeroException</Type>
            </ExceptionDetail>
         </s:Detail>
   </s:Fault>
   </s:Body>
</s:Envelope>



딱 봐도 아시겠지만, 이 전에 봤던 Fault Message에 비해 확실히 더 자세한 내용을 담고 있는 것을 볼 수 있습니다.

사실 이러한 내용들을 다 알 필요는 없습니다. 닷넷으로 클라이언트를 개발한다면 다른 예외와 마찬가지로 try/catch 문을 이용하여 예외를 처리할 수 있을 테니까 말이죠~ 하지만, 개인적으로 이런 기본적인 내용들도 중요하다고 생각하는지라 하나의 포스팅을 통해 정리를 해보았습니다.

아직 할 얘기들이 많지만 너무 길어지면 지루해질 것 같아 여기서 줄일려고 합니다.

다음 포스팅에선 FaultContract 에 대한 설명과 함께 이를 이용해서 에러에 대한 메세지를 정의하고, 이를 클라이언트에 전달하는 방법, 그리고 그외에 에러를 핸들링 하는 방법에 대한 이야기를 써 볼까 합니다.

다음 포스팅을 기대하시는 분은 없으실 거라 예상이 되어 기대해달란 말을 하긴 어려울 것 같지만, 최대한 아주 아주 빠른 시일 내에 업데이트 할 수 있도록 하겠습니다. ^^

Visual Studio Camp #1 세미나를 무사히 마친 지 일주일이 지났습니다. 그 날 날씨가 많이 안좋았음에도 불구하고 많은 분들이 오셔서 너무 고마웠습니다. 나름 준비도 좀 많이 하고, 더 많은 걸 보여드리고 싶었는데, 정해진 시간의 압박으로 그렇게 하지 못해서 아쉬웠습니다. 더구나, 마지막엔 제대로 된 결과도 못 보여드리고,, ㅡㅠ
어찌됐든, 앞으로도 많은 정보를 알려 드릴 수 있도록 열심히 해보겠습니다. 많은 응원 부탁드려요~ ^^

지난 아티클에 이어서, 이번에는 전송 계층에서의 메세지 인증을 할 수 있는 서비스를 만들어 보려 합니다.

ASP.NET 웹 사이트에서 인증을 하는 방법에는 폼 인증과 윈도우즈 인증이 있습니다. 하지만, 보통 웹 어플리케이션을 구축할 때 윈도우즈 인증 보다는 폼 인증을 많이 쓰죠~ (개인적으로, 아직 경험이 미천하여, 윈도우 인증은 적용을 해본 적이 거의 없습니다. ^^;;) 사용자에 대한 정보를 데이터베이스에 따로 저장하고, 그 값을 가져와 인증을 해주는 그러한 방법,,
 
그래서, 이번 아티클에서도 데이터베이스에 사용자 정보를 두고, 이를 이용하여 인증을 할 수 있는 서비스를 만들어보겠습니다.

지난 아티클에서 만들었던 솔루션을 그대로 이용해서, SSL을 이용한 보안을 그대로 사용하려 합니다. 그리고, 여기에 사용자 이름과 패스워드를 이용한 인증을 처리하는 부분을 추가해보도록 하겠습니다. 그래서, 먼저 지난 아티클에서 만들었던 솔루션을 불러오고, 서비스를 다음과 같이 정의합니다.

[ServiceContract]

public interface IService

{

    [OperationContract]

    List<Product> GetAllProducts();

}

 

[DataContract]

public class Product

{

    [DataMember]

    public int Id { get; set; }

 

    [DataMember]

    public string Name { get; set; }

 

    [DataMember]

    public double Price { get; set; }

}


public class Service : IService

{

    public List<Product> GetAllProducts()

    {

        List<Product> products = null;

           

        // (SecurityException)

        if (OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsAuthenticated == false)

        {
            // SecurityException 클래스는 System.Security 네임스페이스에 정의 되어 있다.

            throw new SecurityException();

        }

        else

        {

            products = new List<Product>()

            {

                new Product { Id = 1, Name = "Visual Studio 2010", Price = 223.00 },

                new Product { Id = 2, Name = "Expression Blend 4", Price = 133.00 },

                new Product { Id = 3, Name = "Team Foundation Server 2010", Price = 253.00 }

            };

 

            return products;

        }

    }

}


GetAllProducts 메서드에서 인증이 되지 않았을 경우 예외를 발생하는 부분이 있는데, 이 부분만 조금 주의해서 봐주시면 될 것 같습니다. 다른 부분은 지금까지 해온 여타 서비스와 다를게 없죠,,

이제 인증을 처리하는 코드를 작성하려 합니다. 그 전에 인증에 필요한 사용자 정보를 담아둘 데이터베이스가 필요하니깐, 이를 만들어둡니다. 저는 다음과 같은 간단한 Member 테이블을 만들어 보았습니다.


그리고, AuthenticationHelper 라는 이름으로 새로운 클래스를 하나 추가하고, 다음과 같은 코드를 작성합니다.


public class AuthenticationHelper : UserNamePasswordValidator

{

    SqlConnection conn;

    SqlCommand cmd;

    SqlDataReader reader;

 

    public override void Validate(string userName, string password)

    {

        if (userName == null || password == null)

        {

            throw new Exception("User Name or Password cannot be null");

        }

 

        if (!this.CheckIfUserNameExist(userName))

        {

            throw new Exception("Sorry! This User is Not Present");

        }

 

        if (!this.AuthenticateUser(userName, password))

        {

            throw new Exception("Invalid User Name or Password");

        }

    }

 

    private bool CheckIfUserNameExist(string userName)

    {

        bool exists = false;

        this.conn = new SqlConnection
                         ("Server=.\\SQLEXPRESS;Database=Temp;User Id=sa;Password=1111");

        this.cmd = new SqlCommand();

        this.cmd.CommandText = "SELECT UserName FROM Member WHERE UserName=@UserName";

        this.cmd.Connection = this.conn;

        this.cmd.Parameters.AddWithValue("@UserName", userName);

 

        try

        {

            this.conn.Open();

            this.reader = this.cmd.ExecuteReader();

            DataTable dtUser = new DataTable();

            dtUser.Load(this.reader);

 

            int count = dtUser.Rows.Count;

            if (count != 0)

                exists = true;

        }

        catch (SqlException ex)

        {

            throw ex;

        }

        finally

        {

            this.conn.Close();

        }

 

        return exists;

    }

 

    private bool AuthenticateUser(string userName, string password)

    {

        bool valid = false;

 

        this.conn = this.conn = new SqlConnection
                         ("Server=.\\SQLEXPRESS;Database=Temp;User Id=sa;Password=1111");

        this.cmd = new SqlCommand();

        this.cmd.CommandText = "SELECT Password FROM Member WHERE UserName=@UserName";

        this.cmd.Connection = this.conn;

        this.cmd.Parameters.AddWithValue("@UserName", userName.Trim());

 

        try

        {

            this.conn.Open();

            this.reader = this.cmd.ExecuteReader();

               

            reader.Read();

            if (reader["Password"].ToString() == password.Trim())

                valid = true;

        }

        catch (SqlException ex)

        {

            throw ex;

        }

        finally

        {

            this.conn.Close();

        }

 

        return valid;

    }

}

이번 코드는 조금 길군요 ^^;;
하지만, 코드를 조금 살펴보시면 알겠지만 그렇게 어려운 코드는 아닙니다. 코드가 길다고 어려워 할 필요 없다구요~ ㅎ

주목해야 할 점은 AuthenticationHelper 클래스가 UserNamePasswordValidator 클래스를 상속하고 있다는 것인데, UserNamePasswordValidator 클래스는 WCF 서비스에서 사용자 지정 사용자 이름 및 암호 유효성 검사기를 만들기 위한 클래스입니다. (사용자 지정 사용자 이름 및 암호 유효성 검사기 사용 참고)
한마디로, 윈도우즈 인증이 아닌 사용자가 정의한 인증 방법을 WCF 서비스에 적용하기 위한 유효성 검사기를 만들기 위한 클래스라고 이해하시면 될 것 같습니다.

유효성 검사기를 만드는 방법은 아주 간단한데, UserNamePasswordValidator 클래스에 정의 된 Validate 메서드를 재 정의(overriding) 해주면 됩니다.

이제, 거의 서비스를 다 만든 것 같습니다. 마지막으로 web.config를 수정하여, 사용자 지정 인증 방법을 쓸 수 있도록 해주는 일이 남았습니다. 그리고, 지난번 아티클에서 만들었던 인증서를 사용하도록 해주는 태그도 필요합니다.

web.config 파일을 다음과 같이 수정해 보도록 하겠습니다.

<system.serviceModel>

  <services>

    <service name="SSLService.Service" behaviorConfiguration="MyBehavior">

      <endpoint address="" binding="basicHttpBinding" bindingConfiguration="MyBind"

        contract="SSLService.IService">

        <identity>

          <dns value="localhost"/>

        </identity>

      </endpoint>

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

      <host>

        <baseAddresses>

          <add baseAddress="http://localhost:4949/Service1.svc" />

          <add baseAddress="https://localhost:4948/Service1.svc" />

        </baseAddresses>

      </host>

    </service>

  </services>

 

  <bindings>

    <basicHttpBinding>

      <binding name="MyBind">
        <!-- 메세지 자격증명을 위한 설정 -->

        <security mode="TransportWithMessageCredential">

          <message clientCredentialType="UserName"/>

        </security>

      </binding>

    </basicHttpBinding>

  </bindings>

  <behaviors>

    <serviceBehaviors>

      <behavior name="MyBehavior">

        <serviceCredentials>
          <!-- 메시지 보안 모드를 사용하는 클라이언트에 대한 서비스를
                인증하는 데 사용할 X.509 인증서를 지정합니다-->

          <serviceCertificate storeName="My" storeLocation="LocalMachine"
                                      x509FindType=
"FindBySubjectName"

                                      findValue="Dreamer"/>
          <!-- 사용자 인증을 할 때 사용할 component를 정의합니다. -->

          <userNameAuthentication

            userNamePasswordValidationMode="Custom"

            customUserNamePasswordValidatorType="SSLService.AuthenticationHelper,SSLService"/>

        </serviceCredentials>

        <serviceMetadata httpGetEnabled="true" />

        <serviceDebug includeExceptionDetailInFaults="false" />

      </behavior>

    </serviceBehaviors>

  </behaviors>

  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

</system.serviceModel>


web.config 파일도 뭔가 내용이 많습니다. 역시 보안 설정은 어려워요,, ^^;;

하지만, 자세히 보면 익숙하지 않은 태그는 그리 많지 않습니다. 이 태그들에는 대충의 주석을 달아놨으니 이해하기는 어렵지 않을 것 같구요~

전체적으로 설명을 붙이자면, 서비스에 적용할 Behavior와 Binding에 대한 설정이 필요하여 각각 "MyBehavior", "MyBind" 라는 이름으로 태그를 추가하였고, 그 안에 필요한 태그들을 추가하였습니다.

"serviceCertificate" 태그는 인증 시 사용할 인증서를 지정하는데 지난 아티클에서 만든 인증서를 사용하면 됩니다. 이때, "findValue" 속성에 들어갈 값은 인증서의 발급자에 들어있는 값을 입력하여야 합니다.
그리고, "userNameAuthentication" 태그는 사용자 인증 시 사용할 component를 정의하는데 "customUserNamePasswordValidatorType" 속성에는 UserNamePassowrdValidator 클래스를 상속받아 구현 된 클래스 명을 입력해주면 됩니다.

서비스 구현은 모두 끝났습니다. 이제 콘솔 어플리케이션을 이용해 이 서비스를 사용해보도록 하겠습니다.
클라이언트 구현은 이 전에 구현했던 다른 클라이언트들과 다를바가 없습니다. 단지, 서비스 인증을 위해 사용자 이름과 패스워드를 입력해줘야 하는 부분만 추가해주면 됩니다.

콘솔 어플리케이션 프로젝트를 추가한 후에 서비스를 추가하고(이때, https 로 시작되는 url을 이용하여 서비스를 추가합니다.), 다음과 같이 Main 메소드를 구현합니다.

static void Main(string[] args)

{

    ServiceClient proxy = new ServiceClient();

    // 패스 .

    proxy.ClientCredentials.UserName.UserName = "ruaa";

    proxy.ClientCredentials.UserName.Password = "P@ssw0rd";

 

    Product[] products = proxy.GetAllProducts();

 

    foreach (Product p in products)

    {

        Console.WriteLine("ID : {0}", p.Id);

        Console.WriteLine("Name : {0}", p.Name);

        Console.WriteLine("Price : {0:f}\n", p.Price);

    }

}


보이시죠? 어떻게 인증을 위한 사용자 이름과 패스워드를 입력하는지,, ㅎ

당연히 여기에 입력되는 사용자에 대한 데이터는 앞에서 만들었던 Member 테이블에 존재해야 합니다.

이렇게 하면, 다음과 같은 결과화면을 확인할 수 있습니다. ^^


네~ 이것으로 이번 포스팅도 끝이 났습니다.
긴 글 읽으시느라 모두들 수고하셨고, 다음 포스팅때 뵙겠습니다. 감사합니다~ ^^

WCF Security (1) - SSL을 이용한 전송계층에서의 보안 설정

WCF 2010. 8. 17. 09:00 Posted by 알 수 없는 사용자

모두들 안녕하시죠~? 예년과 다르게 자주 발생하는 열대야 떄문에 다들 고생하시고 있을거라 생각됩니다. 벌써 8월도 중반이 넘어가고 있으니깐요~ 곧 이 더위도 물러날거라 생각됩니다 ㅎㅎ
다들 조금만 더 참아보면 기분 좋은 가을이 찾아오겠죠~ ㅎ

이번 아티클부터는 WCF 의 Security 부분과 관련한 주제로 이야기를 이어가볼까 합니다.

그래서~ 제목에서 확인하셨겠지만, SSL 프로토콜을 이용한 보안 설정을 먼저 다루어 보려 합니다.
SSL(Secure Sockets Layer)은 네트워크를 통해 전달되는 정보의 안전한 전송을 위해 넷스케이프사에서 정한 인터넷 통신규약 프로토콜을 말합니다.
최근에는 SSL을 여러 부분에서 많이 사용하고 있기 떄문에 다들 한번 이상은 들어보았을거라 생각됩니다.

SSL에 대한 자세한 설명은 다음 링크를 참조하시면 될 것 같습니다.
SSL은 무엇이며, 왜 이것을 사용해야 하는가?

그럼, 이제 이 SSL을 적용한 서비스를 개발하는 방법에 대해 설명해보도록 하겠습니다.

먼저, Visual Studio 2010에서 WCF 응용 프로그램 템플릿을 이용해 새로운 솔루션을 만듭니다.
이번 내용도 WCF 서비스가 어떤 기능을 수행하는지에 대한건 그리 중요하지 않으니깐 기본적으로 만들어 지는 코드를 그대로 사용해 보겠습니다. ㅎ

SSL 을 사용하기 위해선 인증서가 필요하기 때문에 서비스에 SSL을 적용하기 전에 우선 인증서를 만들어야 합니다.
SSL 인증서는 공식 인증 기관에서 생성을 해줘야 신뢰할 수 있는 인증서를 만들 수 있지만, 우리는 테스트가 목적이니깐 그렇게까진 필요없고, 윈도우에서 자체 서명된 인증서를 만들어 주면 될 것 같습니다.

다음 그림과 같이 IIS 관리자를 실행 시키고, "서버 인증서" 아이콘을 더블 클릭 합니다.


다음, 오른쪽 "작업" 메뉴에서 "자체 서명된 인증서 만들기..." 메뉴를 클릭합니다. 그러면 다음과 같은 창이 뜨는데 여기서 인증서 이름을 적고 확인 버튼을 클릭하면 새로운 인증서를 만들 수 있습니다.



다음으로 우리가 만든(비록 Visual Studio에서 다 만들어 준 것이지만,,^^;;) WCF 서비스를 IIS에 올리는 작업을 수행합니다. 이 작업은 생략해도 다들 아실거라 생각합니다,, 혹시 모르시는 분이 계시면 댓글로 남겨주세요~ ^^

다음은, IIS 관리자를 통해 WCF 서비스를 호스팅하는 사이트에 바인딩을 추가할 필요가 있습니다. SSL을 사용하는 사이트는 https 로 시작하는 url을 사용하는데, 이에 대한 바인딩을 추가해주어야 하는 것이죠~

IIS 관리자에서 WCF 서비스를 호스팅하는 사이트를 선택하고 작업 메뉴에 있는 "바인딩..." 메뉴를 클릭합니다.


그리고, 새로운 사이트 바인딩을 추가하기 위해 추가 버튼을 클릭하고 다음 그림과 같이 https를 사용하도록 하고 포트 번호를 설정해 줍니다. 또한, SSL 인증서에서 위에서 생성한 인증서를 선택해주고 확인 버튼을 클릭합니다.


자~ 이렇게 하면 WCF 서비스를 호스팅하는 사이트는 SSL을 이용할 수 있게 됩니다.

다음으로는 WCF 서비스에서 SSL을 이용하기 위한 몇 가지 설정을 해주어야 합니다.
앞에서도 얘기했지만 SSL을 사용하는 사이트는 https로 시작하는 url을 사용하기 때문에 이에 대한 설정을 해주어야 합니다. 그리고 전송계층에서의 보안을 설정해주기 위한 작업도 필요합니다.

그래서 web.config 를 다음과 같이 수정하겠습니다.

<system.serviceModel>

    <services>

      <service name="SSLService.Service1">

        <host>

          <baseAddresses>

            <add baseAddress="http://localhost:4949/Service1.svc"/>

            <add baseAddress="https://localhost:4948/Service1.svc"/>     // SSL을 사용하는 URL 등록

          </baseAddresses>

        </host>

        <endpoint address="" binding="basicHttpBinding" contract="SSLService.IService1"
                       bindingConfiguration=
"MyBinding" />

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

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior>

          <serviceMetadata httpGetEnabled="true" />

<serviceDebug includeExceptionDetailInFaults="false" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <bindings>

      <basicHttpBinding>

        <binding name="MyBinding">

<security mode="Transport">     // 전송 계층의 보안을 적용하기 위한 태그

            <transport clientCredentialType="None" />

          </security>

        </binding>

      </basicHttpBinding>

    </bindings>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

  </system.serviceModel>


위의 설정을 보면 아시겠지만 SSL을 사용하기 위한 URL을 base address로 등록을 하고 basicHttpBinding을 사용하는 엔드 포인트를 등록합니다. 그리고 이 엔드 포인트에 사용하는 basdicHttpBinding에 전송계층에서의 보안 설정을 위해 security 태그와 transport 태그가 적용되어 있습니다.

transport 태그의 clientCredentialType 속성은 클라이언트의 인증을 위해 어떤 방식을 사용할 것인지에 대한 것을 설정할 수 있는데 이에 대한 내용은 다음 포스팅에서 설명을 하겠습니다. 이번 서비스는 따로 인증을 하지 않기 때문에 None으로 적용하였습니다.

이제 모든 설정은 끝이 났습니다.
간단한 콘솔 어플리케이션을 새로 만들어서 이 서비스를 참조해보도록 하겠습니다.
콘솔 어플리케이션을 만들고 언제나 그랬듯, "서비스 참조 추가"를 수행하고 서비스 참조 추가 창에서 주소에 IIS에서 설정해 주었던 url을 입력합니다. 저의 경우에는 "https://localhost:4948/Service1.svc"입니다.
그리고, 확인 버튼을 클릭하면 서비스를 찾다가 다음과 같은 화면이 뜹니다.


대충 내용을 보면, 인증서에 포함된 호스트와 주소가 일치하지 않기 때문에 신뢰할 수 없다는 내용인 듯 합니다. 그냥 여기서 "예" 버튼을 클릭해주면, 다음 그림 처럼 아무런 이상없이 서비스를 찾을 수 있고, 참조를 할 수 있습니다.


이렇게 참조를 해주면 아무 문제없이 서비스를 사용할 수 있겠죠~ ㅎ

콘솔 어플리케이션으로 서비스를 이용하는 부분은 생략하도록 하겠습니다~ 별 내용이 없으니깐요,, ㅎ

보안 부분은 개인적으로 제일 어려운 부분이면서 가장 부족한 부분이라 생각하기 때문에 오늘의 내용에 잘못된 부분도 있을거라 생각됩니다. 혹시 잘못된 내용이 있으면 댓글로 알려주세요~ ^^;;

다음 포스팅에서는 SSL을 사용하면서 사용자 인증을 하는 방법에 대해서 포스팅을 해볼까 합니다.

그럼 다음 포스팅때 뵙겠습니다~ ^^

Introducing Visual Studio LightSwitch! - Enjoy your development

Visual Studio 2010 2010. 8. 5. 22:30 Posted by 알 수 없는 사용자

안녕하세요. Visual C# MVP 남정현입니다. 요즈음 날씨가 매우 덥네요. :-)

이번 글은 지난번에 올렸던 2010/06/24 - [Visual Studio 2010/Visual Studio 2010] - Just for fun! / DreamSpark는 대학생 여러분을 위한 솔루션입니다. 글을 보충하고 최신 소식을 전달하기 위한 취지로 포스팅하는 글입니다. 소프트웨어 개발을 처음 시작하시는 분들께 역시 도움이 될 수 있도록 정보를 제공하기 위한 취지로 작성되었습니다. :-)

최근에 VS2010 Live!에서 소개된 Visual Studio LightSwitch라는 신 제품에 대해서 블로그 포스팅을 조촐하게 해봅니다. Visual Studio LightSwitch는 기존의 Visual Studio Express Edition과는 별도로 구분되는 제품으로 매우 신속하고 빠르게 새로운 형태의 소규모 데이터베이스 시스템과 통합하거나, 기존의 WCF RIA Service, SQL Server Database 등과 상호 작용하면서 C/R/U/D (Create/Read/Update/Delete) 및 검색 기능, Office 연동 기능을 지원하는 Rich Application의 생산을 가능하게 해주는 개발 도구입니다. Visual Studio LightSwitch는 2010년 8월 23일 이후부터 베타 버전으로 처음 http://www.microsoft.com/visualstudio/en-us/lightswitch 에서 공개될 예정에 있습니다.

가장 많은 웹 사이트와 가장 많은 도서에서 보여주는 C/R/U/D 기반의 응용프로그램들의 패턴을 Visual Studio LightSwitch는 최신의 UI 기술을 사용하여 그 어떤 도구들보다도 더 쉽게 프로그램이 제작될 수 있도록 도와줍니다. 단순히 Grid Control에서 데이터를 추가, 편집, 삭제할 수 있는 UI가 아니라, 여러분이 원하는 화면의 디자인을 미리 제공되는 데이터 바인딩과 함께 손쉽게 프로그래밍할 수 있도록 돕습니다.

위의 그림에서 보시는것과 같이, Visual Studio LightSwitch는 데이터 가공 방법과 범주에 따라 일반적으로 결정되는 화면의 패턴을 템플릿으로 제공하고 있습니다. 대부분의 경우, 이러한 요구 사항과 부합하는 화면들 내에서 선택이 가능하므로 단순한 데이터 조회 및 검색 화면에 들어가는 작업 소요 기간을 획기적으로 단축시킬 수 있습니다. 뿐만 아니라, 데이터 모델링에서는 단순한 시스템 데이터 형식 뿐만 아니라, 유효성 검사를 염두에 둔 모델링과 UI 연동이 가능하여 세세한 검사를 위한 코드 작성은 하지 않아도 되며, 기본으로 제공되는 Grid Control의 경우 필터링, 열의 재 배치, 행 정렬, 검색, 페이징이 Built-in 기능입니다. 그리고, 요즈음 Microsoft Application UI의 핵심적인 Trademark인 Ribbon Interface도 빠지지 않습니다. :-)

기존에 Windows Forms, Windows Presentation Foundation 기반의 개발 도구를 이용하여 Desktop 및 Office Application을 개발하는 동안 고객으로부터 가장 많이 받게 되는 요구 사항 중 하나인 Excel Export 기능이 Visual Studio LightSwitch를 기반으로 만들어지는 응용프로그램에서는 미리 제공되는 Built-in 기능 중의 하나입니다. 더 이상 Excel 상호운용성 코드나 Primary Interop Assembly를 찾아서 방황하지 않아도 됩니다. :-)

그리고 Visual Studio LightSwitch는 앞으로도 다양한 확장 패키지를 지원해 나갈 수 있으며, 이러한 확장 패키지를 기반으로하여 가까이는 시각 상의 심미적인 효과를 위한 확장, 하드웨어와의 연동 기능 뿐만 아니라 향후에는 Cloud Computing을 위한 응용프로그램 디자인까지도 염두에 둘 수 있습니다.

Visual Studio LightSwitch는 System Integration 개발 부문, Business Intelligence 확장 부문 등 기존에 특별한 기술적 이득 없이 기계적인 반복 작업을 바탕으로 하는 대부분의 소프트웨어 개발 작업에서 더 큰 진가를 발휘할 수 있을 것으로 예상됩니다. 향후에는 Chart, Graph, HTML Editing Control, Built-in Web Browser와 같이 일반적인 Desktop 및 Office Application에서 많이 사용되는 기능에 대한 Extension Pack이 추가될 것도 염두에 두어본다면 반복적인 작업으로부터 많은 일손을 덜어내어줄 수 있는 멋진 도구가 될 수 있을 것 같이 미래가 기대됩니다.

Cloud Computing과의 연계성에 있어서도 Visual Studio LightSwitch의 역할은 매우 클 것으로 보이며, 향후에 Cloud Computing과의 연계 기능에 대해서도 본격적으로 Topic을 다룰 수 있을 때, 상세하게 정보를 전달할 수 있도록 하겠습니다.

사이트 바로가기 및 키노트 동영상 구경하러 가기: http://www.microsoft.com/visualstudio/en-us/lightswitch

오늘도 좋은 하루 되세요. 감사합니다. :-)

WCF Hosting (3) - Windows Service를 이용한 Hosting

WCF 2010. 7. 31. 09:00 Posted by 알 수 없는 사용자
여름의 정점을 지나가고 있는 듯 합니다. 날씨가 무진장 덥네요,,
장마가 끝나면 폭염이라는데,, ㅡ,.ㅡ;;;
식상한 멘트이긴 하겠지만, 이런 날일 수록 정말 건강이 중요한 것 같습니다.
덥다고 에어컨 바람만 쐬면 냉방병 걸리고, 밤에 잘때도 너무 에어컨 틀어놓으면 감기 걸리니깐,,
아프지 않는게 최고죠~ 특히, 저 같이 혼자 자취하는 자취남들은,, ^^
아무쪼록 건강하세요~


이번 아티클의 주제는 Windows Service를 이용한 호스팅입니다.

윈도우즈 서비스에 대해서 모르는 분이 계실까요?
네~ 계실 수 있죠,, 그래서 간략하게 윈도우즈 서비스에 대해 설명을 하고 넘어가도록 하겠습니다.

What is Windows Service?

NT 서비스라고 알려져 있기도 한 윈도우즈 서비스는 자체의 Windows 세션에서 실행되며, 윈도우즈가 구동을 하고 있는 동안 계속 동작을 해야하는 이러한 작업이 필요할 때, 윈도우즈 서비스의 형태로 구현하여 사용할 수 있습니다. 또한, 윈도우즈 서비스는 윈도우즈의 시작과 함께 자동으로 시작할 수 있기 때문에, 서버가 동작함과 동시에 항상 동작해야하는 응용 프로그램이라면 윈도우즈 서비스로 구현하는 것을 고려해 볼 필요가 있을 듯 합니다.

윈도우즈 서비스의 경우는 따로 UI를 가지고 있지 않기 때문에, 윈도우즈 사용자 또는 관리자가 윈도우즈 서비스의 구동 상태를 상세하게 확인할 수는 없습니다. 다만, 윈도우즈에 기본으로 제공되는 서비스 제어 관리자를 통해 서비스의 시작, 중지, 일시정지 등을 컨트롤 할 수 있습니다. (아래 그림은 서비스 제어 관리자의 모습입니다.)


그림을 보니 윈도우즈 서비스가 어떠한 것들을 말하는 것인지 알겠죠? ^^ (역시, 백문이 불여일견,, 엣헴~)

Windows 서비스 응용프로그램에 대한 소개와 개발 방법에 대해 좀 더 자세한 정보를 원하시는 분은 다음 링크를 참고하시기 바랍니다.

"Windows 서비스 응용 프로그램 소개"

이제 본격적으로 이 윈도우즈 서비스를 이용하여 WCF 서비스를 호스팅하는 방법에 대해 적어보겠습니다.
고고씽~

Windows Service를 이용한 WCF 서비스 호스팅

WCF 서비스를 호스팅하는 방법에는 IIS 호스팅, WAS 호스팅, 그리고 셀프 호스팅으로 나뉘어진다고 얘기했었습니다.

그럼, Windows Service를 이용한 호스팅은 어디에 속할까요?
네~!! 당연히 셀프 호스팅에 속합니다. 그리고, 셀프 호스팅에 속한다는 말은 직접 ServiceHost 클래스를 이용하여 호스팅을 구현 해야 한다는 말이기도 합니다.

결국, 여기서 제가 하고 싶은 말은 이것입니다.
 "Windows Service를 이용하여 WCF 서비스를 호스팅하기 위해서는 ServiceHost 클래스를 이용하여 서비스 호스팅하는 부분을 직접 구현해야 한다."
 
WCF 서비스를 호스팅하기 위한 특별한 코드가 필요한 것은 아닙니다. 여타의 다른 윈도우즈 서비스를 개발하는 것과 같이 개발을 하고, WCF 서비스를 호스팅하는 코드만 추가를 해주면 된다는 것입니다~!!
아마, 윈도우즈 서비스를 한번이라도 개발 해 보신 분은 어렵지 않게 개발을 할 수 있을 것 같습니다.

우선, 윈도우즈 서비스 응용프로그램을 만들기 위해 Visual Studio에서 새 프로젝트를 생성할 때, "Windows 서비스" 템플릿을 선택합니다.


프로젝트를 생성하면 Service1.cs 와 Program.cs 파일이 생성되어 있음을 확인할 수 있습니다.
Program.cs 파일은 이 응용 프로그램의 진입점을 가지고 있으며, 실제 서비스가 동작을 할 때의 코드는 Service1.cs 파일에 구현을 하면 됩니다.

그리고, Service1.cs 파일을 확인하면 Service1 클래스가 선언되어 있으며, 이 클래스는 ServiceBase 클래스를 상속 받는 것을 확인할 수 있습니다.
그리고, Service1 클래스에는 기본적으로 OnStart와 OnStop 메소드가 재 정의(override)되어 있는데 메소드의 이름으로 짐작할 수 있겠지만, 각각 서비스가 시작할 때 와 서비스가 멈췄을 때의 동작을 수행하는 메소드입니다.

이 메소드 외에, OnContinue, OnPause, OnShutdown 메소드를 재정의하여 서비스를 일시정지에서 다시 시작했을 때, 서비스를 일시정지 했을 때, 그리고 컴퓨터가 종료될 때의 동작을 구현할 수 있습니다.

이번 아티클의 주제는 Windows 서비스를 이용한 WCF 서비스의 호스팅이니 만큼, Windows 서비스 구현에 대한 자세한 내용은 앞서 걸어놓은 MSDN의 링크로 대신하고 넘어가겠습니다.
(Windows 서비스 응용 프로그램의 구현에 대한 자세한 내용을 모르셔도 아래 내용을 따라 하시면, 아마 무사히 WCF 서비스를 호스팅 할 수 있으실겁니다. )

음,, 일단 우리가 만들 Windows 서비스의 이름을 먼저 변경해보도록 하겠습니다. 이름을 변경하지 않아도 별 상관은 없지만 우리가 만든 서비스란 것을 알아보기 위해서 변경하는게 낫겠죠~ 서비스의 이름을 변경하는 것은 어렵지 않습니다. Service1 클래스의 생성자에서 바꿔줘도 되고, Service1.Designer.cs 파일을 확인하면 Service1 의 partial 클래스가 정의되어 있는데, 이곳에 위치한 InitializeComponent 메소드 내에서 변경해줘도 됩니다. 저는 InitializeComponent 메소드 내에서 다음과 같은 코드로 서비스의 이름을 지정 해주었습니다.

private void InitializeComponent()

{

     components = new System.ComponentModel.Container();

  this.ServiceName = "RuAA WCF Service"; // 서비스의 이름 변경

}


이제 본격적으로 WCF 서비스를 호스팅 해보도록 하겠습니다.
우선, WCF 서비스에서 사용할 ServiceContract와 DataContract 들을 선언해주어야 겠죠. 다음과 같은 인터페이스와 클래스들을 선언해주었습니다.

// ServiceContract 정의
[
ServiceContract]

public interface IProductService

{

    [OperationContract]

    Product GetProductInfo(int id);

}


// DataContract 정의
[
DataContract]

public class Product

{

    [DataMember]

    public int ID;

    [DataMember]

    public string Name;

    [DataMember]

    public string Company;

    [DataMember]

    public int Price;

}

// 서비스 구현

public class ProductService : IProductService

{

    List<Product> productList;

 

    public ProductService()

    {

        productList = new List<Product>();

        productList.Add(new Product {

            ID = 1,

            Name = "ABC Chocolate",

            Company = "RuAA Inc.",

            Price = 5300

        });

    }

 

    public Product GetProductInfo(int id)

    {

        var item = (from p in productList

                    where p.ID == id

                    select p).FirstOrDefault();

 

        return item;

    }

}

항상 그랬지만, 서비스의 역할은 심플합니다. 복잡한 서비스를 만드는게 목표는 아니잖아요~ ㅎ

이제 이렇게 구현된 서비스를 호스팅하는 일 만을 남겨두었습니다.

앞에서도 밝혔듯이 Windows 서비스에서 WCF 서비스를 호스팅 하는 것은 Self Hosting 에 포함되는 것이기 때문에 ServiceHost 클래스를 직접 구현해야 합니다.

근데 이 코드를 어디에 위치해야 할까요? 예상하신 분들이 분명 계실겁니다.
바로 바로 바로~~!! Service1 클래스의 OnStart 메소드입니다. 

또한, 생각해야 할 것이 있습니다.
Windows 서비스가 멈추었을 때, 당연히 WCF 서비스의 호스팅을 멈추어줘야 겠죠. 그래서 OnStop 메소드 내부에 WCF 서비스의 호스팅을 멈추게 하는 코드도 포함이 되어야 할 것입니다.

Service1 클래스를 다음과 같은 코드로 구현해보았습니다.

// ServiceHost 클래스의 인스턴스를 클래스의 멤버로 선언하여 Service1 클래스의 메소드에서 접근이 가능하도록 한다.
private
ServiceHost svcHost;

// 윈도우즈 서비스가 시작할 때의 동작을 구현한다.

protected
override void OnStart(string[] args)

{

    // ServiceHost 인스턴스 생성
    string baseUrl = "http://10.30.101.84:9090/ProductService";

    this.svcHost = new ServiceHost(typeof(ProductService), new Uri(baseUrl));

    // 엔드포인트 추가
   
this.svcHost.AddServiceEndpoint(typeof(IProductService),

        new BasicHttpBinding(),

        "");

           

    // 메타 데이터 엔드포인트를 위한 Behavior 설정
    ServiceMetadataBehavior metaBehavior = new ServiceMetadataBehavior();

    metaBehavior.HttpGetEnabled = true;

    svcHost.Description.Behaviors.Add(metaBehavior);

 

    // 메타 데이터 엔드포인트 추가

    this.svcHost.AddServiceEndpoint(typeof(IMetadataExchange),

        MetadataExchangeBindings.CreateMexHttpBinding(),

        "mex");

 

    svcHost.Open();  // WCF 서비스 오픈

    ServiceEndpoint endpoint = this.svcHost.Description.Endpoints[0];

 

    // 윈도우즈 이벤트 로그에 정보를 남긴다.

    EventLog.WriteEntry(endpoint.Contract.Name + " Started"

        + " listening on " + endpoint.Address

        + " (" + endpoint.Binding.Name + ")",

        System.Diagnostics.EventLogEntryType.Information);

}

 

// 윈도우즈 서비스가 멈췄을 때의 동작을 구현한다.

protected override void OnStop()

{

    this.svcHost.Close();

    EventLog.WriteEntry("RuAA Service Stopping", EventLogEntryType.Information);

}
 
위의 코드에서 그렇게 어려운 점은 보이지 않습니다. Self Hosting을 해보셨던 분이라면 말이죠~
혹시나, Self Hosting을 해보지 못하신 분이 있다면, 첫 WCF 만들기 아티클을 참고해주시기 바랍니다.

각 주요 코드에 주석도 남겨놨으니 따로 긴 설명은 필요없을 듯 합니다. ^^

이제, 서비스의 구현은 모두 끝이 났습니다. 하지만, 우리가 만든 이 Windows 서비스를 컴퓨터에 설치하기 위해서는 설치 관리자가 필요합니다. (설치 관리자에 대한 자세한 설명은 이곳으로~)
Service1.cs 파일의 디자이너 보기에서 마우스 우측 클릭한 후 나타나는 메뉴에서 "설치 관리자 추가"를 선택합니다.


그러면 프로젝트에 ProjectInstaller.cs 라는 파일이 생기는데, 이 클래스의 디자인 뷰를 확인하면,  serviceProcessInstaller1, serviceInstaller1 이라는 이름의 컨트롤들이 포함되어 있는 것을 확인할 수 있습니다.

이 컨트롤들의 속성을 다음 그림과 같이 수정해보겠습니다.



이제서야, 정말 Windows 서비스를 설치할 모든 준비가 끝이 났습니다.
이 Windows 서비스를 설치하기 위하여 Visual Studio 명령 프롬프트를 실행시킵니다. 이때, 관리자 권한으로 실행시켜 주셔야 합니다. 그렇지 않으면 Windows 서비스가 제대로 설치가 되지 않는 경우가 있더라구요~ ㅎ

그리고, 이 프로젝트 폴더의 bin/Debug 폴더로 이동한 후에 다음 그림과 같이, Installutil 이란 명령어를 이용하여 우리가 만든 Windows 서비스를 설치합니다. (Windows 서비스 설치에 대한 자세한 설명은 이곳으로~!!)
참고로, 설치 파일은 프로젝트를 빌드한 후에 생성된 exe 파일입니다.


위의 그림처럼 "트랜잭트 설치가 완료되었습니다." 란 메세지가 떨어졌다면 아무 에러없이 Windows 서비스가 설치되었다는 말입니다. 그럼, 서비스 제어 관리자에서 확인해 보도록 하겠습니다.


네,, Windows 서비스가 올라와있는 것을 볼 수 있네요~ 그럼 시작 버튼을 클릭하여 Windows 서비스를 시작할 수 있습니다. 그리고, Windows 서비스가 시작하면서 우리가 구현한 WCF 서비스가 호스팅되겠죠,, ㅎㅎ

그럼, 이 WCF 서비스가 제대로 호스팅 되고 있는 것인지 확인을 해보아야 할겁니다,,
역시나, 지금까지 그래왔듯이 콘솔 어플리케이션을 이용하여 확인해보도록 하겠습니다.

솔루션에 콘솔 어플리케이션 프로젝트를 추가하고, 이 프로젝트에 서비스 참조를 시켜주었습니다. 이때 너무나도 당연하겠지만, 서비스의 주소는 ServiceHost 인스턴스에 추가 시켜준 엔드 포인트의 주소를 넣어주셔야 합니다.ㅎ


위의 그림처럼, 서비스를 제대로 찾으면~ 모든 것이 OK!!! 입니다. ㅎㅎ

이 서비스를 이용한 콘솔 어플리케이션 코드는 생략해도 되겠죠?? ㅎㅎ (이번 글이 너무 길어진 것 같아,, ^^;;;;)
그래서~~~ 결과 화면만 보여드리겠습니다 ㅎㅎ



후아~ 결과가 잘 나오는 군요,, ^^
이로써, 이번 포스팅도 무사히(?) 끝을 낼 수 있게 되었습니다. ㅎㅎㅎ

이번 포스팅은 Windows 서비스에 대한 설명과 구현에 대한 내용을 함께 적다보니 조금 길어진 것 같습니다. 물론 한번이라도 Windows 서비스 응용 프로그램을 구현해보신 분이라면 아는 내용들이겠지만, 혹시나 모르시는 분도 있을 것 같아 자세한 내용까지 설명드리지 못했지만 최소한의 내용을 포함시켰습니다.

조금 내용이 길어졌지만 끝까지 읽어주신 분들께 심심한 감사의 인사를 드리며, 저는 이만 퇴근(?)하겠습니다 ㅎㅎ

WCF=SOA 에 대한 고찰

Architect Development 2010. 7. 21. 08:30 Posted by POWERUMC

사실 필자는 SOA(Services Oriented Architectures) 에 대해서 심도 있게 알고 있는 전문가는 아닙니다. 전문가는 아니지만 WCF=SOA 에 대해 제가 알고 있는 작은 부분으로 WCF=SOA 를 오해하거나 잘못 알고 계신 분들이 있는 것 같아, 이 부분을 바로 잡아 보려고 합니다.    

우선 SOA(Services Oriented Architectures) 는 직역하면 "서비스 지향 아키텍처"라고 부릅니다. 서비스 지향 아키텍처는 서비스를 제공하는 벤더(Vender) 또는 프로바이더(Provider) 를 통해 유연한 서비스를 제공하거나 제공 받는 아키텍처를 말합니다. 그리고 이 SOA 와 가장 연관 깊은 것이 바로 XML 웹 서비스(Web Services) 입니다.    

XML 웹 서비스는 특정 벤더나 프로바이더를 통해 서비스를 제공 받고, 표준으로 채택됨으로써(http://www.w3.org/2002/ws/) 플랫폼 간의 상호 운용성을 높인 기술입니다. 어떤 운영체제와 플랫폼이든 이 메시지를 이해할 수 있는 텍스트(Plain Text)로 이루어진 XML 과 WSDL, XSD 스키마를 사용하여 해석되는 것입니다. 이것을 가리켜 SOAP 프로토콜이라고 합니다. (사실 Microsoft 만큼 SOAP 을 잘 구현한 벤더는 없습니다. 유효성 검사를 해 보면 정말 엉망으로 구현하는 곳이 의외로 많습니다)    

 

그리고 .NET Framework 3.0 부터 WCF(Windows Communication Foundation) 이라는 기술이 출연하게 됩니다. 그리고 많은 사람들은 .NET 리모팅, XML 웹 서비스, TCP/UDP(UDP는 .NET 4.0 에 포함됨) 등을 통합한 프레임워크가 WCF 라고 이해하고 있습니다. 더불어 SOAP 뿐만 아니라 JSON, REST 방식의 통신 레이어 행위(Behavior)를 지원함으로써 "서비스 지향 아키텍처"라고 말하기도 합니다.    

필자는 이러한 SOA 에 대해서 작은 지식을 가지고 있지만, WCF 와 SOA 와 연관 관계를 지어 대화를 하게 될 때 매우 서먹하기도 합니다. 왜냐하면 바라보는 기술의 관점이 틀리기 때문에 말입니다.    

일단 용어를 명확히 하자면, SOA 는 어떤 명확한 구현 또는 산출물의 기술이 아닌 이상적인 아키텍처 측면을 의미합니다. 그리고 이상적인 아키텍처를 이야기 할 때 양자간의 관점이 틀릴 경우, 사실 그만큼 대화하기 힘든 것도 없었던 것 같습니다.

   

그렇다면, 여기에서 한 가지 궁금한 것이 생깁니다. XML 웹 서비스, WCF 둘 다 서비스 지향적인 아키텍처인가요?

먼저 일부 WCF 를 가리켜 SOA 라고 인지하는 분들의 경우, REST나 JSON 같은 경량화된 데이터 포멧(Data Format) 을 지원하기 때문에 서비스 지향적이라고 말합니다. 이것은 즉, 클라이언트가 웹 브라우저든 어떤 형태건 간에 선택적인 데이터 통신이 가능하다는 의미입니다. WCF 에서는 아주 간단하게 SOAP 데이터를 REST 방식이나 JSON 방식으로 쉽게 전환할 수 있죠.

또, 어떤 사람들은 여러 가지 통신 프로토콜을 통합하였기 때문에 서비스 지향적이라고 말합니다. .NET 리모팅이나 XML 웹 서비스, MSMQ, COM, COM+ 등을 통합했다는 이유로 말입니다.

   

그럼, 다시 질문하자면, XML 웹 서비스는 JSON 과 REST 를 지원하지 못하는 것일까요?

답변은 XML 웹 서비스는 이 과정을 .NET Framework 에서 기본적으로 제공하지 않을 뿐이지, 충분히 가능합니다. XML 웹 서비스는 통신 레이어 이전에 직렬화 및 역직렬화(Serialization/Unserialization) 과정을 거치는데, 이 과정에서 SOAP 을 REST 또는 JSON 으로 직렬화/역직렬화 하면 가능합니다.    

...

   

그렇다면 도대체 뭐가 서비스 지향적인 아키텍처인가?

일반적으로 일부 사람들이 이해하는 WCF 는 어떠한 방법으로도 서비스 지향적인 아키텍처를 제공하지 않습니다. 왜냐하면 WCF 든 XML 웹 서비스든 그 내부를 이해하지 못하고 사용한다면, 통신 프로토콜만 다를 뿐, 똑같은 XML 웹 서비스에 지나지 않기 때문입니다.    

필자는 서비스 지향 아키텍처에 WCF 에 한 표를 던져 주고 싶습니다. WCF 는 기본적인 환경에서 서비스 지향적인 프로그래밍을 제공해 주지는 않지만, 이미 WCF 프레임워크의 내부는 서비스 지향적인 아키텍처로 설계가 되었기 때문입니다.    

그렇다면 우리는 WCF 의 특징을 다시 한번 살펴볼 필요가 있습니다.

   

이렇듯 WCF 프레임워크는 다양한 기능을 제공합니다. 즉, 이러한 프레임워크를 알지 못하고서는 WCF 는 단지 XML 웹 서비스에 불과하다는 것과 같습니다.

   

SOA 에 좀 더 접근하기. ESB(Enterprise Services Bus)…

사실 SOA 는 아키텍처 측면의 용어로써 그 의미를 해석하는 것에 따라서 서로간의 바로 보는 관점이 다를 수 있습니다. SOA 를 이해함에 있어서 XML 웹 서비스도 WCF 도 SOA 에 해당됩니다.

하지만 SOA 적인 아키텍처를 좀 더 구체화한 것이 바로 ESB(Enterprise Services Bus) 라고 보셔도 좋습니다. SOA 를 적용하고 아키텍처링함에 있어서 최소한의 요구 사항을 충실히 구현한 것이 바로 ESB 입니다.    

ESB(Enterprise Services Bus) 에 대해 잘 설명해 놓은 아래의 글을 참고 하십시오.

제 1부 : 서비스 포트폴리오의 구현
제 2부 : Enterprise Service Bus 를 이용한 서비스의 연결

   

즉, ESB(Enterprise Services Bus) 는 서비스 가상화(Services Virtualization) 을 통해 중앙 집약적인 정책을 수립하여 적용하는 것입니다. 서비스의 제공자와 서비스의 소유자간의 명확한 계약(Contracts) 을 통해서 정책적, 중앙 집약적인 서비스가 가능한 것이 ESB 의 모티브이기도 합니다. 바로 서비스 가상화는 이 두 사이의 명확한 계약 관계가 성립됨으로써 가능한 것입니다.    

또한, 서비스 가상화를 통해서 서비스를 재조합(Recomposition) 이 가능한 것 또한 ESB 의 특징이기도 합니다. 서비스의 제공자와 서비스의 소유자 간의 명확한 계약 관계가 성립됨으로써 서비스의 제공자를 다른 서비스로의 전이, 신규 서비스 창출, 서비스의 조합이라는 것이 가능합니다.    

필자는 이러한 ESB 에 좀 더 가까운 개발 프레임워크를 만들기 위해 아래와 같은 프레임워크를 개발한 적이 있습니다. (아래는 관련 업계에 재직 당시에 개발했던 프레임워크입니다)

DxEF.Proxy.Dynamic 프레임워크 개발
DxEF.Proxy.Dynamic.SoaServices 프레임워크 개발

 

첫 번째로, 명확하게 서비스(Services) 와 서비스의 계약(Services Contracts or Interface) 를 구분함으로써 서비스의 소유자와 서비스의 제공자를 구분하였고, Dynamic Proxy 기법을 통해서 동적인 서비스적인 측면을 지향하였습니다.    

다시 말하면, WCF 는 SOA 를 위한 인프라스트럭처(Infrastructure) 를 제공할 뿐이지, XML 웹 서비스와 같이 '서비스 참조' 기능만 이용한다면 그것은 그냥 XML 웹 서비스와 크게 다를 바가 없다는 의미입니다.    

   

좀 더 서비스 지향적인 서비스를 위해...

이미 .NET Framework 는 더 이상 연습하고 학습하는 것만으로 습득할 수 있는 기술이 아닙니다. 마치 수십 수백 권의 "백과 사전" 수천 페이지가 바로 .NET Framework 입니다. 그 백과 사전이 바로 MSDN Documents Library 입니다.    

.NET 기술을 올바르게 사용하는 것은 매우 쉽습니다. 왜냐하면 MSDN 은 너무나도 자세한 부분과 샘플까지 제공하기 때문입니다. 더 중요한 것은 기술을 올바르게 이해하고 활용하는 것이지, 남용을 한다면 .NET 기술은 그저 그런 기술 밖에 되지 않습니다. 마치 .NET vs Java 를 도마 위에 올려 놓고 100분 토론을 하는 것처럼 말이죠.   

필자는 아마도 "서비스 지향적인 아키텍처"가 아니라 "서비스 지향적인 서비스"에 좀 더 초점을 맞추고 .NET 기술이 나아갈 방향을 고민해야 할 시점이 아닌가 생각합니다.

WCF Hosting(2) - ASP.NET 호환성(Compatibility)

WCF 2010. 7. 12. 09:00 Posted by 알 수 없는 사용자

바야흐로, 여름입니다.
아ㅡ 정말 이놈의 귀차니즘 덕분에 너무 띄엄띄엄 포스팅이 되는 것에 대해 죄송하다는 말씀 먼저 드려야할 것 같습니다.
여름이라 더워서 그렇다고 핑계대지 않을게요, 휴가 시즌이라 놀고 싶어서 그렇다고 핑계대지 않을게요~ ;;;
잡담은 여기서 줄이고, 힘을 내어, 이번 포스팅을 시작해 보겠습니다. 레츠 고우~
 
지난 포스트의 주제는 WAS 호스팅이었습니다. 이번 주제는 조금 다르긴 하지만 지난 포스트에 이어서 Hosting과 관련된 내용을 적어볼까 합니다.

WCF 서비스를 호스팅하기 위해 가장 쉬운 방법이 무엇인지 다들 아시죠?
제 개인적인 생각인지는 모르겠지만, Visual Studio를 사용하여 WCF 서비스를 만든다면, 아마도~ 가장 쉬운 호스팅 방법은 IIS 호스팅일 것입니다. 솔루션 만들고 별 수정없이 바로 호스팅이 가능하니깐요,,

갑자기 왜 IIS 호스팅에 대한 얘기를 꺼내냐구요?
음,, 오늘 제가 꺼낼 이야기가 IIS 호스팅일 때 WCF 서비스에 ASP.NET의 몇 가지 특성을 적용할 수 있는 방법에 대한 내용을 적으려다 보니... 네!! 결국, 제가 하고 싶은 얘기는 이번 포스팅에서 나오는 방법들이 IIS 호스팅을 바탕으로 한다는 것을 명심(?)해 달라는 것입니다. ㅎㅎ

닷넷 웹 서비스 와 WCF 서비스

WCF 서비스 얘기를 할 때, 가장 비교를 많이 하는 것이 아마 .NET 웹 서비스 일 듯 합니다. (지금도 이 닷넷 웹 서비스에 대해 얘기를 하려 하구요~ ㅎ)

닷넷 웹 서비스와 WCF 서비스의 가장 큰 차이는 무엇일까요?
구현하는 방법에 대한 차이도 있겠지만, 그것보단 WCF 서비스가 HTTP 프로토콜 이외의 프로토콜(net.tcp, net.pipe, MSMQ)을 이용하여 접근이 가능하게 호스팅할 수 있다는 점일 것입니다. (WAS를 이용한 호스팅 참조)

닷넷 웹 서비스는 WCF 서비스와는 다르게 HTTP 프로토콜만 지원합니다. 그리고 이는, ASP.NET HTTP 파이프라인을 따르고 있습니다.

"아ㅡ ASP.NET 파이프 라인은 또 뭔가요?" 라고 원망 섞인 소리가 여기까지 들리는 것 같습니다. 저도 아직 실력이 미천한 개발자라 자세히 설명드릴 수는 없습니다.
간단하게 설명 드리자면, ASP.NET 에서 Http 프로토콜을 이용하여 들어오는 요청(request)과 응답(response)을 처리하기 위한 파이프라인입니다. 즉, 어떤 요청에 대해서 어떻게 필터링을 수행하고, 어떤 어플리케이션을 호출할 것인지를 처리하며, 파이프라인을 통해서 그에 대한 응답을 전송하는 것입니다.

자세한 내용을 알고 싶은 분은 다음을 참고 하시면 될 것 같습니다.
Securely Implement Request Processing, Filtering, and Content Redirection with HTTP Pipelines in ASP.NET

닷넷 웹 서비스는 이렇게 ASP.NET HTTP 파이프라인을 사용하기 때문에 많은 ASP.NET 의 특징을 함께 사용할 수 있다는 장점을 가지고 있습니다. 이러한 장점에는 다음과 같은 것들이 포함 됩니다. 

  • Authentication
  • Url/File authorization
  • Impersonation
  • Session state
  • Request cache
  • Globaliztion
  • Etc

목록을 보니 인증과 권한에 대한 것, 그리고 세션과 관련한 것들이 있네요~

이제 WCF 서비스 얘기를 해볼까요?
WCF 서비스는 닷넷 웹 서비스와는 다르게 non-HTTP 프로토콜들을 지원해줍니다. 그리고, 이러한 장점을 위하여 프로토콜에 독립적인 디자인을 사용하게 된 것입니다.

조금 둘러서 얘기를 했지만, 제가 하고 싶은 말은 이것입니다. 
"닷넷 웹 서비스와는 다르게 WCF 서비스는 ASP.NET HTTP 파이프 라인을 따르지 않는다!!"


음,, 그렇군요. WCF 서비스는 ASP.NET HTTP 파이프 라인을 따르지 않는군요... 앗~ 그렇다면 닷넷 웹 서비스의 경우 ASP.NET HTTP 파이프 라인을 따랐기에 여러가지 ASP.NET의 특성을 사용할 수 있었는데,, 그럼, WCF 서비스에서는 ASP.NET의 특성들을 사용할 수 없는걸까요??

네~!! 기본적으로는 그렇습니다.
하!지!만!!! ASP.NET 에는 여러 유용한 특성들이 존재했기에 이를 완전히 버리기는 아까웠을겁니다. WCF 서비스를 위해서 같은 특성들을 다시 만들기 보다는 기존에 있던 것들을 가져다 쓰는 방향으로 개발하고 싶었겠지요~(제 개인적인 생각입니다. 아니면 말구요~ ㅎ) 

어떤 이유인지는 확실치 않지만, 어찌됐든 중요한 것은, WCF 서비스에서도 기존의 ASP.NET 특성들을 (전부는 아니고 일부분의 특성들을) 사용할 수 있는 방법을 제공해주고 있다는 것입니다. 단, HTTP 프로토콜을 사용하는 WCF 서비스에서만요~

이번에도 역시 둘러둘러~ 이제서야 본론으로 들어온 것 같습니다 ^^
그럼, 이제 본격적으로 WCF 서비스에서 ASP.NET의 유용한 기능들을 사용하기 위한 방법에 대해서 얘기해보도록 하겠습니다.


WCF 서비스에서 Session 사용하기

이번 포스팅에서는 ASP.NET의 특징들 중에서 간단하게 Session을 사용하는 예제를 구현해보려 합니다. (차후에 WCF의 보안에 대해 포스팅을 할 때에는 Impersonation 과 관련한 예제도 보여드릴 수 있을 것 같습니다.)
여기서 Session은 WCF 의 인스턴스를 생성할 때의 모드인 InstanceContextMode.Session 과는 전혀 무관합니다. 다들 알고 계시리라 생각하지만 혹시나 싶어서요~ ㅎ

우선, ASP.NET의 특징들을 사용하기 위해서는 크게 두 가지의 설정이 필요합니다.

첫 번째, Application Level 에서의 설정이 필요한데, 이는 WCF 서비스 프로젝트의 web.config에서 <system.serviceModel> 의 자식 요소인 <serviceHostingEnvironment> 요소의 속성 aspNetCompatibilityEnabled 의 값을 true로 명시하여 설정할 수 있습니다. 

두 번째로, Service Level 에서의 설정이 필요합니다. 이는 WCF 서비스를 구현하는 클래스에 AspNetCompatibilityRequirements 특성을 통해 설정을 할 수 있습니다.

코드를 보면서 하나씩 해보도록 하죠~

WCF 솔루션을 하나 만듭니다. 좀 편하게 작업을 하기 위해서 셀프 호스팅보다는 Visual Studio 에서 제공해주는 "WCF 서비스 응용 프로그램" 템플릿을 사용하도록 하겠습니다.

그리고, 다음과 같이 서비스 계약을 위한 interface와 WCF 서비스에서 사용할 개체인 Product 클래스를 정의했습니다.

[ServiceContract]

public interface IProductService

{

    [OperationContract]

    Product GetProduct(string ticker);

}

 

[DataContract]

public class Product

{

    [DataMember]

    public string Name;

    [DataMember]

    public int calls;

    [DataMember]

    public double price;

    [DataMember]

    public string RequestedBy;

}


이 다음에 할 일은 당연히 서비스를 구현하는 것이겠죠.
이 서비스에서는 session을 사용하여 현재 메서드가 호출되는 횟수를 기록, 유지하도록 했습니다.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

public class ProductService : IProductService

{

    public Product GetProduct(string ticker)

    {

        Product p = new Product();

        int nCalls = 0;

        // I .

        if (HttpContext.Current.Session["cnt"] != null)

            nCalls = (int)HttpContext.Current.Session["cnt"];

        HttpContext.Current.Session["cnt"] = ++nCalls;

 

        p.Name = "Caramel Latte";

        p.calls = nCalls;

        p.price = 2500;

        p.RequestedBy = "RuAA";

          

        return p;

    }

}


이 코드에서 다시 한번 유의해서 보아야 할 부분은 역시 ProductService 클래스 위에 선언 된 AspNetCompatibilityRequirements 특성입니다. 그 값을 Required 로 주었네요~
이 부분은 앞에서 ASP.NET 특성들을 사용하기 위한 설정 중 Service Level에서의 설정에 해당하는 것이었습니다.

그럼, 이제 Application Level에서의 설정을 해주어야 겠군요. 
web.config 파일을 다음과 같이 수정합니다.

<system.serviceModel>

  <behaviors>

    <serviceBehaviors>

      <behavior>

        <serviceDebug includeExceptionDetailInFaults="true"/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

</system.serviceModel>


밑줄 쳐 있는 부분을 주목하시면 되겠습니다~ ㅎ
이 부분을 추가함으로써 첫 번째 Application Level 에서의 설정까지 완료한 것입니다.
설정이라고 하기엔 너무 간단한가요? ㅎ

이제, 이 서비스를 검증해보아야 겠죠,, 세션을 잘 유지하는지,,
매번 그래왔듯이 콘솔 어플리케이션을 이용하여 클라이언트를 간단히 만들어 보겠습니다.

서비스 참조를 하고, 다음과 같은 코드를 작성하였습니다. 

static void Main(string[] args)

{

    ProductServiceClient client = new ProductServiceClient();

    Product p = null;

    for (int i = 0; i < 5; i++)

    {

        p = client.GetProduct(i.ToString());

        Console.WriteLine(" : {0}", p.calls.ToString());

        Console.WriteLine(" : {0}", p.Name);

        Console.WriteLine(" : {0} ", p.price.ToString());

        Console.WriteLine(" : {0}", p.RequestedBy);

        Console.WriteLine();

    }

}


이 코드에선 그렇게 중요한 부분이 없습니다. 단순히 서비스의 GetProduct 메서드를 연속해서 5번 호출을 해주는 것 밖엔,, 복잡한건 싫으니깐 이렇게 간단히~ ㅎ

그리고 실행을 해보도록 하죠~
 

앗~ 뭔가 이상합니다. 우리가 예상했던 그런 결과가 나오지 않는군요. 세션이 유지가 되었다면 호출 횟수의 값이 1씩 증가하여 1~5의 값을 보여주어야 할텐데 말이죠.......

이런 결과가 나오는 이유는 바로,, Session을 사용하기 위해서는 클라이언트에서 쿠키를 허용해주어야 하는데,  기본 HTTP 바인딩인 basicHttpBinding 과 wsHttpBinding이 기본적으로 쿠키를 허용하지 않기 때문입니다.
HTTP 바인딩에서 쿠키를 허용해주기 위해선 config 파일에서 binding 태그의 allowCookies 속성의 값을 true 로 바꿔주시면 됩니다. 다음과 같이 말이죠~

<basicHttpBinding>

    <binding name="BasicHttpBinding_IProductService" closeTimeout="00:01:00"

        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

        allowCookies="true" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"

        maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"

        useDefaultWebProxy="true">

    ……

</ basicHttpBinding>


이제는 모든 설정이 완벽하게 끝이 난 것 같군요.
다시 실행을 해 보겠습니다.


아~ 이제 예상했던대로 결과 값이 나오는 것 같군요.. ㅎ

문득, 서비스의 InstanceContextMode의 값이 바뀌면 어떻게 될지 궁금해지지 않으신가요? ㅎ
한번 직접 해보시면 알겠지만 이 세션은 InstanceContextMode의 값(PerSession, PerCall, Single)이 무엇이 되든지 간에 유지됩니다. (다들 한번씩 해보시길~ ^^)

이번 포스팅은 여기까지하고 줄이도록 하겠습니다.

사실 이 포스팅은 제가 월드컵이 시작할 때 같이 시작했었는데, 결국 월드컵이 끝날 때 같이 끝나게 되었네요,,
이 놈의 귀차니즘 덕분에 포스팅이 항상 늦게 올려져서,, 정말 죄송한 마음밖엔 없는 것 같습니다.
일을 하면서 포스팅을 한다는 것 자체가 쉬운 일이 아님을 깨달았습니다.(MVP 분들이 존경스러워 지는군요,,ㅎ) 그래도 포기하면 안되겠죠,, ㅎ

다음 포스팅 때 뵙겠습니다. 꾸벅~

WCF - Serialization

WCF 2010. 4. 27. 09:00 Posted by 알 수 없는 사용자
안녕하세요~ ^^
오늘 너무 오랜만에 WCF 포스팅을 하게 되었습니다. 자주자주 인사를 드려야 하는데 그렇게 하지 못해 너무 죄송합니다.
오늘 감기 기운 덕분에 약을 먹어놨더니 정신이 헤롱헤롱 하네요 ^^;;
글이 조금 이상하더라도 하해(?)와 같은 마음으로 이해해주시길 바랄께요~

이번 글에서는 serialization(직렬화)에 대해 얘기를 해볼까 합니다.

우선, serialization이 무엇인지 알아야 하겠죠?
컴퓨터 용어에서 serialization은 종종 하나의 오브젝트를 바이트의 배열로 전환(converting)시키는 것을 의미합니다. 하지만 WCF 에서의 serialization은 이러한 의미로 사용되지는 않구요, 하나의 오브젝트(or 닷넷 클래스)를 XML Information Set(XML Infoset) 으로 전환시킨다는 의미로 사용됩니다.

아직은 조금 이해하기가 어렵나요? 음,, 아마 이번 포스팅을 끝까지 읽으면 이해가 되실 겁니다. ^^
이제부터 WCF에서의 Serialization에 대해 조금 더 자세하게 얘기해보겠습니다.

WCF에서는 아래와 같은 네 가지의 serialization을 위한 클래스를 제공합니다.

  • DataContractSerializer
    : WCF 에서 사용하는 기본 serializer 를 제공한다.
  • NetDataContractSerializer
    : 타입에 대한 추가적인 정보를 제공하는 serializer
  • XmlSerializer
    : .NET 2.0에서 제공되었던 serialization을 수행한다.
  • DataContractJsonSerializer
    : serialization 포맷으로 JSON을 제공한다.

이번 포스팅에서는 이러한 클래스들이 직렬화를 했을 때 어떤 결과물을 보여주는지에 대해 써볼까 합니다. 이러한 내용들이 WCF 서비스를 만들때 직접적인 도움이 되진 않겠지만, WCF 서비스를 이해하고, 목적에 맞는 서비스를 만들기 위한 커스터마이징을 하기 위해선 도움이 될 수 있을 것입니다.

DataContractSerializer

DataContractSerializer는 WCF에서 사용하는 기본 serialization을 수행합니다. (이후 부터는 serialization 대신 "직렬화"를 사용하겠습니다.) 이 serializer를 사용하기 위해서는 직렬화가 되는 클래스에 [DataContract] 특성을 지정하여 주면 됩니다. 이 방법은 WCF 서비스를 만들때 많이 사용했던 방법이기에 다들 익숙하리라 생각됩니다.

DataContractSerializer 클래스가 어떤 형태로 직렬화를 수행하는지 알아보도록 하겠습니다. 우선, 다음과 같은 클래스를 생성합니다.

[DataContract]

public class Employee

{
     public Employee(int employeeID, string firstName, string lastName
     {

         this.EmployeeID = employeeID;

         this.FirstName = firstName;

         this.LastName = lastName;

     }

 

    [DataMember]

    public int EmployeeID { get; set; }

 

    [DataMember]

    public string FirstName { get; set; }

 

    [DataMember]

    public string LastName { get; set; }

}


그리고, 콘솔 어플리케이션에서 다음과 같은 코드를 작성합니다.

using System.Runtime.Serialization;

using System.IO;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee e = new Employee(101, "Tae kyeom", "Oh");

            FileStream writer = new FileStream("sample.xml", FileMode.Create);

 

            DataContractSerializer ser = new DataContractSerializer(typeof(Employee));

            ser.WriteObject(writer, e);

            writer.Close();

        }

    }

}


이 코드를 실행을 시켜보면~ 프로젝트의 bin\Debug 폴더안에 sample.xml 파일이 생성됩니다.
코드는 간단하기에 이해하는데 큰 어려움은 없을 것 같지만, 간단히 설명하자면,,, Employee 클래스 인스턴스를 생성하고, 이 오브젝트를 XML 형태로 직렬화를 시킵니다. 그리고 이에 대한 내용을 sample.xml 파일에 썼구요. 그리고, 직렬화 할 때는, DataContractSerializer 클래스를 사용했습니다

그럼, sample.xml 파일의 내용을 확인 해보겠습니다.

네~ 다음과 같은 내용을 보여주고 있네요, 딱 봐도 Employee 인스턴스가 가지고 있는 데이터를 XML로 표현해주고 있다는 것을 알 수 있습니다.

여기서 다시 한번 더 되새겨봐야 할 것은 WCF에서 [DataContract] 특성이 적용된 클래스의 경우 서비스에서 클라이언트로 전달될 때, 위 모습과 같은 형태로 전달된다는 것입니다.


XmlSerializer

XmlSerializer는 이 전 닷넷 버전에서도 지원해주었던 클래스이며, 이는 ASP.NET 웹 서비스에서 사용하던 직렬화 방법을 제공해줍니다.
이러한 직렬화 방법을 WCF 에서도 사용할 수 있으며, 이는 ASP.NET 웹 서비스와 호환이 가능하다는 장점이 있죠. 또한, 이것은 웹 서비스를 WCF로의 전환하는 것이 그리 어려운 일이 아니라는 것을 의미하기도 합니다.^^

XmlSerializer는 public 접근자의 기본 생성자, 필드, 그리고 프로퍼티를 직렬화 시켜줍니다.

Employee 클래스를 다음과 같이 조금 수정해보았습니다.
public 기본 생성자가 필요하기에 추가시켜주었구요, [DataContract]와 [DataMember] 특성을 뺐습니다.

public class Employee

{
    public int EmployeeID { get; set; }

 

    public string FirstName { get; set; }

 

    public string LastName { get; set; }

 

    public Employee()

    {

    }

 

public Employee(int employeeID, string firstName, string lastName)

{
           
this.EmployeeID = employeeID;

            this.FirstName = firstName;

            this.LastName = lastName;

}

}


그리고, 이 클래스를 XmlSerializer 를 이용하여 직렬화 시켜보겠습니다.


using System.IO;

using System.Xml.Serialization;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee e = new Employee(101, "Tae kyeom", "Oh");

            FileStream writer = new FileStream("sample.xml", FileMode.Create);

 

            XmlSerializer ser = new XmlSerializer(typeof(Employee));

            ser.Serialize(writer, e);

            writer.Close();

        }

    }

}


코드는 아주 간단하죠. DataContractSerializer 클래스를 이용했던 코드와 별반 다를건 없구요, 단지 직렬화 할때 XmlSerializer 클래스를 사용했습니다. 그리고 이 클래스엔 Serialize 메소드를 이용해 직렬화를 수행하죠.

sample.xml 파일을 확인해보면 아래와 같은 모습을 하고 있는 것을 알 수 있을 것입니다.


결과로 생성 된 xml 파일 역시 앞 예제에서의 결과 파일과 많이 다르진 않지만, 네임스페이스가 조금 바뀐 것을 확인할 수 있습니다.

아,, 참고로~ WCF에서 XmlSerializer를 사용할 수 있게끔 하기 위해선 서비스 계약(Service Contract)에서 [XmlSerializerFormat] 특성을 적용해주면 됩니다.


DataContractJsonSerializer

DataContractJsonSerializer는 직렬화의 결과로 JSON 형태를 제공합니다.
JSON 형태의 경우 XML 보다 데이터의 양이 적은 장점이 있고, 이 직렬화를 사용하면, 자바 스크립트를 이용하여 서비스를 호출할 수 있어, 웹 어플리케이션에서 서비스를 쉽게 활용할 수 있다는 장점이 있습니다.

WCF 에서는 REST 서비스를 구현하는 경우 이러한 DataContractJsonSerializer를 사용합니다.

앞 예제에서 사용한 Employee 클래스를 DataContractJsonSerializer를 이용하여 직렬화 시켜보도록 하겠습니다.

using System.IO;

using System.Runtime.Serialization.Json;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee e = new Employee(101, "Tae kyeom", "Oh");

            FileStream writer = new FileStream("sample.txt", FileMode.Create);

 

            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Employee));

            ser.WriteObject(writer, e);

            writer.Close();

        }

    }

}


앞 예제와는 다르게 직렬화 결과를 xml 파일이 아닌 텍스트 파일로 썼습니다. 그리고 DataContractJsonSerializer 클래스를 사용하여 직렬화를 수행했습니다.

다음은 그 결과입니다.


멋지게 JSON 형태로 그 결과를 보여주고 있네요. ㅎ


오늘의 포스팅은 여기까지 하려 합니다. (몸이 좋지 않다는 핑계로 성급히 마무리 하려는,, ㅡ,.ㅡ;;;)

오늘 포스팅의 내용은 WCF 서비스를 만드는 팁도 아니고, 서비스를 만드는데 직접적인 영향을 미치는 것은 아니었던것 같습니다. 하지만, 이 부분은 앞에서도 언급했지만, WCF 서비스에 대한 이해를 위해서 알아두어야 하는 부분이라 생각하기에 포스팅을 감행(?)했습니다. 비록, 실무적으로 많은 도움이 되진 못하겠지만 이러한 기본적인 지식도 중요한 부분이니깐요~ ^^

다음 포스팅에서는 WCF 에서 제공하는 기본 직렬화 방법이 적절하지 않을때 커스터마이징을 수행하는 방법에 대해 알아보도록 하겠습니다.

감사합니다.

WCF 서비스의 동시성(Concurrency) - 2

WCF 2010. 3. 30. 09:00 Posted by 알 수 없는 사용자
지난 포스팅에 이어서 WCF 서비스의 동시성에 대해 이야기 해보겠습니다.
다른 설명 하지 않고, 지난 포스팅에서 했던 것 처럼 예제를 우선 보고 얘기를 진행해볼까 합니다.

Implementing a Singleton

단 하나의 서비스 인스턴스만이 생성되며, 인스턴스에서 동작하는 스레드 역시, 단 하나만 생성되게 하는 경우에 대해 먼저 살펴보겠습니다.
저번 포스팅에서 사용했던 서비스 클래스의 코드를 다음과 같이 굵은 글씨체 부분만을 수정하여 서비스를 실행해 보시기 바랍니다.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

            ConcurrencyMode = ConcurrencyMode.Single)]

class ProductService : IProductService

{

    ProductService()

    {

        Console.WriteLine("{0}: !!", DateTime.Now);

    }
          ... 생략 ...
}

이 코드를 실행하면 다음과 같은 결과를 확인할 수 있을 것입니다.

[서버]


[클라이언트]


결과가 여러분이 예상했던 것과 일치하나요?? ㅎ

이 경우 역시 서비스의 인스턴스는 서버 측 결과 화면을 통해 클라이언트의 요청의 수와는 관계없이 하나 만이 생성됨을 알 수 있습니다.
그리고, 클라이언트에서 서비스를 호출하는 방식으로 비동기 방식을 사용했던 것 기억하실겁니다. 결과 그림만을 봐서는 잘 모를 수도 있지만, 이 때문에 클라이언트 측 결과 화면을 보면, 지연시간 없이(각 호출에 대한 결과를 받지 않아도) 서비스를 연속적으로 세 번 호출함을 볼 수 있습니다.
하지만, 이 호출에 대한 결과는 각각 5초간의 지연시간을 두고 화면에 출력하는데, 이는 서버측 결과 화면을 보면 그 이유를 알 수 있습니다. 만약, 서비스 인스턴스가 여러 개의 스레드를 만들어 요청을 처리했다면, 클라이언트의 각 요청에 대한 결과를 거의 동시에 받을 수 있겠지만, 이 경우에는 하나의 스레드 만이 동작하기 때문에 각 요청을 한번에 하나씩 처리할 수 있어 이러한 결과를 얻을 수 있는 것이죠. 참고로, 각 요청에 대한 처리는 FIFO(First In First Out)의 순서로 동작합니다.

서비스 인스턴스에서 단 하나의 스레드 만이 동작한다는 것은 서버 측 결과에서 Thread ID 값이 3으로 동일한 것을 봐도 증명이 가능합니다. 가끔, 이 thread id의 값이 각 요청마다 다른 값이 나올 수도 있습니다. 그렇다고 잘못된 결과값은 아닙니다. ConcurrencyMode.Single한번에 하나의 스레드만이 동작한다는 것을 명시하는 거지, 단 하나의 스레드만이 만들어진다라는 의미는 아니거든요~,, 약간 헷갈릴 수도 있는 부분인 것 같으니, 꼭 명심해주세요,, ㅎ

이 경우처럼 싱글 인스턴스, 싱글 스레드는 한번에 하나의 클라이언트 요청만을 처리할 수 있기 때문에 throughput을 감소시킨다는 단점이 있지만, 반면에 시스템 자원(resource)에 동시 접근 같은 문제가 일어나지 않아서, 이에 대한 추가적인 관리가 필요하지 않다는 장점도 있습니다.

Session-Level Instances

이번에는 세션 모드가 적용되었을 때, 서비스의 인스턴스가 어떻게 생성되는지 한번 살펴보도록 하겠습니다.

우선, 서비스에서 세션을 지원하도록 하기 위해 서비스 계약의 특성값을 다음과 같이 수정합니다.

[ServiceContract(Namespace = "http://RuAAService.co.kr/",

                     SessionMode = SessionMode.Required)]

interface IProductService

{

    [OperationContract]

    Product GetProduct();

}


SessionMode에 Required 값을 적용하여 이 서비스가 세션 모드를 지원해준다는 것을 명시해 줍니다.
다음은 ServiceBehavior 특성에서 InstanceContextMode의 값을 PerSession 으로, ConcurrencyMode의 값을 Multiple 로 수정을 해줍니다. 그리고 GetProduct 메서드가 한 인스턴스에서 몇 번 호출이 이루어지는지를 체크하기 위해 n_Calls 라는 이름의 필드를 추가해 주었습니다. lockThis 필드는 n_Calls 필드의 값을 증가시킬 때 다른 스레드에서 동시에 n_Calls의 값을 바꾸지 못하도록 하기 위한 목적으로 선언해주었습니다.


[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,

            ConcurrencyMode = ConcurrencyMode.Multiple)]

class ProductService : IProductService

{

    object lockThis = new object();

    private int n_Calls = 0;

       
       ... 중간 생략 ...

   
    public
Product GetProduct()

    {

        Console.WriteLine("{0} : GetProduct , Thread Id {1}", 
                            DateTime
.Now, Thread.CurrentThread.ManagedThreadId);

        Thread.Sleep(1000);

 

        Product p = new Product();

        p.ProductId = 1234;

        p.ProductName = "ABC Chocolate";

        p.Price = 1500.0;

        p.Company = "Lotteee";

        p.CreateDate = DateTime.Parse("2010-01-22");

 

        lock (lockThis)

        {

            p.calls = ++n_Calls;

        }

 

        return p;

    }

}


코드를 다 수정하셨으면, 결과를 확인해보도록 하겠습니다.

당연히, 서버 측 콘솔 어플리케이션을 실행 시키신 후에, 클라이언트 어플리케이션을 실행시켜야겠죠,,^^
아,, 이런~ 저와 같은 방법으로 수정을 한 후에 실행 시키면, 아마 예외가 발생하실겁니다.

예외의 이유는 간단합니다. Service Contract에서 세션 모드의 값을 Required로 설정을 해놓았는데, 실제 서비스를 호스팅할 때 세션을 지원하지 않는 BasicHttpBinding을 사용했기 때문입니다. 따라서, BasicHttpBinding을 WSHttpBinding 으로 수정해주시면 이 예외는 발생하지 않을 것입니다.

자~ 이 부분 수정을 다 하셨다면, 다시 실행을 해보도록 하겠습니다.

세션모드의 지원을 확인하기 위해서 클라이언트 어플리케이션을 두 개 연속해서 실행을 시킵니다.

다음은 서버 어플리케이션의 실행 화면입니다.


인스턴스가 두 개 생성된 것을 확인할 수 있네요,, 왜 인스턴스가 두 개 생성되었을까요?? 당연히 클라이언트 어플리케이션이 두 개 실행이 되었기 때문입니다. 세션을 지원하는 서비스이니깐요,,

자~ 다음은 두 클라이언트 어플리케이션의 실행화면입니다.





각 클라이언트는 호출한 횟수가 1~3인 것을 확인할 수 있습니다. 이것은 각 클라이언트 마다의 서비스 인스턴스가 따로 데이터를 유지한다는 것을 의미하는 것이죠. 이해 되셨죠?? ^^

이번 포스팅은 이것으로 마무리 하려 합니다.
이번에도 포스팅이 조금 늦었습니다. 바로 하려고 했는데 이게 마음처럼 쉽지가 않네요. ^^;;

어찌됐든, 다음 포스팅때 뵙도록 하겠습니다. ㅎ

'WCF' 카테고리의 다른 글

WCF Hosting - WAS를 이용한 Hosting  (9) 2010.06.07
WCF - Serialization  (9) 2010.04.27
WCF 서비스의 동시성(Concurrency) - 1  (7) 2010.03.10
WCF의 기본 <Contract> - Data Contract  (17) 2010.02.09
WCF의 기본 <Contract> - Service Contract  (3) 2010.01.26

WCF 서비스의 동시성(Concurrency) - 1

WCF 2010. 3. 10. 09:00 Posted by 알 수 없는 사용자

봄이 오고 있네요,, 
날씨가 많이 따뜻해졌고, 해도 부쩍 길어졌음을 느낍니다.
최대한 빠른 시일 내에 포스팅을 하려 했는데, 그동안 무기력증(?)에 빠져있다보니,,
하는거 없이 시간만 보내버렸네요,, ^^;;
봄이 찾아온 만큼 새로운 마음가짐으로 다시 시작해보겠습니다. 아자~!

이번 포스팅의 주제는 WCF의 Behaviors 중에서 서비스의 동시성(Concurrency)을 컨트롤 할 수 있는 Behavior 입니다.

Behavior는 서비스가 동작할 때(그러니깐 런타임 시) 동작에 영향을 끼치는 클래스들로, 서비스 클래스의 특성으로 지정하거나, 환경 설정파일을 통해 지정할 수 있습니다.

Behavior와 관련된 여러 가지 내용 중 이번 포스팅에선 동시성(Concurrency)에 대해서 얘기해보도록 하겠습니다.

동시성이라 함은, 여러 task 들이 동시에 동작하는 것을 말합니다.
동시성은 다들 아시겠지만, 그리고 아주 당연하게도 시스템의 throughput(출력률)에 큰 영향을 끼칩니다. 일정 시간동안 처리할 수 있는 작업의 양이 커지기 때문이죠.

WCF 에서는 동시성을 컨트롤할 수 있는 두 종류의 behavior 가 있습니다. 바로 “InstanceContextMode”“ConcurrencyMode” 입니다.

InstanceContextMode는 생성되는 서비스의 인스턴스를 조절할 수 있는 behavior로 다음과 같은 세 종류의 값으로 설정할 수 있습니다.

  • Single : 이 값은 서비스로 들어오는 모든 요청을 하나의 인스턴스에서 처리하도록 설정합니다.
  • PerCall : 서비스로 들어오는 요청마다 서비스의 인스턴스가 만들어지도록 하기 위한 설정입니다.
  • PerSession : 클라이언트 세션마다의 서비스 인스턴스를 생성하기 위한 설정이며, 만약 세션을 사용하지 않는 채널일 때, 이 값으로 설정이 된다면, PerCall과 같은 방식으로 동작합니다.

그리고, InstanceContextMode의 기본값은 PerSession으로 따로 어떠한 값도 설정되어 있지 않은 경우엔 세션 수에 따라 서비스 인스턴스가 생성됩니다.

WCF에서 동시성을 조절할 수 있는 또 다른 모드인 ConcurrencyMode는 하나의 서비스 인스턴스 내에서 동작하는 스레드를 통한 동시성을 컨트롤하는 behavior입니다.
다음은 ConcurrencyMode에서 설정할 수 있는 값에 대한 설명입니다.

  • Single : 하나의 서비스 인스턴스 내에 오로지 하나의 스레드만이 동작하도록 설정하는 값입니다. 따라서, 이 값으로 설정되어 있는 경우엔 스레딩 문제를 고려하지 않아도 된다는 장점이 있습니다.
  • Reentrant : 이 설정 역시 하나의 서비스 인스턴스에서 하나의 스레드만이 동작하도록 하는 설정값입니다. 하지만, 이 설정값이 Single과 다른 점은 하나의 스레드가 동작하는 도중에 다른 작업이 처리될 수 있다는 것입니다. 이 작업의 처리가 완료되면 이 전의 작업이 계속해서 동작됩니다.
  • Multiple : 하나의 서비스 인스턴스에서 하나 이상의 스레드가 동작할 수 있도록 하는 설정입니다. 이 값으로 설정되어 있는 경우엔 여러 개의 스레드에서 서비스 개체를 변경할 수 있기 때문에 항상 동기화와 상태 일관성을 처리해 주어야 합니다.

ConcurrencyMode와 InstanceContextMode의 값을 적절하게 조합하면, 서비스의 기능에 맞게 동시성과 인스턴스 관리를 할 수 있습니다. 지금 이러한 내용을 글로 써내려가봤자 설명하기도 힘들고, 받아들이기도 힘이 들겁니다. 따라서 이러한 내용은 역시 실제 코드를 작성하고, 결과를 보면서 이해하는게 가장 쉽고 빠른 방법이겠죠 ^^

네~ 이제 InstanceContextMode와 ConcurrencyMode의 값을 적절하게 조합하여 서비스에 적용하는 실습을 해보도록 하겠습니다.

우선, 가장 먼저 세션을 사용하지 않는 환경에서 InstaceContextMode와 ConcurrencyMode의 기본값을 사용한 서비스를 구현해보겠습니다. InstanceContextMode의 기본값은 PerSession 이며, ConcurrencyMode의 기본값은 Single 입니다. 이 기본값은 따로 설정해주지 않아도 적용된다는거 아시죠? ㅎ

다음은 서비스를 구현한 클래스의 코드 입니다.

class ProductService : IProductService

{

    ProductService()

    {

        Console.WriteLine("{0}: 서비스의 새로운 인스턴스 생성!!", DateTime.Now);

    }

 

    public Product GetProduct()

    {

        Console.WriteLine("{0} : GetProduct 호출, Thread Id {1}", DateTime.Now,
Thread.CurrentThread.ManagedThreadId);

        Thread.Sleep(5000);

 

        Product p = new Product();

        p.ProductId = 1234;

        p.ProductName = "ABC Chocolate";

        p.Price = 1500.0;

        p.Company = "Lotteee";

        p.CreateDate = DateTime.Parse("2010-01-22");

 

        return p;

    }

}


저번 포스팅에서 사용했던 서비스의 코드를 살짝 수정 해보았습니다.
서비스 클래스 생성자를 만들어 단순하게 인스턴스가 생성되었다는 메시지를 출력해주는 코드를 추가하였구요, GetProduct 메서드 내에서는 현재 스레드의 ID 값을 출력해주는 코드를 추가하였습니다.

다음은 이 서비스를 호출하는 클라이언트 코드입니다. 코드를 보시면 아시겠지만 클라이언트에서 서비스 메서드를 비동기로 호출하고 있습니다. 혹시 WCF 서비스를 비동기로 호출하는 클라이언트를 만들어보시지 않은 분이 계시면 제가 예전에 올렸던 포스팅을 참고해주시기 바랍니다. (http://ruaa.tistory.com/entry/async-call) 자세한 설명은 없지만 대충은 이해하실 수 있으실겁니다 ^^;;

namespace MySvcAsyncClient

{

    class Program

    {

        static int c = 0;

        static void Main(string[] args)

        {

            ProductServiceClient proxy = new ProductServiceClient();

            for (int i = 0; i < 3; i++)

            {

                Console.WriteLine("{0}: GetProduct 메서드 호출", DateTime.Now);

                proxy.BeginGetProduct(GetProductInfoCallback, proxy);

                Thread.Sleep(100);

                Interlocked.Increment(ref c);

            }

            while (c > 0)

            {

                Thread.Sleep(100);

            }

        }

 

        static void GetProductInfoCallback(IAsyncResult ar)

        {

            ProductInfo productInfo = ((ProductServiceClient)ar.AsyncState)
                                           .EndGetProduct(ar);

            Console.WriteLine("{0} : ProductName : {1}",
                                        
DateTime.Now, productInfo.Name);

            Interlocked.Decrement(ref c);

        }

    }

}


Main 메소드 내에서는 for 문을 사용하여 3번 반복하여 GetProduct 메소드를 비동기로 호출하고 있으며, 각각의 비동기 호출에 의한 작업이 끝이 나면 AsyncCallback 대리자인 GetProductInfoCallback 메소드가 호출되며, 서비스에서 받은 Product 데이터를 화면에 출력해줍니다.

이렇게 코드를 작성하고 나면, 역시 결과가 궁금해 질겁니다. 다음은 이 코드에 대한 결과 화면입니다.

[서버]


[클라이언트]


클라이언트 측 결과 화면을 보면 동시에 서비스의 메소드를 세번 호출하는 것을 확인할 수 있습니다. 그리고 6초 정도의 시간 후에 차례대로 결과값을 가져와서 출력하는 것을 볼 수 있습니다.

서비스 측 결과 화면을 확인해 보면, 각 호출마다 생성자를 통해 새로운 인스턴스를 생성하고, 인스턴스 내에 하나의 스레드를 통해 GetProduct 메소드를 호출하는 것을 확인할 수 있습니다.

여기서 잠깐 의문이 들지도 모르겠습니다. 제가 분명, InstanceContextMode의 기본값은 PerSession 이라고 했는데 왜 서버에선 클라이언트의 호출마다 새로운 인스턴스를 생성한 것일까요?

답은 아주 간단합니다. 서비스를 호스팅할 때 사용했던 binding의 종류가 BasicHttpBinding 이었던 것 기억하시나요? BasicHttpBinding의 경우엔 세션을 사용하지 않기 때문에, 이 경우엔 실제로 InstanceContextMode.PerCall 과 같은 형식으로 동작하게 되는 것입니다.

기본값으로 설정한 경우를 알아봤으니, 이번엔 두 모드의 값을 바꿔서 서비스에 적용해보겠습니다.

인스턴스는 모든 호출에 대해 하나만 생성하도록하고, 스레드의 갯수는 하나 이상으로 만들 수 있게끔 설정한 후에 결과값을 살펴보죠~

앞에서 한번 언급했지만 서비스의 Behavior를 적용하는 방법은 서비스 클래스에 특성으로 설정하는 방법과 config 파일에 설정하는 방법이 있습니다. 여기서는 클래스에 특성으로 설정하는 방법을 사용해보겠습니다.

서비스 클래스의 코드를 다음과 같이 굵은 글씨로 적용된 부분만을 추가해보죠~

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,

            ConcurrencyMode=ConcurrencyMode.Multiple)]
class ProductService : IProductService

{

    ProductService()

    {

        Console.WriteLine("{0}: 서비스의 새로운 인스턴스 생성!!", DateTime.Now);

    }

 

    ... 생략 ...

}


이렇게만 수정한 후에 솔루션을 실행시켜 보면, 클라이언트 측 화면은 변화가 없지만 서버 측 결과 화면은 다음과 같이 변화된 것을 확인하실 수 있으실겁니다.



달라진 점이 무엇인지 보이시죠? ^^

네,, 맞습니다. 인스턴스가 하나만 생성되었다는 점이죠. 아~ 그러고보니 동작한 스레드의 ID 값들이 모두 다른 것도 보이네요. 이 말은 곧, 하나의 인스턴스에 여러 개의 스레드가 생성되었다는 것을 의미하는 것이겠죠. 앞에서 설정했던 InstanceContextMode의 값과 ConcurrencyMode의 값이 어떻게 서비스의 동시성에 적용되었는지 이해가 가실겁니다.

이 외에도 서비스의 동시성에 적용할 수 있는 두 모드의 조합이 더 있지만, 다음 포스팅에서 더 다루도록 하겠습니다. 글도 길어졌고, 아직 담아야 할 내용도 많으니깐요.
이번에는 정말 다음 포스팅때 까지 많이 걸리지 않을 것입니다. 약속드릴께요~ ^^;;

제 포스팅에 항상 댓글 남겨주시고 응원해주시는 분들께 감사 드리며, 또 너무 오랜만에 글을 남겨 죄송한 마음도 듭니다. 제가 잠깐 주춤하긴 했지만, 앞으로는 계속 꾸준한 모습 보여드리려 노력하겠습니다. ^^

감사합니다.

WCF의 기본 <Contract> - Data Contract

WCF 2010. 2. 9. 09:00 Posted by 알 수 없는 사용자
2010년도 어느새 한달이 지나가고 두번째 달이 되었습니다. 한달 한달이 왜 이렇게도 빨리 지나가는지... 할 일은 많은데 시간만 무심하게 지나가는 것 같습니다... 드래곤 볼의 "시간의 방" 같은 곳이 있었으면 하는 허무한(?) 생각도 들고.. ㅎ

이번 포스팅은 저번 주제에 이어서 Contract 중 Data Contract에 대해 이야기 해볼까 합니다.

간단히 얘기하면, Data Contract는 WCF 서비스에서 사용하는 개체에 대한 정보를 클라이언트에서 인지할 수 있게끔 XSD 형태로 매핑시켜주는 역할을 합니다.
저번 포스팅에서 충분히 설명했듯이 클라이언트에서는 서비스에 대한 정보를 WSDL을 통해 얻게 됩니다. 이때, 서비스에서 사용하는 개체에 대한 정보 역시 이 WSDL을 통해 전달되는데, 이렇게 XSD 형태로 매핑시켜주는 역할을 하는 것이 Data Contract 입니다.

그럼, 일단 코드를 한번 보고 설명을 이어 나가겠습니다. 역시, 말보다는 코드를 봐야 "아~ 이게 Data Contrat 구나~" 하실겁니다,, ㅋ

저번 포스팅에서 만들었던 서비스에 다음과 같이 Product라는 이름의 새로운 클래스를 추가하였습니다.

using System.ServiceModel;

using System.Runtime.Serialization;

 

namespace MyService

{

    [DataContract]

    public class Product

    {

        [DataMember]

        public int ProductId;

 

        [DataMember]

        public string ProductName;

 

        [DataMember]

        public string Company;

 

        [DataMember]

        public double Price;

 

        [DataMember]

        public DateTime CreateDate;

    }

}

ServiceContract 속성을 줬듯이 DataContract 속성(attribute)은 서비스에서 사용할 새로운 클래스에 지정해 주면 됩니다. 그리고 이 클래스의 필드들에겐 DataMemer 속성을 줬습니다.

이제 이 클래스를 서비스에서 사용하도록 기존 서비스의 코드를 다음과 같이 살짝 바꾸었습니다.

[ServiceContract(Namespace = "http://RuAAService.co.kr/")]

interface IProductService

{

    [OperationContract]

    Product GetProduct();

}

class ProductService : IProductService

{

    public Product GetProduct()

    {

        Product p = new Product();

        p.ProductId = 1234;

        p.ProductName = "ABC Chocolate";

        p.Price = 1500.0;

        p.Company = "Lotteee";

        p.CreateDate = DateTime.Parse("2010-01-22");

 

        return p;

    }

}


사용하는 방법은 특별히 따로 존재하지 않습니다. 다른 클래스들 처럼 그냥 사용하면 되는 것입니다. 여기서 조금 주목해야할 점은 GetProduct 메소드의 반환 타입이 우리가 새로 생성한 Product 클래스라는 것입니다.

Product  클래스는 서비스에서 생성한 클래스이기 때문에 클라이언트에선 알 수 없는 타입이겠죠. 서비스를 이용하는 프로그램이 아닐때는 그냥 참조 추가를 이용해 dll 파일을 참조하여 다른 클래스를 사용할 수 있지만, 서비스를 사용할 땐 이 방법을 쓸 수는 없습니다.

이러한 문제(?)를 해결하는 방법이 바로 wsdl에 이 클래스에 대한 정보를 추가하여 클라이언트에서 인지할 수 있게 하는 것인데, 이걸 Data Contract가 해주게 되는 것입니다.

그럼, 이 클래스에 대한 정보를 닷넷 컴파일러가 어떤 형태의 xsd로 매핑시켜주는지 눈으로 확인해 보겠습니다.

서비스를 실행시킨 상태에서 브라우저를 이용하여 http://localhost:8000/ProductService?wsdl=wsdl0 위치로 이동해 봅니다. 그럼, <wsdl:types> 라는 엘리먼트를 볼 수 있고, 그 밑에 서비스에서 사용하는 여러 가지 스키마에 대한 정보를 명시한 엘리먼트를 확인할 수 있습니다.


이 스키마들 중에 http://localhost:8000/ProductService?xsd=xsd2 위치로 이동해보겠습니다. 그럼 다음과 같은 내용을 확인할 수 있을 것입니다.


complexType 엘리먼트는 우리가 생성한 클래스의 이름을 나타내고 있고, 그 밑으로는 클래스의 멤버들에 대한 정의가 엘리먼트로 포함되어 있는 것을 확인할 수 있습니다.

이제 어떻게 클라이언트에서 이러한 클래스에 대해 인지할 수 있는지,, 아시겠죠? ^^

아~ 참고로 클래스의 필드들을 DataMember 속성을 이용해 노출을 했었는데, 만약 필드에 DataMember 속성을 적용시키지 않으면 아예 노출이 안된다는 것을 유념해주시기 바랍니다.
그리고, 필드들의 한정자가 public 이든, private 이든 이 역시 상관없다는 것도 알아두시면 좋을 것 같습니다. 오로지 DataMember 속성이 적용되었는지만 신경을 써주시면 됩니다.

DataContract 와 DataMember는 몇 개의 프로퍼티(property)를 가지고 있습니다.

DataContract는 Name과 Namespace 프로퍼티를 가지고 있는데, 이는 ServiceContract가 가지고 있는 프로퍼티와 같은 역할을 하는 녀석들이기 때문에 따로 긴 설명을 필요없을 듯 합니다.

그리고, DataMember 는 Name, Order, IsRequired 라는 프로퍼티들을 가지고 있습니다.
Name은 클라이언트에 노출되는 멤버의 이름을 명시적으로 설정하는 역할을 하구요, Order는 클라이언트에 멤버들이 노출될 때 그 순서를 정하는 역할을 수행합니다. (이 순서를 명시적으로 설정하지 않으면 기본적으로 멤버들은 알파벳 순으로 xsd에 나타나게 됩니다.) 사실 .NET 어플리케이션 끼리는 이 순서가 그리 중요하지 않습니다. 하지만 다른 플랫폼의 어플리케이션 간의 상호 운용성을 고려할 땐 중요할 수가 있습니다. 클라이언트로 부터 메시지를 받았을 때, 이 순서가 다르면 서버에선 인식할 수가 없게 되어버리거든요.
IsRequired는 멤버가 적어도 한번은 포함이 되어야 하는지에 대한 정의를 내려주는 역할을 합니다. 이 프로퍼티의 값이 true인 경우엔 설정된 멤버는 메시지에 적어도 한번은 꼭 포함되어야 함을 의미하는 것이죠~

그럼, 이러한 속성들을 적용했을 때, 어떻게 xsd로 표현되는지 한번 보도록 하겠습니다.
Product 클래스를 다음과 같이 살짝 수정해보았습니다.


[DataContract (Namespace="http://RuAAService.co.kr/Product", Name="ProductInfo")]

public class Product

{

    [DataMember(Name = "ID", Order = 1, IsRequired = true)]

    public int ProductId;

 

    [DataMember(Name = "Name", Order = 2, IsRequired = true)]

    public string ProductName;

 

    [DataMember(Order = 3)]

    public string Company;


   
[
DataMember(Name = "Value", Order = 4, IsRequired = true)]

    public double Price;

 

    [DataMember(Order = 5, IsRequired = true)]

    public DateTime CreateDate;

}

이제 xsd를 어떻게 확인하시는지 아시죠? xsd를 확인해 보면 다음과 같이 나타남을 확인할 수 있으실 겁니다.


complextType 엘리먼트에 name 속성의 값이 바뀌고, 네임스페이스의 값도 바뀌고,, 여러가지가 바뀐 것을 확인할 수가 있습니다. 프로퍼티 설정과 xsd를 비교해가면서 어떻게 적용되는지 유심히 살펴보시기 바랍니다. ^^

Company 멤버의 경우 IsRequired 속성을 따로 명시해주지 않았는데, 이 경우엔 minOccrus=0 으로 표현되는 것을 볼 수가 있습니다. 이게 기본값이며, 포함되지 않아도 됨을 나타내주는 것이죠~

이렇게 해서 Data Contract에 관한 기본적인 내용은 끝이 난 것 같습니다.

마지막으로, 수정한 이 서비스를 이용하도록 클라이언트 코드 역시 수정을 조금 해보구요~ 결과 화면을 보는 것으로 이번 포스팅을 마치도록 하겠습니다.

수정한 클라이언트의 코드는 다음과 같습니다.

static void Main(string[] args)

{

    // 프록시 클래스 인스턴스 생성

    ProductServiceClient myService = new ProductServiceClient();

    // 서비스 Operation 호출

    ProductInfo product = myService.GetProduct();

 

    Console.WriteLine("Product ID : {0}", product.ID);

    Console.WriteLine("Product Name: {0}", product.Name);

    Console.WriteLine("Made by :{0}", product.Company);

    Console.WriteLine("Price : {0:c}", product.Value);

    Console.WriteLine("Created Date : {0}", product.CreateDate.ToShortDateString());

}

이 코드에 대한 추가적인 설명은 필요없겠죠? 이제 다들 "이까이꺼~" 하실테니깐,, ^^

수정을 모두 완료한 후에 서비스와 클라이언트를 동시에 실행시키면 다음과 같은 결과 화면을 확인하실 수 있으실 겁니다. 


네~ 무사히 서비스에서 Product 클래스에 대한 데이터를 받아왔고, 이 데이터를 화면에 잘 뿌려주는군요...

아직까지는 WCF의 기본이 되는 내용에 대해서만 포스팅을 하고 있기에 그렇게 어렵지 않으실 거라 생각합니다.
저도 WCF에 대해 마스터하지 못하였지만, WCF를 이제 시작하는 분들께 조금이라도 도움이 되었으면 하는 마음으로 포스팅을 하고 있는 것이라, 아주 기본이 되는 내용들을 주제로 진행하고 있습니다.

이렇게 하나씩 채워나가다 보면, 언젠가 좀 더 복잡한 주제로 포스팅을 할 수 있는 시간도 올꺼라 생각합니다.
너무 조급해하지 마시고 따뜻한 시선으로 지켜봐주셨으면 합니다.
(뭐,, 질책이나 조언도 감사한 마음으로 받겠습니다 ^^)

그럼, 다음 포스팅때 뵙겠습니다 ^^

기본 WCF 프로그래밍 - 첫 WCF 서비스 만들기 2

WCF 2010. 1. 18. 10:00 Posted by 알 수 없는 사용자
요즘, 날씨가 심상치 않습니다. 세계적으로 여기저기서 한파, 폭설로 난리도 아니더군요~
몇몇의 과학자들은 지구가 예전 온도를 찾기 위한 자정작용을 하고 있는 것이라 하는데,,
어쨌든 지구가 정상이 아니란 건 사실인 것 같습니다.
설마,, 2012년에 정말 지구가 멸망하는건 아니겠죠? ^^;;;;;

WCF 세번째 이야기를 시작하겠습니다~ ^^
이번에는 지난 포스팅때 다 하지 못한 내용에 대해 이야기를 해볼까 합니다.
지난 포스팅에서는 Console 어플리케이션을 이용하여 간단한 WCF 서비스를 구현하였었죠,,
서비스를 구현하였으니, 이제 이 서비스를 이용할 수 있는 클라이언트를 구현해야 할 때입니다.

클라이언트도 Console 어플리케이션을 이용해보도록 하겠습니다. 지난번 서비스를 만들었던 같은 솔루션내에 새로운 프로젝트를 추가합니다. (새로운 솔루션을 만들어도 상관은 없습니다 ^^) 아래 그림과 같이 저는 "MyServiceClient"라는 이름의 콘솔 어플리케이션 프로젝트를 추가 하였습니다.


다음으로 클라이언트 프로젝트에 지난번 만들었던 서비스를 참조 추가해야합니다. 서비스를 참조 추가하는 방법은,, 다들 예상 했겠지만,, 아!주! 쉽습니다. ㅎ
비주얼 스튜디오 Solution Explorer의 클라이언트 프로젝트에서 마우스 오른쪽 클릭을 해주면, 다음과 같은 메뉴가 나타납니다. 여기서 "Add Service Reference"를 선택합니다.


그러면, 서비스를 참조 추가할 수 있는 창이 뜹니다. 이 창의 Address 텍스트 박스에"http://localhost:8000/ProductService" 를 입력하고, "Go" 버튼을 클릭합니다. (방금 입력한 주소는 서비스 엔드포인트 주소입니다. 기억나시죠?? ㅎ) 이렇게 하면~ 서비스를 찾는 메시지가 뜨고 얼마 뒤 다음 그림과 같이 서비스를 찾았다는 메시지가 뜨는 것을 확인할 수 있습니다.
참~!! 이때, 아주 당연한 얘기지만, 서비스가 실행 중이어야 합니다. ctrl + F5 를 눌러 서비스를 실행하는 콘솔 창을 띄워놓은 상태에서 서비스를 찾아야 합니다.


Namespace 텍스트 박스엔 "ServiceReference1"이라고 적혀있지만, 이는 개발자 마음대로 변경 가능합니다. 그래서, 저는 "MyService"라고 수정 후에 "OK" 버튼을 클릭하였습니다.

이 작업을 모두 완료하면 Solution Explorer의 모습이 다음 그림과 같이 조금 바뀌게 됩니다.


"Service Reference" 라는 폴더가 새로 생겼고, 그 밑에 방금 등록했던 "MyService"가 추가 되어있는 것을 확인할 수 있습니다.
이로써, 클라이언트에서 서비스를 사용할 준비는 거의 끝났습니다. 너무 쉬운가요? ^^ 

그렇습니다. 아주 쉽죠,, 이렇게 개발자가 쉽게 작업을 할 수 있는 건 역시 대부분의 일을 비주얼 스튜디오가 자동으로 해주는 일이 많기 때문입니다.

비주얼스튜디오가 자동으로 해주는 일은 바로, 서비스와 통신할 수 있는 proxy 클래스를 생성 해 주는 것입니다. 이는 예전 닷넷 웹서비스를 참조 했을 때, proxy 클래스를 생성해 주던 것과 아주 비슷합니다. 여기서 이에 대한 자세한 얘기는 생략하려 합니다. 저도 자동으로 생성되는 개체에 대해선 모르는 것이 많기도 하고, 여기서 이런 얘기까지 하는건 조금 초점이 빗나가는 이야기가 될 것 같기도 하거든요,,^^;;

어쨌든, 서비스와 통신을 할 수 있는 준비가 거의 끝났다는데 큰 의미가 있는 것 같습니다. ㅎㅎ

아ㅡ 본격적으로 서비스를 이용하기 전에 한가지 더 얘기를 하고 넘어가야할 것이 있습니다.
비주얼스튜디오에서 쉽게 서비스를 참조 추가할 수 있었던 또 다른 이유,, 바로 Metadata Exchange Endpoint 입니다.

WCF의 Metadata라 함은, WCF 서비스와 통신하는 방식을 설명한 것이라고 간단하게 생각하시면 됩니다. 그러면 MEX(Metadata Exchange Endpoint) 가 무엇인지 대충 감이 오시나요?

네,, 추측하신대로 이러한 메타데이터를 교환하기 위한 엔드포인트를 말합니다. 클라이언트에서 이 MEX로 요청 메시지(request message)를 보내면, MEX 에서는 서비스가 가지고 있는 엔드포인트에 대한 내용과 메시지의 포맷에 대한 내용을 WSDL 형태로 클라이언트에 전송해 주는 것입니다.

비주얼 스튜디오에서 "서비스 참조 추가"를 실행하였을 때, 프록시 클래스와 config 파일을 생성해 주는 것은 모두 MEX에서 보내준 WSDL을 이용한 것이죠~

MEX에 대해서까지 설명을 들으니, 클라이언트와 서비스가 통신하는 방법에 대한 그림이 대충 그려지지 않으시나요?ㅎ

그럼, MEX를 정의하지 않으면 WCF 서비스와 통신하지 못할까요?

꼭 그렇지만은 않습니다. 물론, 비주얼 스튜디오에서 지원해주는 "서비스 참조 추가"를 이용하진 못합니다.
하지만, svcutil.exe 라는 명령어를 이용하여 프록시 클래스를 생성해 줄 수 있고, 이를 통해 서비스와 통신할 수 있습니다. 이 명령어에 대해서도 정리할 수 있는 시간을 가질 예정이지만, 지금 당장은 그렇게 자세히 알 필요는 없을 듯 합니다. 우리에겐 Visual Studio 라는 훌륭한 툴이 있으니깐요~ ㅎ 
(개발자는 너무 툴에 종속적이면 좋지 않다 생각하고는 있지만,,, ^^;;;)

이제, 드디어,, 서비스에 정의 되어 있는 메소드를 호출하고 사용해 볼 시간이 왔습니다.

using MyServiceClient.MyService;

namespace MyServiceClient
{
    class Program
    {
        static void Main(string[] args)
        {
            ProductServiceClient proxy = new ProductServiceClient();
            string strResult = proxy.GetFirstName("WCF");

            Console.WriteLine(strResult);
        }
    }
}

위의 코드는 클라이언트 Console 어플리케이션의 Program.cs 파일 내용입니다.

using 구문을 이용하여 포함시킨 MyServiceClient.MyService 네임스페이스는 비주얼 스튜디오에 의해 생성된 프록시 클래스의 네임스페이스입니다.
이 네임스페이스에서 상위 네임스페이스는 서비스에 정의 된 네임스페이스에 "Client"가 붙은 형태로 생성되며, 하위 네임스페이스는 서비스 참조 추가를 할 때 입력하여 준 것과 동일한 형태로 생성되어 집니다.

그리고, ProductServiceClient 클래스는 비주얼 스튜디오에 의해 생성된 프록시 클래스 입니다. 이 클래스를 이용하면 서비스에 정의되어 있는 메소드들을 클라이언트에서 맘껏 사용할 수 있게 되는 것입니다. 아래와 같은 방식으로 말이죠~ ^^
string strResult = proxy.GetFirstName("WCF");

이로써, 클라이언트에 작성할 것도 모두 다 했습니다.

그럼, 실행을 한번 시켜 보도록 하죠~

현재, 솔루션에서 서비스 프로젝트와 클라이언트 프로젝트가 모두 동작해야 되기 때문에 솔루션의 속성을 조금 변경할 필요가 있습니다. 
아래 그림에서 볼 수 있듯이, 솔루션 속성 창에서 "Multiple startup projects"를 선택하고 두 개의 프로젝트 모두 "Start" 하도록 값을 변경하여 줍니다.


이제 실행만 하면 됩니다. 과감하게~ F5 키를 눌러 실행을 시켜 보죠~
아래와 같은 화면이 나타납니다. 두둥~~!!


결과 화면을 보고 실망하셨나요?? ^^;;
지금까지, 길~게 설명한 것에 비하면 결과는 아주 보잘것 없습니다. 하지만, 실망(?)하지 마시기 바랍니다 ^^;
처음부터 이 서비스는 아주 아주 간단한 서비스라고 말씀 드렸었고, 이 간단한 서비스를 이용해 우리는 WCF 에 대한 큰 그림을 그릴 수 있었으니깐, 결코 실망스러운 결과는 아닙니다.

이렇게 해서 WCF의 기초에 대해선 모두 끝이 났습니다.
글을 이용하지 않고, 옆에서 말로 설명을 했다면, 금방 끝날 수 있는 내용을 두 개의 포스팅에 걸쳐 설명을 했습니다. 
이렇게 하고 나니, 글을 이용해 정보를 전달한다는 것이 결코 쉬운 일이 아니란 것을 새롭게 깨닫게 되면서, 파워 블로거분들이 존경 스러워 지네요 ^^

포스팅을 시작한지 얼마되지 않아 많이 부족하지만, 꾸준히 하다보면 저도 다른 분들처럼 멋진 글을 쓸 수 있는 날이 오겠죠~ㅎㅎ 그때까지 포기하지 않고 열심히 하겠습니다 ^^

그럼, 다음 포스팅때 뵙겠습니다~

기본 WCF 프로그래밍 - 첫 WCF 서비스 만들기

WCF 2010. 1. 8. 09:00 Posted by 알 수 없는 사용자
새해가 밝았습니다. (조금 늦었지만,, ;;;;)
올해는 60년 만에 찾아 온  백 호랑이의 해라고 하죠~ 
식상한 멘트일 것 같지만, 백 호랑이의 기운을 받아 올 한해 모두 바라는 일 이루시길 바라겠습니다. ^^

오늘은 WCF 두 번째 시간으로 WCF의 기본에 대해 알아보고, 간단한 WCF 서비스를 만들어보도록 하겠습니다.

지난 포스팅에서 WCF가 웹 서비스와 비슷하게, 분산 어플리케이션을 쉽게 개발할 수 있는 .NET 기술이라고 설명했었습니다.
분산 어플리케이션은 많은 분들이 아시겠지만, 특정 기능을 수행하는 서버 프로그램과 그리고 이 서버 프로그램을 호출하는 클라이언트로 이루어져 있는 이러한 구조를 가집니다. (쉽게 웹 서비스를 사용하는 어플리케이션 구조를 생각하면 될 것 같습니다.)

물론, WCF도 예외는 아닙니다. WCF는 크게 클라이언트와 서버 프로그램,, 그러니깐 WCF 서비스로 나눌 수 있습니다. (이제부터는 서버 쪽 WCF 프로그램을 WCF 서비스(또는 서비스)라고 지칭하겠습니다.) 

이러한 구조에서 클라이언트와 서비스는 메세지를 주고 받기 위해 아래 그림과 같이 Endpoint 를 제공합니다.


Endpoint라,, 약간 생소한 단어죠? ㅎ,,  endpoint는 WCF 에서 새롭게 정의되어진 단어로서 서비스에 접근할 수 있는 interface라 생각하면 될 것 같습니다. Endpoint를 "종단점"이라고 해석하던데, 개인적으로는 종단점보다는 엔드포인트(endpoint)가 더 와닿는 것 같아서 잘 안씁니다 ㅎ

엔드포인트는 Address, Binding, Contract 세가지의 구성 요소로 이루어집니다. (이를 "WCF 서비스의 ABC" 라고 기억하시면 됩니다.)

그럼, 각 요소들에 대해 좀 더 자세한 설명을 해보겠습니다.

  • Address (Where) : Address는 말 그대로 주소입니다. 서비스가 어디에 있는지에 대한 정보를 나타내는 것으로 메세지가 보내어져야 하는 곳을 말합니다. 메세지 전송을 위해 HTTP 프로토콜을 사용한다면 address는 "http://myserver/myservice/" 와 같은 모습을 할 것이며, 만약, TCP 프로토콜을 사용한다면 "net.tcp://myserver:8080/myservice" 와 같이 표현될 수 있습니다.
  • Binding (How)BindingChannel을 정의합니다. Channel이란 메시지를 주고 받기 위한 여러 프로토콜을 명세하는 것을 말하는데, 여기에는 메시지를 전송하기 위한 전송 프로토콜, 보안의 적용 여부 그리고, 트랜잭션의 지원 여부 등이 포함됩니다. 전송 프로토콜의경우 HTTP, TCP, Named Pipes, MSMQ 등을 지원하여 서비스의 목적이나 환경에 따라서 적절하게 사용할 수 있다는 장점이 있습니다.
  • Contract (What)Contract는 서비스의 operation에 필요한 메시지의 포맷을 정의합니다. 좀 더 쉽게 설명하자면, 메시지의 포맷이란 결국 서비스에서 제공하는 메소드와 이 메소드의 매개변수를 정의한 것입니다.(서비스가 제공하는 기능들을 정의한 것이라고 볼 수도 있겠네요~^^) 실제로, 이후에 WCF 서비스를 만들어보면 알겠지만 이 Contract에는 서비스가 제공하는 메소드를 정의한 인터페이스가 매핑되는 것을 볼 수 있을 것입니다.

위의 그림을 조금 발전시킨 그림입니다. WCF 서비스와 클라이언트는 특수한 상황이 아닌 경우 양방향 통신을 하기 때문에 클라이언트 역시 엔드포인트를 가지고 있어야 합니다. 물론, 서비스와 클라이언트의 엔드포인트는 각각 A,B,C를 정의해야 겠죠~!!

서비스를 개발하고, 엔드포인트까지 정의가 끝이 나고 나면, 이제 이 서비스를 호스팅(Hosting)해야 합니다. 마지막으로 호스팅 작업을 해줘야 서비스는 외부에서 접근할 수 있는 상태가 됩니다.

WCF는 서비스를 호스팅 하기 위해 여러 가지의 방법을 제공합니다. 가장 보편적인 방법으로 IIS Hosting이 있구요, 이 외에 Windows Service를 이용한 Hosting과 윈폼 또는 콘솔 어플리케이션을 이용해서 호스팅을 수행할 수도 있습니다
(호스팅 부분만 다루더라도 내용이 많기 때문에 여기서는 간단하게 설명하고 넘어가도록 하겠습니다. 물론, 차후에 이 주제로 포스팅을 할 예정이니 Don’t worry about that~!! ^^;;)

여기서도 WCF의 장점이 팍팍 느껴지지 않으시나요? ^^ 
기존 웹 서비스의 경우에는 항상 IIS를 사용해야 했었고, 그 덕분에 http 프로토콜 만을 이용할 수 밖에 없었죠. 하지만, WCF 서비스는 여러 방식을 통해 호스팅 할 수 있는 장점을 가짐으로써, 적시적소에 서비스를 적용할 수 있는 큰 장점을 제공해 주는 것입니다. 더군다나, 이러한 것들을 개발자가 쉽게 개발할 수 있도록 해주었다는 것 역시 WCF의 큰 장점입니다. (보면 볼수록 너무나도 매력적인 플랫폼이에요~ ^^*)

일단, 기본적인 사항은 여기까지 설명을 하구요, 나머지는 실제로 간단한 WCF 서비스를 만들어보면서 추가적으로 설명을 하겠습니다.
다음으로 넘어가기 전에, 아래와 같은 내용을 다시 한번 되새김질(?) 하고 넘어가도록 하죠~ ^^

서비스를 개발하기 위해선,,
  • 서비스가 제공하는 기능들을 정의 한 Contract 가 존재해야 한다.
  • 서비스에 접근하기 위한 엔드포인트가 필요하며, 엔드포인트는 Address, Binding, Contract 로 구성되어 있다.
  • 서비스를 노출하기 위해 서비스를 호스트 해야하며, WCF는 호스팅을 수행하기 위한 여러가지 방식을 제공해 준다.

이제~ 간단한 WCF 서비스를 개발해 볼까요? 


간단한 WCF 서비스 개발하기

앞에서도 설명을 했었지만, WCF 서비스는 호스팅을 위한 여러 방법이 존재합니다. 처음으로 만드는 이 WCF 서비스는 여러 방법 중 Console 어플리케이션을 이용한 방법으로 간단하게 만들어볼까 합니다. (이 방법이 가장 심플하니깐요~ 흣,,)
여기서는 아주*10000 간단한 서비스를 만들어볼꺼구요, “WCF 서비스가 어떤 모습을 하고 있는지,,” 정도만 알고 넘어가시면 될 듯 합니다.

우선, VS2010에서 Console Application 프로젝트를 생성합니다. (아,, 개발 언어는 C#을 사용할 것입니다. 앞으로도 쭈~욱~~ )
그리고, 프로젝트에 아래 그림과 같이 각각 IProductService.cs, ProductService.cs 라는 이름을 가진  두 개의 파일을 추가 하였습니다.


IProductService는 인터페이스며, 서비스의 계약을 정의합니다. 서비스의 계약은 한마디로 서비스가 제공하는 여러 메소드를 정의하는 인터페이스라고 생각하시면 됩니다. 그리고, ProductService는 IProductService를 상속받아 실제 메소드를 구현하는 클래스입니다.

파일을 추가한 후에, 프로젝트에 System.ServiceModel.dll 어셈블리를 참조 추가합니다.
(System.ServiceModel.dll 에 WCF 서비스를 위한 대부분의 클래스들이 포함되어 있습니다. 앞으로도 계속 쓰이게 될 중요한 어셈블리죠~ ^^)

이제, 서비스를 개발 할 준비가 다 되었습니다. 먼저, IProductService 인터페이스 부터 구현해보겠습니다. 
(아래 코드에는 생략되었지만, using 문을 사용하여 System.ServiceModel 네임스페이스를 사용하도록 해주는 것도 잊지 마세요~)

[ServiceContract]
interface IProductService
{
    [OperationContract]
    string GetFirstName(string empID);
}

너무 간단한가요? ㅎ,, 
서비스의 계약을 정의해 주는 일은 봐서 알겠지만 아주 쉽습니다. 클래스에 "ServiceContract" 특성을 지정하고, 그 메소드에는 "OperationContract" 특성을 지정해 주는 것만으로도 계약을 정의해 줄 수 있습니다.이 외에 여러 옵션들을 줄 수 있지만, 차후에 다루게 될 것이니 이것만으로 넘어가겠습니다.
(다시 한번 강조하지만, 이번 WCF 서비스는 아주 간단한 서비스라는거~ 아시죠?? ^^)

다음으로 ProductService 클래스를 구현해보겠습니다.

class ProductService: IProductService
{
    public string GetFirstName(string empID)
    {
        return"Steve";
    }
}


음,, ProductService도 아주 아주 간단합니다. (제가 민망할 정도로,,~ ^^;;)
차후에 이 서비스를 수정해서 쓰긴 하겠지만, 지금은 별 다른 기능없이 단순하게 "Steve" 라는 문자열을 반환해주는 메소드를 구현하였습니다.
사실, 구현 부분은 지금 상황에서 그렇게 중요하지 않습니다.

서비스의 계약과 관련한 구현은 다 되었습니다. 이제 해야할 작업은 이 서비스를 호스팅하는 일이죠~
Console 어플리케이션을 이용하여 호스팅을 하기 위해서 Program.cs 에 관련 코드를 다음과 같이 추가 하였습니다.

using System.ServiceModel;
using System.ServiceModel.Description;

namespace MyService
{
    class Program
    {
        static void Main(string[]args)
        {
            Uri baseUri = new Uri("http://localhost:8000/ProductService");
            using(ServiceHost serviceHost = new ServiceHost(typeof(ProductService), baseUri))
            {
               //Add Service Endpoint
               serviceHost.AddServiceEndpoint(typeof(IProductService), new BasicHttpBinding(), "");
               
               //Add Metadata Behavior
               ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
               mexBehavior.HttpGetEnabled = true;
               serviceHost.Description.Behaviors.Add(mexBehavior);

               //Add Metadata Exchange Endpoint
               serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), 
                                              MetadataExchangeBindings.CreateMexHttpBinding(),"mex");
               serviceHost.Open();


               Console.WriteLine("Press <ENTER> to terminate WCFService.\n");
               Console.ReadLine();
            }
        }
    }
}

호스트 구현은 조금 코드가 길죠,, ^^;
사실, 서비스 자체만 호스팅 하는 코드는 그렇게 길지 않습니다. 하지만, 서비스에 Metadata Exchange Endpoint를 추가하려다 보니 코드가 조금 길어졌습니다. 

이 코드에서의 핵심은 ServiceHost 클래스입니다. ServiceHost 객체를 이용하면, WCF 서비스를 호스팅 할 수 있다는 사실을 마음 속 아니, 머리 속 깊이 넣어주세요~

ServiceHost 클래스의 생성자는 두 개의 파라미터를 받습니다.  첫번째 파라미터는 호스팅 하려는 클래스의 타입이며, 두번째 파라미터는 Base Uri 입니다. Base Uri는 말 그대로 서비스의 기본 주소(address)를 나타냅니다.

ServiceHost 객체를 생성한 후에는 이 개체에 AddServiceEndpoint 메소드를 이용하여 endpoint를 추가하여 줍니다.
AddServiceEndpoint 메소드는 기본적으로 세 개의 파라미터를 필요로 하는데, 이 파라미터가 앞에서 설명했던 Address, Binding, Contract 입니다.

Contract는 서비스의 계약을 정의 했던 IProductService 인터페이스를 지정하구요, BindingBasicHttpBinding 클래스를 사용하였습니다. BasicHttpBinding 클래스는 WCF에서 기본적으로 제공하는 여러 Binding 개체 중에 하나로 이름에서 알 수 있듯이 기본적인 Http 프로토콜을 사용합니다. 그리고, 마지막 Address 는 빈 문자열을 주었습니다. 이렇게 빈 문자열을 주게 되면 endpoint의 주소는 ServiceHost 개체를 만들 때 사용했던 Base Uri와 동일한 값을 가지게 됩니다.

Endpoint 추가까지 끝이 나면 호스트를 수행할 준비가 모두 끝납니다. 이제 ServiceHost 개체의 Open 메소드를 사용하여 서비스를 시작할 수 있는데, Open 메소드는 각 채널에 맞는 리스너(listener)를 별도의 스레드로 수행을 하여 클라이언트의 요청을 처리할 수 있게 합니다.

(혹시,, 제가 Metadata Exchange Endpoint 에 대한 설명은 살짝 넘어갈려고 한 걸 눈치 채셨나요? ^^;; MEX 에 대해선 다음 포스팅 때 꼭 설명을 하도록 할께요~ 한번만 눈 감아주시길,, ㅋ)

서비스 구현은 모두 끝이 났습니다. 한번 실행해 볼께요~

실행을 하면 다음과 같은 Console 창이 뜹니다.


이 창이 무사히 뜨면, 서비스가 아무 탈 없이 잘 동작하고 있다는 말입니다.
음,, 이것만 봐서는 믿음이 안 갈 수 있으니, 한번 검증해 보죠~ ㅎ,, 

이 콘솔 창을 그대로 띄워 놓은 상태에서 브라우저를 열고 주소창에 http://localhost:8000/ProductService (이 주소는 ServiceHost 개체를 생성할 때 입력했던 Base Uri 인거,, 기억하시죠? ^^) 를 입력해보겠습니다~
다음과 같은 내용을 확인할 수 있습니다. 짜잔~


이 화면은 어디서 많이 본 것 같죠?? 네,, 예전 .NET 웹 서비스를 만든 후 실행했을 때의 화면과 비스무리(??) 합니다~ ^^
(서비스가 잘 동작하고 있군요,, ㅎ)

이로써, 첫 WCF 서비스 만들기가 끝이 났습니다. 유후~~

이제 Client를 만들어야 되는데,,(흠,,) 글이 너무 길어진 것 같은,,;;;;; 
어쩔 수 없군요~ Client 구현은 다음으로,, (MEX 설명과 함께~ ㅎㅎ)

빠른 시일 내에 다음 포스팅을 올리도록 할테니, 너무 노여워 하지 말아주세요~ (기다리시는 분이 있을 것 같진 않지만,, ^^;;)

또 다시 강조하지만, 이번 포스팅의 목적은 "WCF 서비스는 어떤 식으로 구현하는가?" 에 있습니다.
따라서, WCF에 대해 전체적인 그림(?)을 그릴 수 있는 내용이 되었으면 해서 Binding 이나 Behavior 등 자세한 설명은 하지 않았습니다.
세부적인 설명들은 앞으로 차차 하게 될 것이니깐요,, (가야 할 길은 멀고도 험하죠,, ^^;;)

어쨌든 이 자료가 WCF를 시작하는 분들께 많은 도움이 되었으면 합니다.
그럼 다음 포스팅때 뵙겠습니다~ ^^

WCF란 무엇인가?

WCF 2009. 12. 29. 09:11 Posted by 알 수 없는 사용자

안녕하십니까? 이번에 새롭게 vs2010 team 에 합류하게 된 오태겸이라고 합니다. 
앞으로, WCF를 주제로 한 포스팅을 맡아서 활동을 하게 되었습니다. 
부족한 점이 많지만 열심히 활동 할테니 이쁘게(?) 봐주셨으면 합니다. ^^;;

이제, 첫 포스팅을 시작하도록 하겠습니다.

첫 포스팅의 주제는 “WCF란 무엇인가?” 입니다.

WCF는 “Windows Communication Foundation”의 약자로서, 이 이름만 보더라도 왠지 ‘여러 가지 Communication을 지원하기 위한 기술인 것 같다,,’ 라는 예상을 하게 됩니다.
네!! 맞습니다. WCF는 여러 가지 컴포넌트(응용프로그램, 서비스 등,,)와의 Communication을 쉽게 구현할 수 있도록 해주는, Microsoft에서 새롭게(이미 몇 년 지났지만,,^^;;) 개발한 기술입니다.

한마디로 정의하자면, WCF는 분산 어플리케이션 개발과 플랫폼에 상관없는 높은 상호 운용성을 지원하는 어플리케이션을 쉽게 개발할 수 있도록 해주는 기반 기술입니다.

분산 어플리케이션이란 단어는 이제 너무 친숙한 단어가 되었으며,  꽤 오랜 시간에 걸쳐 이러한 분산 어플리케이션을 쉽게 구현하기 위한 여러 가지 기술들이 개발되어왔습니다. 이러한 노력에 의해 CORBA(Common Object Request Broker Architecture), DCOM(Distributed Component Object Model), Web Service 등의 기술들이 개발되어 적용되어 왔으며, 특히, Web Service는 이 전의 기술에 비해 인터넷을 기반으로 높은 상호 운용성을 지원했기 때문에 많은 곳에서 활용되어 왔습니다.

Web Service가 많은 곳에서 환영(?)을 받고, 활용될 수 있었던 이유에는 아마도 XML이라는 인터넷 표준과 이를 기반으로 한 SOAP이라는 표준 프로토콜 사용에 있었다고 생각합니다. 앞에서도 언급했지만, 인터넷과 이러한 표준 기술들을 사용함으로써 좀 더 쉽게 높은 상호 운용성을 지원하는 분산 어플리케이션을 구현할 수 있었기 때문입니다.

저는 개인적으로, “Web Service를 대체할 만한 기술이 나오는 것은 당분간 어렵다-!” 라고 생각했었습니다. 하지만 Microsoft 에선 이런 저의 생각을 보기 좋게 뻥~! 차버렸습니다. 저의 생각이 너무 짧았던 거죠 (역시 난 아직 멀었어,, ㅡㅠ)

WCF와 처음 만났을 때(그리 오래되진 않았지만), WCF의 확장성과 상호 운용성에 조금 놀라기도 하고, 신기해 하기도 했었던 기억이 납니다.

이제 WCF의 장점에 대해 몇 가지 설명을 해보도록 하겠습니다.

우선, WCF의 클라이언트 및 서비스는 기본적으로 SOAP을 사용하여 통신하며, 서비스의 메타데이터를 전달하기 위한 방식으로 WSDL을 사용합니다. 이는 Web Service와 동일한 방식이며, 앞에서 언급한 Web Service가 널리 활용될 수 있었던 이유와 동일한 장점을 가지고 있습니다.

또한, 기존의 Microsoft의 분산 어플리케이션 개발 기술을 통합하여 사용할 수 있다는 장점도 가지고 있습니다.
예를 들어 WCF 와 기존의 .NET Web Service는 모두 SOAP을 사용하기 때문에 WCF 기반 응용 프로그램은 .NET Web Service에 구축된 응용 프로그램과 직접 상호 운용할 수 있습니다. 그리고, WCF 기반 응용 프로그램은 MSMQ(Microsoft Message Queue)를 이용하여 통신을 할 수 있기 때문에 기존의 MSMQ 인터페이스를 사용하여 구축된 응용 프로그램과도 직접 상호 운용할 수 있습니다.

이러한 장점 이외에 HTTP 통신 뿐만 아니라, TCP 통신을 사용할 수도 있다는 장점 등 WCF는 많은 장점을 가지고 있는 기술입니다.
앞으로, WCF에 대해 포스팅을 해 가면서 WCF의 많은 장점들을 보여드릴 예정이니 많은 관심과 격려 부탁 드리겠습니다 ^^*

음,, 글만 생각 나는대로 적다보니 조금 지루해지는 것 같습니다.
WCF의 아키텍처를 간단한 설명과 함께 그림으로 보여드리고 이번 첫 포스팅을 마칠까 합니다.

 

위 그림은 WCF의 아키텍처를 보여주고 있습니다.

WCF 를 처음 접하시는 분이라면, 이 그림을 보고 한번에 이해하기는 좀 어려울 것이라 생각합니다. 하지만, WCF에 대해 조금 알게 된다면 그렇게 이해하기 어려운 그림은 아닐 듯 합니다. (지금 이해하기 어렵다고 걱정할 필요는 없단 말이죠 ^^)

WCF의 아키텍처 중 계약 계층은 서비스에서 제공하는 실제 메서드를 정의하거나 서비스와 통신할 때 사용되는 메시지 또는 데이터를 정의하는 부분으로 서비스의 기본이 되는 계층입니다.

메시징 계층은 채널로 구성되며, 채널은 크게 전송 채널과 프로토콜 채널의 두 가지 유형으로 구분되어집니다.
전송채널은 메시지를 전송하기 위한 전송 프로토콜에 관한 채널을 정의하며, HTTP, TCP, 명명된 파이프 및 MSMQ가 있습니다.
프로토콜 채널은 메시지를 처리하기 위한 프로토콜을 구현합니다. WS-Security와 WS-Reliability 채널을 이용하여 메시지의 보안과 신뢰적인 전달을 위한 추가적인 기능을 정의할 수 있습니다.

활성화 및 호스팅 계층은 서비스가 호스팅될 수 있는 방식을 정의합니다. IIS 7의 WAS를 이용한 호스팅, 실행 파일로 호스팅 하는 자체 호스팅, Windows 서비스를 이용한 호스팅, 그리고 COM+ 구성 요소를 이용한 호스팅 등 여러 가지 방식으로 서비스를 호스팅할 수 있습니다.

WCF 아키텍처에 대해 짧게 설명을 했는데, 이 아키텍처만 보더라도 WCF의 기능에 어떤 것이 있는지 조금은 예상할 수 있을 듯합니다.
WCF는 Web Service와 마찬가지로 SOAP과 WSDL 같은 표준을 사용하여 플랫폼에 상관없는 분산 어플리케이션 개발을 쉽게 지원하지만, Web Service와는 다르게 전송 프로토콜이라던지, 호스팅을 하는 방식이라던지, 여러 가지 기능들을 제공하여 Web Service 보다 더 큰 확장성과 상호 운용성을 지원하는 기술이라 생각하면 될 것 같습니다.

아- 이것으로 첫 번째 포스팅을 마무리할까 합니다.
사실, WCF가 아직까진 국내에 많이 활용되고 있는 것 같진 않습니다. 자료도 그렇게 많지 않은 것 같구요. 제가 꾸준히 포스팅을 하고 제가 남겨놓은 자료가 단, 한 사람에게라도 좋은 자료가 될 수 있다면 기분 좋을 것 같습니다.
앞으로는 WCF의 기초에 대한 내용으로 포스팅을 하고, 그 이후에 WCF 4.0에 대한 내용, 그리고 WCF의 활용에 관한 내용으로 포스팅을 할 예정입니다. 많은 관심과 격려 부탁 드립니다 ^^

첫 포스팅이라 어떻게 진행을 해야 할지,, 감도 안잡히고, 어설퍼 보이는 부분이 한 둘이 아닐 듯 합니다. 아직 모르는 것도 많고, 부족한 것도 많기 때문에 지금 당장 전문가 다운 모습을 보이긴 어렵겠지만, 욕심 부리지 않고 꾸준하게 정진하는게 가장 바람직한 모습일 것 같습니다.

그럼, 다음 포스팅때 뵙겠습니다 ^^