2009-12-09 3 views
56

나는 클라이언트 측에서 [DataContract]를 통해 사용할 수있게 만드는 서버 측 클래스가 있습니다. 이 클래스에는 속성을 통해 사용할 수 있도록하려는 읽기 전용 필드가 있습니다. 그러나 얻을 수없고 설정하지 않고도 [DataMember] 속성을 추가 할 수있는 것처럼 보이지 않기 때문에 그렇게 할 수 없습니다.WCF : 설정없이 읽기 전용 DataMember 속성 노출?

그래서 setter없이 [DataMember] 속성을 사용할 수 있습니까?

[DataContract] 
class SomeClass 
{ 
    private readonly int _id; 

    public SomeClass() { .. } 

    [DataMember] 
    public int Id { get { return _id; } }   

    [DataMember] 
    public string SomeString { get; set; } 
} 

또는 용액은 [DataMember를] 필드로 사용한다 - (같은 예를 도시 here)? 이것도 시도해 보았지만, 그 필드가 읽기 전용인지 신경 쓰지 않는 것 같은데 ..?

편집 : 이렇게 해킹하여 읽기 전용 속성을 만들 수있는 유일한 방법입니까? (아니요 - 이것을하고 싶지 않습니다 ...)

[DataMember] 
public int Id 
{ 
    get { return _id; } 
    private set { /* NOOP */ } 
} 
+2

당신이 클라이언트 측에서 WCF를 사용한다면 NOOP 설정기에 대한 귀하의 생각은 올바르게 전달되지 않을 것입니다 :'DataContract' 직렬화에서 클래스는 생성자를 호출하지 않고 인스턴스화되고' DataMember' 속성은 serialization 할 때 해당 속성의 getter에서 반환 한 값을 전달합니다. 따라서 NOOP 설정자는 속성을 버려서 deserialization에 기본값으로 남겨 둡니다. 대신 실제로 작동하는 개인용 setter를 작성하거나 속성을 표시하는 대신 보조 변수를'DataMember'로 표시하십시오. –

답변

48

"서버 측"클래스는 실제로 클라이언트에 "사용 가능"하지 않습니다.

데이터 계약에 따라 클라이언트는 서비스의 XML 스키마와 새로운 클래스를 새로 만듭니다. 그것 수 없습니다 그 자체가 서버 쪽 클래스를 사용!

XML 스키마 정의에서 새 클래스를 다시 작성하지만 해당 스키마에는 가시성 또는 액세스 한정자와 같은 .NET 특정 항목이 포함되지 않습니다. 결국 XML 스키마 일뿐입니다. 클라이언트 측 클래스는 와이어에서 동일한 "발자국"을 가지도록 생성됩니다 (예 : 그것은 기본적으로 동일한 XML 형식으로 직렬화됩니다.

당신 수없는 표준 SOAP 기반 서비스를 통해 클래스에 대한 "전송".NET 특정 노하우 - 아니 클래스 - 결국, 당신이 주변에 전달하는 모든 직렬화 된 메시지가 있습니다! (마이크로 소프트의 돈 상자에 의해 정의)

검사에게 "SOA의 네 신조"

  1. 경계는
  2. 서비스가 자율적
  3. 서비스를 클래스가 아닌 스키마와 계약을 공유
  4. 있습니다 명시 적있다 안정성은 정책을 기반으로합니다.

포인트 3 참조 - 서비스 공유 스키마 및 계약 아니요 클래스 - 데이터 계약에 대한 인터페이스와 XML 스키마 만 공유합니다. 모든 것이 .NET 클래스가 아닙니다.

+1

아주 잘 설명합니다. 명확히 해 주셔서 감사합니다! – stiank81

+0

기꺼이 도와 드리겠습니다! –

+28

이 정보는 훌륭하지만 질문에 직접 답하는 것은 아니라고 생각합니다. – atoumey

-3

클래스를 사용하여 계약을 구현하기 전에.

+0

무엇을 의미합니까? DataMember는 DataContract를 통해 사용할 수있는 DTO 클래스에 있습니다. 나는 ServiceContract도 가지고 있지만 여기에는 실제로 관련이 없다. – stiank81

+1

그것은 서비스 계약이 아닌 datacontract입니다. –

10

필드에 속성이 아닌 DataMember 특성을 넣습니다.

WCF는 캡슐화를 알지 못한다는 것을 기억하십시오. 캡슐화는 SOA 용어가 아니라 OOP 용어입니다.

그런데이 필드는 수업을 사용하는 사람들을 위해 읽기 전용으로 사용됩니다. 서비스를 사용하는 모든 사용자는 자기 분야의 모든 필드에 액세스 할 수 있습니다.

+0

아, 예, 저는 DataMember로 필드를 설정하려고했지만 클라이언트 측에서 읽기 전용으로 노출되지 않았습니다. 그러나 클라이언트 측에서 읽기 전용으로 만들 방법이 없습니다. – stiank81

+4

번호. READONLY는 SOA가 아닌 C# 용어입니다. XML의 일부만 읽을 수는 없습니다 –

+0

고마워요. 이것은 데이터에 특화된 클래스를 만드는 것 이외의 최선의 선택 인 것처럼 보입니다 ... 그리고 작은 애플 리케이션을 위해, 그것은 너무 많은 여분의 코드입니다. – ChrisG

7

내 서비스 계층의 클래스에 일부 속성이 있는데 Silverlight로 전달하려고했습니다. 나는 완전히 새로운 수업을 만들고 싶지 않았습니다.

실제로는 '권장'은 아니지만, 이것은 Total 속성을 실버 라이트로 전달하는 데 드는 두 가지 문제 중 적은 것으로 보입니다 (시각적 데이터 바인딩 전용).

public class PricingSummary 
{ 
    public int TotalItemCount { get; set; } // doesnt ideally belong here but used by top bar when out of store area 

    public decimal SubTotal { get; set; } 
    public decimal? Taxes { get; set; } 
    public decimal Discount { get; set; } 
    public decimal? ShippingTotal { get; set; } 
    public decimal Total 
    { 
     get 
     { 
      return + SubTotal 
        + (ShippingTotal ?? 0) 
        + (Taxes ?? 0) 
        - Discount; 
     } 
     set 
     { 
      throw new ApplicationException("Cannot be set"); 
     } 
    } 
} 
+1

이 솔루션에서 본 문제점은 ISerializable과 DataContract를 함께 사용할 수 없기 때문에 DataContract에서 직렬화를 정의하기 때문입니다. 이 객체를 직렬화하려고하면 직렬화 해제 중에 예외가 발생합니다. 따라서 해킹을하지 않는 것이 유일한 선택 인 것처럼 보이며 예외를 던집니다. –

+0

이 상황에서 확장 메서드로 "Total"을 구현하면 멋지게 작동합니다 (이 게시물을 작성할 때 확장 메서드 *가 사용되지 않았을 수도 있음을 알고 있습니다). –

+0

@PaulSuart 데이터 바인딩을위한 속성이어야하므로 속성이 필요하며 확장 속성과 같은 것은 없습니다 .- 그렇지만 라이브러리를 확장 할 때를 제외하고 확장 메서드를 잊어 버리는 경향이 있습니다 –

4

이 방법이 있습니다. 그러나 그것이 this answer :

"3. 서비스는 스키마가 아니라 계약서가 아닌 클래스"에 인용 된 다음 원칙에 위배된다는 것을주의해야합니다.

이 위반을 우려하지 않는 경우

, 이것은 당신이 무엇을 :

  1. 이동 별도의 (휴대용) 클래스 라이브러리에 서비스 및 데이터 계약. [DataMember]가 백업 분야에 적용되는

    namespace SomeService.Contracts 
    { 
        [DataContract] 
        public sealed class Foo 
        { 
         public Foo(int x) 
         { 
          this.x = x; 
         } 
    
         public int X 
         { 
          get 
          { 
           return x; 
          } 
         } 
    
         [DataMember] // NB: applied to the backing field, not to the property! 
         private readonly int x; 
        } 
    } 
    

    하는 것으로하고, 해당 읽기 전용 속성에 하지 : 이것은 당신이 불변 [DataContract] 클래스를 정의하는 것 방법이다 (.의이 조립 SomeService.Contracts를 부르 자).

  2. 서비스 응용 프로그램 프로젝트 (고객 번호 SomeService.Web)와 고객 프로젝트 (내 이름은 SomeService.Client)의 계약 어셈블리를 참조하십시오. 이 솔루션 내부의 다음 프로젝트 종속성이 발생할 수 있습니다 :

    screenshot highlighting the project dependencies in Solution Explorer

  3. 당신이 당신의 클라이언트 프로젝트에 서비스 참조를 추가 할 때
  4. 다음, 확인을 옵션 "재사용 유형"를 사용할 수 있고, 보장해야 계약 어셈블리 (SomeService.Contracts)이 포함됩니다

    screenshot highlighting the relevant service reference setting

자보세요! Visual Studio는 서비스의 WSDL 스키마에서 Foo 형식을 새로 생성하는 대신 계약 어셈블리에서 변경할 수없는 Foo 형식을 다시 사용합니다.

마지막 경고 하나 : that other answer에 인용 된 서비스 원칙을 이미 벗어났습니다. 그러나 더 이상 이탈하지 않도록하십시오. 데이터 계약 클래스에 (비즈니스) 논리를 추가하기 시작하면 좋을지도 모릅니다. 하지마. 사용자는 관리 할 수있는 것처럼 바보 데이터 전송 개체 (DTO)에 가까이 있어야합니다.