다음을 통해 공유


서비스 버전 관리

초기 배포 후 수명 동안 여러 번 서비스(및 노출하는 엔드포인트)를 변경하거나 비즈니스 요구 사항, 정보 기술 요구 사항 또는 기타 문제를 해결하기 위해 다양한 이유로 변경해야 할 수 있습니다. 각 변경 내용에는 새 버전의 서비스가 도입됩니다. 이 항목에서는 WCF(Windows Communication Foundation)에서 버전 관리 방법을 설명합니다.

서비스 변경의 네 가지 범주

필요할 수 있는 서비스에 대한 변경 내용은 다음 네 가지 범주로 분류할 수 있습니다.

  • 계약 변경: 예를 들어 작업이 추가되거나 메시지의 데이터 요소가 추가되거나 변경될 수 있습니다.

  • 주소 변경: 예를 들어 서비스는 엔드포인트에 새 주소가 있는 다른 위치로 이동합니다.

  • 바인딩 변경: 예를 들어 보안 메커니즘이 변경되거나 설정이 변경됩니다.

  • 구현 변경: 예를 들어 내부 메서드 구현이 변경되는 경우입니다.

일부 변화는 "호환성 깨짐"이라고 하며, 다른 변화는 "호환성 유지"라고 합니다. 이전 버전에서 성공적으로 처리된 모든 메시지가 새 버전에서도 성공적으로 처리될 경우, 그 변화는 호환성 유지입니다. 해당 조건을 충족하지 않는 모든 변경은 호환성이 손상 되는 변경입니다.

서비스 방향 및 버전 관리

서비스 지향의 기본 사항 중 하나는 서비스와 클라이언트가 자율적이거나 독립적이라는 것입니다. 무엇보다도 이는 서비스 개발자가 모든 서비스 클라이언트를 제어하거나 알고 있다고 가정할 수 없음을 의미합니다. 이렇게 하면 서비스가 버전을 변경할 때 모든 클라이언트를 다시 빌드하고 다시 배포하는 옵션이 제거됩니다. 이 항목에서는 서비스가 이 원칙을 준수하므로 클라이언트와 독립적으로 변경하거나 "버전 관리"해야 한다고 가정합니다.

호환성이 손상되는 변경을 예기치 않게 방지할 수 없는 경우 애플리케이션은 이 테넌트를 무시하고 클라이언트를 다시 빌드하고 새 버전의 서비스로 다시 배포하도록 요구할 수 있습니다.

계약 버전 관리

클라이언트에서 사용하는 계약은 서비스에서 사용하는 계약과 동일할 필요가 없습니다. 호환되기만 하면 됩니다.

서비스 계약의 경우 호환성은 서비스에서 노출하는 새 작업을 추가할 수 있지만 기존 작업을 의미 체계적으로 제거하거나 변경할 수 없음을 의미합니다.

데이터 계약의 경우 호환성은 새 스키마 형식 정의를 추가할 수 있지만 기존 스키마 형식 정의를 호환성이 손상되는 방식으로 변경할 수 없음을 의미합니다. 호환성이 손상되는 변경에는 데이터 멤버를 제거하거나 데이터 형식을 호환되지 않게 변경하는 것이 포함될 수 있습니다. 이 기능을 사용하면 서비스에서 클라이언트를 중단하지 않고 계약 버전을 변경할 때 약간의 위도를 사용할 수 있습니다. 다음 두 부분에서는 WCF 데이터 및 서비스 계약에 적용할 수 있는 호환성 무관한 변경 및 호환성을 깨는 변경에 대해 설명합니다.

데이터 계약 버전 관리

이 섹션에서는 DataContractSerializerDataContractAttribute 클래스를 사용할 때 데이터 버전 관리를 다룹니다.

엄격한 버전 관리

버전 변경이 문제가 되는 많은 시나리오에서 서비스 개발자는 클라이언트를 제어할 수 없으므로 메시지 XML 또는 스키마의 변경 내용에 어떻게 반응할지를 가정할 수 없습니다. 이러한 경우 다음 두 가지 이유로 새 메시지가 이전 스키마에 대해 유효성을 검사해야 합니다.

  • 이전 클라이언트는 스키마가 변경되지 않는다는 가정하에 개발되었습니다. 설계되지 않은 메시지를 처리하지 못할 수 있습니다.

  • 이전 클라이언트는 메시지를 처리하기도 전에 이전 스키마에 대해 실제 스키마 유효성 검사를 수행할 수 있습니다.

이러한 시나리오에서 권장되는 방법은 기존 데이터 계약을 변경할 수 없는 것으로 처리하고 고유한 XML 정규화된 이름을 사용하여 새 계약을 만드는 것입니다. 그런 다음 서비스 개발자는 기존 서비스 계약에 새 메서드를 추가하거나 새 데이터 계약을 사용하는 메서드를 사용하여 새 서비스 계약을 만듭니다.

서비스 개발자가 데이터 계약의 모든 버전과 각 데이터 계약의 버전별 비즈니스 코드 내에서 실행되어야 하는 일부 비즈니스 논리를 작성해야 하는 경우가 종종 있습니다. 이 항목의 끝에 있는 부록은 인터페이스를 사용하여 이러한 요구를 충족하는 방법을 설명합니다.

느슨한 버전 관리

다른 많은 시나리오에서 서비스 개발자는 데이터 계약에 새 선택적 멤버를 추가해도 기존 클라이언트가 중단되지 않는다고 가정할 수 있습니다. 이렇게 하려면 서비스 개발자가 기존 클라이언트가 스키마 유효성 검사를 수행하지 않고 알 수 없는 데이터 멤버를 무시하는지 조사해야 합니다. 이러한 시나리오에서는 새로운 멤버를 획기적이지 않은 방식으로 추가하기 위해 데이터 계약 기능을 활용할 수 있습니다. 서비스 개발자는 버전 관리용 데이터 계약 기능이 서비스의 첫 번째 버전에 이미 사용된 경우 확신을 가지고 이 가정을 할 수 있습니다.

WCF, ASP.NET Web Services 및 기타 많은 웹 서비스 스택은 느슨한 버전 지정을 지원합니다. 즉, 수신된 데이터에 알 수 없는 새 데이터 멤버에 대한 예외를 throw하지 않습니다.

새 멤버를 추가해도 기존 고객에게 문제가 없다고 잘못 믿기 쉽습니다. 모든 클라이언트가 느슨한 버전 관리 작업을 처리할 수 있는지 확실하지 않은 경우 엄격한 버전 관리 지침을 사용하고 데이터 계약을 변경할 수 없는 것으로 처리하는 것이 좋습니다.

데이터 계약의 느슨한 버전 관리와 엄격한 버전 관리 모두에 대한 자세한 지침은 모범 사례: 데이터 계약 버전 관리를 참조하세요.

데이터 계약과 .NET 형식 구분

.NET 클래스 또는 구조체는 클래스에 특성을 적용하여 DataContractAttribute 데이터 계약으로 프로젝션할 수 있습니다. .NET 형식과 해당 데이터 계약 프로젝션은 두 가지 고유한 문제입니다. 동일한 데이터 계약 프로젝션을 사용하여 여러 .NET 형식을 가질 수 있습니다. 이러한 구분은 프로젝션된 데이터 계약을 유지하면서 .NET 형식을 변경하여 단어의 엄격한 의미에서도 기존 클라이언트와의 호환성을 유지할 수 있도록 하는 데 특히 유용합니다. .NET 형식과 데이터 계약을 구분하기 위해 항상 해야 할 두 가지가 있습니다.

  • NameNamespace를 지정하십시오. .NET 형식의 이름과 네임스페이스가 계약에 노출되지 않도록 데이터 계약의 이름과 네임스페이스를 항상 지정해야 합니다. 이렇게 하면 나중에 .NET 네임스페이스 또는 형식 이름을 변경하기로 결정한 경우 데이터 계약은 동일하게 유지됩니다.

  • Name을 지정합니다. .NET 멤버 이름이 계약에 노출되지 않도록 항상 데이터 멤버의 이름을 지정해야 합니다. 이렇게 하면 나중에 멤버의 .NET 이름을 변경하기로 결정한 경우 데이터 계약은 동일하게 유지됩니다.

멤버 변경 또는 제거

멤버의 이름 또는 데이터 형식을 변경하거나 데이터 멤버를 제거하는 것은 느슨한 버전 관리가 허용되는 경우에도 호환성이 손상되는 변경입니다. 필요한 경우 새 데이터 계약을 만듭니다.

서비스 호환성이 중요한 경우 코드에서 사용되지 않는 데이터 멤버를 무시하고 그대로 두는 것이 좋습니다. 데이터 멤버를 여러 멤버로 분할하는 경우 하위 수준 클라이언트(최신 버전으로 업그레이드되지 않은 클라이언트)에 필요한 분할 및 다시 집계를 수행할 수 있는 속성으로 기존 멤버를 그대로 두는 것이 좋습니다.

마찬가지로 데이터 계약의 이름 또는 네임스페이스 변경 사항은 호환성을 깨뜨리는 변경입니다.

Round-Trips 알 수 없는 데이터

일부 시나리오에서는 새 버전에 추가된 멤버의 알 수 없는 데이터를 "왕복"해야 합니다. 예를 들어 "versionNew" 서비스는 새로 추가된 멤버가 포함된 데이터를 "versionOld" 클라이언트로 보냅니다. 클라이언트는 메시지를 처리할 때 새로 추가된 멤버를 무시하지만 새로 추가된 멤버를 포함하여 동일한 데이터를 versionNew 서비스로 다시 보냅니다. 이에 대한 일반적인 시나리오는 서비스에서 데이터를 검색하고, 변경하고, 반환하는 데이터 업데이트입니다.

특정 형식에 대해 라운드트립을 사용하도록 설정하려면 형식이 인터페이스를 IExtensibleDataObject 구현해야 합니다. 인터페이스에는 형식을 반환하는 하나의 속성 ExtensionData 이 포함되어 있습니다 ExtensionDataObject . 이 속성은 현재 버전에 알 수 없는 이후 버전의 데이터 계약의 데이터를 저장하는 데 사용됩니다. 이 데이터는 클라이언트에 불투명하지만 인스턴스가 serialize되면 속성의 ExtensionData 콘텐츠가 나머지 데이터 계약 멤버의 데이터와 함께 작성됩니다.

모든 타입이 새로운 멤버와 미래의 알 수 없는 멤버를 수용할 수 있도록 이 인터페이스를 구현하는 것이 권장됩니다.

데이터 계약 라이브러리

계약이 중앙 리포지토리에 게시되는 데이터 계약의 라이브러리가 있을 수 있으며, 서비스 및 형식 구현자는 해당 리포지토리에서 데이터 계약을 구현하고 노출합니다. 이 경우 데이터 계약을 리포지토리에 게시할 때 해당 계약을 구현하는 형식을 만드는 사용자를 제어할 수 없습니다. 따라서 계약을 게시한 후에는 수정할 수 없으므로 사실상 변경할 수 없게 됩니다.

XmlSerializer를 사용하는 경우

클래스를 사용할 때 동일한 버전 관리 원칙이 XmlSerializer 적용됩니다. 엄격한 버전 관리가 필요한 경우 데이터 계약을 변경할 수 없는 것으로 처리하고 새 버전에 대한 고유한 정규화된 이름을 사용하여 새 데이터 계약을 만듭니다. 느슨한 버전 관리가 사용될 수 있다고 확신하는 경우 새 버전에서 직렬화 가능한 새 멤버를 추가할 수 있지만 기존 멤버를 변경하거나 제거할 수는 없습니다.

비고

XmlSerializer 특성과 XmlAnyElementAttribute, XmlAnyAttributeAttribute 특성을 사용하여 알 수 없는 데이터의 라운드트립을 지원합니다.

메시지 계약 버전 관리

메시지 계약 버전 관리 지침은 데이터 계약의 버전 관리와 매우 유사합니다. 엄격한 버전 관리가 필요한 경우 메시지 본문을 변경하지 말고 고유한 정규화된 이름으로 새 메시지 계약을 만들어야 합니다. 느슨한 버전 관리 기능을 사용할 수 있다는 것을 알고 있는 경우 새 메시지 본문 부분을 추가할 수 있지만 기존 메시지 본문 부분을 변경하거나 제거할 수는 없습니다. 이 지침은 단순 및 포장된 메시지 계약에 모두 적용됩니다.

엄격한 버전 관리가 사용 중인 경우에도 메시지 헤더를 항상 추가할 수 있습니다. MustUnderstand 플래그는 버전 관리에 영향을 줄 수 있습니다. 일반적으로 WCF의 헤더에 대한 버전 관리 모델은 SOAP 사양에 설명되어 있습니다.

서비스 계약 버전 관리

데이터 계약 버전 관리와 마찬가지로 서비스 계약 버전 관리에도 작업 추가, 변경 및 제거가 포함됩니다.

이름, 네임스페이스 및 작업 지정

기본적으로 서비스 계약의 이름은 인터페이스의 이름입니다. 기본 네임스페이스는 http://tempuri.org이며 각 작업의 동작은 http://tempuri.org/contractname/methodname입니다. 서비스 계약에 대한 이름과 네임스페이스를 명시적으로 지정하고, 각 작업에 대한 액션을 명시적으로 설정하여 http://tempuri.org를 사용하지 않고, 인터페이스와 메서드 이름이 서비스 계약에서 노출되지 않도록 하는 것이 좋습니다.

매개 변수 및 작업 추가

기존 클라이언트는 이러한 새 작업에 대해 걱정할 필요가 없으므로 서비스에서 노출하는 서비스 작업을 추가하는 것은 변경되지 않는 변경입니다.

비고

이중 콜백 계약에 연산을 추가하는 것은 호환성을 깨뜨리는 변경입니다.

작업 매개 변수 또는 반환 형식 변경

새 형식이 이전 형식에서 구현한 동일한 데이터 계약을 구현하지 않는 한 일반적으로 매개 변수 또는 반환 형식을 변경하는 것은 호환성이 손상되는 변경입니다. 이러한 변경을 수행하려면 서비스 계약에 새 작업을 추가하거나 새 서비스 계약을 정의합니다.

작업 제거

작업을 제거하는 것도 호환성을 깨는 변경입니다. 이러한 변경을 수행하려면 새 서비스 계약을 정의하고 새 엔드포인트에 노출합니다.

오류 계약

FaultContractAttribute 특성을 사용하면 서비스 계약 개발자가 계약 작업에서 반환할 수 있는 오류에 대한 정보를 지정할 수 있습니다.

서비스 계약에 설명된 오류 목록은 전체적인 것으로 간주되지 않습니다. 언제든지 작업은 계약에 설명되지 않은 오류를 반환할 수 있습니다. 따라서 계약에 설명된 오류 집합을 변경하는 것은 호환성이 손상되는 것으로 간주되지 않습니다. 예를 들어 계약에 새 오류를 추가하거나 계약 FaultContractAttribute 에서 기존 오류를 제거합니다.

서비스 계약 라이브러리

조직에는 계약이 중앙 리포지토리에 게시되고 서비스 구현자가 해당 리포지토리에서 계약을 구현하는 계약 라이브러리가 있을 수 있습니다. 이 경우 서비스 계약을 리포지토리에 게시할 때 서비스 계약을 구현하는 서비스를 만드는 사용자를 제어할 수 없습니다. 따라서 서비스 계약을 게시한 후에는 수정할 수 없으므로 사실상 변경할 수 없습니다. WCF는 기존 계약을 확장하는 새 계약을 만드는 데 사용할 수 있는 계약 상속을 지원합니다. 이 기능을 사용하려면 이전 서비스 계약 인터페이스에서 상속되는 새 서비스 계약 인터페이스를 정의한 다음 새 인터페이스에 메서드를 추가합니다. 그런 다음 이전 계약을 구현하는 서비스를 변경하여 새 계약을 구현하고 새 계약을 사용하도록 "versionOld" 엔드포인트 정의를 변경합니다. "versionOld" 클라이언트에 엔드포인트는 "versionOld" 계약을 노출하는 것으로 계속 표시됩니다. "versionNew" 클라이언트에 엔드포인트가 "versionNew" 계약을 노출하는 것처럼 표시됩니다.

주소 및 바인딩 버전 관리

클라이언트가 새 엔드포인트 주소 또는 바인딩을 동적으로 검색할 수 있는 기능이 없는 경우, 엔드포인트 주소 및 바인딩의 변경은 중단적인 변경 사항입니다. 이 기능을 구현하기 위한 한 가지 메커니즘은 UDDI(유니버설 검색 설명 및 통합) 레지스트리와 클라이언트가 엔드포인트와 통신을 시도하고 실패 시 현재 엔드포인트 메타데이터에 대해 잘 알려진 UDDI 레지스트리를 쿼리하는 UDDI 호출 패턴을 사용하는 것입니다. 그런 다음 클라이언트는 이 메타데이터의 주소 및 바인딩을 사용하여 엔드포인트와 통신합니다. 이 통신이 성공하면 클라이언트는 나중에 사용하기 위해 주소 및 바인딩 정보를 캐시합니다.

라우팅 서비스 및 버전 관리

서비스에 호환성을 깨는 변경이 발생하고 동시에 여러 버전의 서비스가 실행되어야 하는 경우, WCF 라우팅 서비스를 사용하여 메시지를 적절한 서비스 인스턴스로 라우팅할 수 있습니다. WCF 라우팅 서비스는 콘텐츠 기반 라우팅을 사용합니다. 즉, 메시지 내의 정보를 사용하여 메시지를 라우팅할 위치를 결정합니다. WCF 라우팅 서비스에 대한 자세한 내용은 라우팅 서비스를 참조하세요. 서비스 버전 관리용 WCF 라우팅 서비스를 사용하는 방법에 대한 예제는 방법: 서비스 버전 관리 방법을 참조하세요.

부록

엄격한 버전 관리가 필요한 경우 일반적인 데이터 계약 버전 관리 지침은 데이터 계약을 변경할 수 없는 것으로 처리하고 변경이 필요할 때 새 계약을 만드는 것입니다. 각 새 데이터 계약에 대해 새 클래스를 만들어야 하므로 이전 데이터 계약 클래스를 기준으로 작성된 기존 코드를 사용하고 새 데이터 계약 클래스를 기준으로 다시 작성할 필요가 없도록 메커니즘이 필요합니다.

이러한 메커니즘 중 하나는 인터페이스를 사용하여 각 데이터 계약의 멤버를 정의하고 인터페이스를 구현하는 데이터 계약 클래스가 아닌 인터페이스 측면에서 내부 구현 코드를 작성하는 것입니다. 서비스 버전 1의 다음 코드는 IPurchaseOrderV1 인터페이스와 PurchaseOrderV1를 보여줍니다.

public interface IPurchaseOrderV1  
{  
    string OrderId { get; set; }  
    string CustomerId { get; set; }  
}  
  
[DataContract(  
Name = "PurchaseOrder",  
Namespace = "http://examples.microsoft.com/WCF/2005/10/PurchaseOrder")]  
public class PurchaseOrderV1 : IPurchaseOrderV1  
{  
    [DataMember(...)]  
    public string OrderId {...}  
    [DataMember(...)]  
    public string CustomerId {...}  
}  

서비스 계약의 운영은 PurchaseOrderV1의 관점에서 작성되지만, 실제 비즈니스 논리는 IPurchaseOrderV1의 관점에서 이루어집니다. 그런 다음 버전 2에는 다음 코드와 같이 새 IPurchaseOrderV2 인터페이스와 새 PurchaseOrderV2 클래스가 있습니다.

public interface IPurchaseOrderV2  
{  
    DateTime OrderDate { get; set; }  
}

[DataContract(
Name = "PurchaseOrder",  
Namespace = "http://examples.microsoft.com/WCF/2006/02/PurchaseOrder")]  
public class PurchaseOrderV2 : IPurchaseOrderV1, IPurchaseOrderV2  
{  
    [DataMember(...)]  
    public string OrderId {...}  
    [DataMember(...)]  
    public string CustomerId {...}  
    [DataMember(...)]  
    public DateTime OrderDate { ... }  
}  

서비스 계약은 용어 PurchaseOrderV2로 작성된 새 작업을 포함하도록 업데이트됩니다. 기존 비즈니스 논리가 IPurchaseOrderV1의 용어로 작성되어 PurchaseOrderV2 계속 작동하며, OrderDate 속성이 필요한 새 비즈니스 논리는 IPurchaseOrderV2의 용어로 작성됩니다.

참고하십시오