September, 2004

Posts
  • Michaeljon Miller

    (Nearly) complete MS-CRM entity serialization sample

    • 1 Comments

    [I’m finally getting around to formatting this thing so it’s readable and changing the broken links]

    This example assumes that you've created correct XSD from the MS-CRM metadata (see http://blogs.msdn.com/mikemill/archive/2004/12/01/273254.aspx) and that you've run that XSD through the XSD Object Generator. The one change you should making prior to creating classes is to change the tns:dateTimeType to derive from xsd:string instead of xsd:dateTime, otherwise you'll end up serializing dates that the platform can't really cope with.

    With a few simple tweaks to the XSD generator you can create XSD that the VS XSD.EXE tool can use. The way I've done this is to change the generated xsd:complexType to be the entity name followed by 'Type' and to create xsd:elements that reference the complexType.

    (Apologies in advance if the formatting here is off, I'm still working my way around the .Text editor).

    using System;

    using System.Text;

    using System.Web.Services;

    using System.Runtime.Serialization;

    using System.Xml.Serialization;

    using System.IO;

    using System.Globalization;

    using Microsoft.Crm.Entities;

    using Microsoft.Crm.Platform.Proxy;

     

    namespace Cheerios

    {

        class SerializerSample

        {

            /// <summary>

            /// Returns a string (XML) representation of a serializable

            /// entity. The namespaces are removed because the CRM

            /// platform deserialization code won't cope welll with them.

            /// </summary>

            /// <param name="o">The instance to serialize</param>

            /// <returns></returns>

            public static string ToString(object o)

            {

                StringBuilder sb = new StringBuilder();

                XmlSerializer serializer = new XmlSerializer(o.GetType());

                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

                ns.Add("", ""); TextWriter writer = new StringWriter(sb);

                serializer.Serialize(writer, o, ns); return sb.ToString();

            }

     

            /// <summary>

            /// Returns an instance of a object created from the supplied

            /// XML. You must cast the return value to the correct class.

            /// </summary>

            /// <param name="t"></param>

            /// <param name="s"></param>

            /// <returns></returns>

            public static object ToObject(Type t, string s)

            {

                XmlSerializer serializer = new XmlSerializer(t);

                TextReader reader = new StringReader(s);

                return serializer.Deserialize(reader);

            }

     

            /// <summary> /// The main entry point for the application.

            /// </summary>

            [STAThread]

            static void Main(string[] args)

            {

                // create the service proxies

                BizUser userService = new BizUser();

                userService.Url = "http://paint/mscrmservices/bizuser.srf";

                userService.Credentials = System.Net.CredentialCache.DefaultCredentials;

               

                CRMContact contactService = new CRMContact();

                contactService.Url = "http://paint/mscrmservices/crmcontact.srf";

                contactService.Credentials = System.Net.CredentialCache.DefaultCredentials;

     

                // get our credentials from the platform

                CUserAuth userAuth = userService.WhoAmI();

     

                // create an contact object in "client-space" and set some properties

                contact theContact = new contact();

     

                // the CRM platform wants to see dates like YYYY-MM-DDTHH:MM:SS

                theContact.birthdate.Value =

                    DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.SortableDateTimePattern);

     

                // set some other properties on the object

                theContact.customertypecode.Value = 6;

                theContact.creditlimit.Value = 123456.0F;

                theContact.creditonhold.Value = true;

                theContact.firstname = "Bob";

                theContact.lastname = "Jones";

                theContact.description = "This is my sample contact....";

     

                // set up the ownership information because the platform won't

                // automatically do that for you

                theContact.ownerid.Value = userAuth.UserId;

                theContact.ownerid.type = 8;

     

                // turn it into XML

                string initialContactXml = SerializerSample.ToString(theContact);

                Console.WriteLine("Created contact XML\n{0}\n", initialContactXml);

     

                // stuff in into the platform and get the new one back

                string updatedContactXml =

                    contactService.CreateAndRetrieve(userAuth, initialContactXml);

                Console.WriteLine("Retrieved contact XML\n{0}\n", updatedContactXml);

     

                // turn the new one into an object

                theContact = (contact)ToObject(typeof(contact), updatedContactXml);

                Console.WriteLine("Serialized new contact to\n{0}\n", SerializerSample.ToString(theContact));

                Console.WriteLine("Hit <return> to continue"); Console.ReadLine();

            }

        }

    }

    The XML generated from the first serialization (from theContact to initialContactXml) looks like the following. This string can be passed directly to the MS-CRM platform as the ContactXml parameter.

    <?xml version="1.0" encoding="utf-16"?>

    <contact>

        <birthdate>2004-09-10T16:40:54</birthdate>

        <creditlimit>123456</creditlimit>

        <creditonhold>true</creditonhold>

        <customertypecode>6</customertypecode>

        <description>This is my sample contact....</description>

        <firstname>Bob</firstname>

        <lastname>Jones</lastname>

        <ownerid type="8">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</ownerid>

    </contact>

    The call to CreateAndRetrieve returns the following XML (note, I've formatted this a bit so that it's readable). Notice the date, boolean, and lookup elements have extra XML attributes automatically. These will be mapped to corresponding values in the supporting C# types. One thing to notice here is that the platform XML doesn't include the processing instruction. You can assume that the platform will return UTF-8 formatted XML.

    <?xml version="1.0" encoding="utf-16"?>

    <contact>

        <contactid>{CD303B40-B8E5-4B84-ABFF-A2DA4C6D9E35}</contactid>

        <customertypecode>6</customertypecode>

        <owningbusinessunit>{7DE28647-59CA-4C95-B7A3-FA7E31CD6DA8}</owningbusinessunit>

        <participatesinworkflow>0</participatesinworkflow>

        <firstname>Bob</firstname>

        <lastname>Jones</lastname>

        <fullname>Jones, Bob</fullname>

        <birthdate date="09/10/2004" time="4:40 PM">2004-09-10T16:40:54-07:00</birthdate>

        <description>This is my sample contact....</description>

        <creditlimit>123456</creditlimit>

        <createdon date="09/10/2004" time="9:40 AM">2004-09-10T09:40:32-07:00</createdon>

        <creditonhold name="Yes">1</creditonhold>

        <createdby name="Miller, Michaeljon" dsc="0">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</createdby>

        <modifiedon date="09/10/2004" time="9:40 AM">2004-09-10T09:40:32-07:00</modifiedon>

        <modifiedby name="Miller, Michaeljon" dsc="0">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</modifiedby>

        <statecode name="Active">0</statecode>

        <statuscode name="Active">1</statuscode>

        <address1_addressid>{B315C1B1-ACFF-4438-97B5-FF9EA34A681F}</address1_addressid>

        <address2_addressid>{80FB9B47-4F68-44B1-A619-402F4AD94061}</address2_addressid>

        <ownerid name="Miller, Michaeljon" dsc="0" type="8">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</ownerid>

    </contact>

     

    Finally we can take the returned platform XML and convert it into a class. For this example I'm simply turning the class back into an XML string, but you can use that resulting object like you would any object. It's also quite possible to create collection classes and use the bulk retrieve operations to hold collections of CRM "objects".

    <?xml version="1.0" encoding="utf-16"?>

    <contact>

        <address1_addressid>{2025B5AA-BAD7-4816-9406-BEF62BA89358}</address1_addressid>

        <address2_addressid>{5135ECBE-56E3-41A7-99F8-7ACC3C3B9FDA}</address2_addressid>

        <birthdate date="09/10/2004" time="4:50 PM">2004-09-10T16:50:08-07:00</birthdate>

        <contactid>{012014CF-350C-42CE-90D1-533A222CEE0A}</contactid>

        <createdby name="Miller, Michaeljon" dsc="0">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</createdby>

        <createdon date="09/10/2004" time="9:49 AM">2004-09-10T09:49:55-07:00</createdon>

        <creditlimit>123456</creditlimit>

        <creditonhold name="Yes">true</creditonhold>

        <customertypecode>6</customertypecode>

        <description>This is my sample contact....</description>

        <firstname>Bob</firstname>

        <fullname>Jones, Bob</fullname>

        <lastname>Jones</lastname>

        <modifiedby name="Miller, Michaeljon" dsc="0">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</modifiedby>

        <modifiedon date="09/10/2004" time="9:49 AM">2004-09-10T09:49:55-07:00</modifiedon>

        <ownerid name="Miller, Michaeljon" type="8" dsc="0">{9CBA0E1D-882F-4A39-9441-B4FA3BA14724}</ownerid>

        <owningbusinessunit>{7DE28647-59CA-4C95-B7A3-FA7E31CD6DA8}</owningbusinessunit>

        <participatesinworkflow>false</participatesinworkflow>

        <statecode name="Active">0</statecode>

        <statuscode name="Active">1</statuscode>

    </contact>

     I hope this helps developers better understand the relationship between the MS-CRM XML and .Net classes.

     

  • Michaeljon Miller

    Listing of recent posts

    • 0 Comments

    I was playing around on blogger this morning trying to figure out if it made sense to move my posts over here and to post a final "farewell" over there. Turns out I can't post that final message for some reason. I hate it when software doesn't work. So, I took a slightly different approach and I've grabbed just the links and have pasted them below. These are listed by date in reverse order.

    If you haven't read any of my rantings before, this list will give you an idea of the kinds of things I go on about.

  • Michaeljon Miller

    Obligatory welcome message

    • 0 Comments

    After a few months of hanging out over at http://inside-mscrm.blogspot.com/ I thought it might really be time to join the rest of my team over in the "official" Microsoft blogsphere. To save myself a lot of time rehashing who I am and what background makes me qualified to talk about MS-CRM, I'll just refer you to http://inside-mscrm.blogspot.com/2004/05/just-getting-started.html.

    I haven't yet figured out how to move the content over and I'm not going to copy it verbatim if I can help it. The good thing about being "in the fold" is that I get better support for what I do. I'm looking forward to hearing from new folks who've been watching this spot for MS-CRM information (I know, there still isn't that much of it available and the product's been shippinf for a while now).

    By the way I did have a life before Microsoft and before MS-CRM. Occassionally I may yammer on a bit about "the good ol' days" and how we did things outside of Microsoft. The only reason I'll do that is because I'm feeling frustrated that long-time 'softies somehow don't get corporate or IT development. Really though, it's just my view on things and probably doesn't reflect reality within the company. Probably.

    So, welcome to "Inside MS-CRM".

Page 1 of 1 (3 items)