/// <summary>
        /// Generates a ProcessSingle User API Request
        /// </summary>
        /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
        /// <returns><see cref="Response"/>object</returns>
        public Response ProcessSingleRequest(ProcessSingleRequest request)
        {
            API.enterprise enterprise = null;
            Response response = null;

            try
            {
                // Validate the SingleRequest Object prior to attempting the Request
                ValidateProcessSingleRequest(request);

                // Intialize Request
                enterprise = CreateEnterprise(request);

                // Build the Response object from the SOAP response
                response = ReadResponse(enterprise);
            }
            catch (Exception ex)
            {
                Logger.Error("Exception from ProcessSingleRequest: ", ex);
                throw;
            }
            finally
            {
                if (userAPI != null)
                    userAPI.Close();
            }

            return response;
        }
        /// <summary>
        /// Creates the Membership child element for the User API Request
        /// </summary>
        /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
        /// <returns><see cref="API.membership"/>object</returns>
        private API.membership CreateMembership(ProcessSingleRequest request)
        {
            // Initialize and Set the Membership Element
            API.membership membership = new API.membership();
            membership.sourcedid = new API.sourcedid();

            // Set the SourcedId value accordingly
            if (request.CallNumber != null)
            {
                membership.sourcedid.source = request.Source;
                membership.sourcedid.id = request.CallNumber;
            }
            else
            {
                membership.sourcedid.source = INTERNAL_IDENTIFIER;
                membership.sourcedid.id = request.NodeString;
            }

            membership.member = new API.member[1];
            membership.member[0] = new API.member();
            membership.member[0].sourcedid = new API.sourcedid();
            membership.member[0].sourcedid.source = request.Source;
            membership.member[0].sourcedid.id = request.Id;

            membership.member[0].role = new API.role[1];
            membership.member[0].role[0] = new API.role();
            membership.member[0].role[0].subrole = request.RoleId;

            return membership;
        }
        /// <summary>
        /// Creates the Group child element for the User API Request
        /// </summary>
        /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
        /// <returns><see cref="API.group"/>object</returns>
        private API.group CreateGroup(ProcessSingleRequest request)
        {
            // Initialize and Set the Group Element
            API.group group = new API.group();
            group.sourcedid = new API.sourcedid[1];
            group.sourcedid[0] = new API.sourcedid();

            // Set the SourcedId accordingly
            if (request.CallNumber != null)
            {
                group.sourcedid[0].source = request.Source;
                group.sourcedid[0].id = request.CallNumber;
            }
            else
            {
                group.sourcedid[0].source = INTERNAL_IDENTIFIER;
                group.sourcedid[0].id = request.NodeString;
            }

            group.grouptype = new API.grouptype[1];
            group.grouptype[0] = new API.grouptype();
            group.grouptype[0].typevalue = new API.typevalue[1];
            group.grouptype[0].typevalue[0] = new API.typevalue();
            group.grouptype[0].typevalue[0].level = "";

            // Setup either a Course Enrollment or Node Enrollment accordingly
            if (request.CallNumber != null)
                group.grouptype[0].typevalue[0].Value = "Call Number";
            else
                group.grouptype[0].typevalue[0].Value = "Enrollable Node";

            return group;
        }
        /// <summary>
        /// Marshals and Creates the full XML payload for the User API Request
        /// </summary>
        /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
        /// <returns><see cref="API.enterprise"/>object</returns>
        private API.enterprise CreateEnterprise(ProcessSingleRequest request)
        {
            // Initialize and Set the Enterprise object and the core Child Elements
            API.enterprise enterprise = new API.enterprise();
            enterprise.properties = request.Properties;

            enterprise.person = new API.person[1];
            enterprise.person[0] = CreatePerson(request);

            // Handle User Property Only Update requests appropriately
            if (request.CallNumber != null || request.NodeString != null)
            {
                enterprise.group = new API.group[1];
                enterprise.group[0] = CreateGroup(request);

                enterprise.membership = new API.membership[1];
                enterprise.membership[0] = CreateMembership(request);
            }

            return enterprise;
        }
 /// <summary>
 /// Performs validation and business logic checks on the ProcessSingleRequest values
 /// </summary>
 /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
 /// <exception cref="ArgumentNullException">Thrown when a required value is not set in the <see cref="ProcessSingleRequest">object</see></exception>
 /// <exception cref="ArgumentException">Thrown when there is a conflict between the values in the <see cref="ProcessSingleRequest">object</see></exception>
 private static void ValidateProcessSingleRequest(ProcessSingleRequest request)
 {
     // Perform a Parameter Validation and Business Logic Check on the Request
     if (request.Source == null)
         throw new ArgumentNullException("The Source value is required.  Please correct and try the reqeust again.");
     else if (request.Id == null)
         throw new ArgumentNullException("The Id value is required.  Please correct and try the request again.");
     else if (request.LoginId == null)
         throw new ArgumentNullException("The LoginId value is required.  Please correct and try the request again.");
     else if (request.FirstName == null)
         throw new ArgumentNullException("The FirstName value is required.  Please correct and try the request again.");
     else if (request.LastName == null)
         throw new ArgumentNullException("The LastName value is required.  Please correct and try the request again.");
     else if (request.Email == null)
         throw new ArgumentNullException("The Email value is required.  Please correct and try the request again.");
     // Try to distinguish a Bad Enrollment Request from a User Property Update Only Request
     // The CallNumber and NodeString will be Null on a User Property Update Only Request but cannot on an Enrollment Request
     else if (request.CallNumber == null && request.NodeString == null && request.RoleId != null)
         throw new ArgumentNullException("Either a CallNumber or NodeString value is required.  Set the CallNumber value for a Course Enrollment " +
             "or set the NodeString value for a Node Enrollment.  Please correct and try the request again");
     else if (request.CallNumber != null && request.NodeString != null)
         throw new ArgumentException("The CallNumber and NodeString values are mutually exclusive.  Only set the CallNumber value for a Course Enrollment " +
             "or set the NodeString value for a Node Enrollment.  Please correct and try the request again");
 }
        /// <summary>
        /// Creates the Pearson child element for the User API Request
        /// </summary>
        /// <param name="request"><see cref="ProcessSingleRequest">object</see></param>
        /// <returns><see cref="API.person"/>object</returns>
        private static API.person CreatePerson(ProcessSingleRequest request)
        {
            // Initialize and Set the Person Element
            API.person person = new API.person();
            person.sourcedid = new API.sourcedid[1];
            person.sourcedid[0] = new API.sourcedid();
            person.sourcedid[0].source = request.Source;
            person.sourcedid[0].id = request.Id;
            person.sourcedid[0].sourcedidtypeSpecified = true;

            person.userid = new API.userid[1];
            person.userid[0] = new API.userid();
            person.userid[0].Value = request.LoginId;

            // If Password is used Set it
            if (request.Password != null)
                person.userid[0].password = request.Password;

            person.name = new API.name();
            person.name.n = new API.n();
            person.name.n.family = request.LastName;
            person.name.n.given = request.FirstName;

            // If Middle Name is used Set it
            if (request.MiddleName != null)
            {
                person.name.n.partname = new API.partname[1];
                person.name.n.partname[0] = new API.partname();
                person.name.n.partname[0].partnametype = "Middlename";
                person.name.n.partname[0].Value = request.MiddleName;
            }

            // If any Demographic values are used set them
            if (request.Gender != null || request.DOB != null || request.Disability != null)
            {
                person.demographics = new API.demographics();

                if (request.Gender != null)
                    person.demographics.gender = request.Gender;

                if (request.DOB != null)
                    person.demographics.bday = request.DOB;

                if (request.Disability != null)
                    person.demographics.disability = new string[1];
                    person.demographics.disability[0] = request.Disability;
            }

            person.email = request.Email;

            // If Phone Number is used set it
            if (request.PhoneNumber != null)
            {
                person.tel = new API.tel[1];
                person.tel[0] = new API.tel();
                person.tel[0].teltype = API.telTeltype.Voice;
                person.tel[0].Value = request.PhoneNumber;
            }

            // If any Address values are used set them
            if (request.Address1 != null || request.Address2 != null || request.City != null ||
                request.State != null || request.ZipCode != null || request.Country != null)
            {
                person.adr = new API.adr();

                if (request.Address1 != null && request.Address2 != null)
                    person.adr.street = new string[2];
                else if (request.Address1 != null || request.Address2 != null)
                    person.adr.street = new string[1];

                if (request.Address1 != null)
                    person.adr.street[0] = request.Address1;

                if (request.Address2 != null)
                {
                    if (request.Address1 != null)
                        person.adr.street[1] = request.Address2;
                    else
                        person.adr.street[0] = request.Address2;
                }

                if (request.City != null)
                    person.adr.locality = request.City;

                if (request.State != null)
                    person.adr.region = request.State;

                if (request.ZipCode != null)
                    person.adr.pcode = request.ZipCode;

                if (request.Country != null)
                    person.adr.country = request.Country;
            }

            // If any Extended User Properties are used Set them
            if (request.ExtendedUserProperties != null)
            {
                person.extension = new API.extension();
                person.extension.Any = new XmlElement[request.ExtendedUserProperties.Count];
                XmlDocument xml = new XmlDocument();
                int i = 0;

                foreach (string key in request.ExtendedUserProperties.Keys)
                {
                    XmlElement eup =  xml.CreateElement("personproperty");
                    eup.InnerText = request.ExtendedUserProperties[key];
                    XmlAttribute attr = xml.CreateAttribute("propertytype");
                    attr.Value = key;
                    eup.Attributes.Append(attr);

                    person.extension.Any[i] = eup;
                    i++;
                }

            }

            return person;
        }