• Wiz/dumb

    DeleteItem Ignores ChangeKeys

    • 0 Comments

    According to our documentation, DeleteItem calls should fail with a ErrorStaleObject error when the ChangeKey is not the most recent one. This, however, is not the case. In Exchange 2007, the ChangeKey is completely ignored in DeleteItem calls. This decision was made on the logic that if you are trying to delete an item, chances are you don’t care if you have the most recent copy or not. But, what if you do?

    You could try doing a GetItem, check the ChangeKey and then call DeleteItem right after, but that still leaves a small window of time between your GetItem and your DeleteItem calls where the item may have been changed.

    Here’s a workaround which will help you implement the logic yourself using pull notifications.

    1. Do a Subscribe on the folder of the item to subscribe for Pull notifications.
    2. Next, do a GetItem and ensure that you do, in fact, have the most recent copy.
    3. Do your DeleteItem.
    4. Do your GetEvents to check for notifications.
    5. If you get just a MovedEvent, then your item was deleted without having been modified (you get a MovedEvent because the item was moved to the Deleted Items folder). You may get a DeletedEvent depending on which flags you passed to DeleteItem. If you get a ModifiedEvent before your MovedEvent, you can then go retrieve the item from the Deleted Items folder and check the values of the properties from the item there. If you hard deleted the item (and therefore got a DeletedEvent) you cannot go get the latest copy from Deleted Items, because it isn’t there.
    6. Unsubscribe.
  • Wiz/dumb

    ConfigureMsgService fails with MAPI_E_INVALID_PARAMETER (0x80070057)

    • 0 Comments

    I recently helped a customer with an issue where they were calling ConfigureMsgService and that call was failing, returning an HRESULT of MAPI_E_INVALID_PARAMETER (0x80070057). After debugging it, we established that the reason that ConfigureMsgService was failing was that the PR_PROFILE_HOME_SERVER_ADDRS property was missing from the profile. Outlook seemed to work fine, logons worked, sending mail worked; it was just that ConfigureMsgService would fail. We tried recreating the profile, but still the property wasn’t being set on the profile.

    It turns out that PR_PROFILE_HOME_SERVER_ADDRS gets its value from PR_EMS_AB_NETWORK_ADDRESS, which in turn, gets its value from the networkAddress attribute on the server object in Active Directory. That value was set correctly, but permissions to that object were not. After following the requirements laid out on technet for permissions to AD objects, we determined that the Authenticated Users group was missing the ACL for Read All Properties on the server object. Once we set that permission and recreated the profile, the property was set correctly on the profile and ConfigureMsgService started succeeding.

  • Wiz/dumb

    Line Breaks in Managed Web Service Proxy Classes

    • 0 Comments

    Matt, Rick, and I were working on an issue recently where when an application using EWS would set a contact’s Street address to a value containing a carriage return and line feed, like this:

    physicalAddress.Street = "1234 56 Ave NE\r\nc/oPatrick Creehan";

    the address card control in Outlook would render it like this:

    image

    Ugly, right? The problem was that the XMLSerializer would strip out the line feed and leave the carriage return, which the address card didn’t like.

    We could prove by sending raw XML requests in a separate application that sending 
 for the carriage return line feed would make everything right, however, if we set the street address like this:

    physicalAddress.Street = "1234 56 Ave NE
c/oPatrick Creehan";

    then the contact’s address card would look like this:

    image

    Even uglier! It seems that the .net framework, in an attempt to help us out is encoding our string for XML but it wasn’t letting us specify the value we knew was right.

    So – the solution is to implement your own class which can handle the XmlSerialization yourself, and replace the auto-generated proxy class’s decision for the type to yours.

    Here’s my simple class:

    1.     [SoapTypeAttribute(Namespace = "http://schemas.microsoft.com/exchange/services/2006/types",TypeName="text")]
    2.     public class mstring:IXmlSerializable  
    3.     {
    4.         private string m_string = string.Empty;
    5.         public override string ToString()
    6.         {
    7.             return m_string;
    8.         }
    9.         
    10.         public static mstring CreateMString(string str){
    11.             mstring newmstring = new mstring();
    12.             newmstring.m_string = str;
    13.             return newmstring;
    14.         }
    15.         public static implicit operator mstring(string str)
    16.         {
    17.             return CreateMString(str);
    18.         }
    19.         #region IXmlSerializable Members
    20.         public System.Xml.Schema.XmlSchema GetSchema()
    21.         {
    22.             return new System.Xml.Schema.XmlSchema();
    23.         }
    24.         public void ReadXml(XmlReader reader)
    25.         {
    26.             m_string = reader.ReadContentAsString();
    27.         }
    28.         public void WriteXml(XmlWriter writer)
    29.         {
    30.             string outString = m_string;
    31.             outString = HttpUtility.HtmlEncode(outString);
    32.             outString = outString.Replace("\r", "
");
    33.             outString = outString.Replace("\n", "
");
    34.             writer.WriteRaw(outString.ToString());
    35.         \

    A few things to point out is that I decorated this class with the XML namespace for the Exchange Web Services so that it doesn’t fail schema validation. Also, I didn’t really test whether this works when binding to an existing contact – there may be more work needed in the ReadXML section. In order to support still setting the Street property to a string, I had to override the implicit operator. That allows me to set Street to a string even though technically, now Street is an “mstring.” You’ll notice that the work of actually writing the correct value occurs in WriteXml which we got by implementing IXmlSerializable. Now when the SOAP infrastructure goes to build the request, it will call into our interface to serialize this class.

    That reminds me, the last thing you need to do to hook all this up is to go into the web service proxy class Reference.cs and modify the PhysicalAddressDictionaryEntryType so the street properties use your new mstring class instead of string:

    1.     /// <remarks/>
    2.     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.4918")]
    3.     [System.SerializableAttribute()]
    4.     [System.Diagnostics.DebuggerStepThroughAttribute()]
    5.     [System.ComponentModel.DesignerCategoryAttribute("code")]
    6.     [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/exchange/services/2006/types")]
    7.     public partial class PhysicalAddressDictionaryEntryType {
    8.         
    9.         private mstring streetField;
    10.         
    11.         private string cityField;
    12.         
    13.         private string stateField;
    14.         
    15.         private string countryOrRegionField;
    16.         
    17.         private string postalCodeField;
    18.         
    19.         private PhysicalAddressKeyType keyField;
    20.         
    21.         /// <remarks/>
    22.         public mstring Street {
    23.             get {
    24.                 return this.streetField;
    25.             }
    26.             set {
    27.                 this.streetField = value;
    28.             }
    29.         }
    30.         /// <remarks/>
    31.         public string City {
    32.             get {
    33.                 return this.cityField;
    34.             }
    35.             set {
    36.                 this.cityField = value;
    37.             }
    38.         }
    39.         
    40.         /// <remarks/>
    41.         public string State {
    42.             get {
    43.                 return this.stateField;
    44.             }
    45.             set {
    46.                 this.stateField = value;
    47.             }
    48.         }
    49.         
    50.         /// <remarks/>
    51.         public string CountryOrRegion {
    52.             get {
    53.                 return this.countryOrRegionField;
    54.             }
    55.             set {
    56.                 this.countryOrRegionField = value;
    57.             }
    58.         }
    59.         
    60.         /// <remarks/>
    61.         public string PostalCode {
    62.             get {
    63.                 return this.postalCodeField;
    64.             }
    65.             set {
    66.                 this.postalCodeField = value;
    67.             }
    68.         }
    69.         
    70.         /// <remarks/>
    71.         [System.Xml.Serialization.XmlAttributeAttribute()]
    72.         public PhysicalAddressKeyType Key {
    73.             get {
    74.                 return this.keyField;
    75.             }
    76.             set {
    77.                 this.keyField = value;
    78.             }
    79.         }
    80.     \

    and (after removing the email address so the address will fit on the card) it looks like this:

    image

     

    Cake.

Page 1 of 1 (3 items)