Class used to store API Key, username and password for the Constant Contact REST API
 private void button1_Click(object sender, EventArgs e)
 {
     //DEBUG TESTING
     AuthenticationData authdata = new AuthenticationData();  //Set your credentials for basic or OAuth2 inside the parentheses
   
     //Your test code below
 }
 private void button1_Click(object sender, EventArgs e)
 {
     //DEBUG TESTING
     AuthenticationData authdata = new AuthenticationData();
     authdata.Username = "";
     authdata.Password = "";
     authdata.ApiKey = "";
 }
        /// <summary>
        /// Verify user authentication
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <exception cref="ConstantAuthenticationException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server 
        /// or if ApiKey, Username or Password are null or empty</exception>
        public static void IsValidUserAuthentication(AuthenticationData authenticationData)
        {
            ValidateAuthenticationData(authenticationData);

            try
            {
                // try to access the Service Document resource
                // it will throw a WebException if Constant Contact credentials are invalid

                GetResponseStream(new Uri(authenticationData.AccountServiceDocumentUri), authenticationData);
            }
            catch (Exception e)
            {
                throw new ConstantAuthenticationException("Account authentication failed", e,
                                                          authenticationData.Username);
            }
        }
        /// <summary>
        /// Retrieves the collection of user Contact Lists returned by the server at current chunk Id.        
        /// The collection is sorted by the Sort Order and it will not include the system 
        /// predefined lists ("Active", "Removed", "DoNotEmail")
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="currentChunkId">Link to the current chunk data</param>
        /// <param name="nextChunkId">Link to the next chunk of data</param>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>The collection of user Contact Lists</returns>
        public static IList<ContactList> GetUserContactListCollection(AuthenticationData authenticationData, string currentChunkId, out string nextChunkId)
        {
            // get the collection of Contact Lists
            IList<ContactList> list = GetContactListCollection(authenticationData, currentChunkId, out nextChunkId);

            IList<ContactList> nonSystemList = new List<ContactList>();

            foreach (ContactList contactList in list)
            {
                if (!contactList.IsSystemList)
                {
                    nonSystemList.Add(contactList);
                }
            }

            return nonSystemList;
        }
        /// <summary>
        /// Remove Contact from all Contact Lists
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contactId">Contact Id</param>
        /// <exception cref="ArgumentException">Thrown if Id of specified Contact is null or empty</exception>        
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server or if no Contact with specified Id exists
        /// or if ApiKey, Username or Password are null or empty</exception>
        public static void RemoveContactFromAllLists(AuthenticationData authenticationData, string contactId)
        {
            ValidateAuthenticationData(authenticationData);

            if (string.IsNullOrEmpty(contactId))
            {
                throw new ArgumentException("Contact Id cannot be null or empty", "contactId");
            }

            // create the URI for specified Contact Id
            string completeUri = String.Format(CultureInfo.InvariantCulture, "{0}/{1}",
                                               authenticationData.AccountContactsUri, contactId);

            // get Contact by Id
            Contact contact = GetContactDetailsById(authenticationData, contactId);

            // consider that Contact does not needs to be updated
            bool needUpdate = false;

            if (contact.ContactLists.Count != 0)
            {
                // remove Contact from all Contact Lists
                contact.ContactLists.Clear();

                // Contact must be updated
                needUpdate = true;
            }

            if (!needUpdate)
            {
                // no need to update Contact
                return;
            }

            // get the Atom entry for specified Contact
            StringBuilder data = ContactComponent.RemoveContactFromAllLists(contact,
                                                                            authenticationData.AccountContactsUri);

            try
            {
                // put the Atom entry at specified Uri
                PutInformation(authenticationData, new Uri(completeUri), data.ToString());
            }
            catch (Exception e)
            {
                // possible that the Contact does not exist any more; not sure if this could happened
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Contact with Id '{0}' does not exist.", contactId));
                }

                throw new ConstantException(e.Message, e);
            }
        }
        /// <summary>
        /// Sends a Http GET request and returns the response Stream from the specified Uri address
        /// </summary>
        /// <param name="address">Uri address</param>     
        /// <param name="authenticationData">Authentication data</param>
        /// <returns>Response Stream</returns>
        private static Stream GetResponseStream(Uri address, AuthenticationData authenticationData)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
            request.Credentials = CreateCredentialCache(address, authenticationData);
            request.Method = WebRequestMethods.Http.Get;

            // request MUST include a WWW-Authenticate
            request.PreAuthenticate = true;

            Stream stream = Stream.Null;
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                // get the response Stream
                stream = response.GetResponseStream();

                // read the response stream and save it into a memory stream
                return ReadResponseStream(stream);
            }
            catch (WebException e)
            {
                if (null != e.Response)
                {
                    Console.Out.WriteLine("WebException Response Headers =");
                    Console.Out.WriteLine(e.Response.Headers);
                }
                throw;
            }
            finally
            {
                if (stream != Stream.Null)
                {
                    // close response stream; it also closes the web response
                    stream.Close();
                }
            }
        }
        /// <summary>
        /// Delete a Contact List specified by list ID
        /// </summary>
        /// <param name="authdata">Authentication data (username, password and API Key)</param>
        /// <param name="listID">ID of target list to delete</param> 
        public static void deleteList(AuthenticationData authdata, string listID)
        {
            if (string.IsNullOrEmpty(listID))
            {
                throw new ArgumentException("List Id cannot be null or empty", "id");
            }
            try
            {
                httpDelete(authdata, authdata.AccountContactListsUri + "/" + listID);
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "List with ID '{0}' does not exist.", listID));
                }

                throw new ConstantException(e.Message, e);
            }
        }
        /// <summary>
        /// Sends a Http DELETE request at the specified Uri address
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="address">Uri address</param>
        private static void DeleteInformation(AuthenticationData authenticationData, Uri address)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
            request.Credentials = CreateCredentialCache(address, authenticationData);

            request.Method = "DELETE";

            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
                                                "Method {0}, response description: {1}", request.Method,
                                                response.StatusDescription));
            }
            finally
            {
                if (response != null)
                {
                    // close the response
                    response.Close();
                }
            }
        }
        /// <summary>
        /// Sends a Http request on specified Uri address and returns the response Stream
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="address">Uri address</param>
        /// <param name="requestMethod">Type of Http request</param>
        /// <param name="contentType">Content type of the Http request</param>
        /// <param name="data">Data to be send at specified Uri address</param>
        /// <returns>Response Stream</returns>
        private static Stream GetResponseStream(AuthenticationData authenticationData,
            Uri address, string requestMethod, string contentType, string data)
        {
            // get data bytes
            byte[] dataByte = Encoding.ASCII.GetBytes(data);

            // send the request and return the response Stream
            return GetResponseStream(authenticationData, address, requestMethod, contentType, dataByte);
        }
        /// <summary>
        /// Opting-out ("Unsubscribe") a Contact
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contactId">Contact Id</param>
        /// <exception cref="ArgumentException">Thrown if Id of specified Contact is null or empty</exception>        
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server or if no Contact with specified Id exists
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <remarks>Opted-out Contacts become members of the Do-Not-Mail special list</remarks>
        public static void UnsubscribeContact(AuthenticationData authenticationData, string contactId)
        {
            ValidateAuthenticationData(authenticationData);

            if (string.IsNullOrEmpty(contactId))
            {
                throw new ArgumentException("Contact Id cannot be null or empty", "contactId");
            }

            // create the URI for specified Contact List Id
            string completeUri = String.Format(CultureInfo.InvariantCulture, "{0}/{1}",
                                               authenticationData.AccountContactsUri, contactId);

            try
            {
                // issue a Http DELETE and specified Uri
                DeleteInformation(authenticationData, new Uri(completeUri));
            }
            catch (Exception e)
            {
                // possible that the Contact does not exist any more
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Contact with Id '{0}' does not exist.", contactId));
                }

                throw new ConstantException(e.Message, e);
            }
        }
 /// <summary>
 /// Update a Contact using the simplified form. Only the following fields will be updated: 
 /// EmailAddress, FirstName, LastName, MiddleName, HomePhone, Addr1, Addr2, Addr3,
 /// City, StateCode, StateName, CountryCode, CountryName, PostalCode, SubPostalCode
 /// </summary>
 /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
 /// <param name="contact">Contact to be updated</param>
 /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
 /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
 /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
 /// or other related with the response from server, if no Contact with specified Id exists 
 /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
 /// or if ApiKey, Username or Password are null or empty</exception>        
 public static void UpdateContactSmallForm(AuthenticationData authenticationData, Contact contact)
 {
     UpdateContact(authenticationData, contact, false);
 }
        /// <summary>
        /// Gets a list of email campaigns filtered by status
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="status">campaign status</param>
        /// <returns>filtered email campaigns</returns>
        public static List<EmailCampaign> GetEmailCampaignCollection(AuthenticationData authenticationData, string status)
        {
            string currentAddress = string.Format("{0}?status={1}", authenticationData.AccountEmailCampaignsListUri, status);

            Stream stream = Stream.Null;
            try
            {
                // get the response stream
                stream = GetResponseStream(new Uri(currentAddress), authenticationData);

                // parse the stream and get a collection of Contact Lists
                return EmailCampaignComponent.GetEmailCampaignCollection(stream);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
        /// <summary>
        /// Retrieves the first chunk collection of Contacts that match specified Email Addresses
        /// </summary>
        /// <remarks>Constant Contact server provides paged collections</remarks>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="emailAddresses">One or more Email Addresses</param>
        /// <param name="nextChunkId">Link to the next chunk of data</param>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server 
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>The collection of Contacts</returns>
        public static IList<Contact> SearchContactByEmail(AuthenticationData authenticationData, IEnumerable<string> emailAddresses, out string nextChunkId)
        {
            ValidateAuthenticationData(authenticationData);

            return SearchContactByEmail(authenticationData, emailAddresses, null, out nextChunkId);
        }
        /// <summary>
        /// Get EmailCampaign By Id
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="id">campaign id</param>
        /// <returns>Email campaign with the specified id</returns>
        public static EmailCampaign GetEmailCampaignById(AuthenticationData authenticationData, string id)
        {
            string currentAddress = string.Format("{0}/{1}", authenticationData.AccountEmailCampaignsListUri, id);

            Stream stream = Stream.Null;
            try
            {
                // get the response stream
                stream = GetResponseStream(new Uri(currentAddress), authenticationData);

                // parse the stream and get an Email Campaign
                return EmailCampaignComponent.GetEmailCampaign(stream);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
 /// <summary>
 /// Get details of activity with specified ID
 /// </summary>
 /// <param name="Authdata">Authentication Data</param>
 /// <param name="id">ID of target activity</param>
 /// <returns>Returns details of activity of specified id</returns>
 public static Activity getActivityDetails(AuthenticationData Authdata, string id)
 {
     //verify id was specified
     if (string.IsNullOrEmpty(id))
     {
         throw new ArgumentException("Activity Id cannot be null or empty", "id");
     }
     string blank = "";
     string fullcall = Authdata.accountActivitiesUri + "/" + id;
     //return Activity
     return getActivities(Authdata, id, out blank)[0];
 }
        /// <summary>
        /// Gets chunk of activites at specified link
        /// </summary>
        /// <param name="Authdata">Authentication Data</param>
        /// <param name="link">Link to target chunk of data</param>
        /// <param name="nextChunk">out link to next chunk of data</param>
        /// <returns>returns list up to 50 activities of specified chunk. if more than 50, out nextChunk link to next chunk of data</returns>
        public static IList<Activity> getActivities(AuthenticationData Authdata, string link, out string nextChunk)
        {
            //Create new xmldocument, create activitieslist uri, GET, load XML.
            XmlDocument xDoc = new XmlDocument();
            string URI = "";
            if (link == "")
            {
                URI = Authdata.accountActivitiesUri;
            }
            else
            {
                URI = Authdata.ApiRootUri + link;
            }
            try
            {
                xDoc.LoadXml(Utility.httpGet(Authdata, URI));
                //Define namespaces
                XmlNamespaceManager xnsmgr = new XmlNamespaceManager(xDoc.NameTable);
                xnsmgr.AddNamespace("ns1", "http://www.w3.org/2005/Atom");
                xnsmgr.AddNamespace("ns2", "http://ws.constantcontact.com/ns/1.0/");
                //Check for link to next chunk of data. If no next chunk, return empty string.
                nextChunk = "";
                XmlNodeList xnlLinks = xDoc.SelectNodes("//ns1:link", xnsmgr);
                foreach (XmlNode xnLink in xnlLinks)
                {
                    if (xnLink.Attributes["rel"] != null)
                    {
                        if (xnLink.Attributes["rel"].Value == "next")
                        {
                            nextChunk = xnLink.Attributes["href"].Value;
                        }
                    }
                }
                //Select nodes
                XmlNodeList xnlActivities = xDoc.SelectNodes("//ns2:Activity", xnsmgr);
                //parse XML
                IList<Activity> Activities = new List<Activity>();
                foreach (XmlNode xnMember in xnlActivities)
                {
                    Activity activity = new Activity();

                    XmlNode xnName = xnMember.SelectSingleNode("../../ns1:title", xnsmgr);
                    activity.activityName = xnName.InnerText;

                    XmlNode xnID = xnMember.SelectSingleNode("../../ns1:id", xnsmgr);
                    activity.activityId = xnID.InnerText;

                    XmlNode xnUpdated = xnMember.SelectSingleNode("../../ns1:updated", xnsmgr);
                    activity.updated = xnUpdated.InnerText;

                    XmlNode xnLink = xnMember.SelectSingleNode("../../ns1:link", xnsmgr);
                    activity.activityLink = xnLink.Attributes["href"].Value;

                    XmlNode xnType = xnMember.SelectSingleNode("ns2:Type", xnsmgr);
                    activity.Type = xnType.InnerText;

                    XmlNode xnStatus = xnMember.SelectSingleNode("ns2:Status", xnsmgr);
                    activity.Status = xnStatus.InnerText;

                    XmlNode xnTransactions = xnMember.SelectSingleNode("ns2:TransactionCount", xnsmgr);
                    activity.transactionCount = xnTransactions.InnerText;

                    XmlNode xnErrors = xnMember.SelectSingleNode("ns2:Errors", xnsmgr);
                    activity.Errors = xnErrors.InnerText;

                    XmlNode xnRunStart = xnMember.SelectSingleNode("ns2:RunStartTime", xnsmgr);
                    activity.runStartTime = xnRunStart.InnerText;

                    XmlNode xnRunFinish = xnMember.SelectSingleNode("ns2:RunFinishTime", xnsmgr);
                    activity.runFinishTime = xnRunFinish.InnerText;

                    XmlNode xnInsert = xnMember.SelectSingleNode("ns2:InsertTime", xnsmgr);
                    activity.insertTime = xnInsert.InnerText;

                    Activities.Add(activity);
                }
                return Activities;
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Activity at link '{0}' does not exist.", link));
                }

                throw new ConstantException(e.Message, e);

            }
        }
 /// <summary>
 /// Gets first chunk of all activities
 /// </summary>
 /// <param name="Authdata">Authentication Data</param>
 /// <param name="nextChunk">Out Link to next chunk of data if</param>
 /// <returns>returns list up to 50 first activities. if more than 50, out nextChunk link to next chunk of data</returns>
 public static IList<Activity> getActivities(AuthenticationData Authdata, out string nextChunk)
 {
     return getActivities(Authdata, "", out nextChunk);
 }
        /// <summary>
        /// Creates export all contacts activity for targeded list.
        /// </summary>
        /// <param name="authdata">Authenticatoin Data</param>
        /// <param name="listId">ID of target list</param>
        /// <param name="fileType">Export File Type (TXT or CSV)</param>
        /// <param name="exportOptDate">if add/remove date is included in file</param>
        /// <param name="exportOptSource">if add/removed by (contact or site owner) is included</param>
        /// <param name="exportListName">if name of list is included in file</param>
        /// <param name="sortBy">sort by Email Address in Ascending Order (EMAIL_ADDRESS) or Date in Descending Order (DATE_DESC)</param>
        /// <param name="columns">List of what columns to include in exported file</param>
        /// <returns>Calls urlEncodedPost, which returns the response from server after HTTP POST</returns>
        public static string exportContacts(AuthenticationData authdata, int listId, string fileType, bool exportOptDate, bool exportOptSource, bool exportListName, string sortBy, IList<string> columns)
        {
            fileType = fileType.ToUpper();
            sortBy = sortBy.ToUpper();
            if (fileType != "TXT")
            {
                if (fileType != "CSV")
                {
                    throw new ArgumentException("File Type Must be CSV or TXT", "fileType");
                }
            }
            if (sortBy != "EMAIL_ADDRESS")
            {
                if (fileType != "DATE_DESC")
                {
                    throw new ArgumentException("Invalid Sort By Type Specified (must be DATE_DESC or EMAIL_ADDRESS)", "sortBy");
                }
            }
            string uri = authdata.accountActivitiesUri;
            string options = "activityType=EXPORT_CONTACTS&fileType=" + fileType + "&exportOptDate=" + exportOptDate.ToString() + "&exportOptSource="
                + exportOptSource.ToString() + "&exportListName=" + exportListName.ToString() + "&sortBy=" + sortBy;
            string calldata = "";
            int i;
            for (i = 0; i < columns.Count; i++)
            {
                string thisline = columns[i];
                thisline = HttpUtility.UrlEncode(thisline);
                calldata = calldata + "&columns=" + thisline;
            }
            string targetlist = authdata.AccountContactListsUri + "/" + listId.ToString();
            targetlist = HttpUtility.UrlEncode(targetlist);
            string fullrequest = options + calldata + "&listId=" + targetlist;
            try
            {
                return Utility.urlEncodedPost(authdata, uri, fullrequest);
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "List with ID of '{0}' does not exist.", listId));
                }

                throw new ConstantException(e.Message, e);

            }
        }
        /// <summary>
        /// Retrieves the collection of Contacts that match specified Email Addresses, returned by the server at current chunk Id.
        /// Entire collection of Contacts will be returned if no Email Address is specified
        /// </summary>
        /// <remarks>Constant Contact server provides paged collections</remarks>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="emailAddresses">One or more Email Addresses</param>
        /// <param name="currentChunkId">Link to the current chunk data</param>
        /// <param name="nextChunkId">Link to the next chunk of data</param>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server 
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>The collection of Contacts</returns>
        public static List<Contact> SearchContactByEmail(AuthenticationData authenticationData, IEnumerable<string> emailAddresses, string currentChunkId, out string nextChunkId)
        {
            if (null == emailAddresses)
            {
                throw new ArgumentNullException("emailAddresses");
            }

            // create the Uri address with the Email address query
            StringBuilder uriAddress = new StringBuilder();
            uriAddress.Append(authenticationData.AccountContactsUri);
            uriAddress.Append("?");
            // loop the Email Address and create the query
            foreach (string email in emailAddresses)
            {
                uriAddress.AppendFormat("email={0}&", HttpUtility.UrlEncode(email.ToLower(CultureInfo.CurrentCulture)));
            }
            // remove the last '&' character from the query
            uriAddress.Remove(uriAddress.Length - 1, 1);

            string currentAddress = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
                                                  uriAddress, currentChunkId);

            Stream stream = Stream.Null;
            try
            {
                // get the response stream
                stream = GetResponseStream(new Uri(currentAddress), authenticationData);

                // parse the stream and get a collection of Contacts
                return ContactComponent.GetContactCollection(stream, out nextChunkId);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
        /// <summary>
        /// Update a Contact
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contact">Contact to be updated</param>
        /// <param name="fullUpdate">True if all Contact fields will be update; False otherwise (only the following fields 
        /// will be updated: EmailAddress, FirstName, LastName, MiddleName, HomePhone, Addr1, Addr2, Addr3,
        /// City, StateCode, StateName, CountryCode, CountryName, PostalCode, SubPostalCode)</param>
        /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
        /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server, if no Contact with specified Id exists 
        /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
        /// or if ApiKey, Username or Password are null or empty</exception>        
        private static void UpdateContact(AuthenticationData authenticationData, Contact contact, bool fullUpdate)
        {
            ValidateAuthenticationData(authenticationData);

            if (null == contact)
            {
                throw new ArgumentNullException("contact");
            }

            if (string.IsNullOrEmpty(contact.Id))
            {
                throw new ArgumentException("Contact Id cannot be null or empty", "contact");
            }

            if (string.IsNullOrEmpty(contact.EmailAddress))
            {
                throw new ArgumentException("Contact Email Address cannot be null or empty", "contact");
            }

            // create the URI for specified Contact Id
            string completeUri = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
                                               AuthenticationData.HostAddress, contact.Link);

            // get the Atom entry for specified Contact
            StringBuilder data = ContactComponent.UpdateContact(contact, authenticationData.ApiRootUri,
                                                                authenticationData.AccountContactListsUri, fullUpdate);

            try
            {
                // put the Atom entry at specified Uri
                PutInformation(authenticationData, new Uri(completeUri), data.ToString());
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Contact with Id '{0}' does not exist.", contact.Id));
                }
                if (string.Compare(e.Message, WebExceptionCode403Message) == 0)
                {
                    throw new ConstantException("Contact cannot be updated. It belongs to the Do-Not-Mail list.");
                }

                throw new ConstantException(e.Message, e);
            }
        }
 /// <summary>
 /// Update a Contact using the full form. All Contact fields will be updated
 /// </summary>
 /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
 /// <param name="contact">Contact to be updated</param>
 /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
 /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
 /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
 /// or other related with the response from server, if no Contact with specified Id exists 
 /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
 /// or if ApiKey, Username or Password are null or empty</exception>        
 public static void UpdateContactFullForm(AuthenticationData authenticationData, Contact contact)
 {
     UpdateContact(authenticationData, contact, true);
 }
        /// <summary>
        /// Check if API Key, Username and Password are not null or empty        
        /// </summary>
        /// <param name="authenticationData">Authentication data to be validated</param>
        /// <exception cref="ConstantException">Thrown if API Key, Username or Password are null or empty</exception>
        private static void ValidateAuthenticationData(AuthenticationData authenticationData)
        {
            if (string.IsNullOrEmpty(authenticationData.Username))
            {
                throw new ConstantException("Username cannot be null or empty");
            }

            if (string.IsNullOrEmpty(authenticationData.Password))
            {
                throw new ConstantException("Password cannot be null or empty");
            }

            if (string.IsNullOrEmpty(authenticationData.ApiKey))
            {
                throw new ConstantException("API Key cannot be null or empty");
            }
        }
        /// <summary>
        /// Create credentials for network transport
        /// </summary>
        /// <param name="address">Uri address</param>
        /// <param name="authenticationData">Authentication data</param>
        /// <returns>The Credentials for specified Uri address</returns>
        private static ICredentials CreateCredentialCache(Uri address, AuthenticationData authenticationData)
        {
            NetworkCredential networkCred = new NetworkCredential(authenticationData.AccountUserName, authenticationData.Password);
            CredentialCache cacheCred = new CredentialCache();
            cacheCred.Add(address, "Basic", networkCred);

            return cacheCred;
        }
        /// <summary>
        /// Create a New Contact
        /// </summary>        
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contact">Contact to be created</param>        
        /// <remarks>The POST data presents only values for EmailAddress, FirstName, LastName, OptInSource and ContactLists elements</remarks>        
        /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
        /// <exception cref="ArgumentException">Thrown if E-mail Address of specified Contact is null or empty</exception>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server or if specified Contact does not belongs to any list
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>Newly created Contact</returns>
        public static Contact CreateNewContact(AuthenticationData authenticationData, Contact contact)
        {
            ValidateAuthenticationData(authenticationData);

            if (null == contact)
            {
                throw new ArgumentNullException("contact");
            }

            if (string.IsNullOrEmpty(contact.EmailAddress))
            {
                throw new ArgumentException("Contact E-mail Address cannot be null or empty", "contact");
            }

            if (null == contact.ContactLists
                || contact.ContactLists.Count == 0)
            {
                throw new ConstantException("Contact does not belongs to any contact list");
            }

            // get the Atom entry for specified Contact
            StringBuilder data = ContactComponent.CreateNewContact(contact, authenticationData.AccountContactListsUri);

            Stream stream = Stream.Null;
            try
            {
                // post the Atom entry at specified Uri and save the response stream
                stream = PostInformation(authenticationData, new Uri(authenticationData.AccountContactsUri),
                                         data.ToString());

                // return newly created Contact
                return ContactComponent.GetContactDetails(stream);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
        /// <summary>
        /// Retrieves the collection of Contact Lists returned by the server at current chunk Id.
        /// The collection is sorted by the Sort Order and it will include the system 
        /// predefined lists ("Active", "Removed", "DoNotEmail")
        /// </summary>
        /// <remarks>Constant Contact server provides paged collections</remarks>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="currentChunkId">Link to the current chunk data</param>
        /// <param name="nextChunkId">Link to the next chunk of data</param>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server 
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>The collection of Contact Lists</returns>
        private static IList<ContactList> GetContactListCollection(AuthenticationData authenticationData, string currentChunkId, out string nextChunkId)
        {
            string currentAddress = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
                                                  authenticationData.AccountContactListsUri, currentChunkId);

            Stream stream = Stream.Null;
            try
            {
                // get the response stream
                stream = GetResponseStream(new Uri(currentAddress), authenticationData);

                // parse the stream and get a collection of Contact Lists
                return ContactListComponent.GetContactListsCollection(stream, out nextChunkId);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
 /// <summary>
 /// Retrieves the first chunk collection of Contacts that the server provides        
 /// </summary>
 /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
 /// <remarks>Constant Contact server provides paged collections</remarks>
 /// <param name="nextChunkId">Link to the next chunk of data</param>
 /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
 /// or other related with the response from server 
 /// or if ApiKey, Username or Password are null or empty</exception>
 /// <returns>The collection of Contacts</returns>
 public static IList<Contact> GetContactCollection(AuthenticationData authenticationData, out string nextChunkId)
 {
     return GetContactCollection(authenticationData, null, out nextChunkId);
 }
        /// <summary>
        /// Sends a Http request on specified Uri address and returns the response Stream
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="address">Uri address</param>
        /// <param name="requestMethod">Type of Http request</param>
        /// <param name="contentType">Content type of the Http request</param>
        /// <param name="data">Data to be send at specified Uri address</param>
        /// <returns>Response Stream</returns>
        private static Stream GetResponseStream(AuthenticationData authenticationData,
            Uri address, string requestMethod, string contentType, byte[] data)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
            request.Credentials = CreateCredentialCache(address, authenticationData);

            request.Method = requestMethod;
            // set the content type of the data being posted
            request.ContentType = contentType;
            // request MUST include a WWW-Authenticate
            request.PreAuthenticate = true;

            // set the content length of the data being posted
            request.ContentLength = data.Length;

            // write data
            Stream stream = request.GetRequestStream();
            stream.Write(data, 0, data.Length);

            Stream responseStream = Stream.Null;
            try
            {
                // get the response Stream
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
                                                "Method {0}, response description: {1}", request.Method,
                                                response.StatusDescription));

                if (response.StatusCode == HttpStatusCode.NoContent)
                {
                    // server don't send any response to us
                    return Stream.Null;
                }

                // get the response Stream
                responseStream = response.GetResponseStream();

                // read the response stream and save it into a memory stream
                MemoryStream memoryStream = ReadResponseStream(responseStream);

                return memoryStream;
            }
            finally
            {
                // close the Stream object
                stream.Close();

                // close response stream; it also closes the web response
                responseStream.Close();
            }
        }
        /// <summary>
        /// Retrieve an individual Contact by its Id
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="id">Contact Id</param>        
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server or if no Contact with specified Id exists
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>Contact with specified Id</returns>
        public static Contact GetContactDetailsById(AuthenticationData authenticationData, string id)
        {
            ValidateAuthenticationData(authenticationData);

            if (string.IsNullOrEmpty(id))
            {
                throw new ArgumentException("Contact Id cannot be null or empty", "id");
            }

            // create the URI for specified Contact Id
            string completeUri = String.Format(CultureInfo.InvariantCulture, "{0}/{1}",
                                               authenticationData.AccountContactsUri, id);

            // get the response stream
            Stream stream = Stream.Null;
            try
            {
                stream = GetResponseStream(new Uri(completeUri), authenticationData);

                // parse the stream and obtain a Contact object
                return ContactComponent.GetContactDetails(stream);
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Contact with Id '{0}' does not exist.", id));
                }

                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
        /// <summary>
        /// PUT the data at the specified Uri address. 
        /// Constant Contact server will not send any response
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="address">Uri address</param>
        /// <param name="data">Data to be send at specified Uri address</param>        
        private static void PutInformation(AuthenticationData authenticationData, Uri address, string data)
        {
            // set the Http request content type
            const string contentType = @"application/atom+xml";

            // send a Http PUT request and return the response Stream
            GetResponseStream(authenticationData, address, WebRequestMethods.Http.Put, contentType, data);
        }
        /// <summary>
        /// Retrieves the first chunk collection of user Contact Lists that the server provides 
        /// for current Contact Account Owner.
        /// The collection is sorted by the Sort Order and it will not include the system 
        /// predefined lists ("Active", "Removed", "DoNotEmail")
        /// </summary>
        /// <remarks>Constant Contact server provides paged collections</remarks>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="nextChunkId">Link to the next chunk data</param>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server 
        /// or if ApiKey, Username or Password are null or empty</exception>        
        /// <returns>The collection of user Contact Lists</returns>
        public static IList<ContactList> GetUserContactListCollection(AuthenticationData authenticationData, out string nextChunkId)
        {
            ValidateAuthenticationData(authenticationData);

            return GetUserContactListCollection(authenticationData, null, out nextChunkId);
        }