简体   繁体   中英

WCF service - update operation best practice

Let's assume we have a simple DTO that we want to use as an input parameter of a CustomerUpdate method:

[DataContract]
public class CustomerUpdateDTO
{
    [DataMember(IsRequired = true, Order = 0)]
    public int CustomerId { get; set; }

    [DataMember(Order = 1)]
    public string FirstName { get; set; }

    [DataMember(Order = 2)]
    public string LastName { get; set; }

    [DataMember(Order = 3)]
    public string Address { get; set; }
}

Only one filed is required - CustomerId - which is rather obvious, as we have to know which customer to update. I would like to achieve the following:

If the incoming SOAP message contains a given value (ex: Joe) i means that the client wants to update this property. If the SOAP message does not contain a value, then the value should not be updated. If the property's value should be deleted (nulled), the client should explicitly declare this by using nil="true" attribute (so explicitly passing a null value).

Example:

<CustomerUpdateDTO>
  <CustomerId>1</CustomerId>
  <FirstName>Joe</FirstName>
  <Address xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</CustomerUpdateDTO>

A message formatted like that would mean, that the client wants to update ONLY the FirstName, leave LastName unchanged, and set the address to null.

The problem is, that under default configuration, a message like that is deserialized as:

CustomerId = 1
FirstName = "Joe"
LastName = null
Address = null

So both LastName and Address end up as nulls.

Is there a way to tell which "null" was caused by omitting the value in the SOAP message, and which "null" was explicitly set?

If not, what would be a "best practice" for a situation like this?

After googling around a bit I've finally found an answer to my question :)

Data member default values, how to figure out whether something was really sent?

This is a very elegant and simple solution. Right now it seems so obvious to me :)

[DataContract]
public class CustomerUpdateDTO
{

    private string firstName;
    public bool FirstNameSpecified { get; set; }

    ...

    [DataMember(Order = 1)]
    public string FirstName
    {
        get
        {
            return firstName;
        }

        set
        {
            FirstNameSpecified = true;
            firstName = value;
        }
    }

    ...

}

When the SOAP message is deserialized and the value is present, the ...Specified flag is set to true.

And that's it! Pure awesomeness :)

A message formatted like that would mean, that the client wants to update ONLY the FirstName, leave LastName unchanged, and set the address to null.

Either break update operation into several distinct update operations:

class FirstNameUpdate
    public Customer as integer
    public FirstName as string
end class 

class LastNameUpdate
    public Customer as integer
    public LastName as string
end class

class AddressUpdate
    public Customer as integer
    public Address as string
end class

or resend the known value that doesn't change

dim Customer = Service.GetCustomer(10)

dim CustomerUpdate as new CustomerUpdateDTO with {
    .CustomerID = Customer.ID,
    .FirstName = "Joe",
    .LastName = Customer.LastName,
    .Address = Nothing}

Service.Update(CustomerUpdate)

Notice LastName is taken from Customer DTO and is sent back to the service in CustomerUpdate DTO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM