views:

873

answers:

3

Hello, I have a following problem. A customer requested a web service that returns data in following format:

<status>
 <name1>Some name</name1>
 ...
</status>

But when an error occurs they want to get a following message:

<status>
 <error>Error description</error>
</status>

I created a web service using WCF and in order to fulfill the requirements I defined a following service contract:


    [ServiceContract]
    public interface IPatronStatus
    {
        [OperationContract]
        [ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]
        [WebGet(UriTemplate = "/service/status?user={unilogin}")]
        StatusData GetPatronStatus(string unilogin);
    }

And also defined a following base class:


    [DataContract(Name="status")]
    public class StatusData
    {

    }

And two derrived classes:


public class PatronStatusData : StatusData
{
        private string _name;
        [DataMember(Name = "name1", Order = 0)]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        } 
...
}

And:


public class UniLoginNotFoundError : StatusData 
    {
        public UniLoginNotFoundError()
        { }

        private string _description = "UniLoginNotFoundError";
        [DataMember(Name = "error", Order = 0)]
        public string Description
        {
            get 
            {
                return _description;
            }

        }
    }

The problem is that when I pull the data from the web service the data contract name ("status") and the names of the data members are ignored and the type's and properties' names are used.

Is it possible to use the custome names?

+3  A: 

You should decorate both UniLoginNotFoundError and PatronStatusData with DataContract(Name="Something") to make this work. But you won't be allowed to set the same name ("status") for them. In your particular case I'd better use single class with unused properties set to null.

[DataContract(Name="status")]
public class StatusData
{
    private string _name;
    private string _errorDescription = null;


    [DataMember(Name = "name1", Order = 0, EmitDefaultValue=false)]
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }


    [DataMember(Name = "error", Order = 1, EmitDefaultValue=false)]
    public string Description
    {
        get{ return _errorDescription ;}
        set {_errorDescription =value ;}
    }
...
}
Dmitry Ornatsky
+1 yup, that's the way to go. if you want to be extra clear, you could also add an "IsRequired=false" to the DataMember attributes, to make it crystal-clear that neither of the two strings is indeed required.
marc_s
A: 

Generally speaking, it's a mistake to want too much control over the XML generated by serializing a Data Contract. That's the trap of the XML Serializer. Define the contract in general terms, and have the clients just consume the result, which will generally be simple enough.

John Saunders
A: 

I very much appreciate your answers. It worked your way Dmitry. Thanks a lot!

Borat