I found the answer to this after much debugging. I'm not going to explore more to find out why, but you can't do this:
updateContact = Contact.Bind(service, itemId);
updateContact.PhoneNumbers[PhoneNumberKey.HomePhone] = customContact.HomePhone;
updateContact.PhoneNumbers[PhoneNumberKey.MobilePhone] = customContact.MobilePhone;
updateContact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = customContact.BusinessPhone;
updateContact.Update(ConflictResolutionMode.AlwaysOverwrite);
You can, however, set only one phone number and then change the values for the other two while debugging (while on a break point). Weird.
Anyway, there is a problem - you can't update one of these dictionary values if the value does not change (that's the answer in short), so do a check first to see if the value changed. Next, if a value is an empty string, you need to rather save it as null. You also need to check whether the dictionary entry exists before trying to read its value.
string number;
bool numberFound;
numberFound = updateContact.PhoneNumbers.TryGetValue(PhoneNumberKey.HomePhone, out number);
if ((numberFound && number != customContact.HomePhone) ||
(!numberFound && !string.IsNullOrEmpty(customContact.HomePhone)))
{
updateContact = Contact.Bind(service, itemId);
updateContact.PhoneNumbers[PhoneNumberKey.HomePhone] = customContact.HomePhone == "" ? null : customContact.HomePhone;
updateContact.Update(ConflictResolutionMode.AlwaysOverwrite);
}
To update an address:
updateContact = Contact.Bind(service, itemId);
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].Street = customContact.Street == "" ? null : customContact.Street;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].State = customContact.Suburb == "" ? null : customContact.Suburb;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].City = customContact.City == "" ? null : customContact.City;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].CountryOrRegion = customContact.Country == "" ? null : customContact.Country;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].PostalCode = customContact.AreaCode == "" ? null : customContact.AreaCode;
updateContact.Update(ConflictResolutionMode.AlwaysOverwrite);
This, in my opinion, is sloppy implementation of the API (and poor documentation).
The fact that an update needs to be performed for each property of an item could possibly be due to the server running Exchange 2007, but this has yet to be confirmed.
I tried with both version 14 and 15 of Microsoft.Exchange.WebServices with the same results.
Update
But wait, there's more.
I'm posting a lot of code to illustrate how to update different phone numbers, addresses, etc. The code also shows how to update (or set) title, gender, suffix and a custom property (user defined field - which if you want to appear in Outlook, you need to add the user defined field to the contacts folder).
Here is a complete, working piece of code:
Contact updateContact = Contact.Bind(service, itemId);
updateContact.GivenName = customContact.Name;
updateContact.Surname = customContact.Surname;
EmailAddress emailAddress;
bool emailAddressFound;
emailAddressFound = updateContact.EmailAddresses.TryGetValue(EmailAddressKey.EmailAddress1, out emailAddress);
if (emailAddressFound && emailAddress.Address != customContact.Email)
{
emailAddress.Address = customContact.Email == "" ? null : customContact.Email;
}
else if (!emailAddressFound && !string.IsNullOrEmpty(customContact.Email))
{
updateContact.EmailAddresses[EmailAddressKey.EmailAddress1] = customContact.Email;
}
updateContact.Initials = customContact.Initials;
string number;
bool numberFound;
numberFound = updateContact.PhoneNumbers.TryGetValue(PhoneNumberKey.HomePhone, out number);
if ((numberFound && number != customContact.HomePhone) || (!numberFound && !string.IsNullOrEmpty(customContact.HomePhone)))
{
updateContact.PhoneNumbers[PhoneNumberKey.HomePhone] = customContact.HomePhone == "" ? null : customContact.HomePhone;
}
numberFound = updateContact.PhoneNumbers.TryGetValue(PhoneNumberKey.MobilePhone, out number);
if ((numberFound && number != customContact.CellPhone) || (!numberFound && !string.IsNullOrEmpty(customContact.CellPhone)))
{
updateContact.PhoneNumbers[PhoneNumberKey.MobilePhone] = customContact.CellPhone == "" ? null : customContact.CellPhone;
}
numberFound = updateContact.PhoneNumbers.TryGetValue(PhoneNumberKey.BusinessPhone, out number);
if ((numberFound && number != customContact.WorkPhone) || (!numberFound && !string.IsNullOrEmpty(customContact.WorkPhone)))
{
updateContact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = customContact.WorkPhone == "" ? null : customContact.WorkPhone;
}
PhysicalAddressEntry phsicalAddress;
bool phsicalAddressFound;
int phsicalAddressLength = (customContact.Street + customContact.Suburb + customContact.City + customContact.Country + customContact.AreaCode).Length;
phsicalAddressFound = updateContact.PhysicalAddresses.TryGetValue(PhysicalAddressKey.Home, out phsicalAddress);
if (phsicalAddressFound)
{
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].Street = customContact.Street == "" ? null : customContact.Street;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].State = customContact.Suburb == "" ? null : customContact.Suburb;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].City = customContact.City == "" ? null : customContact.City;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].CountryOrRegion = customContact.Country == "" ? null : customContact.Country;
updateContact.PhysicalAddresses[PhysicalAddressKey.Home].PostalCode = customContact.AreaCode == "" ? null : customContact.AreaCode;
}
else if (!phsicalAddressFound && phsicalAddressLength > 0)
{
updateContact.PhysicalAddresses[PhysicalAddressKey.Home] = homeAddress;
}
phsicalAddressLength = (customContact.BusinessStreet + customContact.BusinessSuburb + customContact.BusinessCity + customContact.BusinessCountry + customContact.BusinessAreaCode).Length;
phsicalAddressFound = updateContact.PhysicalAddresses.TryGetValue(PhysicalAddressKey.Business, out phsicalAddress);
if (phsicalAddressFound)
{
updateContact.PhysicalAddresses[PhysicalAddressKey.Business].Street = customContact.BusinessStreet == "" ? null : customContact.BusinessStreet;
updateContact.PhysicalAddresses[PhysicalAddressKey.Business].State = customContact.BusinessSuburb == "" ? null : customContact.BusinessSuburb;
updateContact.PhysicalAddresses[PhysicalAddressKey.Business].City = customContact.BusinessCity == "" ? null : customContact.BusinessCity;
updateContact.PhysicalAddresses[PhysicalAddressKey.Business].CountryOrRegion = customContact.BusinessCountry == "" ? null : customContact.BusinessCountry;
updateContact.PhysicalAddresses[PhysicalAddressKey.Business].PostalCode = customContact.BusinessAreaCode == "" ? null : customContact.BusinessAreaCode;
}
else if (!phsicalAddressFound && phsicalAddressLength > 0)
{
updateContact.PhysicalAddresses[PhysicalAddressKey.Business] = businessAddress;
}
updateContact.Birthday = customContact.Birthdate;
updateContact.WeddingAnniversary = customContact.MaritalStatusDate;
ExtendedPropertyDefinition extendedPropertyDefinition;
if (!string.IsNullOrEmpty(customContact.Gender))
{
extendedPropertyDefinition = new ExtendedPropertyDefinition(0x3a4d, MapiPropertyType.Short);
switch (customContact.Gender)
{
case "Male":
updateContact.SetExtendedProperty(extendedPropertyDefinition, 2);
break;
case "Female":
updateContact.SetExtendedProperty(extendedPropertyDefinition, 1);
break;
default:
updateContact.SetExtendedProperty(extendedPropertyDefinition, 3);
break;
}
}
if (!string.IsNullOrEmpty(customContact.Title))
{
extendedPropertyDefinition = new ExtendedPropertyDefinition(0x3a45, MapiPropertyType.String);
updateContact.SetExtendedProperty(extendedPropertyDefinition, customContact.Title);
}
if (!string.IsNullOrEmpty(customContact.Suffix))
{
extendedPropertyDefinition = new ExtendedPropertyDefinition(0x3a05, MapiPropertyType.String);
updateContact.SetExtendedProperty(extendedPropertyDefinition, customContact.Suffix);
}
extendedPropertyDefinition = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "customProperty", MapiPropertyType.String);
updateContact.SetExtendedProperty(extendedPropertyDefinition, customContact.CustomProperty);
updateContact.Subject = customContact.Name + " " + customContact.Surname;
updateContact.DisplayName = customContact.Name + " " + customContact.Surname;
updateContact.Update(ConflictResolutionMode.AlwaysOverwrite);