2017-11-06 12 views
2

에 잘못된 열거 값을 무시합니다. 새로운 값이 추가되고 그 값이 함수 호출에 의해 반환되면 웹 서비스의 소비자는 해당 enum 값을 신경 쓰지 않아도 예외를 throw합니다.내가 열거의 배열을 반환하는 ASP.NET 웹 서비스에의 WebMethod를 SOAP 직렬화 복원

[WebMethod] 
public UserRole[] GetRoles(string token) 

부분 WSDL :

<s:simpleType name="UserRole"> 
    <s:restriction base="s:string"> 
     <s:enumeration value="Debug" /> 
     <s:enumeration value="EventEditor" /> 
     <s:enumeration value="InvoiceEntry" /> 
    </s:restriction> 
    </s:simpleType> 

(소비자가이 WSDL로 컴파일,하지만 WSDL 변화와 새로운 값이 현재 허용 - 그 값이 반환되는 경우, XML 예외가에 의해 발생합니다 클라이언트.)

내가 오류를 잡아 두 배열에서 해당 항목을 제거하거나 디폴트 값으로 대체 할 수 있도록 이러한 유형의 SOAP 직렬화 복원을 오버라이드 (override) 할 수있는 방법이 있습니까? 이것이 XML 대신 JSON을 사용했다면 JsonConverter를 등록하여 해당 유형을 처리 할 수 ​​있으므로 유사한 전역 "RegisterConverter"유형 함수를 찾고 있다고 생각합니다. 나는 존재하지 않는다고 생각하지만 어떤 도움을 원한다면 ...

모든 코드가 wsdl에 의해 생성되고 웹 참조가 업데이트 될 때 재생성되므로 속성이있는 열거 형을 장식하는 방법은 작동하지 않습니다 . 일반적으로 wsdl에 의해 생성 된 클래스를 수정하려는 경우 부분 클래스를 만들 수 있지만 Enum에는 작동하지 않습니다. 심지어 클래스 일지라도 XmlSerialization 코드를 재정의 할 수 있는지 여부는 확실하지 않습니다.



일부 추가 배경 :

이 실제로 동적 열거에 나의 시도로 구현됩니다. wsdl은 데이터베이스에 추가 값을 추가 할 수 있도록 데이터베이스 조회에서 생성되며 소비하는 응용 프로그램은 웹 서비스를 다시 컴파일 할 필요없이 허용 된 값에 액세스 할 수 있습니다. 이렇게하면 enum 유형을 통해 인텔리 센스 및 제약 조건 적용이 가능하지만 웹 서비스 코드와 클라이언트 코드를 긴밀하게 연결하지 않고도 값을 추가 할 수 있습니다. 문제는 새로운 값을 추가하면 새로운 wsdl로 업데이트되지 않은 소비자를 깰 가능성이 있다는 것입니다. 소비자는 그 값을 무시할 것입니다. 왜냐하면 소비자는 무엇을해야할지 모르기 때문입니다. 어쨌든.

SOAP 확장은 SOAP 확장을 WebService 자체에 추가하는 방법을 알고 있지만 클라이언트 측에 SOAP 확장을 추가하는 방법을 알고 있습니다. 그러나 SOAP 확장은 다음과 같은 이유로 적합하지 않습니다. 나는 이것을 쉽게 처리 할 수있는 일반적인 방법을 원한다. 그래서 나는 동적 인 enum을 코드에 넣을 수있다. (동적 인 것은 아니지만 아이디어는 값이 webservice의 중간 레이어를 통과하지 않아도된다. 그 중간 계층을 다시 컴파일하십시오). "XmlSerialization.RegisterConverter (MyDynamicEnumType, DynamicEnum.Convert)"와 같은 것이 가장 이상적입니다.

+0

음, 두 가지 가능한 해결책을 생각했습니다. 하나는 (부분 클래스에서) WebService 선언에서 GetReaderForMessage를 재정의 한 다음 열거 형 이름과 값에 대해 Regex 일치를 수행하고 다른 하나는 허용 가능한 값 목록을 웹 서비스에 보내고 웹 서비스가 보내지 않기를 요청하는 것입니다. 그 목록에없는 값. 그것들은 모두 빨고, 나는 지금까지 얻은 것보다 더 나은 대답을 누군가가 얻을 수 있기를 바라고있다. 그렇지 않다면 나는 내일 내 자신의 janky 대답을 올릴 것이다. –

+0

글쎄, 나는 GetReaderForMessage를 무시하는 것을 끝내었지만 정규 표현식보다 열거 이름의 전체 메시지 문자열을 일치시키는 것이 더 좋았다. 열거 형의 deserialization을 재정의하는 더 나은 방법이 필요했다. –

+0

WSDL과 XSD의 요점은 서비스와 클라이언트 사이에 계약을 맺는 것입니다.이 계약을 위반하기 위해 뭔가를 구현하고 있습니다. 다른 구현을 재고해야합니까? 또는 열거 형 대신 다른 것을 허용하도록 WSDL을 변경하십시오. –

답변

0

그래도 다른 사람이 대답을하기를 희망하지만 적어도 나왔습니다. 뭔가 내가 Regex.Replace를 사용하여 내 원래 생각보다 조금 더 나은 열거 가치에 대한 참조를 제거합니다.

나는 웹 서비스에 대한 부분 클래스를 사용하여 아래로 GetReaderForMessage을 무시하고

:

namespace Program.userws //note this namespace must match the namespace 
          //that the webservice is declared in (in auto-generated code) 
{ 
    partial class UserWebService 
    { 
     protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize) 
     { 
      return new EnumSafeXmlReader(message.Stream); 
     } 
    } 
} 

이 EnumSafeXmlReader에 대한 정의입니다 :

public class EnumSafeXmlReader : XmlTextReader 
{ 
    private Assembly _callingAssembly; 

    public EnumSafeXmlReader(Stream input) : base(input) 
    { 
     _callingAssembly = Assembly.GetCallingAssembly(); 
    } 

    public override string ReadElementString() 
    { 
     string typename = this.Name; 
     var val = base.ReadElementString(); 

     var possibleTypes = _callingAssembly.GetTypes().Where(t => t.Name == typename); 
     Type enumType = possibleTypes.FirstOrDefault(t => t.IsEnum); 

     if (enumType != null) 
     { 
      string[] allowedValues = Enum.GetNames(enumType); 

      if (!allowedValues.Contains(val)) 
      { 
       val = Activator.CreateInstance(enumType).ToString(); 
      } 
     } 

     return val; 
    } 
} 

가 나는 또한 UserRole에 대한 새 값을 추가 - UserRole.Unknown이며 허용 된 값 목록의 첫 번째 항목인지 확인해야합니다. 이 인식되지 않는 경우

<s:simpleType name="AcctUserRole"> 
    <s:restriction base="s:string"> 
    <s:enumeration value="Unknown"/> 
    <s:enumeration value="Debug"/> 
    <s:enumeration value="EventEditor"/> 
    <s:enumeration value="InvoiceEntry"/> 
    </s:restriction> 
</s:simpleType> 

은 그래서 오랫동안이 열거의 값이 유형 이름 <UserRole>UnexpectedRole</UserRole>와 태그에 싸여로, 그것은 내 클라이언트가 행복하게 무시할 수 UserRole.Unknown로 대체 될 것이다. 이 열거 형이 아니며 예를 들어 string 또는 int 일 것으로 예상되는 UserRole이라는 또 다른 태그가있는 경우에도이 오류가 발생할 수 있습니다. 상당히 부서지기 쉽습니다.


이 솔루션은 여전히 ​​원하는 수 많은 나뭇잎,하지만 일반적으로 ... 열거 값 목록에서 작동합니다

<GetRolesForUserResult> 
    <UserRole>InvoiceEntry</UserRole> 
    <UserRole>UnexpectedRole</UserRole> 
</GetRolesForUserResult> 

UserRole.InvoiceEntryUserRole.Unknown를 포함하는 UserRole[]의 결과로 끝날 것 .

그러나 나는 형 UserRole의 필드 나 속성이있는 경우 : 독자는 "PrimaryRole는"UserRole를 입력 직렬화 할 필요가 있음을 알 수있는 방법이 없기 때문에,

<User> 
    <ID>5</ID> 
    <Name>Zorak</Name> 
    <PrimaryRole>UnexpectedRole</PrimaryRole> <!-- causes an exception --> 
</User> 

이 실패 할 것이다. XmlSerializer는 이것을 알고 있지만, 내가 알 수있는 한, XmlSerializer를 오버라이드 할 방법이 없으며 XmlReader 만 오버라이드 할 수 있습니다.

enumSafeXml Reader에게 enum 유형으로 deserialize 할 태그를 인식하는 데 충분한 정보를 제공하는 것이 완전히 불가능하지는 않지만, 지금 당장에 갈 의향이 있습니다. "enum 값의 배열"의 경우.

유형에 캐싱을 추가하여 태그 이름을 한 번만 확인하여 열거 형 이름인지 확인해야하지만이 예제에서는 명확하게하기 위해 태그를 제거했습니다.


이 솔루션을 개선하기위한 가능한 다른 해결책이나 권장 사항을 환영합니다.

-1

은 내가 downvote 위험을 감수하고 명백한 상태 것이다 : 당신의 서비스 계약에 열거를 사용하지 마십시오. 당신이 확인한대로 그들은 고정 된 영역을 제외하고는 부서지기 쉽습니다.

내가 서비스 소비자 인 경우 Unknown 항목을 사용하면 "서비스에서 반환 할 때 무엇을해야합니까?"라는 질문을 받게됩니다. "걱정하지 마라. 고객과의 호환성을 위해서만 존재할 것"이라고 대답 할 것입니다. "서비스가 계약서에서 무엇을하고 있는지를 돌려주지 않으면 답장을 보내겠습니까?"

돌려 string[]와 클라이언트가 처리 할 수있는 정보의 배열을 구문 분석합니다. Intellisense가 실제로 목표 인 경우 클라이언트에서 열거 형의 하위 집합을 정의 할 수 있습니다. 더 정교한 솔루션을 검색하는 데 수백 배를 구현할 수 있습니다. 단계. 떨어져. 에서. 그만큼. ENUMS.

+0

이것은 유용한 대답이 아닙니다. 데이터에 대한 제약이있는 좋은 이유가 있으며 조회 테이블, 열거 형, 문자열 값 및 매직 넘버 사이의 최선의 해답을 찾기 위해 수년간 노력해 왔습니다. 혼자서, 그들 중 누구도 꽤 일하지 않습니다. 필자는 Intellisense, 데이터 제약, 검색 가능성 및 확장 성을 제공하는 방식으로 조회 테이블과 열거 형을 연결하는 방법을 마침내 얻었습니다. XML 디시리얼라이저를 사용하면 적합성을 포기하지 않고 전체 프로그램을 중단하지 않을 수 있습니다. 이해한다. 그렇게 할 방법을 찾았지만 좀 더 우아한 것을 찾고 있습니다. –

+0

찾아보기 테이블은 열거 형이 아닙니다. "동적 enums"는 열거 형이 아닙니다. 서비스 계약은 인터페이스와 다릅니다. 디자인의 미묘한 불일치로 인해 머리를 벽에 부딪히는 이유가 있습니다. 지금 당신은 망치가 있고 모든 것은 손톱처럼 보입니다. 대신 드라이버를 사용해보십시오. – batwad

+0

조회 테이블, 열거 형, "문자열 형식의"변수 및 마법 번호는 모두 최종 목표가 있으며 선택 가능한 값을 나타냅니다. 그들 중 누구도 그 목표를 완벽하게 성취하지 못합니다. 제약, 확장 성, 이식성, 관심사 분리, 발견 가능성 등을 모두 동시에 구현하는 사람은 없을 것입니다. 어려운 문제인데, 그 이유는 제가 고심하는 이유입니다. 왜냐하면 제가 "나사를 망치 려 고 노력하고 있기 때문이 아닙니다." 지금 가지고있는 유일한 문제는 deserialization 코드를 무시하는 것입니다. –