DataServiceContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / DataServiceContext.cs / 5 / DataServiceContext.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
// context
//  
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client 
{
    using System;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.ObjectModel;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Linq; 
    using System.Linq.Expressions;
#if !ASTORIA_LIGHT // Data.Services http stack
    using System.Net;
#else 
    using System.Data.Services.Http;
#endif 
    using System.Text; 
    using System.Xml;
    using System.Xml.Linq; 

    /// 
    /// context
    ///  
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506", Justification = "Central class of the API, likely to have many cross-references")]
    public class DataServiceContext 
    { 
        /// represents identity for a resource without one
        private const Uri NoIdentity = null; 

        /// represents entityset for a resource without one
        private const string NoEntitySet = null;
 
        /// represents empty etag
        private const string NoETag = null; 
 
        /// base uri prepended to relative uri
        private readonly System.Uri baseUri; 

        /// base uri with guranteed trailing slash
        private readonly System.Uri baseUriWithSlash;
 
#if !ASTORIA_LIGHT  // Credentials not available
        /// Authentication interface for retrieving credentials for Web client authentication. 
        private System.Net.ICredentials credentials; 
#endif
 
        /// Override the namespace used for the data parts of the ATOM entries
        private string dataNamespace;

        /// resolve type from a typename 
        private Func resolveName;
 
        /// resolve typename from a type 
        private Func resolveType;
 
#if !ASTORIA_LIGHT  // Timeout not available
        /// time-out value in seconds, 0 for default
        private int timeout;
#endif 

        /// whether to use post-tunneling for PUT/DELETE 
        private bool postTunneling; 

        /// Options when deserializing properties to the target type. 
        private bool ignoreMissingProperties;

        /// Used to specify a value synchronization strategy.
        private MergeOption mergeOption; 

        /// Default options to be used while doing savechanges. 
        private SaveChangesOptions saveChangesDefaultOptions; 

        /// Override the namespace used for the scheme in the category for ATOM entries. 
        private Uri typeScheme;

        #region Resource state management
 
        /// change order
        private uint nextChange; 
 
        /// Set of tracked resources by ResourceBox.Resource
        private Dictionary objectToResource = new Dictionary(); 

        /// Set of tracked resources by ResourceBox.Identity
        private Dictionary identityToResource;
 
        /// Set of tracked bindings by ResourceBox.Identity
        private Dictionary bindings = new Dictionary(RelatedEnd.EquivalenceComparer); 
 
        #endregion
 
        #region ctor

        /// 
        /// Instantiates a new context with the specified  Uri. 
        /// The library expects the Uri to point to the root of a data service,
        /// but does not issue a request to validate it does indeed identify the root of a service. 
        /// If the Uri does not identify the root of the service, the behavior of the client library is undefined. 
        /// 
        ///  
        /// An absolute, well formed http or https URI without a query or fragment which identifies the root of a data service.
        /// A Uri provided with a trailing slash is equivalent to one without such a trailing character
        /// 
        /// if the  is not an absolute, well formed http or https URI without a query or fragment 
        /// when the  is null
        ///  
        /// With Silverlight, the  can be a relative Uri 
        /// that will be combined with System.Windows.Browser.HtmlPage.Document.DocumentUri.
        ///  
        public DataServiceContext(Uri serviceRoot)
        {
            Util.CheckArgumentNull(serviceRoot, "serviceRoot");
 
#if ASTORIA_LIGHT
            if (!serviceRoot.IsAbsoluteUri) 
            { 
                serviceRoot = new Uri(System.Windows.Browser.HtmlPage.Document.DocumentUri, serviceRoot);
            } 
#endif
            if (!serviceRoot.IsAbsoluteUri ||
                !Uri.IsWellFormedUriString(serviceRoot.OriginalString, UriKind.Absolute) ||
                !String.IsNullOrEmpty(serviceRoot.Query) || 
                !string.IsNullOrEmpty(serviceRoot.Fragment) ||
                ((serviceRoot.Scheme != "http") && (serviceRoot.Scheme != "https"))) 
            { 
                throw Error.Argument(Strings.Context_BaseUri, "serviceRoot");
            } 

            this.baseUri = serviceRoot;
            this.baseUriWithSlash = serviceRoot;
            if (!serviceRoot.OriginalString.EndsWith("/", StringComparison.Ordinal)) 
            {
                this.baseUriWithSlash = Util.CreateUri(serviceRoot.OriginalString + "/", UriKind.Absolute); 
            } 

            this.mergeOption = MergeOption.AppendOnly; 
            this.DataNamespace = XmlConstants.DataWebNamespace;
            this.UsePostTunneling = false;
            this.typeScheme = new Uri(XmlConstants.DataWebSchemeNamespace);
        } 
        #endregion
 
#if !ASTORIA_LIGHT // Data.Services http stack 
        /// 
        /// This event is fired before a request it sent to the server, giving 
        /// the handler the opportunity to inspect, adjust and/or replace the
        /// WebRequest object used to perform the request.
        /// 
        ///  
        /// When calling BeginSaveChanges and not using SaveChangesOptions.Batch,
        /// this event may be raised from a different thread. 
        ///  
        public event EventHandler SendingRequest;
#endif 

        /// 
        /// This event fires once an entry has been read into a .NET object
        /// but before the serializer returns to the caller, giving handlers 
        /// an opporunity to read further information from the incoming ATOM
        /// entry and updating the object 
        ///  
        /// 
        /// This event should only be raised from the thread that was used to 
        /// invoke Execute, EndExecute, SaveChanges, EndSaveChanges.
        /// 
        public event EventHandler ReadingEntity;
 
        /// 
        /// This event fires once an ATOM entry is ready to be written to 
        /// the network for a request, giving handlers an opportunity to 
        /// customize the entry with information from the corresponding
        /// .NET object or the environment. 
        /// 
        /// 
        /// When calling BeginSaveChanges and not using SaveChangesOptions.Batch,
        /// this event may be raised from a different thread. 
        /// 
        public event EventHandler WritingEntity; 
 
        #region BaseUri, Credentials, MergeOption, Timeout, Links, Entities
        ///  
        /// Absolute Uri identifying the root of the target data service.
        /// A Uri provided with a trailing slash is equivalent to one without such a trailing character.
        /// 
        ///  
        /// Example: http://server/host/myservice.svc
        ///  
        public Uri BaseUri 
        {
            get { return this.baseUri; } 
        }

#if !ASTORIA_LIGHT  // Credentials not available
        ///  
        /// Gets and sets the authentication information used by each query created using the context object.
        ///  
        public System.Net.ICredentials Credentials 
        {
            get { return this.credentials; } 
            set { this.credentials = value; }
        }
#endif
 
        /// 
        /// Used to specify a synchronization strategy when sending/receiving entities to/from a data service. 
        /// This value is read by the deserialization component of the client prior to materializing objects. 
        /// As such, it is recommended to set this property to the appropriate materialization strategy
        /// before executing any queries/updates to the data service. 
        /// 
        /// 
        /// The default value is .AppendOnly.
        ///  
        public MergeOption MergeOption
        { 
            get { return this.mergeOption; } 
            set { this.mergeOption = Util.CheckEnumerationValue(value, "MergeOption"); }
        } 

        /// 
        /// Are properties missing from target type ignored?
        ///  
        /// 
        /// This also affects responses during SaveChanges. 
        ///  
        public bool IgnoreMissingProperties
        { 
            get { return this.ignoreMissingProperties; }
            set { this.ignoreMissingProperties = value; }
        }
 
        /// Override the namespace used for the data parts of the ATOM entries
        public string DataNamespace 
        { 
            get
            { 
                return this.dataNamespace;
            }

            set 
            {
                Util.CheckArgumentNull(value, "value"); 
                this.dataNamespace = value; 
            }
        } 

        /// 
        /// Enables one to override the default type resolution strategy used by the client library.
        /// Set this property to a delegate which identifies a function that resolves 
        /// a type within the client application to a namespace-qualified type name.
        /// This enables the client to perform custom mapping between the type name 
        /// provided in a response from the server and a type on the client. 
        /// 
        ///  
        /// This method enables one to override the entity name that is serialized
        /// to the target representation (ATOM,JSON, etc) for the specified type.
        /// 
        public Func ResolveName 
        {
            get { return this.resolveName; } 
            set { this.resolveName = value; } 
        }
 
        /// 
        /// Enables one to override the default type resolution strategy used by the client library.
        /// Set this property to a delegate which identifies a function that resolves a
        /// namespace-qualified type name to type within the client application. 
        /// This enables the client to perform custom mapping between the type name
        /// provided in a response from the server and a type on the client. 
        ///  
        /// 
        /// Overriding type resolution enables inserting a custom type name to type mapping strategy. 
        /// It does not enable one to affect how a response is materialized into the identified type.
        /// 
        public Func ResolveType
        { 
            get { return this.resolveType; }
            set { this.resolveType = value; } 
        } 

#if !ASTORIA_LIGHT  // Timeout not available 
        /// 
        /// Get and sets the timeout span in seconds to use for the underlying HTTP request to the data service.
        /// 
        ///  
        /// A value of 0 will use the default timeout of the underlying HTTP request.
        /// This value must be set before executing any query or update operations against 
        /// the target data service for it to have effect on the on the request. 
        /// The value may be changed between requests to a data service and the new value
        /// will be picked up by the next data service request. 
        /// 
        public int Timeout
        {
            get 
            {
                return this.timeout; 
            } 

            set 
            {
                if (value < 0)
                {
                    throw Error.ArgumentOutOfRange("Timeout"); 
                }
 
                this.timeout = value; 
            }
        } 
#endif

        /// Gets or sets the URI used to indicate what type scheme is used by the service.
        public Uri TypeScheme 
        {
            get 
            { 
                return this.typeScheme;
            } 

            set
            {
                Util.CheckArgumentNull(value, "value"); 
                this.typeScheme = value;
            } 
        } 

        /// whether to use post-tunneling for PUT/DELETE 
        public bool UsePostTunneling
        {
            get { return this.postTunneling; }
            set { this.postTunneling = value; } 
        }
 
        ///  
        /// Returns a collection of all the links (ie. associations) currently being tracked by the context.
        /// If no links are being tracked, a collection with 0 elements is returned. 
        /// 
        public ReadOnlyCollection Links
        {
            get 
            {
                return (from link in this.bindings.Values 
                        orderby link.ChangeOrder 
                        select new LinkDescriptor(link.SourceResource, link.SourceProperty, link.TargetResouce, link.State))
                        .ToList().AsReadOnly(); 
            }
        }

        ///  
        /// Returns a collection of all the resources currently being tracked by the context.
        /// If no resources are being tracked, a collection with 0 elements is returned. 
        ///  
        public ReadOnlyCollection Entities
        { 
            get
            {
                return (from entity in this.objectToResource.Values
                        orderby entity.ChangeOrder 
                        select new EntityDescriptor(entity.Resource, entity.ETag, entity.State))
                        .ToList().AsReadOnly(); 
            } 
        }
 
        /// 
        /// Default SaveChangesOptions that needs to be used when doing SaveChanges.
        /// 
        public SaveChangesOptions SaveChangesDefaultOptions 
        {
            get 
            { 
                return this.saveChangesDefaultOptions;
            } 

            set
            {
                ValidateSaveChangesOptions(value); 
                this.saveChangesDefaultOptions = value;
            } 
        } 

        #endregion 

        /// base uri with guranteed trailing slash
        internal Uri BaseUriWithSlash
        { 
            get { return this.baseUriWithSlash; }
        } 
 
        /// Indicates if there are subscribers for the ReadingEntity event
        internal bool HasReadingEntityHandlers 
        {
            [DebuggerStepThrough]
            get { return this.ReadingEntity != null; }
        } 

        #region CreateQuery 
        ///  
        /// create a query based on (BaseUri + relativeUri)
        ///  
        /// type of object to materialize
        /// entitySetName
        /// composible, enumerable query object
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "required for this feature")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "required for this feature")]
        public DataServiceQuery CreateQuery(string entitySetName) 
        { 
            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName");
            this.ValidateEntitySetName(ref entitySetName); 

            ResourceSetExpression rse = new ResourceSetExpression(typeof(IOrderedQueryable), null, Expression.Constant(entitySetName), typeof(T), null, null);
            return new DataServiceQuery.DataServiceOrderedQuery(rse, new DataServiceQueryProvider(this));
        } 
        #endregion
 
        #region GetMetadataUri 
        /// 
        /// Given the base URI, resolves the location of the metadata endpoint for the service by using an HTTP OPTIONS request or falling back to convention ($metadata) 
        /// 
        /// Uri to retrieve metadata from
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "required for this feature")]
        public Uri GetMetadataUri() 
        {
            // 
            Uri metadataUri = Util.CreateUri(this.baseUriWithSlash.OriginalString + XmlConstants.UriMetadataSegment, UriKind.Absolute); 
            return metadataUri;
        } 
        #endregion

        #region LoadProperty
 
        /// 
        /// Begin getting response to load a collection or reference property. 
        ///  
        /// actually doesn't modify the property until EndLoadProperty is called.
        /// entity 
        /// name of collection or reference property to load
        /// The AsyncCallback delegate.
        /// The state object for this request.
        /// An IAsyncResult that references the asynchronous request for a response. 
        public IAsyncResult BeginLoadProperty(object entity, string propertyName, AsyncCallback callback, object state)
        { 
            LoadPropertyAsyncResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state); 
            result.BeginExecute(null);
            return result; 
        }

        /// 
        /// Load a collection or reference property from a async result. 
        /// 
        /// async result generated by BeginLoadProperty 
        /// QueryOperationResponse instance containing information about the response. 
        public QueryOperationResponse EndLoadProperty(IAsyncResult asyncResult)
        { 
            LoadPropertyAsyncResult response = QueryAsyncResult.EndExecute(this, "LoadProperty", asyncResult);
            return response.LoadProperty();
        }
 
#if !ASTORIA_LIGHT // Synchronous methods not available
        ///  
        /// Load a collection or reference property. 
        /// 
        ///  
        /// An entity in detached or added state will throw an InvalidOperationException
        /// since there is nothing it can load from the server.
        ///
        /// An entity in unchanged or modified state will load its collection or 
        /// reference elements as unchanged with unchanged bindings.
        /// 
        /// An entity in deleted state will loads its collection or reference elements 
        /// in the unchanged state with bindings in the deleted state.
        ///  
        /// entity
        /// name of collection or reference property to load
        /// QueryOperationResponse instance containing information about the response.
        public QueryOperationResponse LoadProperty(object entity, string propertyName) 
        {
            LoadPropertyAsyncResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null); 
            result.Execute(null); 
            return result.LoadProperty();
        } 
#endif
        #endregion

        #region ExecuteBatch, BeginExecuteBatch, EndExecuteBatch 

        ///  
        /// Batch multiple queries into a single async request. 
        /// 
        /// User callback when results from batch are available. 
        /// user state in IAsyncResult
        /// queries to batch
        /// async result object
        public IAsyncResult BeginExecuteBatch(AsyncCallback callback, object state, params DataServiceRequest[] queries) 
        {
            Util.CheckArgumentNotEmpty(queries, "queries"); 
 
            SaveAsyncResult result = new SaveAsyncResult(this, "ExecuteBatch", queries, SaveChangesOptions.Batch, callback, state, true);
            result.BatchBeginRequest(false /*replaceOnUpdate*/); 
            return result;
        }

        ///  
        /// Call when results from batch are desired.
        ///  
        /// async result object returned from BeginExecuteBatch 
        /// batch response from which query results can be enumerated.
        public DataServiceResponse EndExecuteBatch(IAsyncResult asyncResult) 
        {
            SaveAsyncResult result = BaseAsyncResult.EndExecute(this, "ExecuteBatch", asyncResult);
            return result.EndRequest();
        } 

#if !ASTORIA_LIGHT // Synchronous methods not available 
        ///  
        /// Batch multiple queries into a single request.
        ///  
        /// queries to batch
        /// batch response from which query results can be enumerated.
        public DataServiceResponse ExecuteBatch(params DataServiceRequest[] queries)
        { 
            Util.CheckArgumentNotEmpty(queries, "queries");
 
            SaveAsyncResult result = new SaveAsyncResult(this, "ExecuteBatch", queries, SaveChangesOptions.Batch, null, null, false); 
            result.BatchRequest(false /*replaceOnUpdate*/);
            return result.EndRequest(); 
        }
#endif

        #endregion 

        #region Execute(Uri), BeginExecute(Uri), EndExecute(Uri) 
 
        /// begin the execution of the request uri
        /// element type of the result 
        /// request to execute
        /// User callback when results from execution are available.
        /// user state in IAsyncResult
        /// async result object 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")]
        public IAsyncResult BeginExecute(Uri requestUri, AsyncCallback callback, object state) 
        { 
            requestUri = Util.CreateUri(this.baseUriWithSlash, requestUri);
            return (new DataServiceRequest(requestUri)).BeginExecute(this, this, callback, state); 
        }

        /// 
        /// Call when results from batch are desired. 
        /// 
        /// element type of the result 
        /// async result object returned from BeginExecuteBatch 
        /// batch response from which query results can be enumerated.
        /// asyncResult is null 
        /// asyncResult did not originate from this instance or End was previously called
        /// problem in request or materializing results of query into objects
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")]
        public IEnumerable EndExecute(IAsyncResult asyncResult) 
        {
            QueryAsyncResult response = QueryAsyncResult.EndExecute(this, "Execute", asyncResult); 
            IEnumerable results = response.ServiceRequest.Materialize(this, response.ContentType, response.GetResponseStream).Cast(); 
            return (IEnumerable)response.GetResponse(results, typeof(TElement));
        } 

#if !ASTORIA_LIGHT // Synchronous methods not available
        /// 
        /// Execute the requestUri 
        /// 
        /// element type of the result 
        /// request uri to execute 
        /// batch response from which query results can be enumerated.
        /// null requestUri 
        /// !BaseUri.IsBaseOf(requestUri)
        /// problem materializing results of query into objects
        /// failure to get response for requestUri
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")] 
        public IEnumerable Execute(Uri requestUri)
        { 
            requestUri = Util.CreateUri(this.baseUriWithSlash, requestUri); 
            DataServiceRequest request = DataServiceRequest.GetInstance(typeof(TElement), requestUri);
            return request.Execute(this, requestUri); 
        }
#endif
        #endregion
 
        #region SaveChanges, BeginSaveChanges, EndSaveChanges
 
        ///  
        /// submit changes to the server in a single change set
        ///  
        /// callback
        /// state
        /// async result
        public IAsyncResult BeginSaveChanges(AsyncCallback callback, object state) 
        {
            return this.BeginSaveChanges(this.SaveChangesDefaultOptions, callback, state); 
        } 

        ///  
        /// begin submitting changes to the server
        /// 
        /// options on how to save changes
        /// The AsyncCallback delegate. 
        /// The state object for this request.
        /// An IAsyncResult that references the asynchronous request for a response. 
        public IAsyncResult BeginSaveChanges(SaveChangesOptions options, AsyncCallback callback, object state) 
        {
            ValidateSaveChangesOptions(options); 
            SaveAsyncResult result = new SaveAsyncResult(this, "SaveChanges", null, options, callback, state, true);
            bool replaceOnUpdate = IsFlagSet(options, SaveChangesOptions.ReplaceOnUpdate);
            if (IsFlagSet(options, SaveChangesOptions.Batch))
            { 
                result.BatchBeginRequest(replaceOnUpdate);
            } 
            else 
            {
                result.BeginNextChange(replaceOnUpdate); // may invoke callback before returning 
            }

            return result;
        } 

        ///  
        /// done submitting changes to the server 
        /// 
        /// The pending request for a response.  
        /// changeset response
        public DataServiceResponse EndSaveChanges(IAsyncResult asyncResult)
        {
            SaveAsyncResult result = BaseAsyncResult.EndExecute(this, "SaveChanges", asyncResult); 
            return result.EndRequest();
        } 
 
#if !ASTORIA_LIGHT // Synchronous methods not available
        ///  
        /// submit changes to the server in a single change set
        /// 
        /// changeset response
        public DataServiceResponse SaveChanges() 
        {
            return this.SaveChanges(this.SaveChangesDefaultOptions); 
        } 

        ///  
        /// submit changes to the server
        /// 
        /// options on how to save changes
        /// changeset response 
        /// 
        /// MergeOption.NoTracking is tricky but supported because to insert a relationship we need the identity 
        /// of both ends and if one end was an inserted object then its identity is attached, but may not match its value 
        ///
        /// This initial implementation does not do batching. 
        /// Things are sent to the server in the following order
        /// 1) delete relationships
        /// 2) delete objects
        /// 3) update objects 
        /// 4) insert objects
        /// 5) insert relationship 
        ///  
        public DataServiceResponse SaveChanges(SaveChangesOptions options)
        { 
            DataServiceResponse errors = null;
            ValidateSaveChangesOptions(options);

            SaveAsyncResult result = new SaveAsyncResult(this, "SaveChanges", null, options, null, null, false); 
            bool replaceOnUpdate = IsFlagSet(options, SaveChangesOptions.ReplaceOnUpdate);
            if (IsFlagSet(options, SaveChangesOptions.Batch)) 
            { 
                result.BatchRequest(replaceOnUpdate);
            } 
            else
            {
                result.BeginNextChange(replaceOnUpdate);
            } 

            errors = result.EndRequest(); 
 
            Debug.Assert(null != errors, "null errors");
            return errors; 
        }
#endif
        #endregion
 
        #region Add, Attach, Delete, Detach, Update, TryGetEntity, TryGetUri
 
        ///  
        /// Notifies the context that a new link exists between the  and  objects
        /// and that the link is represented via the source. which is a collection. 
        /// The context adds this link to the set of newly created links to be sent to
        /// the data service on the next call to SaveChanges().
        /// 
        ///  
        /// Links are one way relationships.  If a back pointer exists (ie. two way association),
        /// this method should be called a second time to notify the context object of the second link. 
        ///  
        /// Source object participating in the link.
        /// The name of the property on the source object which represents a link from the source to the target object. 
        /// The target object involved in the link which is bound to the source object also specified in this call.
        /// If ,  or  are null.
        /// if link already exists
        /// if source or target are detached 
        /// if source or target are in deleted state
        /// if sourceProperty is not a collection 
        public void AddLink(object source, string sourceProperty, object target) 
        {
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Added); 

            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.ContainsKey(relation))
            { 
                throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
            } 
 
            relation.State = EntityStates.Added;
            this.bindings.Add(relation, relation); 
            this.objectToResource[source].RelatedLinkCount++;
            this.IncrementChange(relation);
        }
 
        /// 
        /// Notifies the context to start tracking the specified link between source and the specified target entity. 
        ///  
        /// Source object participating in the link.
        /// The name of the property on the source object which represents a link from the source to the target object. 
        /// The target object involved in the link which is bound to the source object also specified in this call.
        /// If ,  or  are null.
        /// if binding already exists
        /// if source or target are in added state 
        /// if source or target are in deleted state
        public void AttachLink(object source, string sourceProperty, object target) 
        { 
            this.AttachLink(source, sourceProperty, target, MergeOption.NoTracking);
        } 

        /// 
        /// Removes the specified link from the list of links being tracked by the context.
        /// Any link being tracked by the context, regardless of its current state, can be detached. 
        /// 
        /// Source object participating in the link. 
        /// The name of the property on the source object which represents a link from the source to the target object. 
        /// The target object involved in the link which is bound to the source object also specified in this call.
        /// If  or  are null. 
        /// if sourceProperty is empty
        /// true if binding was previously being tracked, false if not
        public bool DetachLink(object source, string sourceProperty, object target)
        { 
            Util.CheckArgumentNull(source, "source");
            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty"); 
 
            RelatedEnd existing;
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target); 
            if (!this.bindings.TryGetValue(relation, out existing))
            {
                return false;
            } 

            this.DetachExistingLink(existing); 
            return true; 
        }
 
        /// 
        /// Notifies the context that a link exists between the  and  object
        /// and that the link is represented via the source. which is a collection.
        /// The context adds this link to the set of deleted links to be sent to 
        /// the data service on the next call to SaveChanges().
        /// If the specified link exists in the "Added" state, then the link is detached (see DetachLink method) instead. 
        ///  
        /// Source object participating in the link.
        /// The name of the property on the source object which represents a link from the source to the target object. 
        /// The target object involved in the link which is bound to the source object also specified in this call.
        /// If ,  or  are null.
        /// if source or target are detached
        /// if source or target are in added state 
        /// if sourceProperty is not a collection
        public void DeleteLink(object source, string sourceProperty, object target) 
        { 
            bool delay = this.EnsureRelatable(source, sourceProperty, target, EntityStates.Deleted);
 
            RelatedEnd existing = null;
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.TryGetValue(relation, out existing) && (EntityStates.Added == existing.State))
            {   // Added -> Detached 
                this.DetachExistingLink(existing);
            } 
            else 
            {
                if (delay) 
                {   // can't have non-added relationship when source or target is in added state
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithInsertEnd);
                }
 
                if (null == existing)
                {   // detached -> deleted 
                    this.bindings.Add(relation, relation); 
                    this.objectToResource[source].RelatedLinkCount++;
                    existing = relation; 
                }

                if (EntityStates.Deleted != existing.State)
                { 
                    existing.State = EntityStates.Deleted;
 
                    this.IncrementChange(existing); 
                    this.IncrementChange(this.objectToResource[source]);
                    this.IncrementChange(this.objectToResource[target]); 
                }
            }
        }
 
        /// 
        /// Notifies the context that a modified link exists between the  and  objects 
        /// and that the link is represented via the source. which is a reference. 
        /// The context adds this link to the set of modified created links to be sent to
        /// the data service on the next call to SaveChanges(). 
        /// 
        /// 
        /// Links are one way relationships.  If a back pointer exists (ie. two way association),
        /// this method should be called a second time to notify the context object of the second link. 
        /// 
        /// Source object participating in the link. 
        /// The name of the property on the source object which represents a link from the source to the target object. 
        /// The target object involved in the link which is bound to the source object also specified in this call.
        /// If ,  or  are null. 
        /// if link already exists
        /// if source or target are detached
        /// if source or target are in deleted state
        /// if sourceProperty is not a reference property 
        public void SetLink(object source, string sourceProperty, object target)
        { 
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Modified); 

            RelatedEnd relation = this.DetachReferenceLink(source, sourceProperty, target, MergeOption.NoTracking); 
            if (null == relation)
            {
                relation = new RelatedEnd(source, sourceProperty, target);
                this.bindings.Add(relation, relation); 
            }
 
            Debug.Assert( 
                0 == relation.State ||
                IncludeLinkState(relation.State), 
                "set link entity state");

            if (EntityStates.Modified != relation.State)
            { 
                relation.State = EntityStates.Modified;
                this.objectToResource[source].RelatedLinkCount++; 
                this.IncrementChange(relation); 
            }
        } 

        #endregion

        #region AddObject, AttachTo, DeleteObject, Detach, TryGetEntity, TryGetUri 
        /// 
        /// Add entity into the context in the Added state for tracking. 
        /// It does not follow the object graph and add related objects. 
        /// 
        /// EntitySet for the object to be added. 
        /// entity graph to add
        /// if entitySetName is null
        /// if entitySetName is empty
        /// if entity is null 
        /// if entity does not have a key property
        /// if entity is already being tracked by the context 
        ///  
        /// Any leading or trailing forward slashes will automatically be trimmed from entitySetName.
        /// Objects in the added state don't have an Identity. 
        /// 
        public void AddObject(string entitySetName, object entity)
        {
            this.ValidateEntitySetName(ref entitySetName); 
            ValidateEntityWithKey(entity);
 
            Uri editLink = Util.CreateUri(entitySetName, UriKind.Relative); 
            ResourceBox resource = new ResourceBox(NoIdentity, editLink, entity);
            resource.State = EntityStates.Added; 

            try
            {
                this.objectToResource.Add(entity, resource); 
            }
            catch (ArgumentException) 
            { 
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained);
            } 

            this.IncrementChange(resource);
        }
 
        /// 
        /// Attach entity into the context in the Unchanged state for tracking. 
        /// It does not follow the object graph and attach related objects. 
        /// If entity was already being tracked by the context, will be changed to the Unchanged state.
        ///  
        /// EntitySet for the object to be attached.
        /// entity graph to attach
        /// if entitySetName is null
        /// if entitySetName is empty 
        /// if entity is null
        /// if entity does not have a key property 
        /// if entity is already being tracked by the context 
        public void AttachTo(string entitySetName, object entity)
        { 
            this.AttachTo(entitySetName, entity, NoETag);
        }

        ///  
        /// Attach entity into the context in the Unchanged state for tracking.
        /// It does not follow the object graph and attach related objects. 
        /// If entity was already being tracked by the context, will be changed to the Unchanged state. 
        /// 
        /// EntitySet for the object to be attached. 
        /// entity graph to attach
        /// etag
        /// if entitySetName is null
        /// if entitySetName is empty 
        /// if entity is null
        /// if entity does not have a key property 
        /// if entity is already being tracked by the context 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704", MessageId = "etag", Justification = "represents ETag in request")]
        public void AttachTo(string entitySetName, object entity, string etag) 
        {
            this.ValidateEntitySetName(ref entitySetName);
            ValidateEntityWithKey(entity);
 
            Uri editLink = GenerateEditLinkUri(this.baseUriWithSlash, entitySetName, entity);
 
            // we fake the identity by using the generated edit link 
            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
            Uri identity = Util.ReferenceIdentity(editLink); 

            this.AttachTo(identity, editLink, etag, entity, true);
        }
 
        /// 
        /// Mark an existing object being tracked by the context for deletion. 
        ///  
        /// entity to be mark deleted
        /// if entity is null 
        /// if entity is not being tracked by the context
        /// 
        /// Existings objects in the Added state become detached.
        ///  
        public void DeleteObject(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity"); 

            ResourceBox resource = null; 
            if (!this.objectToResource.TryGetValue(entity, out resource))
            {   // detached object
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            } 

            EntityStates state = resource.State; 
            if (EntityStates.Added == state) 
            {   // added -> detach
                if ((null != resource.Identity) && 
                    !this.identityToResource.Remove(resource.Identity))
                {   // added objects can have identity via NoTracking
                    Debug.Assert(false, "didn't remove identity");
                } 

                this.DetachRelated(resource); 
 
                resource.State = EntityStates.Detached;
                bool flag = this.objectToResource.Remove(entity); 
                Debug.Assert(flag, "should have removed existing entity");
            }
            else if (EntityStates.Deleted != state)
            { 
                Debug.Assert(
                    IncludeLinkState(state), 
                    "bad state transition to deleted"); 

                this.DeleteRelated(resource); 

                resource.State = EntityStates.Deleted;
                this.IncrementChange(resource);
            } 
        }
 
        ///  
        /// Detach entity from the context.
        ///  
        /// entity to detach.
        /// true if object was detached
        /// if entity is null
        public bool Detach(object entity) 
        {
            Util.CheckArgumentNull(entity, "entity"); 
 
            ResourceBox resource = null;
            if (this.objectToResource.TryGetValue(entity, out resource)) 
            {
                return this.DetachResource(resource);
            }
 
            return false;
        } 
 
        /// 
        /// Mark an existing object for update in the context. 
        /// 
        /// entity to be mark for update
        /// if entity is null
        /// if entity is detached 
        public void UpdateObject(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity"); 

            ResourceBox resource = null; 
            if (!this.objectToResource.TryGetValue(entity, out resource))
            {
                throw Error.Argument(Strings.Context_EntityNotContained, "entity");
            } 

            if (EntityStates.Unchanged == resource.State) 
            { 
                resource.State = EntityStates.Modified;
                this.IncrementChange(resource); 
            }
        }

        ///  
        /// Find tracked entity by its identity.
        ///  
        /// entities in added state are not likely to have a identity 
        /// entity type
        /// identity 
        /// entity being tracked by context
        /// true if entity was found
        /// identity is null
        public bool TryGetEntity(Uri identity, out TEntity entity) where TEntity : class 
        {
            entity = null; 
            Util.CheckArgumentNull(identity, "relativeUri"); 

            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink 
            identity = Util.ReferenceIdentity(identity);

            EntityStates state;
            entity = (TEntity)this.TryGetEntity(identity, null, MergeOption.AppendOnly, out state); 
            return (null != entity);
        } 
 
        /// 
        /// Identity uri for tracked entity. 
        /// Though the identity might use a dereferencable scheme, you MUST NOT assume it can be dereferenced.
        /// 
        /// Entities in added state are not likely to have an identity.
        /// entity being tracked by context 
        /// identity
        /// true if entity is being tracked and has a identity 
        /// entity is null 
        public bool TryGetUri(object entity, out Uri identity)
        { 
            identity = null;
            Util.CheckArgumentNull(entity, "entity");

            ResourceBox resource = null; 
            if (this.objectToResource.TryGetValue(entity, out resource) &&
                (null != resource.Identity)) 
            { 
                // DereferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
                identity = Util.DereferenceIdentity(resource.Identity); 
            }

            return (null != identity);
        } 

        ///  
        /// Handle response by looking at status and possibly throwing an exception. 
        /// 
        /// response status code 
        /// Version string on the response header; possibly null.
        /// delegate to get response stream
        /// throw or return on failure
        /// exception on failure 
        internal static Exception HandleResponse(
            HttpStatusCode statusCode, 
            string responseVersion, 
            Func getResponseStream,
            bool throwOnFailure) 
        {
            InvalidOperationException failure = null;
            if (!CanHandleResponseVersion(responseVersion))
            { 
                string description = Strings.Context_VersionNotSupported(
                    responseVersion, 
                    XmlConstants.DataServiceClientVersionCurrentMajor, 
                    XmlConstants.DataServiceClientVersionCurrentMinor);
                failure = Error.InvalidOperation(description); 
            }

            if (failure == null && !WebUtil.SuccessStatusCode(statusCode))
            { 
                failure = GetResponseText(getResponseStream, statusCode);
            } 
 
            if (failure != null && throwOnFailure)
            { 
                throw failure;
            }

            return failure; 
        }
 
        /// response materialization has an identity to attach to the inserted object 
        /// identity of entity
        /// edit link of entity 
        /// inserted object
        /// etag of attached object
        internal void AttachIdentity(Uri identity, Uri editLink, object entity, string etag)
        {   // insert->unchanged 
            Debug.Assert(null != identity && identity.IsAbsoluteUri, "must have identity");
 
            this.EnsureIdentityToResource(); 

            ResourceBox resource = this.objectToResource[entity]; 
            Debug.Assert(EntityStates.Added == resource.State, "didn't find expected entity in added state");

            if ((null != resource.Identity) &&
                !this.identityToResource.Remove(resource.Identity)) 
            {
                Debug.Assert(false, "didn't remove added identity"); 
            } 

            resource.ETag = etag; 
            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink;

            resource.State = EntityStates.Unchanged; 

            this.identityToResource.Add(identity, resource); 
        } 

        /// use location from header to generate initial edit and identity 
        /// entity in added state
        /// location from post header
        internal void AttachLocation(object entity, string location)
        { 
            Debug.Assert(null != entity, "null != entity");
            Uri editLink = new Uri(location, UriKind.Absolute); 
            Uri identity = Util.ReferenceIdentity(editLink); 

            this.EnsureIdentityToResource(); 

            ResourceBox resource = this.objectToResource[entity];
            Debug.Assert(EntityStates.Added == resource.State, "didn't find expected entity in added state");
 
            if ((null != resource.Identity) &&
                !this.identityToResource.Remove(resource.Identity)) 
            { 
                Debug.Assert(false, "didn't remove added identity");
            } 

            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink;
            this.identityToResource.Add(identity, resource); 
        }
 
        ///  
        /// Track a binding.
        ///  
        /// Source resource.
        /// Property on the source resource that relates to the target resource.
        /// Target resource.
        /// merge operation 
        internal void AttachLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        { 
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Unchanged); 

            RelatedEnd existing = null; 
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.TryGetValue(relation, out existing))
            {
                switch (linkMerge) 
                {
                    case MergeOption.AppendOnly: 
                        break; 

                    case MergeOption.OverwriteChanges: 
                        relation = existing;
                        break;

                    case MergeOption.PreserveChanges: 
                        if ((EntityStates.Added == existing.State) ||
                            (EntityStates.Unchanged == existing.State) || 
                            (EntityStates.Modified == existing.State && null != existing.TargetResouce)) 
                        {
                            relation = existing; 
                        }

                        break;
 
                    case MergeOption.NoTracking: // public API point should throw if link exists
                        throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained); 
                } 
            }
            else 
            {
                bool collectionProperty = (null != ClientType.Create(source.GetType()).GetProperty(sourceProperty, false).CollectionType);
                if (collectionProperty || (null == (existing = this.DetachReferenceLink(source, sourceProperty, target, linkMerge))))
                { 
                    this.bindings.Add(relation, relation);
                    this.objectToResource[source].RelatedLinkCount++; 
                    this.IncrementChange(relation); 
                }
                else if (!((MergeOption.AppendOnly == linkMerge) || 
                           (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State)))
                {
                    // AppendOnly doesn't change state or target
                    // OverWriteChanges changes target and state 
                    // PreserveChanges changes target if unchanged, leaves modified target and state alone
                    relation = existing; 
                } 
            }
 
            relation.State = EntityStates.Unchanged;
        }

        ///  
        /// Attach entity into the context in the Unchanged state.
        ///  
        /// Identity for the object to be attached. 
        /// EntitySet for the object to be attached.
        /// etag for the entity 
        /// entity graph to attach
        /// fail for public api else change existing relationship to unchanged
        /// if entitySetName is empty
        /// if entitySetName is null 
        /// if entity is null
        /// if entity is already being tracked by the context 
        internal void AttachTo(Uri identity, Uri editLink, string etag, object entity, bool fail) 
        {
            Debug.Assert((null != identity && identity.IsAbsoluteUri), "must have identity"); 
            Debug.Assert(null != editLink, "must have editLink");
            Debug.Assert(null != entity && ClientType.Create(entity.GetType()).HasKeys, "entity must have keys to attach");

            this.EnsureIdentityToResource(); 

            Debug.Assert(identity.IsAbsoluteUri, "Uri is not absolute"); 
 
            ResourceBox resource;
            this.objectToResource.TryGetValue(entity, out resource); 

            ResourceBox existing;
            this.identityToResource.TryGetValue(identity, out existing);
 
            if (fail && (null != resource))
            { 
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained); 
            }
            else if (resource != existing) 
            {
                throw Error.InvalidOperation(Strings.Context_DifferentEntityAlreadyContained);
            }
            else if (null == resource) 
            {
                resource = new ResourceBox(identity, editLink, entity); 
                this.IncrementChange(resource); 

                this.objectToResource.Add(entity, resource); 
                this.identityToResource.Add(identity, resource);
            }

            resource.State = EntityStates.Unchanged; 
            resource.ETag = etag;
        } 
 
        #endregion
 
        /// 
        /// create the request object
        /// 
        /// requestUri 
        /// updating
        /// Whether the request/response should request/assume ATOM or any MIME type 
        /// content type for the request 
        /// a request ready to get a response
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType) 
        {
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri");
            Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.baseUriWithSlash, requestUri), "context is not base of request uri"); 

            Debug.Assert( 
                Object.ReferenceEquals(XmlConstants.HttpMethodDelete, method) || 
                Object.ReferenceEquals(XmlConstants.HttpMethodGet, method) ||
                Object.ReferenceEquals(XmlConstants.HttpMethodPost, method) || 
                Object.ReferenceEquals(XmlConstants.HttpMethodPut, method) ||
                Object.ReferenceEquals(XmlConstants.HttpMethodMerge, method),
                "unexpected http method string reference");
 
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
 
#if !ASTORIA_LIGHT  // Credentials not available 
            if (null != this.Credentials)
            { 
                request.Credentials = this.Credentials;
            }
#endif
 
#if !ASTORIA_LIGHT  // Timeout not available
            if (0 != this.timeout) 
            { 
                request.Timeout = (int)Math.Min(Int32.MaxValue, new TimeSpan(0, 0, this.timeout).TotalMilliseconds);
            } 
#endif

#if !ASTORIA_LIGHT // KeepAlive not available
            request.KeepAlive = true; 
#endif
 
#if !ASTORIA_LIGHT // UserAgent not available 
            request.UserAgent = "Microsoft ADO.NET Data Services";
#endif 

            if (this.UsePostTunneling &&
                (!Object.ReferenceEquals(XmlConstants.HttpMethodPost, method)) &&
                (!Object.ReferenceEquals(XmlConstants.HttpMethodGet, method))) 
            {
                request.Headers[XmlConstants.HttpXMethod] = method; 
                request.Method = XmlConstants.HttpMethodPost; 
            }
            else 
            {
                request.Method = method;
            }
 
#if !ASTORIA_LIGHT // Data.Services http stack
            // Fires whenever a new HttpWebRequest has been created 
            // The event fires early - before the client library sets many of its required property values. 
            // This ensures the client library has the last say on the value of mandated properties
            // such as the HTTP verb  being used for the request. 
            if (this.SendingRequest != null)
            {
                SendingRequestEventArgs args = new SendingRequestEventArgs(request);
                this.SendingRequest(this, args); 
                if (!Object.ReferenceEquals(args.Request, request))
                { 
                    request = (HttpWebRequest)args.Request; 
                }
            } 
#endif

            request.Accept = allowAnyType ?
                    XmlConstants.MimeAny : 
                    (XmlConstants.MimeApplicationAtom + "," + XmlConstants.MimeApplicationXml);
            request.Headers[HttpRequestHeader.AcceptCharset] = XmlConstants.Utf8Encoding; 
 
            // Always sending the version along allows the server to fail before processing.
            request.Headers[XmlConstants.HttpDataServiceVersion] = XmlConstants.DataServiceClientVersionCurrent; 
            request.Headers[XmlConstants.HttpMaxDataServiceVersion] = XmlConstants.DataServiceClientVersionCurrent;

#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available
            bool allowStreamBuffering = false; 
#endif
            bool removeXMethod = true; 
 
            if (!Object.ReferenceEquals(XmlConstants.HttpMethodGet, method))
            { 
                Debug.Assert(!String.IsNullOrEmpty(contentType), "Content-Type must be specified for non get operation");
                request.ContentType = contentType;
                if (Object.ReferenceEquals(XmlConstants.HttpMethodDelete, method))
                { 
                    request.ContentLength = 0;
                } 
#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available 
                // else
                {   // always set to workaround NullReferenceException in HttpWebRequest.GetResponse when ContentLength = 0 
                    allowStreamBuffering = true;
                }
#endif
 
                if (this.UsePostTunneling && (!Object.ReferenceEquals(XmlConstants.HttpMethodPost, method)))
                { 
                    request.Headers[XmlConstants.HttpXMethod] = method; 
                    method = XmlConstants.HttpMethodPost;
                    removeXMethod = false; 
                }
            }
            else
            { 
                Debug.Assert(contentType == null, "Content-Type for get methods should be null");
            } 
 
#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available
            // When AllowWriteStreamBuffering is true, the data is buffered in memory so it is ready to be resent 
            // in the event of redirections or authentication requests.
            request.AllowWriteStreamBuffering = allowStreamBuffering;
#endif
 
            ICollection headers;
#if !ASTORIA_LIGHT  // alternate Headers.AllKeys 
            headers = request.Headers.AllKeys; 
#else
            headers = request.Headers.Headers; 
#endif

            if (headers.Contains(XmlConstants.HttpRequestIfMatch))
            { 
#if !ASTORIA_LIGHT  // alternate IfMatch header doesn't work
                request.Headers.Remove(HttpRequestHeader.IfMatch); 
#endif 
            }
 
            if (removeXMethod && headers.Contains(XmlConstants.HttpXMethod))
            {
#if !ASTORIA_LIGHT  // alternate HttpXMethod header doesn't work
                request.Headers.Remove(XmlConstants.HttpXMethod); 
#endif
            } 
 
            request.Method = method;
            return request; 
        }

        /// 
        /// get an enumerable materializes the objects the response 
        /// 
        /// http response 
        /// base elementType being materialized 
        /// delegate to create the materializer
        /// an enumerable 
        internal MaterializeAtom GetMaterializer(QueryAsyncResult response, Type elementType, Func create)
        {
            if (HttpStatusCode.NoContent == response.StatusCode)
            {   // object was deleted 
                return null;
            } 
 
            if (HttpStatusCode.Created == response.StatusCode &&
                response.ContentLength == 0) 
            {
                // created but no response back
                return null;
            } 

            if (null != response) 
            { 
                return (MaterializeAtom)this.GetMaterializer(elementType, response.ContentType, response.GetResponseStream, create);
            } 

            return null;
        }
 
        /// 
        /// get an enumerable materializes the objects the response 
        ///  
        /// elementType
        /// contentType 
        /// method to get http response stream
        /// method to create a materializer
        /// an enumerable
        internal object GetMaterializer( 
            Type elementType,
            string contentType, 
            Func response, 
            Func create)
        { 
            Debug.Assert(null != create, "null create");

            string mime = null;
            Encoding encoding = null; 
            if (!String.IsNullOrEmpty(contentType))
            { 
                HttpProcessUtility.ReadContentType(contentType, out mime, out encoding); 
            }
 
            if (String.Equals(mime, XmlConstants.MimeApplicationAtom, StringComparison.OrdinalIgnoreCase) ||
                String.Equals(mime, XmlConstants.MimeApplicationXml, StringComparison.OrdinalIgnoreCase))
            {
                System.IO.Stream rstream = response(); 
                if (null != rstream)
                { 
                    XmlReader reader = XmlUtil.CreateXmlReader(rstream, encoding); 
                    return create(this, reader, elementType);
                } 

                return null;
            }
 
            throw Error.InvalidOperation(Strings.Deserialize_UnknownMimeTypeSpecified(mime));
        } 
 
        /// 
        /// Find tracked entity by its resourceUri and update its etag. 
        /// 
        /// resource id
        /// updated etag
        /// merge option 
        /// state of entity
        /// entity if found else null 
        internal object TryGetEntity(Uri resourceUri, string etag, MergeOption merger, out EntityStates state) 
        {
            Debug.Assert(null != resourceUri, "null uri"); 
            state = EntityStates.Detached;

            ResourceBox resource = null;
            if ((null != this.identityToResource) && 
                 this.identityToResource.TryGetValue(resourceUri, out resource))
            { 
                state = resource.State; 
                if ((null != etag) && (MergeOption.AppendOnly != merger))
                {   // don't update the etag if AppendOnly 
                    resource.ETag = etag;
                }

                Debug.Assert(null != resource.Resource, "null entity"); 
                return resource.Resource;
            } 
 
            return null;
        } 

        /// 
        /// get the resource box for an entity
        ///  
        /// entity
        /// resource box 
        internal ResourceBox GetEntity(object source) 
        {
            return this.objectToResource[source]; 
        }

        /// 
        /// get the related links ignoring target entity 
        /// 
        /// source entity 
        /// source entity's property 
        /// enumerable of related ends
        internal IEnumerable GetLinks(object source, string sourceProperty) 
        {
            return this.bindings.Values.Where(o => (o.SourceResource == source) && (o.SourceProperty == sourceProperty));
        }
 
        /// 
        /// user hook to resolve name into a type 
        ///  
        /// name to resolve
        /// base type associated with name 
        /// null to skip node
        /// if ResolveType function returns a type not assignable to the userType
        internal Type ResolveTypeFromName(string wireName, Type userType)
        { 
            Debug.Assert(null != userType, "null != baseType");
 
            if (String.IsNullOrEmpty(wireName)) 
            {
                return userType; 
            }

            Type payloadType;
            if (!ClientConvert.ToNamedType(wireName, out payloadType)) 
            {
                payloadType = null; 
 
                Func resolve = this.ResolveType;
                if (null != resolve) 
                {
                    // if the ResolveType property is set, call the provided type resultion method
                    payloadType = resolve(wireName);
                } 

                if (null == payloadType) 
                { 
                    // if the type resolution method returns null or the ResolveType property was not set
#if !ASTORIA_LIGHT 
                    payloadType = ClientType.ResolveFromName(wireName, userType);
#else
                    payloadType = ClientType.ResolveFromName(wireName, userType, this.GetType());
#endif 
                }
 
                if ((null != payloadType) && (!userType.IsAssignableFrom(payloadType))) 
                {
                    // throw an exception if the type from the resolver is not assignable to the expected type 
                    throw Error.InvalidOperation(Strings.Deserialize_Current(userType, payloadType));
                }
            }
 
            return payloadType ?? userType;
        } 
 
        /// 
        /// The reverse of ResolveType 
        /// 
        /// client type
        /// type for the server
        internal string ResolveNameFromType(Type type) 
        {
            Debug.Assert(null != type, "null type"); 
            Func resolve = this.ResolveName; 
            return ((null != resolve) ? resolve(type) : (String)null);
        } 

        /// 
        /// Fires the ReadingEntity event
        ///  
        /// Entity being (de)serialized
        /// XML data of the ATOM entry 
        internal void FireReadingEntityEvent(object entity, XElement data) 
        {
            Debug.Assert(entity != null, "entity != null"); 
            Debug.Assert(data != null, "data != null");

            ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(entity, data);
            this.ReadingEntity(this, args); 
        }
 
        #region Ensure 

        /// Filter to verify states 
        /// x
        /// true if added/updated/deleted
        private static bool HasModifiedResourceState(Entry x)
        { 
            Debug.Assert(
                (EntityStates.Added == x.State) || 
                (EntityStates.Modified == x.State) || 
                (EntityStates.Unchanged == x.State) ||
                (EntityStates.Deleted == x.State), 
                "entity state is not valid");

            return (EntityStates.Unchanged != x.State);
        } 

        /// modified or unchanged 
        /// state to test 
        /// true if modified or unchanged
        private static bool IncludeLinkState(EntityStates x) 
        {
            return ((EntityStates.Modified == x) || (EntityStates.Unchanged == x));
        }
 
        #endregion
 
        /// Checks whether an ADO.NET Data Service version string can be handled. 
        /// Version string on the response header; possibly null.
        /// true if the version can be handled; false otherwise. 
        private static bool CanHandleResponseVersion(string responseVersion)
        {
            if (!String.IsNullOrEmpty(responseVersion))
            { 
                KeyValuePair version;
                if (!HttpProcessUtility.TryReadVersion(responseVersion, out version)) 
                { 
                    return false;
                } 

                // For the time being, we only handle 1.0 responses.
                if (version.Key.Major != XmlConstants.DataServiceClientVersionCurrentMajor ||
                    version.Key.Minor != XmlConstants.DataServiceClientVersionCurrentMinor) 
                {
                    return false; 
                } 
            }
 
            return true;
        }

        /// generate a Uri based on key properties of the entity 
        /// baseUri
        /// entitySetName 
        /// entity 
        /// absolute uri
        private static Uri GenerateEditLinkUri(Uri baseUriWithSlash, string entitySetName, object entity) 
        {
            Debug.Assert(null != baseUriWithSlash && baseUriWithSlash.IsAbsoluteUri && baseUriWithSlash.OriginalString.EndsWith("/", StringComparison.Ordinal), "baseUriWithSlash");
            Debug.Assert(!String.IsNullOrEmpty(entitySetName) && !entitySetName.StartsWith("/", StringComparison.Ordinal), "entitySetName");
            Debug.Assert(null != entity, "entity"); 

            StringBuilder builder = new StringBuilder(); 
            builder.Append(baseUriWithSlash.AbsoluteUri); 
            builder.Append(entitySetName);
            builder.Append("("); 

            string prefix = String.Empty;
            ClientType clientType = ClientType.Create(entity.GetType());
            Debug.Assert(clientType.HasKeys, "requires keys"); 

            ClientType.ClientProperty[] keys = clientType.Properties.Where(ClientType.ClientProperty.GetKeyProperty).ToArray(); 
            foreach (ClientType.ClientProperty property in keys) 
            {
#if ASTORIA_OPEN_OBJECT 
                Debug.Assert(!property.OpenObjectProperty, "key property values can't be OpenProperties");
#endif

                builder.Append(prefix); 
                if (1 < keys.Length)
                { 
                    builder.Append(property.PropertyName).Append("="); 
                }
 
                object value = property.GetValue(entity);
                if (null == value)
                {
                    throw Error.InvalidOperation(Strings.Serializer_NullKeysAreNotSupported(property.PropertyName)); 
                }
 
                string converted; 
                if (!ClientConvert.TryKeyPrimitiveToString(value, out converted))
                { 
                    throw Error.InvalidOperation(Strings.Deserialize_Current(typeof(string), value.GetType()));
                }

                builder.Append(converted); 
                prefix = ",";
            } 
 
            builder.Append(")");
 
            return Util.CreateUri(builder.ToString(), UriKind.Absolute);
        }

        /// Get http method string from entity resource state 
        /// resource state
        /// whether we need to update MERGE or PUT method for update. 
        /// http method string delete, put or post 
        private static string GetEntityHttpMethod(EntityStates state, bool replaceOnUpdate)
        { 
            switch (state)
            {
                case EntityStates.Deleted:
                    return XmlConstants.HttpMethodDelete; 
                case EntityStates.Modified:
                    if (replaceOnUpdate) 
                    { 
                        return XmlConstants.HttpMethodPut;
                    } 
                    else
                    {
                        return XmlConstants.HttpMethodMerge;
                    } 

                case EntityStates.Added: 
                    return XmlConstants.HttpMethodPost; 
                default:
                    throw Error.InternalError(InternalError.UnvalidatedEntityState); 
            }
        }

        /// Get http method string from link resource state 
        /// resource
        /// http method string put or post 
        private static string GetLinkHttpMethod(RelatedEnd link) 
        {
            bool collection = (null != ClientType.Create(link.SourceResource.GetType()).GetProperty(link.SourceProperty, false).CollectionType); 
            if (!collection)
            {
                Debug.Assert(EntityStates.Modified == link.State, "not Modified state");
                if (null == link.TargetResouce) 
                {   // REMOVE/DELETE a reference
                    return XmlConstants.HttpMethodDelete; 
                } 
                else
                {   // UPDATE/PUT a reference 
                    return XmlConstants.HttpMethodPut;
                }
            }
            else if (EntityStates.Deleted == link.State) 
            {   // you call DELETE on $links
                return XmlConstants.HttpMethodDelete; 
            } 
            else
            {   // you INSERT/POST into a collection 
                Debug.Assert(EntityStates.Added == link.State, "not Added state");
                return XmlConstants.HttpMethodPost;
            }
        } 

        ///  
        /// get the response text into a string 
        /// 
        /// method to get response stream 
        /// status code
        /// text
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031", Justification = "Cache exception so user can examine it later")]
        private static DataServiceClientException GetResponseText(Func getResponseStream, HttpStatusCode statusCode) 
        {
            string message = null; 
            using (System.IO.Stream stream = getResponseStream()) 
            {
                if ((null != stream) && stream.CanRead) 
                {
                    message = new StreamReader(stream).ReadToEnd();
                }
            } 

            if (String.IsNullOrEmpty(message)) 
            { 
                message = statusCode.ToString();
            } 

            return new DataServiceClientException(message, (int)statusCode);
        }
 
        /// Handle changeset response.
        /// headers of changeset response 
        private static void HandleResponsePost(RelatedEnd entry) 
        {
            if (!((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State && null != entry.TargetResouce))) 
            {
                Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState);
            }
 
            entry.State = EntityStates.Unchanged;
        } 
 
        /// Handle changeset response.
        /// updated entity or link 
        /// updated etag
        private static void HandleResponsePut(Entry entry, string etag)
        {
            if (entry.IsResource) 
            {
                if (EntityStates.Modified != entry.State) 
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.EntryNotModified);
                } 

                entry.State = EntityStates.Unchanged;
                ((ResourceBox)entry).ETag = etag;
            } 
            else
            { 
                RelatedEnd link = (RelatedEnd)entry; 
                if ((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State))
                { 
                    link.State = EntityStates.Unchanged;
                }
                else
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.LinkBadState);
                } 
            } 
        }
 
        /// 
        /// write out an individual property value which can be a primitive or link
        /// 
        /// writer 
        /// namespaceName in which we need to write the property element.
        /// property which contains name, type, is key (if false and null value, will throw) 
        /// property value 
        private static void WriteContentProperty(XmlWriter writer, string namespaceName, ClientType.ClientProperty property, object propertyValue)
        { 
            writer.WriteStartElement(property.PropertyName, namespaceName);

            string typename = ClientConvert.GetEdmType(property.PropertyType);
            if (null != typename) 
            {
                writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.DataWebMetadataNamespace, typename); 
            } 

            if (null == propertyValue) 
            {   // 
                writer.WriteAttributeString(XmlConstants.AtomNullAttributeName, XmlConstants.DataWebMetadataNamespace, XmlConstants.XmlTrueLiteral);

                if (property.KeyProperty) 
                {
                    throw Error.InvalidOperation(Strings.Serializer_NullKeysAreNotSupported(property.PropertyName)); 
                } 
            }
            else 
            {
                string convertedValue = ClientConvert.ToString(propertyValue);
                if (0 == convertedValue.Length)
                {   //  
                    writer.WriteAttributeString(XmlConstants.AtomNullAttributeName, XmlConstants.DataWebMetadataNamespace, XmlConstants.XmlFalseLiteral);
                } 
                else 
                {   // value
                    if (Char.IsWhiteSpace(convertedValue[0]) || 
                        Char.IsWhiteSpace(convertedValue[convertedValue.Length - 1]))
                    {   // xml:space="preserve"
                        writer.WriteAttributeString(XmlConstants.XmlSpaceAttributeName, XmlConstants.XmlNamespacesNamespace, XmlConstants.XmlSpacePreserveValue);
                    } 

                    writer.WriteValue(convertedValue); 
                } 
            }
 
            writer.WriteEndElement();
        }

        /// validate  
        /// entity to validate
        /// if entity was null 
        /// if entity does not have a key property 
        private static void ValidateEntityWithKey(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity");

            if (!ClientType.Create(entity.GetType()).HasKeys)
            { 
                throw Error.Argument(Strings.Content_EntityWithoutKey, "entity");
            } 
        } 

        ///  
        /// Validate the SaveChanges Option
        /// 
        /// options as specified by the user.
        private static void ValidateSaveChangesOptions(SaveChangesOptions options) 
        {
            const SaveChangesOptions All = 
                SaveChangesOptions.ContinueOnError | 
                SaveChangesOptions.Batch |
                SaveChangesOptions.ReplaceOnUpdate; 

            // Make sure no higher order bits are set.
            if ((options | All) != All)
            { 
                throw Error.ArgumentOutOfRange("options");
            } 
 
            // Both batch and continueOnError can't be set together
            if (IsFlagSet(options, SaveChangesOptions.Batch | SaveChangesOptions.ContinueOnError)) 
            {
                throw Error.ArgumentOutOfRange("options");
            }
        } 

        ///  
        /// checks whether the given flag is set on the options 
        /// 
        /// options as specified by the user. 
        /// whether the given flag is set on the options
        /// true if the given flag is set, otherwise false.
        private static bool IsFlagSet(SaveChangesOptions options, SaveChangesOptions flag)
        { 
            return ((options & flag) == flag);
        } 
 
        /// 
        /// Write the batch headers along with the first http header for the batch operation. 
        /// 
        /// Stream writer which writes to the underlying stream.
        /// HTTP method name for the operation.
        /// uri for the operation. 
        private static void WriteOperationRequestHeaders(StreamWriter writer, string methodName, string uri)
        { 
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationHttp); 
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentTransferEncoding, XmlConstants.BatchRequestContentTransferEncoding);
            writer.WriteLine(); 

            writer.WriteLine("{0} {1} {2}", methodName, uri, XmlConstants.HttpVersionInBatching);
        }
 
        /// 
        /// Write the batch headers along with the first http header for the batch operation. 
        ///  
        /// Stream writer which writes to the underlying stream.
        /// status code for the response. 
        private static void WriteOperationResponseHeaders(StreamWriter writer, int statusCode)
        {
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationHttp);
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentTransferEncoding, XmlConstants.BatchRequestContentTransferEncoding); 
            writer.WriteLine();
 
            writer.WriteLine("{0} {1} {2}", XmlConstants.HttpVersionInBatching, statusCode, (HttpStatusCode)statusCode); 
        }
 
        /// 
        /// Check to see if the resource to be inserted is a media entry, and if so
        /// setup a POST request for the media content first and turn the rest of
        /// the operation into a PUT to update the rest of the properties. 
        /// 
        /// The resource to check/process 
        /// A web request setup to do POST the media resource 
        private HttpWebRequest CheckAndProcessMediaEntry(ResourceBox box)
        { 
            //
            ClientType type = ClientType.Create(box.Resource.GetType());

            if (type.MediaDataMember == null) 
            {
                // this is not a media link entry, process normally 
                return null; 
            }
 
            HttpWebRequest mediaRequest = this.CreateRequest(box.GetResourceUri(this.baseUriWithSlash), XmlConstants.HttpMethodPost, true, XmlConstants.MimeApplicationAtom);

            if (type.MediaDataMember.MimeTypeProperty == null)
            { 
                mediaRequest.ContentType = XmlConstants.MimeApplicationOctetStream;
            } 
            else 
            {
                string mimeType = type.MediaDataMember.MimeTypeProperty.GetValue(box.Resource).ToString(); 

                if (string.IsNullOrEmpty(mimeType))
                {
                    throw Error.InvalidOperation( 
                        Strings.Context_NoContentTypeForMediaLink(
                            type.ElementTypeName, 
                            type.MediaDataMember.MimeTypeProperty.PropertyName)); 
                }
 
                mediaRequest.ContentType = mimeType;
            }

            object value = type.MediaDataMember.GetValue(box.Resource); 
            if (value == null)
            { 
                mediaRequest.ContentLength = 0; 
            }
            else 
            {
                byte[] buffer = value as byte[];
                if (buffer == null)
                { 
                    string mime;
                    Encoding encoding; 
                    HttpProcessUtility.ReadContentType(mediaRequest.ContentType, out mime, out encoding); 

                    if (encoding == null) 
                    {
                        encoding = Encoding.UTF8;
                        mediaRequest.ContentType += XmlConstants.MimeTypeUtf8Encoding;
                    } 

                    buffer = encoding.GetBytes(ClientConvert.ToString(value)); 
                } 

                mediaRequest.ContentLength = buffer.Length; 

                using (Stream s = mediaRequest.GetRequestStream())
                {
                    s.Write(buffer, 0, buffer.Length); 
                }
            } 
 
            // Convert the insert into an update for the media link entry we just created
            // (note that the identity still needs to be fixed up on the resbox once 
            // the response comes with the 'location' header; that happens during processing
            // of the response in SavedResource())
            box.State = EntityStates.Modified;
 
            return mediaRequest;
        } 
 
        /// the work to detach a resource
        /// resource to detach 
        /// true if detached
        private bool DetachResource(ResourceBox resource)
        {
            this.DetachRelated(resource); 

            resource.ChangeOrder = UInt32.MaxValue; 
            resource.State = EntityStates.Detached; 
            bool flag = this.objectToResource.Remove(resource.Resource);
            Debug.Assert(flag, "should have removed existing entity"); 

            if (null != resource.Identity)
            {
                flag = this.identityToResource.Remove(resource.Identity); 
                Debug.Assert(flag, "should have removed existing identity");
            } 
 
            return true;
        } 

        /// 
        /// write out binding payload using POST with http method override for PUT
        ///  
        /// binding
        /// for non-batching its a request object ready to get a response from else null when batching 
        private HttpWebRequest CreateRequest(RelatedEnd binding) 
        {
            Debug.Assert(null != binding, "null binding"); 
            if (binding.ContentGeneratedForSave)
            {
                return null;
            } 

            ResourceBox sourceResource = this.objectToResource[binding.SourceResource]; 
            ResourceBox targetResource = (null != binding.TargetResouce) ? this.objectToResource[binding.TargetResouce] : null; 

            // these failures should only with SaveChangesOptions.ContinueOnError 
            if (null == sourceResource.Identity)
            {
                Debug.Assert(!binding.ContentGeneratedForSave, "already saved link");
                binding.ContentGeneratedForSave = true; 
                Debug.Assert(EntityStates.Added == sourceResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, sourceResource.SaveError); 
            } 
            else if ((null != targetResource) && (null == targetResource.Identity))
            { 
                Debug.Assert(!binding.ContentGeneratedForSave, "already saved link");
                binding.ContentGeneratedForSave = true;
                Debug.Assert(EntityStates.Added == targetResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, targetResource.SaveError); 
            }
 
            Debug.Assert(null != sourceResource.Identity, "missing sourceResource.Identity"); 
            return this.CreateRequest(this.CreateRequestUri(sourceResource, binding), GetLinkHttpMethod(binding), false, XmlConstants.MimeApplicationXml);
        } 

        /// create the uri for a link
        /// edit link of source
        /// link 
        /// appropriate uri for link state
        private Uri CreateRequestUri(ResourceBox sourceResource, RelatedEnd binding) 
        { 
            Uri requestUri = Util.CreateUri(sourceResource.GetResourceUri(this.baseUriWithSlash), this.CreateRequestRelativeUri(binding));
            return requestUri; 
        }

        /// 
        /// create the uri for the link relative to its source entity 
        /// 
        /// link 
        /// uri 
        private Uri CreateRequestRelativeUri(RelatedEnd binding)
        { 
            Uri relative;
            bool collection = (null != ClientType.Create(binding.SourceResource.GetType()).GetProperty(binding.SourceProperty, false).CollectionType);
            if (collection && (EntityStates.Added != binding.State))
            {   // you DELETE(PUT NULL) from a collection 
                Debug.Assert(null != binding.TargetResouce, "null target in collection");
                ResourceBox targetResource = this.objectToResource[binding.TargetResouce]; 
                relative = this.baseUriWithSlash.MakeRelativeUri(targetResource.GetResourceLinkUri(this.baseUriWithSlash)); 
            }
            else 
            {   // UPDATE(PUT ID) a reference && INSERT(POST ID) into a collection
                relative = Util.CreateUri(XmlConstants.UriLinkSegment + "/" + binding.SourceProperty, UriKind.Relative);
            }
 
            Debug.Assert(!relative.IsAbsoluteUri, "should be relative uri");
            return relative; 
        } 

        ///  
        /// write content to batch text stream
        /// 
        /// link
        /// batch text stream 
        private void CreateRequestBatch(RelatedEnd binding, StreamWriter text)
        { 
            Uri relative = this.CreateRequestRelativeUri(binding); 
            ResourceBox sourceResource = this.objectToResource[binding.SourceResource];
            string requestString; 
            if (null != sourceResource.Identity)
            {
                requestString = this.CreateRequestUri(sourceResource, binding).AbsoluteUri;
            } 
            else
            { 
                requestString = "$" + sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) + "/" + relative.OriginalString; 
            }
 
            WriteOperationRequestHeaders(text, GetLinkHttpMethod(binding), requestString);
            text.WriteLine("{0}: {1}", XmlConstants.HttpDataServiceVersion, XmlConstants.DataServiceClientVersionCurrent);
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, binding.ChangeOrder);
 
            // if (EntityStates.Deleted || (EntityState.Modifed && null == TargetResource))
            // then the server will fail the batch section if content type exists 
            if ((EntityStates.Added == binding.State) || (EntityStates.Modified == binding.State && (null != binding.TargetResouce))) 
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationXml); 
            }
        }

        ///  
        /// create content memory stream for link
        ///  
        /// link 
        /// should newline be written
        /// memory stream 
        private MemoryStream CreateRequestData(RelatedEnd binding, bool newline)
        {
            Debug.Assert(
                (binding.State == EntityStates.Added) || 
                (binding.State == EntityStates.Modified && null != binding.TargetResouce),
                "This method must be called only when a binding is added or put"); 
            MemoryStream stream = new MemoryStream(); 
            XmlWriter writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
            ResourceBox targetResource = this.objectToResource[binding.TargetResouce]; 

            #region 
            writer.WriteStartElement(XmlConstants.UriElementName, XmlConstants.DataWebMetadataNamespace);
 
            string id;
            if (null != targetResource.Identity) 
            { 
                id = Util.DereferenceIdentity(targetResource.Identity).AbsoluteUri;
            } 
            else
            {
                id = "$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture);
            } 

            writer.WriteValue(id); 
            writer.WriteEndElement(); //  
            #endregion
 
            writer.Flush();

            if (newline)
            { 
                // end the xml content stream with a newline
                stream.WriteByte((byte)'\r'); 
                stream.WriteByte((byte)'\n'); 
            }
 
            // strip the preamble.
            stream.Position = 0;
            return stream;
        } 

        ///  
        /// Create HttpWebRequest from a resource 
        /// 
        /// resource 
        /// resource state
        /// whether we need to update MERGE or PUT method for update.
        /// web request
        private HttpWebRequest CreateRequest(ResourceBox box, EntityStates state, bool replaceOnUpdate) 
        {
            Debug.Assert(null != box && ((EntityStates.Added == state) || (EntityStates.Modified == state) || (EntityStates.Deleted == state)), "unexpected entity ResourceState"); 
 
            string httpMethod = GetEntityHttpMethod(state, replaceOnUpdate);
            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash); 
            HttpWebRequest request = this.CreateRequest(requestUri, httpMethod, false, XmlConstants.MimeApplicationAtom);
            if ((null != box.ETag) && ((EntityStates.Deleted == state) || (EntityStates.Modified == state)))
            {
#if !ASTORIA_LIGHT  // different way to write Request headers 
                request.Headers.Set(HttpRequestHeader.IfMatch, box.ETag);
#else 
                request.Headers[XmlConstants.HttpRequestIfMatch] = box.ETag; 
#endif
            } 

            return request;
        }
 
        /// 
        /// generate batch request for entity 
        ///  
        /// entity
        /// batch stream to write to 
        /// whether we need to update MERGE or PUT method for update.
        private void CreateRequestBatch(ResourceBox box, StreamWriter text, bool replaceOnUpdate)
        {
            Debug.Assert(null != box, "null box"); 
            Debug.Assert(null != text, "null text");
 
            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash); 

            Debug.Assert(null != requestUri, "request uri is null"); 
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri");
            Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.baseUriWithSlash, requestUri), "context is not base of request uri");

            WriteOperationRequestHeaders(text, GetEntityHttpMethod(box.State, replaceOnUpdate), requestUri.AbsoluteUri); 
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, box.ChangeOrder);
            if (EntityStates.Deleted != box.State) 
            { 
                text.WriteLine("{0}: {1};{2}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationAtom, XmlConstants.MimeTypeEntry);
            } 

            if ((null != box.ETag) && (EntityStates.Deleted == box.State || EntityStates.Modified == box.State))
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpRequestIfMatch, box.ETag); 
            }
        } 
 
        /// 
        /// create memory stream with entity data 
        /// 
        /// entity
        /// should newline be written
        /// memory stream containing data 
        private MemoryStream CreateRequestData(ResourceBox box, bool newline)
        { 
            Debug.Assert(null != box, "null box"); 
            MemoryStream stream = null;
            switch (box.State) 
            {
                case EntityStates.Deleted:
                    break;
                case EntityStates.Modified: 
                case EntityStates.Added:
                    stream = new MemoryStream(); 
                    break; 
                default:
                    Error.ThrowInternalError(InternalError.UnvalidatedEntityState); 
                    break;
            }

            if (null != stream) 
            {
                XmlWriter writer; 
                XDocument node = null; 
                if (this.WritingEntity != null)
                { 
                    // if we have to fire the WritingEntity event, buffer the content
                    // in an XElement so we can present the handler with the data
                    node = new XDocument();
                    writer = node.CreateWriter(); 
                }
                else 
                { 
                    writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
                } 

                ClientType type = ClientType.Create(box.Resource.GetType());

                string typeName = this.ResolveNameFromType(type.ElementType); 

                #region  
                writer.WriteStartElement(XmlConstants.AtomEntryElementName, XmlConstants.AtomNamespace); 
                writer.WriteAttributeString(XmlConstants.DataWebNamespacePrefix, XmlConstants.XmlNamespacesNamespace, this.DataNamespace);
                writer.WriteAttributeString(XmlConstants.DataWebMetadataNamespacePrefix, XmlConstants.XmlNamespacesNamespace, XmlConstants.DataWebMetadataNamespace); 

                // 
                if (!String.IsNullOrEmpty(typeName))
                { 
                    writer.WriteStartElement(XmlConstants.AtomCategoryElementName, XmlConstants.AtomNamespace);
                    writer.WriteAttributeString(XmlConstants.AtomCategorySchemeAttributeName, this.typeScheme.OriginalString); 
                    writer.WriteAttributeString(XmlConstants.AtomCategoryTermAttributeName, typeName); 
                    writer.WriteEndElement();
                } 

                // 
                // <updated>2008-05-05T21:44:55Z</updated>
                // <author><name /></author> 
                writer.WriteElementString(XmlConstants.AtomTitleElementName, XmlConstants.AtomNamespace, String.Empty);
                writer.WriteElementString(XmlConstants.AtomUpdatedElementName, XmlConstants.AtomNamespace, XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind)); 
                writer.WriteStartElement(XmlConstants.AtomAuthorElementName, XmlConstants.AtomNamespace); 
                writer.WriteElementString(XmlConstants.AtomNameElementName, XmlConstants.AtomNamespace, String.Empty);
                writer.WriteEndElement(); 

                if (EntityStates.Modified == box.State)
                {
                    // <id>http://host/service/entityset(key)</id> 
                    writer.WriteElementString(XmlConstants.AtomIdElementName, Util.DereferenceIdentity(box.Identity).AbsoluteUri);
                } 
                else 
                {
                    writer.WriteElementString(XmlConstants.AtomIdElementName, XmlConstants.AtomNamespace, String.Empty); 
                }

                #region <link href=”%Identity%” rel=”%DataWebRelatedNamespace%%AssociationName%” type=”application/atom+xml;feed” />
                if (EntityStates.Added == box.State) 
                {
                    this.CreateRequestDataLinks(box, writer); 
                } 
                #endregion
 
                #region <content type="application/xml"><m:Properites> or <m:Properties>
                if (type.MediaDataMember == null)
                {
                    writer.WriteStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); 
                    writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.MimeApplicationXml); // empty namespace
                } 
 
                writer.WriteStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace);
 
                this.WriteContentProperties(writer, type, box.Resource);

                writer.WriteEndElement(); // </adsm:Properties>
 
                if (type.MediaDataMember == null)
                { 
                    writer.WriteEndElement(); // </atom:content> 
                }
 
                writer.WriteEndElement(); // </atom:entry>
                writer.Flush();
                writer.Close();
                #endregion 
                #endregion
 
                if (this.WritingEntity != null) 
                {
                    ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(box.Resource, node.Root); 
                    this.WritingEntity(this, args);

                    // copy the buffered XDocument to the memory stream. no easy way of avoiding
                    // the copy given that we need to know the length before scanning the stream 
                    node.Save(new StreamWriter(stream));    // defaults to UTF8 w/o preamble & Save will Flush
                } 
 
                if (newline)
                { 
                    // end the xml content stream with a newline
                    stream.WriteByte((byte)'\r');
                    stream.WriteByte((byte)'\n');
                } 

                stream.Position = 0; 
            } 

            return stream; 
        }

        /// <summary>
        /// add the related links for new entites to non-new entites 
        /// </summary>
        /// <param name="box">entity in added state</param> 
        /// <param name="writer">writer to add links to</param> 
        private void CreateRequestDataLinks(ResourceBox box, XmlWriter writer)
        { 
            Debug.Assert(EntityStates.Added == box.State, "entity not added state");

            ClientType clientType = null;
            foreach (RelatedEnd end in this.RelatedLinks(box)) 
            {
                Debug.Assert(!end.ContentGeneratedForSave, "already saved link"); 
                end.ContentGeneratedForSave = true; 

                if (null == clientType) 
                {
                    clientType = ClientType.Create(box.Resource.GetType());
                }
 
                string typeAttributeValue;
                if (null != clientType.GetProperty(end.SourceProperty, false).CollectionType) 
                { 
                    typeAttributeValue = XmlConstants.MimeApplicationAtom + ";" + XmlConstants.MimeTypeFeed;
                } 
                else
                {
                    typeAttributeValue = XmlConstants.MimeApplicationAtom + ";" + XmlConstants.MimeTypeEntry;
                } 

                Debug.Assert(null != end.TargetResouce, "null is DELETE"); 
                Uri targetIdentity = Util.DereferenceIdentity(this.objectToResource[end.TargetResouce].Identity); 

                writer.WriteStartElement(XmlConstants.AtomLinkElementName, XmlConstants.AtomNamespace); 
                writer.WriteAttributeString(XmlConstants.AtomHRefAttributeName, targetIdentity.ToString());
                writer.WriteAttributeString(XmlConstants.AtomLinkRelationAttributeName, XmlConstants.DataWebRelatedNamespace + end.SourceProperty);
                writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, typeAttributeValue);
                writer.WriteEndElement(); 
            }
        } 
 
        /// <summary>Handle response to deleted entity.</summary>
        /// <param name="entry">deleted entity</param> 
        private void HandleResponseDelete(Entry entry)
        {
            if (EntityStates.Deleted != entry.State)
            { 
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotDeleted);
            } 
 
            if (entry.IsResource)
            { 
                ResourceBox resource = (ResourceBox)entry;
                this.DetachResource(resource);
            }
            else 
            {
                this.DetachExistingLink((RelatedEnd)entry); 
            } 
        }
 
        /// <summary>Handle changeset response.</summary>
        /// <param name="entry">headers of changeset response</param>
        /// <param name="materializer">changeset response stream</param>
        /// <param name="editLink">editLink of the newly created item (non-null if materialize is null)</param> 
        /// <param name="etag">ETag header value from the server response (or null if no etag or if there is an actual response)</param>
        private void HandleResponsePost(ResourceBox entry, MaterializeAtom materializer, Uri editLink, string etag) 
        { 
            Debug.Assert((materializer != null) || (editLink != null), "must have either materializer or editLink");
 
            if (EntityStates.Added != entry.State)
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotAddedState);
            } 

            ResourceBox box = (ResourceBox)entry; 
 
            if (materializer == null)
            { 
                Uri identity = Util.ReferenceIdentity(editLink);
                this.AttachIdentity(identity, editLink, entry.Resource, etag);
            }
            else 
            {
                materializer.SetInsertingObject(box.Resource); 
 
                foreach (object x in materializer)
                { 
                    Debug.Assert(null != box.Identity, "updated inserted should always gain an identity");
                    Debug.Assert(x == box.Resource, "x == box.Resource, should have same object generated by response");
                    Debug.Assert(EntityStates.Unchanged == box.State, "should have moved out of insert");
                    Debug.Assert((null != this.identityToResource) && this.identityToResource.ContainsKey(box.Identity), "should have identity tracked"); 
                }
            } 
 
            foreach (RelatedEnd end in this.RelatedLinks(box))
            { 
                Debug.Assert(0 != end.SaveResultWasProcessed, "link should have been saved with the enty");
                if (IncludeLinkState(end.SaveResultWasProcessed))
                {
                    HandleResponsePost(end); 
                }
            } 
        } 

        /// <summary>flag results as being processed</summary> 
        /// <param name="entry">result entry being processed</param>
        /// <returns>count of related links that were also processed</returns>
        private int SaveResultProcessed(Entry entry)
        { 
            Debug.Assert(0 == entry.SaveResultWasProcessed, "this entity/link already had a result");
            entry.SaveResultWasProcessed = entry.State; 
 
            int count = 0;
            if (entry.IsResource && (EntityStates.Added == entry.State)) 
            {
                foreach (RelatedEnd end in this.RelatedLinks((ResourceBox)entry))
                {
                    Debug.Assert(end.ContentGeneratedForSave, "link should have been saved with the enty"); 
                    if (end.ContentGeneratedForSave)
                    { 
                        Debug.Assert(0 == end.SaveResultWasProcessed, "this link already had a result"); 
                        end.SaveResultWasProcessed = end.State;
                        count++; 
                    }
                }
            }
 
            return count;
        } 
 
        /// <summary>
        /// enumerate the related Modified/Unchanged links for an added item 
        /// </summary>
        /// <param name="box">entity</param>
        /// <returns>related links</returns>
        private IEnumerable<RelatedEnd> RelatedLinks(ResourceBox box) 
        {
            int related = box.RelatedLinkCount; 
            if (0 < related) 
            {
                foreach (RelatedEnd end in this.bindings.Values) 
                {
                    if (end.SourceResource == box.Resource)
                    {
                        if (null != end.TargetResouce) 
                        {   // null TargetResource is equivalent to Deleted
                            ResourceBox target = this.objectToResource[end.TargetResouce]; 
                            if (IncludeLinkState(target.SaveResultWasProcessed) || ((0 == target.SaveResultWasProcessed) && IncludeLinkState(target.State))) 
                            {
                                Debug.Assert(box.ChangeOrder < end.ChangeOrder, "saving is out of order"); 
                                yield return end;
                            }
                        }
 
                        if (0 == --related)
                        { 
                            break; 
                        }
                    } 
                }
            }

            Debug.Assert(0 == related, "related count mismatch"); 
        }
 
        /// <summary> 
        /// delete related bindings
        /// </summary> 
        /// <param name="entity">entity being deleted</param>
        private void DeleteRelated(ResourceBox entity)
        {
            List<RelatedEnd> detached = null; 
            foreach (RelatedEnd end in this.bindings.Values.Where<RelatedEnd>(entity.IsRelatedEntity))
            { 
                if (EntityStates.Added == end.State) 
                {   // added -> detached
                    (detached ?? (detached = new List<RelatedEnd>())).Add(end); 
                }
                else if (!((EntityStates.Deleted == end.State) || (EntityStates.Modified == end.State && null == end.TargetResouce)))
                {   // modified/unchanged -> deleted
                    end.State = EntityStates.Deleted; 
                    this.IncrementChange(end);
                } 
            } 

            if (null != detached) 
            {
                foreach (RelatedEnd end in detached)
                {
                    this.DetachExistingLink(end); 
                }
            } 
        } 

        /// <summary> 
        /// detach related bindings
        /// </summary>
        /// <param name="entity">detached entity</param>
        private void DetachRelated(ResourceBox entity) 
        {
            foreach (RelatedEnd end in this.bindings.Values.Where(entity.IsRelatedEntity).ToList()) 
            { 
                this.DetachExistingLink(end);
            } 
        }

        /// <summary>
        /// create the load property request 
        /// </summary>
        /// <param name="entity">entity</param> 
        /// <param name="propertyName">name of collection or reference property to load</param> 
        /// <param name="callback">The AsyncCallback delegate.</param>
        /// <param name="state">user state</param> 
        /// <returns>a aync result that you can get a response from</returns>
        private LoadPropertyAsyncResult CreateLoadPropertyRequest(object entity, string propertyName, AsyncCallback callback, object state)
        {
            ResourceBox box = this.EnsureContained(entity, "entity"); 
            Util.CheckArgumentNotEmpty(propertyName, "propertyName");
 
            ClientType type = ClientType.Create(entity.GetType()); 
            Debug.Assert(type.HasKeys, "must have keys to be contained");
 
            if (EntityStates.Added == box.State)
            {
                throw Error.InvalidOperation(Strings.Context_NoLoadWithInsertEnd);
            } 

            ClientType.ClientProperty property = type.GetProperty(propertyName, false); 
            Debug.Assert(null != property, "should have thrown if propertyName didn't exist"); 

            Uri relativeUri; 
            bool allowAnyType = false;
            if (type.MediaDataMember != null && propertyName == type.MediaDataMember.PropertyName)
            {
                // special case for requesting the "media" value of an ATOM media link entry 
                relativeUri = Util.CreateUri(XmlConstants.UriValueSegment, UriKind.Relative);
                allowAnyType = true; // $value can be of any MIME type 
            } 
            else
            { 
                relativeUri = Util.CreateUri(propertyName + (null != property.CollectionType ? "()" : String.Empty), UriKind.Relative);
            }

            Uri requestUri = Util.CreateUri(box.GetResourceUri(this.baseUriWithSlash), relativeUri); 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, allowAnyType, null);
            DataServiceRequest dataServiceRequest = DataServiceRequest.GetInstance(property.PropertyType, requestUri); 
            return new LoadPropertyAsyncResult(entity, propertyName, this, request, callback, state, dataServiceRequest); 
        }
 
        /// <summary>
        /// write the content section of the atom payload
        /// </summary>
        /// <param name="writer">writer</param> 
        /// <param name="type">resource type</param>
        /// <param name="resource">resource value</param> 
        private void WriteContentProperties(XmlWriter writer, ClientType type, object resource) 
        {
            #region <d:property>value</property> 
            foreach (ClientType.ClientProperty property in type.Properties)
            {
                // don't write mime data member or the mime type member for it
                if (property == type.MediaDataMember || 
                    (type.MediaDataMember != null &&
                     type.MediaDataMember.MimeTypeProperty == property)) 
                { 
                    continue;
                } 

                object propertyValue = property.GetValue(resource);

                if (property.IsKnownType) 
                {
                    WriteContentProperty(writer, this.DataNamespace, property, propertyValue); 
                } 
#if ASTORIA_OPEN_OBJECT
                else if (property.OpenObjectProperty) 
                {
                    foreach (KeyValuePair<string, object> pair in (IDictionary<string, object>)propertyValue)
                    {
                        if ((null == pair.Value) || ClientConvert.IsKnownType(pair.Value.GetType())) 
                        {
                            WriteContentProperty(writer, pair.Key, pair.Value, false); 
                        } 
                    }
                } 
#endif
                else if (null == property.CollectionType)
                {
                    ClientType nested = ClientType.Create(property.PropertyType); 
                    if (!nested.HasKeys)
                    { 
                        #region complex type 
                        writer.WriteStartElement(property.PropertyName, this.DataNamespace);
                        string typeName = this.ResolveNameFromType(nested.ElementType); 
                        if (!String.IsNullOrEmpty(typeName))
                        {
                            writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.DataWebMetadataNamespace, typeName);
                        } 

                        this.WriteContentProperties(writer, nested, propertyValue); 
 
                        writer.WriteEndElement();
                        #endregion 
                    }
                }
            }
            #endregion 
        }
 
        /// <summary> 
        /// detach existing link
        /// </summary> 
        /// <param name="existing">link to detach</param>
        private void DetachExistingLink(RelatedEnd existing)
        {
            Debug.Assert(EntityStates.Detached != existing.State, "already detached"); 
            bool flag = this.bindings.Remove(existing);
            Debug.Assert(flag, "didn't detach existing link"); 
 
            existing.State = EntityStates.Detached;
            this.objectToResource[existing.SourceResource].RelatedLinkCount--; 
        }

        /// <summary>
        /// find and detach link for reference property 
        /// </summary>
        /// <param name="source">source entity</param> 
        /// <param name="sourceProperty">source entity property name for target entity</param> 
        /// <param name="target">target entity</param>
        /// <param name="linkMerge">link merge option</param> 
        /// <returns>true if found and not removed</returns>
        private RelatedEnd DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            RelatedEnd existing = this.GetLinks(source, sourceProperty).FirstOrDefault(); 
            if (null != existing)
            { 
                if ((target == existing.TargetResouce) || 
                    (MergeOption.AppendOnly == linkMerge) ||
                    (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State)) 
                {
                    return existing;
                }
 
                this.DetachExistingLink(existing);
                Debug.Assert(!this.bindings.Values.Any(o => (o.SourceResource == source) && (o.SourceProperty == sourceProperty)), "only expecting one"); 
            } 

            return null; 
        }

        /// <summary>
        /// verify the resource being tracked by context 
        /// </summary>
        /// <param name="resource">resource</param> 
        /// <param name="parameterName">parameter name to include in ArgumentException</param> 
        /// <returns>The given resource.</returns>
        /// <exception cref="ArgumentException">if resource is not contained</exception> 
        private ResourceBox EnsureContained(object resource, string parameterName)
        {
            Util.CheckArgumentNull(resource, parameterName);
 
            ResourceBox box = null;
            if (!this.objectToResource.TryGetValue(resource, out box)) 
            { 
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            } 

            return box;
        }
 
        /// <summary>
        /// verify the source and target are relatable 
        /// </summary> 
        /// <param name="source">source Resource</param>
        /// <param name="sourceProperty">source Property</param> 
        /// <param name="target">target Resource</param>
        /// <param name="state">destination state of relationship to evaluate for</param>
        /// <returns>true if DeletedState and one of the ends is in the added state</returns>
        /// <exception cref="ArgumentNullException">if source or target are null</exception> 
        /// <exception cref="ArgumentException">if source or target are not contained</exception>
        /// <exception cref="ArgumentNullException">if source property is null</exception> 
        /// <exception cref="ArgumentException">if source property empty</exception> 
        /// <exception cref="InvalidOperationException">Can only relate ends with keys.</exception>
        /// <exception cref="ArgumentException">If target doesn't match property type.</exception> 
        /// <exception cref="InvalidOperationException">If adding relationship where one of the ends is in the deleted state.</exception>
        /// <exception cref="InvalidOperationException">If attaching relationship where one of the ends is in the added or deleted state.</exception>
        private bool EnsureRelatable(object source, string sourceProperty, object target, EntityStates state)
        { 
            ResourceBox sourceResource = this.EnsureContained(source, "source");
            ResourceBox targetResource = null; 
            if ((null != target) || ((EntityStates.Modified != state) && (EntityStates.Unchanged != state))) 
            {
                targetResource = this.EnsureContained(target, "target"); 
            }

            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty");
 
            ClientType type = ClientType.Create(source.GetType());
            Debug.Assert(type.HasKeys, "should be enforced by just adding an object"); 
 
            // will throw InvalidOperationException if property doesn't exist
            ClientType.ClientProperty property = type.GetProperty(sourceProperty, false); 

            if (property.IsKnownType)
            {
                throw Error.InvalidOperation(Strings.Context_RelationNotRefOrCollection); 
            }
 
            if ((EntityStates.Unchanged == state) && (null == target) && (null != property.CollectionType)) 
            {
                targetResource = this.EnsureContained(target, "target"); 
            }

            if (((EntityStates.Added == state) || (EntityStates.Deleted == state)) && (null == property.CollectionType))
            { 
                throw Error.InvalidOperation(Strings.Context_AddLinkCollectionOnly);
            } 
            else if ((EntityStates.Modified == state) && (null != property.CollectionType)) 
            {
                throw Error.InvalidOperation(Strings.Context_SetLinkReferenceOnly); 
            }

            // if (property.IsCollection) then property.PropertyType is the collection elementType
            // either way you can only have a relation ship between keyed objects 
            type = ClientType.Create(property.CollectionType ?? property.PropertyType);
            Debug.Assert(type.HasKeys, "should be enforced by just adding an object"); 
 
            if ((null != target) && !type.ElementType.IsInstanceOfType(target))
            { 
                // target is not of the correct type
                throw Error.Argument(Strings.Context_RelationNotRefOrCollection, "target");
            }
 
            if ((EntityStates.Added == state) || (EntityStates.Unchanged == state))
            { 
                if ((sourceResource.State == EntityStates.Deleted) || 
                    ((targetResource != null) && (targetResource.State == EntityStates.Deleted)))
                { 
                    // can't add/attach new relationship when source or target in deleted state
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithDeleteEnd);
                }
            } 

            if ((EntityStates.Deleted == state) || (EntityStates.Unchanged == state)) 
            { 
                if ((sourceResource.State == EntityStates.Added) ||
                    ((targetResource != null) && (targetResource.State == EntityStates.Added))) 
                {
                    // can't have non-added relationship when source or target is in added state
                    if (EntityStates.Deleted == state)
                    { 
                        return true;
                    } 
 
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithInsertEnd);
                } 
            }

            return false;
        } 

        /// <summary>validate <paramref name="entitySetName"/> and trim leading and trailing forward slashes</summary> 
        /// <param name="entitySetName">resource name to validate</param> 
        /// <exception cref="ArgumentNullException">if entitySetName was null</exception>
        /// <exception cref="ArgumentException">if entitySetName was empty or contained only forward slash</exception> 
        private void ValidateEntitySetName(ref string entitySetName)
        {
            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName");
            entitySetName = entitySetName.Trim(Util.ForwardSlash); 

            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName"); 
 
            Uri tmp = Util.CreateUri(entitySetName, UriKind.RelativeOrAbsolute);
            if (tmp.IsAbsoluteUri || 
                !String.IsNullOrEmpty(Util.CreateUri(this.baseUriWithSlash, tmp)
                                     .GetComponents(UriComponents.Query | UriComponents.Fragment, UriFormat.SafeUnescaped)))
            {
                throw Error.Argument(Strings.Context_EntitySetName, "entitySetName"); 
            }
        } 
 
        /// <summary>create this.identityToResource when necessary</summary>
        private void EnsureIdentityToResource() 
        {
            if (null == this.identityToResource)
            {
                System.Threading.Interlocked.CompareExchange(ref this.identityToResource, new Dictionary<Uri, ResourceBox>(), null); 
            }
        } 
 
        /// <summary>
        /// increment the resource change for sorting during submit changes 
        /// </summary>
        /// <param name="box">the resource to update the change order</param>
        private void IncrementChange(RelatedEnd box)
        { 
            box.ChangeOrder = ++this.nextChange;
        } 
 
        /// <summary>
        /// increment the resource change for sorting during submit changes 
        /// </summary>
        /// <param name="box">the resource to update the change order</param>
        private void IncrementChange(ResourceBox box)
        { 
            box.ChangeOrder = ++this.nextChange;
        } 
 
        /// <summary>
        /// Entity and LinkDescriptor base class that contains change order and state 
        /// </summary>
        internal abstract class Entry
        {
            /// <summary>change order</summary> 
            private uint changeOrder = UInt32.MaxValue;
 
            /// <summary>was content generated for the entity</summary> 
            private bool saveContentGenerated;
 
            /// <summary>was this entity save result processed</summary>
            /// <remarks>0 - no processed, otherwise reflects the previous state</remarks>
            private EntityStates saveResultProcessed;
 
            /// <summary>state</summary>
            private EntityStates state; 
 
            /// <summary>last save exception per entry</summary>
            private Exception saveError; 

            /// <summary>changeOrder</summary>
            internal uint ChangeOrder
            { 
                get { return this.changeOrder; }
                set { this.changeOrder = value; } 
            } 

            /// <summary>true if resource, false if link</summary> 
            internal abstract bool IsResource
            {
                get;
            } 

            /// <summary>was content generated for the entity</summary> 
            internal bool ContentGeneratedForSave 
            {
                get { return this.saveContentGenerated; } 
                set { this.saveContentGenerated = value; }
            }

            /// <summary>was this entity save result processed</summary> 
            internal EntityStates SaveResultWasProcessed
            { 
                get { return this.saveResultProcessed; } 
                set { this.saveResultProcessed = value; }
            } 

            /// <summary>last save exception per entry</summary>
            internal Exception SaveError
            { 
                get { return this.saveError; }
                set { this.saveError = value; } 
            } 

            /// <summary>state</summary> 
            internal EntityStates State
            {
                get { return this.state; }
                set { this.state = value; } 
            }
        } 
 
        /// <summary>
        /// An untyped container for a resource and its identity 
        /// </summary>
        [DebuggerDisplay("State = {state}, Uri = {editLink}, Element = {resource.GetType().ToString()}")]
        internal class ResourceBox : Entry
        { 
            /// <summary>uri to identitfy the entity</summary>
            /// <remarks><atom:id>identity</id></remarks> 
            private Uri identity; 

            /// <summary>uri to edit the entity</summary> 
            /// <remarks><atom:link rel="edit" href="editLink" /></remarks>
            private Uri editLink;

            // /// <summary>uri to query the entity</summary> 
            // /// <remarks><atom:link rel="self" href="queryLink" /></remarks>
            // private Uri queryLink; 
 
            /// <summary>entity ETag (concurrency token)</summary>
            private string etag; 

            /// <summary>entity</summary>
            private object resource;
 
            /// <summary>count of links for which this entity is the source</summary>
            private int relatedLinkCount; 
 
            /// <summary>constructor</summary>
            /// <param name="identity">resource Uri</param> 
            /// <param name="editLink">resource EntitySet</param>
            /// <param name="resource">non-null resource</param>
            internal ResourceBox(Uri identity, Uri editLink, object resource)
            { 
                Debug.Assert(null == identity || identity.IsAbsoluteUri, "bad identity");
                Debug.Assert(null != editLink, "null editLink"); 
                this.identity = identity; 
                this.editLink = editLink;
                this.resource = resource; 
            }

            /// <summary>this is a entity</summary>
            internal override bool IsResource 
            {
                get { return true; } 
            } 

            /// <summary>uri to edit entity</summary> 
            internal Uri EditLink
            {
                get { return this.editLink; }
                set { this.editLink = value; } 
            }
 
            /// <summary>etag</summary> 
            internal string ETag
            { 
                get { return this.etag; }
                set { this.etag = value; }
            }
 
            /// <summary>entity uri identity</summary>
            internal Uri Identity 
            { 
                get { return this.identity; }
                set { this.identity = Util.CheckArgumentNull(value, "Identity"); } 
            }

            /// <summary>count of links for which this entity is the source</summary>
            internal int RelatedLinkCount 
            {
                get { return this.relatedLinkCount; } 
                set { this.relatedLinkCount = value; } 
            }
 
            /// <summary>entity</summary>
            internal object Resource
            {
                get { return this.resource; } 
            }
 
            /// <summary>uri to edit the entity</summary> 
            /// <param name="baseUriWithSlash">baseUriWithSlash</param>
            /// <returns>absolute uri which can be used to edit the entity</returns> 
            internal Uri GetResourceUri(Uri baseUriWithSlash)
            {
                Uri result = Util.CreateUri(baseUriWithSlash, this.EditLink);
                return result; 
            }
 
            /// <summary> 
            /// uri to edit the link entry
            /// </summary> 
            /// <param name="baseUriWithSlash">baseUriWithSlash</param>
            /// <returns>absolute uri which can be used to edit the link</returns>
            internal Uri GetResourceLinkUri(Uri baseUriWithSlash)
            { 
                Uri result = Util.CreateUri(baseUriWithSlash, new Uri(XmlConstants.UriLinkSegment, UriKind.Relative));
                result = Util.CreateUri(result, this.EditLink); 
                return result; 
            }
 
            /// <summary>is the entity the same as the source or target entity</summary>
            /// <param name="related">related end</param>
            /// <returns>true if same as source or target entity</returns>
            internal bool IsRelatedEntity(RelatedEnd related) 
            {
                return ((this.resource == related.SourceResource) || (this.resource == related.TargetResouce)); 
            } 
        }
 
        /// <summary>
        /// An untyped container for a resource and its related end
        /// </summary>
        [DebuggerDisplay("State = {state}")] 
        internal sealed class RelatedEnd : Entry
        { 
            /// <summary>IEqualityComparer to compare equivalence between to related ends</summary> 
            internal static readonly IEqualityComparer<RelatedEnd> EquivalenceComparer = new EqualityComparer();
 
            /// <summary>source entity</summary>
            private readonly object source;

            /// <summary>name of property on source entity that references the target entity</summary> 
            private readonly string sourceProperty;
 
            /// <summary>target entity</summary> 
            private readonly object target;
 
            // /// <summary>Property on the target resource that relates back to the source resource</summary>
            // internal readonly string ChildProperty;

            /// <summary>constructor</summary> 
            /// <param name="source">parentResource</param>
            /// <param name="property">sourceProperty</param> 
            /// <param name="target">childResource</param> 
            internal RelatedEnd(object source, string property, object target)
            { 
                Debug.Assert(null != source, "null source");
                Debug.Assert(!String.IsNullOrEmpty(property), "null target");

                this.source = source; 
                this.sourceProperty = property;
                this.target = target; 
            } 

            /// <summary>this is a link</summary> 
            internal override bool IsResource
            {
                get { return false; }
            } 

            /// <summary>target resource</summary> 
            internal object TargetResouce 
            {
                get { return this.target; } 
            }

            /// <summary>source resource property name</summary>
            internal string SourceProperty 
            {
                get { return this.sourceProperty; } 
            } 

            /// <summary>source resource</summary> 
            internal object SourceResource
            {
                get { return this.source; }
            } 

            /// <summary> 
            /// Are the two related ends equivalent? 
            /// </summary>
            /// <param name="x">x</param> 
            /// <param name="y">y</param>
            /// <returns>true if the related ends are equivalent</returns>
            public static bool Equals(RelatedEnd x, RelatedEnd y)
            { 
                return ((x.SourceResource == y.SourceResource) &&
                        (x.TargetResouce == y.TargetResouce) && 
                        (x.SourceProperty == y.SourceProperty)); 
            }
 
            /// <summary>test for equivalence</summary>
            private sealed class EqualityComparer : IEqualityComparer<RelatedEnd>
            {
                /// <summary>test for equivalence</summary> 
                /// <param name="x">x</param>
                /// <param name="y">y</param> 
                /// <returns>true if equivalent</returns> 
                bool IEqualityComparer<RelatedEnd>.Equals(RelatedEnd x, RelatedEnd y)
                { 
                    return RelatedEnd.Equals(x, y);
                }

                /// <summary>hash code based on the contained resources</summary> 
                /// <param name="x">x</param>
                /// <returns>hash code</returns> 
                int IEqualityComparer<RelatedEnd>.GetHashCode(RelatedEnd x) 
                {
                    return (x.SourceResource.GetHashCode() ^ 
                            ((null != x.TargetResouce) ? x.TargetResouce.GetHashCode() : 0) ^
                            x.SourceProperty.GetHashCode());
                }
            } 
        }
 
        /// <summary>wrapper around loading a property from a response</summary> 
        private class LoadPropertyAsyncResult : QueryAsyncResult
        { 
            /// <summary>entity whose property is being loaded</summary>
            private readonly object entity;

            /// <summary>name of the property on the entity that is being loaded</summary> 
            private readonly string propertyName;
 
            /// <summary>constructor</summary> 
            /// <param name="entity">entity</param>
            /// <param name="propertyName">name of collection or reference property to load</param> 
            /// <param name="context">Originating context</param>
            /// <param name="request">Originating WebRequest</param>
            /// <param name="callback">user callback</param>
            /// <param name="state">user state</param> 
            /// <param name="dataServiceRequest">request object.</param>
            internal LoadPropertyAsyncResult(object entity, string propertyName, DataServiceContext context, HttpWebRequest request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest) 
                : base(context, "LoadProperty", dataServiceRequest, request, callback, state) 
            {
                this.entity = entity; 
                this.propertyName = propertyName;
            }

            /// <summary> 
            /// loading a property from a response
            /// </summary> 
            /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
            internal QueryOperationResponse LoadProperty()
            { 
                IEnumerable results = null;

                DataServiceContext context = (DataServiceContext)this.Source;
 
                ClientType type = ClientType.Create(this.entity.GetType());
                Debug.Assert(type.HasKeys, "must have keys to be contained"); 
 
                ResourceBox box = context.EnsureContained(this.entity, "entity");
 
                if (EntityStates.Added == box.State)
                {
                    throw Error.InvalidOperation(Strings.Context_NoLoadWithInsertEnd);
                } 

                ClientType.ClientProperty property = type.GetProperty(this.propertyName, false); 
                Type elementType = property.CollectionType ?? property.NullablePropertyType; 
                try
                { 
                    if (type.MediaDataMember == property)
                    {
                        results = this.ReadPropertyFromRawData(property);
                    } 
                    else
                    { 
                        results = this.ReadPropertyFromAtom(box, property); 
                    }
 
                    return this.GetResponse(results, elementType);
                }
                catch (InvalidOperationException ex)
                { 
                    QueryOperationResponse response = this.GetResponse(results, elementType);
                    if (response != null) 
                    { 
                        response.Error = ex;
                        throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, response); 
                    }

                    throw;
                } 
            }
 
            /// <summary> 
            /// Load property data from an ATOM response
            /// </summary> 
            /// <param name="box">Box pointing to the entity to load this to</param>
            /// <param name="property">The property being loaded</param>
            /// <returns>property values as IEnumerable.</returns>
            private IEnumerable ReadPropertyFromAtom(ResourceBox box, ClientType.ClientProperty property) 
            {
                DataServiceContext context = (DataServiceContext)this.Source; 
 
                bool deletedState = (EntityStates.Deleted == box.State);
 
                Type nestedType;
#if ASTORIA_OPEN_OBJECT
                if (property.OpenObjectProperty)
                { 
                    nestedType = typeof(OpenObject);
                } 
                else 
#endif
                { 
                    nestedType = property.CollectionType ?? property.NullablePropertyType;
                }

                ClientType clientType = ClientType.Create(nestedType); 

                // when setting a reference, use the entity 
                // when adding an item to a collection, use the collection object referenced by the entity 
                bool setNestedValue = false;
                object collection = this.entity; 
                if (null != property.CollectionType)
                {   // get the collection that we actually add nested
                    collection = property.GetValue(this.entity);
                    if (null == collection) 
                    {
                        setNestedValue = true; 
                        collection = Activator.CreateInstance(typeof(List<>).MakeGenericType(nestedType)); 
                    }
                } 

                Func<DataServiceContext, XmlReader, Type, object> create = delegate(DataServiceContext ctx, XmlReader reader, Type elmentType)
                {
                    return new MaterializeAtom(ctx, reader, elmentType, ctx.MergeOption); 
                };
 
                // store the results so that they can be there in the response body. 
                Type elementType = property.CollectionType ?? property.NullablePropertyType;
                IList results = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)); 

                // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                using (MaterializeAtom materializer = context.GetMaterializer(this, nestedType, create))
                { 
                    if (null != materializer)
                    { 
                        int count = 0; 
#if ASTORIA_OPEN_OBJECT
                        object openProperties = null; 
#endif
                        foreach (object child in materializer)
                        {
                            results.Add(child); 
                            count++;
#if ASTORIA_OPEN_OBJECT 
                            property.SetValue(collection, child, this.propertyName, ref openProperties, true); 
#else
                            property.SetValue(collection, child, this.propertyName, true); 
#endif

                            // via LoadProperty, you can have a property with <id> and null value
                            if ((null != child) && (MergeOption.NoTracking != materializer.MergeOptionValue) && clientType.HasKeys) 
                            {
                                if (deletedState) 
                                { 
                                    context.DeleteLink(this.entity, this.propertyName, child);
                                } 
                                else
                                {   // put link into unchanged state
                                    context.AttachLink(this.entity, this.propertyName, child, materializer.MergeOptionValue);
                                } 
                            }
                        } 
                    } 

                    // we don't do this because we are loading, not refreshing 
                    // if ((0 == count) && (MergeOption.OverwriteChanges == this.mergeOption))
                    // { property.Clear(entity); }
                }
 
                if (setNestedValue)
                { 
#if ASTORIA_OPEN_OBJECT 
                    object openProperties = null;
                    property.SetValue(this.entity, collection, this.propertyName, ref openProperties, false); 
#else
                    property.SetValue(this.entity, collection, this.propertyName, false);
#endif
                } 

                return results; 
            } 

            /// <summary> 
            /// Load property data form a raw response
            /// </summary>
            /// <param name="property">The property being loaded</param>
            /// <returns>property values as IEnumerable.</returns> 
            private IEnumerable ReadPropertyFromRawData(ClientType.ClientProperty property)
            { 
                // if this is the data property for a media entry, what comes back 
                // is the raw value (no markup)
#if ASTORIA_OPEN_OBJECT 
                object openProps = null;
#endif
                string mimeType = null;
                Encoding encoding = null; 
                Type elementType = property.CollectionType ?? property.NullablePropertyType;
                IList results = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)); 
                HttpProcessUtility.ReadContentType(this.ContentType, out mimeType, out encoding); 

                using (Stream responseStream = this.GetResponseStream()) 
                {
                    // special case byte[], and for everything else let std conversion kick-in
                    if (property.PropertyType == typeof(byte[]))
                    { 
                        int total = checked((int)this.ContentLength);
                        byte[] buffer = new byte[total]; 
                        int read = 0; 
                        while (read < total)
                        { 
                            int r = responseStream.Read(buffer, read, total - read);
                            if (r <= 0)
                            {
                                throw Error.InvalidOperation(Strings.Context_UnexpectedZeroRawRead); 
                            }
 
                            read += r; 
                        }
 
                        results.Add(buffer);

#if ASTORIA_OPEN_OBJECT
                        property.SetValue(this.entity, buffer, this.propertyName, ref openProps, false); 
#else
                        property.SetValue(this.entity, buffer, this.propertyName, false); 
#endif 
                    }
                    else 
                    {
                        StreamReader reader = new StreamReader(responseStream, encoding);
                        object convertedValue = property.PropertyType == typeof(string) ?
                                                    reader.ReadToEnd() : 
                                                    ClientConvert.ChangeType(reader.ReadToEnd(), property.PropertyType);
                        results.Add(convertedValue); 
#if ASTORIA_OPEN_OBJECT 
                        property.SetValue(this.entity, convertedValue, this.propertyName, ref openProps, false);
#else 
                        property.SetValue(this.entity, convertedValue, this.propertyName, false);
#endif
                    }
                } 

#if ASTORIA_OPEN_OBJECT 
                Debug.Assert(openProps == null, "These should not be set in this path"); 
#endif
                if (property.MimeTypeProperty != null) 
                {
                    // an implication of this 3rd-arg-null is that mime type properties cannot be open props
#if ASTORIA_OPEN_OBJECT
                    property.MimeTypeProperty.SetValue(this.entity, mimeType, null, ref openProps, false); 
                    Debug.Assert(openProps == null, "These should not be set in this path");
#else 
                    property.MimeTypeProperty.SetValue(this.entity, mimeType, null, false); 
#endif
                } 

                return results;
            }
        } 

        /// <summary> 
        /// implementation of IAsyncResult for SaveChanges 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Pending")] 
        private class SaveAsyncResult : BaseAsyncResult
        {
            /// <summary>where to pull the changes from</summary>
            private readonly DataServiceContext Context; 

            /// <summary>sorted list of entries by change order</summary> 
            private readonly List<Entry> ChangedEntries; 

            /// <summary>array of queries being executed</summary> 
            private readonly DataServiceRequest[] Queries;

            /// <summary>operations</summary>
            private readonly List<OperationResponse> Responses; 

            /// <summary>boundary used when generating batch boundary</summary> 
            private readonly string batchBoundary; 

            /// <summary>option in use for SaveChanges</summary> 
            private readonly SaveChangesOptions options;

            /// <summary>if true then async, else [....]</summary>
            private readonly bool executeAsync; 

            /// <summary>debugging trick to track number of completed requests</summary> 
            private int changesCompleted; 

            /// <summary>wrapped request</summary> 
            private PerRequest request;

            /// <summary>batch web response</summary>
            private HttpWebResponse batchResponse; 

            /// <summary>response stream for the batch</summary> 
            private Stream httpWebResponseStream; 

            /// <summary>service response</summary> 
            private DataServiceResponse service;

            /// <summary>The ResourceBox or RelatedEnd currently in flight</summary>
            private int entryIndex = -1; 

            /// <summary> 
            /// True if the current in-flight request is a media link entry POST 
            /// that needs to be followed by a PUT for the rest of the properties
            /// </summary> 
            private bool procesingMediaLinkEntry;

            /// <summary>response stream</summary>
            private BatchStream responseBatchStream; 

            /// <summary>temporary buffer when cache results from CUD op in non-batching save changes</summary> 
            private byte[] buildBatchBuffer; 

            /// <summary>temporary writer when cache results from CUD op in non-batching save changes</summary> 
            private StreamWriter buildBatchWriter;

            /// <summary>count of data actually copied</summary>
            private long copiedContentLength; 

            /// <summary>what is the changset boundary</summary> 
            private string changesetBoundary; 

            /// <summary>is a change set being cached</summary> 
            private bool changesetStarted;

            #region constructors
            /// <summary> 
            /// constructor for async operations
            /// </summary> 
            /// <param name="context">context</param> 
            /// <param name="method">method</param>
            /// <param name="queries">queries</param> 
            /// <param name="options">options</param>
            /// <param name="callback">user callback</param>
            /// <param name="state">user state object</param>
            /// <param name="async">async or [....]</param> 
            internal SaveAsyncResult(DataServiceContext context, string method, DataServiceRequest[] queries, SaveChangesOptions options, AsyncCallback callback, object state, bool async)
                : base(context, method, callback, state) 
            { 
                this.executeAsync = async;
                this.Context = context; 
                this.Queries = queries;
                this.options = options;

                this.Responses = new List<OperationResponse>(); 

                if (null == queries) 
                { 
                    #region changed entries
                    this.ChangedEntries = context.objectToResource.Values.Cast<Entry>() 
                                          .Union(context.bindings.Values.Cast<Entry>())
                                          .Where(HasModifiedResourceState)
                                          .OrderBy(o => o.ChangeOrder)
                                          .ToList(); 

                    foreach (Entry e in this.ChangedEntries) 
                    { 
                        e.ContentGeneratedForSave = false;
                        e.SaveResultWasProcessed = 0; 
                        e.SaveError = null;

                        if (!e.IsResource)
                        { 
                            object target = ((RelatedEnd)e).TargetResouce;
                            if (null != target) 
                            { 
                                Entry f = context.objectToResource[target];
                                if (EntityStates.Unchanged == f.State) 
                                {
                                    f.ContentGeneratedForSave = false;
                                    f.SaveResultWasProcessed = 0;
                                    f.SaveError = null; 
                                }
                            } 
                        } 
                    }
                    #endregion 
                }
                else
                {
                    this.ChangedEntries = new List<Entry>(); 
                }
 
                if (IsFlagSet(options, SaveChangesOptions.Batch)) 
                {
                    this.batchBoundary = XmlConstants.HttpMultipartBoundaryBatch + "_" + Guid.NewGuid().ToString(); 
                }
                else
                {
                    this.batchBoundary = XmlConstants.HttpMultipartBoundaryBatchResponse + "_" + Guid.NewGuid().ToString(); 
                    this.DataServiceResponse = new DataServiceResponse(null, -1, this.Responses, false /*batchResponse*/);
                } 
            } 
            #endregion constructor
 
            #region end

            /// <summary>generate the batch request of all changes to save</summary>
            internal DataServiceResponse DataServiceResponse 
            {
                get 
                { 
                    Debug.Assert(null != this.service, "null service");
                    return this.service; 
                }

                set
                { 
                    this.service = value;
                } 
            } 

            /// <summary>process the batch</summary> 
            /// <returns>data service response</returns>
            internal DataServiceResponse EndRequest()
            {
                if ((null != this.responseBatchStream) || (null != this.httpWebResponseStream)) 
                {
                    this.HandleBatchResponse(); 
                } 

                return this.DataServiceResponse; 
            }

            #endregion
 
            #region start a batch
 
            /// <summary>initial the async batch save changeset</summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BatchBeginRequest(bool replaceOnUpdate) 
            {
                PerRequest pereq = null;
                try
                { 
                    MemoryStream memory = this.GenerateBatchRequest(replaceOnUpdate);
                    if (null != memory) 
                    { 
                        HttpWebRequest httpWebRequest = this.CreateBatchRequest(memory);
 
                        this.request = pereq = new PerRequest();
                        pereq.Request = httpWebRequest;
                        pereq.RequestStreamContent = memory;
 
                        this.httpWebResponseStream = new MemoryStream();
 
                        int step = ++pereq.RequestStep; 

                        IAsyncResult asyncResult = httpWebRequest.BeginGetRequestStream(this.AsyncEndGetRequestStream, pereq); 

                        bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep);
                        pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously;
                    } 
                    else
                    { 
                        Debug.Assert(this.CompletedSynchronously, "completedSynchronously"); 
                        Debug.Assert(this.IsCompleted, "completed");
                    } 
                }
                catch (Exception e)
                {
                    this.HandleFailure(pereq, e); 
                    throw; // to user on BeginSaveChangeSet, will still invoke Callback
                } 
                finally 
                {
                    this.HandleCompleted(pereq); // will invoke user callback 
                }

                Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "[....] without complete");
            } 

#if !ASTORIA_LIGHT // Synchronous methods not available 
            /// <summary> 
            /// Synchronous batch request
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BatchRequest(bool replaceOnUpdate)
            {
                MemoryStream memory = this.GenerateBatchRequest(replaceOnUpdate); 
                if ((null != memory) && (0 < memory.Length))
                { 
                    HttpWebRequest httpWebRequest = this.CreateBatchRequest(memory); 
                    using (System.IO.Stream requestStream = httpWebRequest.GetRequestStream())
                    { 
                        byte[] buffer = memory.GetBuffer();
                        int bufferOffset = checked((int)memory.Position);
                        int bufferLength = checked((int)memory.Length) - bufferOffset;
 
                        // the following is useful in the debugging Immediate Window
                        // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength); 
                        requestStream.Write(buffer, bufferOffset, bufferLength); 
                    }
 
                    HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                    this.batchResponse = httpWebResponse;

                    if (null != httpWebResponse) 
                    {
                        this.httpWebResponseStream = httpWebResponse.GetResponseStream(); 
                    } 
                }
            } 
#endif
            #endregion

            #region start a non-batch requests 
            /// <summary>
            /// This starts the next change 
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BeginNextChange(bool replaceOnUpdate) 
            {
                Debug.Assert(!this.IsCompleted, "why being called if already completed?");

                // SaveCallback can't chain synchronously completed responses, caller will loop the to next change 
                PerRequest pereq = null;
                do 
                { 
                    HttpWebRequest httpWebRequest = null;
                    HttpWebResponse response = null; 
                    try
                    {
                        if (null != this.request)
                        { 
                            this.IsCompleted = true;
                            Error.ThrowInternalError(InternalError.InvalidBeginNextChange); 
                        } 

                        httpWebRequest = this.CreateNextRequest(replaceOnUpdate); 
                        if ((null != httpWebRequest) || (this.entryIndex < this.ChangedEntries.Count))
                        {
                            if (this.ChangedEntries[this.entryIndex].ContentGeneratedForSave)
                            { 
                                Debug.Assert(this.ChangedEntries[this.entryIndex] is RelatedEnd, "only expected RelatedEnd to presave");
                                Debug.Assert( 
                                    this.ChangedEntries[this.entryIndex].State == EntityStates.Added || 
                                    this.ChangedEntries[this.entryIndex].State == EntityStates.Modified,
                                    "only expected added to presave"); 
                                continue;
                            }

                            MemoryStream memoryStream = null; 
                            if (this.executeAsync)
                            { 
                                #region async 
                                this.request = pereq = new PerRequest();
                                pereq.Request = httpWebRequest; 

                                IAsyncResult asyncResult;
                                int step = ++pereq.RequestStep;
                                if (this.procesingMediaLinkEntry || (null == (memoryStream = this.CreateChangeData(this.entryIndex, false)))) 
                                {
                                    asyncResult = httpWebRequest.BeginGetResponse(this.AsyncEndGetResponse, pereq); 
                                } 
                                else
                                { 
                                    httpWebRequest.ContentLength = memoryStream.Length - memoryStream.Position;
                                    pereq.RequestStreamContent = memoryStream;
                                    asyncResult = httpWebRequest.BeginGetRequestStream(this.AsyncEndGetRequestStream, pereq);
                                } 

                                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                                pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; 
                                this.CompletedSynchronously &= reallyCompletedSynchronously;
                                #endregion 
                            }
#if !ASTORIA_LIGHT // Synchronous methods not available
                            else
                            { 
                                #region [....]
                                memoryStream = this.CreateChangeData(this.entryIndex, false); 
                                if (null != memoryStream) 
                                {
                                    byte[] buffer = memoryStream.GetBuffer(); 
                                    int bufferOffset = checked((int)memoryStream.Position);
                                    int bufferLength = checked((int)memoryStream.Length) - bufferOffset;

                                    httpWebRequest.ContentLength = bufferLength; 
                                    using (Stream stream = httpWebRequest.GetRequestStream())
                                    { 
                                        // the following is useful in the debugging Immediate Window 
                                        // string x = System.Text.Encoding.UTF8.GetString(memoryStream.GetBuffer(), bufferOffset, (int)memoryStream.Length);
                                        stream.Write(buffer, bufferOffset, bufferLength); 
                                    }
                                }

                                response = (HttpWebResponse)httpWebRequest.GetResponse(); 
                                if (!this.procesingMediaLinkEntry)
                                { 
                                    this.changesCompleted++; 
                                }
 
                                this.HandleOperationResponse(httpWebRequest, response);
                                this.HandleOperationResponseData(response);
                                this.HandleOperationEnd();
                                this.request = null; 
                                #endregion
                            } 
#endif 
                        }
                        else 
                        {
                            this.IsCompleted = true;

                            if (this.CompletedSynchronously) 
                            {
                                this.HandleCompleted(pereq); 
                            } 
                        }
                    } 
                    catch (InvalidOperationException e)
                    {
                        WebUtil.GetHttpWebResponse(e, ref response);
                        this.HandleOperationException(e, httpWebRequest, response); 
                        this.HandleCompleted(pereq);
                    } 
                    finally 
                    {
                        if (null != response) 
                        {
                            response.Close();
                        }
                    } 

                    // either everything completed synchronously until a change is saved and its state changed 
                    // and we don't return to this loop until then or something was asynchronous 
                    // and we won't continue in this loop, instead letting the inner most loop start the next request
                } 
                while (((null == pereq) || (pereq.RequestCompleted && pereq.RequestCompletedSynchronously)) && !this.IsCompleted);

                Debug.Assert(this.executeAsync || this.CompletedSynchronously, "[....] !CompletedSynchronously");
                Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "[....] without complete"); 
                Debug.Assert(this.entryIndex < this.ChangedEntries.Count || this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links");
            } 
 
            /// <summary>cleanup work to do once the batch / savechanges is complete</summary>
            protected override void CompletedRequest() 
            {
                this.buildBatchBuffer = null;
                if (null != this.buildBatchWriter)
                { 
                    Debug.Assert(!IsFlagSet(this.options, SaveChangesOptions.Batch), "should be non-batch");
                    this.HandleOperationEnd(); 
                    this.buildBatchWriter.WriteLine("--{0}--", this.batchBoundary); 

                    this.buildBatchWriter.Flush(); 
                    Debug.Assert(Object.ReferenceEquals(this.httpWebResponseStream, this.buildBatchWriter.BaseStream), "expected different stream");
                    this.httpWebResponseStream.Position = 0;

                    this.buildBatchWriter = null; 

                    // the following is useful in the debugging Immediate Window 
                    // string x = System.Text.Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); 
                    this.responseBatchStream = new BatchStream(this.httpWebResponseStream, this.batchBoundary, HttpProcessUtility.EncodingUtf8NoPreamble, false);
                } 
            }

            /// <summary>build the *Descriptor object in the ChangeList</summary>
            /// <param name="entry">entry to build from</param> 
            /// <returns>EntityDescriptor or LinkDescriptor</returns>
            private static Descriptor BuildReturn(Entry entry) 
            { 
                if (entry.IsResource)
                { 
                    ResourceBox box = (ResourceBox)entry;
                    EntityDescriptor obj = new EntityDescriptor(box.Resource, box.ETag, box.State);
                    return obj;
                } 
                else
                { 
                    RelatedEnd end = (RelatedEnd)entry; 
                    LinkDescriptor obj = new LinkDescriptor(end.SourceResource, end.SourceProperty, end.TargetResouce, end.State);
                    return obj; 
                }
            }

            /// <summary>verify non-null and not completed</summary> 
            /// <param name="value">the request in progress</param>
            /// <param name="errorcode">error code if null or completed</param> 
            /// <returns>the next step to validate CompletedSyncronously</returns> 
            private static int CompleteCheck(PerRequest value, InternalError errorcode)
            { 
                if ((null == value) || value.RequestCompleted)
                {
                    Error.ThrowInternalError(errorcode);
                } 

                return ++value.RequestStep; 
            } 

            /// <summary>verify they have the same reference</summary> 
            /// <param name="actual">the actual thing</param>
            /// <param name="expected">the expected thing</param>
            /// <param name="errorcode">error code if they are not</param>
            private static void EqualRefCheck(PerRequest actual, PerRequest expected, InternalError errorcode) 
            {
                if (!Object.ReferenceEquals(actual, expected)) 
                { 
                    Error.ThrowInternalError(errorcode);
                } 
            }

            /// <summary>Set the AsyncWait and invoke the user callback.</summary>
            /// <param name="pereq">the request object</param> 
            private void HandleCompleted(PerRequest pereq)
            { 
                if (null != pereq) 
                {
                    this.CompletedSynchronously &= pereq.RequestCompletedSynchronously; 

                    if (pereq.RequestCompleted)
                    {
                        System.Threading.Interlocked.CompareExchange(ref this.request, null, pereq); 
                        if (IsFlagSet(this.options, SaveChangesOptions.Batch))
                        {   // all competing thread must complete this before user calback is invoked 
                            System.Threading.Interlocked.CompareExchange(ref this.batchResponse, pereq.HttpWebResponse, null); 
                            pereq.HttpWebResponse = null;
                        } 

                        pereq.Dispose();
                    }
                } 

                this.HandleCompleted(); 
            } 

            /// <summary>Cache the exception that happened on the background thread for the caller of EndSaveChanges.</summary> 
            /// <param name="pereq">the request object</param>
            /// <param name="e">exception object from background thread</param>
            /// <returns>true if the exception should be rethrown</returns>
            private bool HandleFailure(PerRequest pereq, Exception e) 
            {
                if (null != pereq) 
                { 
                    pereq.RequestCompleted = true;
                } 

                return this.HandleFailure(e);
            }
 
            /// <summary>
            /// Create HttpWebRequest from the next availabe resource 
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            /// <returns>web request</returns> 
            private HttpWebRequest CreateNextRequest(bool replaceOnUpdate)
            {
                if (!this.procesingMediaLinkEntry)
                { 
                    this.entryIndex++;
                } 
                else 
                {
                    // if we were creating a media entry before, then the "next change" 
                    // is to do the second step of the creation, a PUT to update
                    // metadata
                    this.procesingMediaLinkEntry = false;
                } 

                if (unchecked((uint)this.entryIndex < (uint)this.ChangedEntries.Count)) 
                { 
                    Entry entry = this.ChangedEntries[this.entryIndex];
                    if (entry.IsResource) 
                    {
                        ResourceBox box = (ResourceBox)entry;

                        HttpWebRequest req; 
                        if ((EntityStates.Added == entry.State) && (null != (req = this.Context.CheckAndProcessMediaEntry(box))))
                        { 
                            this.procesingMediaLinkEntry = true; 
                        }
                        else 
                        {
                            Debug.Assert(!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified");
                            req = this.Context.CreateRequest(box, entry.State, replaceOnUpdate);
                        } 

                        return req; 
                    } 

                    return this.Context.CreateRequest((RelatedEnd)entry); 
                }

                return null;
            } 

            /// <summary> 
            /// create memory stream for entry (entity or link) 
            /// </summary>
            /// <param name="index">index into changed entries</param> 
            /// <param name="newline">include newline in output</param>
            /// <returns>memory stream of data for entry</returns>
            private MemoryStream CreateChangeData(int index, bool newline)
            { 
                Entry entry = this.ChangedEntries[index];
                Debug.Assert(!entry.ContentGeneratedForSave, "already saved entity/link"); 
                entry.ContentGeneratedForSave = true; 

                if (entry.IsResource) 
                {
                    ResourceBox box = (ResourceBox)entry;
                    if (!this.procesingMediaLinkEntry)
                    { 
                        Debug.Assert(!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified");
                        return this.Context.CreateRequestData(box, newline); 
                    } 
                }
                else 
                {
                    RelatedEnd link = (RelatedEnd)entry;
                    if ((EntityStates.Added == link.State) ||
                        ((EntityStates.Modified == link.State) && (null != link.TargetResouce))) 
                    {
                        return this.Context.CreateRequestData(link, newline); 
                    } 
                }
 
                return null;
            }
            #endregion
 
            #region generate batch response from non-batch
 
            /// <summary>basic separator between response</summary> 
            private void HandleOperationStart()
            { 
                this.HandleOperationEnd();

                if (null == this.httpWebResponseStream)
                { 
                    this.httpWebResponseStream = new MemoryStream();
                } 
 
                if (null == this.buildBatchWriter)
                { 
                    this.buildBatchWriter = new StreamWriter(this.httpWebResponseStream);     // defaults to UTF8 w/o preamble
                }

                if (null == this.changesetBoundary) 
                {
                    this.changesetBoundary = XmlConstants.HttpMultipartBoundaryChangesetResponse + "_" + Guid.NewGuid().ToString(); 
                } 

                this.changesetStarted = true; 
                this.buildBatchWriter.WriteLine("--{0}", this.batchBoundary);
                this.buildBatchWriter.WriteLine("{0}: {1}; boundary={2}", XmlConstants.HttpContentType, XmlConstants.MimeMultiPartMixed, this.changesetBoundary);
                this.buildBatchWriter.WriteLine();
                this.buildBatchWriter.WriteLine("--{0}", this.changesetBoundary); 
            }
 
            /// <summary>write the trailing --changesetboundary--</summary> 
            private void HandleOperationEnd()
            { 
                if (this.changesetStarted)
                {
                    Debug.Assert(null != this.buildBatchWriter, "buildBatchWriter");
                    Debug.Assert(null != this.changesetBoundary, "changesetBoundary"); 
                    this.buildBatchWriter.WriteLine();
                    this.buildBatchWriter.WriteLine("--{0}--", this.changesetBoundary); 
                    this.changesetStarted = false; 
                }
            } 

            /// <summary>operation with exception</summary>
            /// <param name="e">exception object</param>
            /// <param name="httpWebRequest">request object</param> 
            /// <param name="response">response object</param>
            private void HandleOperationException(Exception e, HttpWebRequest httpWebRequest, HttpWebResponse response) 
            { 
                if (null != response)
                { 
                    this.HandleOperationResponse(httpWebRequest, response);
                    this.HandleOperationResponseData(response);
                    this.HandleOperationEnd();
                } 
                else
                { 
                    this.HandleOperationStart(); 
                    WriteOperationResponseHeaders(this.buildBatchWriter, 500);
                    this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeTextPlain); 
                    this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentID, this.ChangedEntries[this.entryIndex].ChangeOrder);
                    this.buildBatchWriter.WriteLine();
                    this.buildBatchWriter.WriteLine(e.ToString());
                    this.HandleOperationEnd(); 
                }
 
                this.request = null; 
                if (!IsFlagSet(this.options, SaveChangesOptions.ContinueOnError))
                { 
                    this.IsCompleted = true;

                    // if it was a media link entry don't even try to do a PUT if the POST didn't succeed
                    this.procesingMediaLinkEntry = false; 
                }
            } 
 
            /// <summary>operation with HttpWebResponse</summary>
            /// <param name="httpWebRequest">request object</param> 
            /// <param name="response">response object</param>
            private void HandleOperationResponse(HttpWebRequest httpWebRequest, HttpWebResponse response)
            {
                this.HandleOperationStart(); 
                string location = null;
 
                if (this.ChangedEntries[this.entryIndex].IsResource && 
                    this.ChangedEntries[this.entryIndex].State == EntityStates.Added)
                { 
                    location = response.Headers[XmlConstants.HttpResponseLocation];

                    if (WebUtil.SuccessStatusCode(response.StatusCode))
                    { 
                        if (null != location)
                        { 
                            this.Context.AttachLocation(((ResourceBox)this.ChangedEntries[this.entryIndex]).Resource, location); 
                        }
                        else 
                        {
                            throw Error.NotSupported(Strings.Deserialize_NoLocationHeader);
                        }
                    } 
                }
 
                if ((null == location) && (null != httpWebRequest)) 
                {
                    location = httpWebRequest.RequestUri.OriginalString; 
                }

                WriteOperationResponseHeaders(this.buildBatchWriter, (int)response.StatusCode);
                foreach (string name in response.Headers.AllKeys) 
                {
                    if (XmlConstants.HttpContentLength != name) 
                    { 
                        this.buildBatchWriter.WriteLine("{0}: {1}", name, response.Headers[name]);
                    } 
                }

                this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentID, this.ChangedEntries[this.entryIndex].ChangeOrder);
                this.buildBatchWriter.WriteLine(); 
            }
 
            /// <summary> 
            /// copy the response data
            /// </summary> 
            /// <param name="response">response object</param>
            private void HandleOperationResponseData(HttpWebResponse response)
            {
                using (Stream stream = response.GetResponseStream()) 
                {
                    if (null != stream) 
                    { 
                        this.buildBatchWriter.Flush();
                        if (0 == WebUtil.CopyStream(stream, this.buildBatchWriter.BaseStream, ref this.buildBatchBuffer)) 
                        {
                            this.HandleOperationResponseNoData();
                        }
                    } 
                }
            } 
 
            /// <summary>only call when no data was written to added "Content-Length: 0"</summary>
            private void HandleOperationResponseNoData() 
            {
#if DEBUG
                MemoryStream memory = this.buildBatchWriter.BaseStream as MemoryStream;
                Debug.Assert(null != memory, "expected MemoryStream"); 
                Debug.Assert(
                    (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' && 
                    (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n', 
                    "didn't end with newline");
#endif 
                this.buildBatchWriter.BaseStream.Position -= 2;
                this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentLength, 0);
                this.buildBatchWriter.WriteLine();
            } 

            #endregion 
 
            /// <summary>
            /// create the web request for a batch 
            /// </summary>
            /// <param name="memory">memory stream for length</param>
            /// <returns>httpweb request</returns>
            private HttpWebRequest CreateBatchRequest(MemoryStream memory) 
            {
                Uri requestUri = Util.CreateUri(this.Context.baseUriWithSlash, Util.CreateUri("$batch", UriKind.Relative)); 
                string contentType = XmlConstants.MimeMultiPartMixed + "; " + XmlConstants.HttpMultipartBoundary + "=" + this.batchBoundary; 
                HttpWebRequest httpWebRequest = this.Context.CreateRequest(requestUri, XmlConstants.HttpMethodPost, false, contentType);
                httpWebRequest.ContentLength = memory.Length - memory.Position; 
                return httpWebRequest;
            }

            /// <summary>generate the batch request of all changes to save</summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            /// <returns>buffer containing data for request stream</returns> 
            private MemoryStream GenerateBatchRequest(bool replaceOnUpdate) 
            {
                this.changesetBoundary = null; 
                if (null != this.Queries)
                {
                }
                else if (0 == this.ChangedEntries.Count) 
                {
                    this.DataServiceResponse = new DataServiceResponse(null, (int)WebExceptionStatus.Success, this.Responses, true /*batchResponse*/); 
                    this.IsCompleted = true; 
                    return null;
                } 
                else
                {
                    this.changesetBoundary = XmlConstants.HttpMultipartBoundaryChangeSet + "_" + Guid.NewGuid().ToString();
                } 

                MemoryStream memory = new MemoryStream(); 
                StreamWriter text = new StreamWriter(memory);     // defaults to UTF8 w/o preamble 

                if (null != this.Queries) 
                {
                    for (int i = 0; i < this.Queries.Length; ++i)
                    {
                        Uri requestUri = Util.CreateUri(this.Context.baseUriWithSlash, this.Queries[i].RequestUri); 

                        Debug.Assert(null != requestUri, "request uri is null"); 
                        Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
                        Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.Context.baseUriWithSlash, requestUri), "context is not base of request uri");
 
                        text.WriteLine("--{0}", this.batchBoundary);
                        WriteOperationRequestHeaders(text, XmlConstants.HttpMethodGet, requestUri.AbsoluteUri);
                        text.WriteLine();
                    } 
                }
                else if (0 < this.ChangedEntries.Count) 
                { 
                    text.WriteLine("--{0}", this.batchBoundary);
                    text.WriteLine("{0}: {1}; boundary={2}", XmlConstants.HttpContentType, XmlConstants.MimeMultiPartMixed, this.changesetBoundary); 
                    text.WriteLine();

                    for (int i = 0; i < this.ChangedEntries.Count; ++i)
                    { 
                        #region validate changeset boundary starts on newline
#if DEBUG 
                        { 
                            text.Flush();
                            Debug.Assert( 
                                (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' &&
                                (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n',
                                "boundary didn't start with newline");
                        } 
#endif
                        #endregion 
 
                        Entry entry = this.ChangedEntries[i];
                        if (entry.ContentGeneratedForSave) 
                        {
                            continue;
                        }
 
                        text.WriteLine("--{0}", this.changesetBoundary);
 
                        MemoryStream stream = this.CreateChangeData(i, true); 
                        if (entry.IsResource)
                        { 
                            ResourceBox box = (ResourceBox)entry;

                            // media link entry creation is not supported in batch mode
                            if (box.State == EntityStates.Added && 
                                ClientType.Create(box.Resource.GetType()).MediaDataMember != null)
                            { 
                                throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink); 
                            }
 
                            this.Context.CreateRequestBatch(box, text, replaceOnUpdate);
                        }
                        else
                        { 
                            this.Context.CreateRequestBatch((RelatedEnd)entry, text);
                        } 
 
                        byte[] buffer = null;
                        int bufferOffset = 0, bufferLength = 0; 
                        if (null != stream)
                        {
                            buffer = stream.GetBuffer();
                            bufferOffset = checked((int)stream.Position); 
                            bufferLength = checked((int)stream.Length) - bufferOffset;
                        } 
 
                        if (0 < bufferLength)
                        { 
                            text.WriteLine("{0}: {1}", XmlConstants.HttpContentLength, bufferLength);
                        }

                        text.WriteLine(); // NewLine separates header from message 

                        if (0 < bufferLength) 
                        { 
                            text.Flush();
                            text.BaseStream.Write(buffer, bufferOffset, bufferLength); 
                        }
                    }

                    #region validate changeset boundary ended with newline 
#if DEBUG
                    { 
                        text.Flush(); 
                        Debug.Assert(
                            (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' && 
                            (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n',
                            "post CreateRequest boundary didn't start with newline");
                    }
 
#endif
                    #endregion 
 
                    // The boundary delimiter line following the last body part
                    // has two more hyphens after the boundary parameter value. 
                    text.WriteLine("--{0}--", this.changesetBoundary);
                }

                text.WriteLine("--{0}--", this.batchBoundary); 

                text.Flush(); 
                Debug.Assert(Object.ReferenceEquals(text.BaseStream, memory), "should be same"); 
                Debug.Assert(this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links");
 
                #region Validate batch format
#if DEBUG
                int testGetCount = 0;
                int testOpCount = 0; 
                int testBeginSetCount = 0;
                int testEndSetCount = 0; 
                memory.Position = 0; 
                BatchStream testBatch = new BatchStream(memory, this.batchBoundary, HttpProcessUtility.EncodingUtf8NoPreamble, true);
                while (testBatch.MoveNext()) 
                {
                    switch (testBatch.State)
                    {
                        case BatchStreamState.StartBatch: 
                        case BatchStreamState.EndBatch:
                        default: 
                            Debug.Assert(false, "shouldn't happen"); 
                            break;
 
                        case BatchStreamState.Get:
                            testGetCount++;
                            break;
 
                        case BatchStreamState.BeginChangeSet:
                            testBeginSetCount++; 
                            break; 
                        case BatchStreamState.EndChangeSet:
                            testEndSetCount++; 
                            break;
                        case BatchStreamState.Post:
                        case BatchStreamState.Put:
                        case BatchStreamState.Delete: 
                        case BatchStreamState.Merge:
                            testOpCount++; 
                            break; 
                    }
                } 

                Debug.Assert((null == this.Queries && 1 == testBeginSetCount) || (0 == testBeginSetCount), "more than one BeginChangeSet");
                Debug.Assert(testBeginSetCount == testEndSetCount, "more than one EndChangeSet");
                Debug.Assert((null == this.Queries && testGetCount == 0) || this.Queries.Length == testGetCount, "too many get count"); 
                // Debug.Assert(this.ChangedEntries.Count == testOpCount, "too many op count");
                Debug.Assert(BatchStreamState.EndBatch == testBatch.State, "should have ended propertly"); 
#endif 
                #endregion
 
                this.changesetBoundary = null;

                memory.Position = 0;
                return memory; 
            }
 
            #region handle batch response 

            /// <summary> 
            /// process the batch changeset response
            /// </summary>
            private void HandleBatchResponse()
            { 
                string boundary = this.batchBoundary;
                Encoding encoding = Encoding.UTF8; 
                Dictionary<string, string> headers = null; 
                Exception exception = null;
 
                try
                {
                    if (IsFlagSet(this.options, SaveChangesOptions.Batch))
                    { 
                        if ((null == this.batchResponse) || (HttpStatusCode.NoContent == this.batchResponse.StatusCode))
                        {   // we always expect a response to our batch POST request 
                            throw Error.InvalidOperation(Strings.Batch_ExpectedResponse(1)); 
                        }
 
                        headers = WebUtil.WrapResponseHeaders(this.batchResponse);
                        HandleResponse(
                            this.batchResponse.StatusCode,                                      // statusCode
                            this.batchResponse.Headers[XmlConstants.HttpDataServiceVersion],    // responseVersion 
                            delegate() { return this.httpWebResponseStream; },                  // getResponseStream
                            true);                                                              // throwOnFailure 
 
                        if (!BatchStream.GetBoundaryAndEncodingFromMultipartMixedContentType(this.batchResponse.ContentType, out boundary, out encoding))
                        { 
                            string mime;
                            Exception inner = null;
                            HttpProcessUtility.ReadContentType(this.batchResponse.ContentType, out mime, out encoding);
                            if (String.Equals(XmlConstants.MimeTextPlain, mime)) 
                            {
                                inner = GetResponseText(this.batchResponse.GetResponseStream, this.batchResponse.StatusCode); 
                            } 

                            throw Error.InvalidOperation(Strings.Batch_ExpectedContentType(this.batchResponse.ContentType), inner); 
                        }

                        if (null == this.httpWebResponseStream)
                        { 
                            Error.ThrowBatchExpectedResponse(InternalError.NullResponseStream);
                        } 
 
                        this.DataServiceResponse = new DataServiceResponse(headers, (int)this.batchResponse.StatusCode, this.Responses, true /*batchResponse*/);
                    } 

                    bool close = true;
                    BatchStream batchStream = null;
                    try 
                    {
                        batchStream = this.responseBatchStream ?? new BatchStream(this.httpWebResponseStream, boundary, encoding, false); 
                        this.httpWebResponseStream = null; 
                        this.responseBatchStream = null;
 
                        IEnumerable<OperationResponse> responses = this.HandleBatchResponse(batchStream);
                        if (IsFlagSet(this.options, SaveChangesOptions.Batch) && (null != this.Queries))
                        {
                            // ExecuteBatch, EndExecuteBatch 
                            close = false;
                            this.responseBatchStream = batchStream; 
 
                            this.DataServiceResponse = new DataServiceResponse(
                                (Dictionary<string, string>)this.DataServiceResponse.BatchHeaders, 
                                this.DataServiceResponse.BatchStatusCode,
                                responses,
                                true /*batchResponse*/);
                        } 
                        else
                        {   // SaveChanges, EndSaveChanges 
                            // enumerate the entire response 
                            foreach (ChangeOperationResponse response in responses)
                            { 
                                if (exception == null && response.Error != null)
                                {
                                    exception = response.Error;
                                } 
                            }
                        } 
                    } 
                    finally
                    { 
                        if (close && (null != batchStream))
                        {
                            batchStream.Close();
                        } 
                    }
                } 
                catch (InvalidOperationException ex) 
                {
                    exception = ex; 
                }

                if (exception != null)
                { 
                    if (this.DataServiceResponse == null)
                    { 
                        int statusCode = this.batchResponse == null ? (int)HttpStatusCode.InternalServerError : (int)this.batchResponse.StatusCode; 
                        this.DataServiceResponse = new DataServiceResponse(headers, statusCode, null, IsFlagSet(this.options, SaveChangesOptions.Batch));
                    } 

                    throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, exception, this.DataServiceResponse);
                }
            } 

            /// <summary> 
            /// process the batch changeset response 
            /// </summary>
            /// <param name="batch">batch stream</param> 
            /// <returns>enumerable of QueryResponse or null</returns>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506", Justification = "Central method of the API, likely to have many cross-references")]
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031", Justification = "Cache exception so user can examine it later")]
            private IEnumerable<OperationResponse> HandleBatchResponse(BatchStream batch) 
            {
                if (!batch.CanRead) 
                { 
                    yield break;
                } 

                string contentType;
                string location;
                string etag; 

                Uri editLink = null; 
 
                HttpStatusCode status;
                int changesetIndex = 0; 
                int queryCount = 0;
                int operationCount = 0;
                this.entryIndex = 0;
                while (batch.MoveNext()) 
                {
                    var contentHeaders = batch.ContentHeaders; // get the headers before materialize clears them 
 
                    Entry entry;
                    switch (batch.State) 
                    {
                        #region BeginChangeSet
                        case BatchStreamState.BeginChangeSet:
                            if ((IsFlagSet(this.options, SaveChangesOptions.Batch) && (0 != changesetIndex)) || 
                                (!IsFlagSet(this.options, SaveChangesOptions.Batch) && (this.ChangedEntries.Count <= changesetIndex)) ||
                                (0 != operationCount)) 
                            {   // for now, we only send a single batch, single changeset 
                                Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                            } 

                            break;
                        #endregion
 
                        #region EndChangeSet
                        case BatchStreamState.EndChangeSet: 
                            // move forward to next expected changelist 
                            changesetIndex++;
                            operationCount = 0; 
                            break;
                        #endregion

                        #region GetResponse 
                        case BatchStreamState.GetResponse:
                            Debug.Assert(0 == operationCount, "missing an EndChangeSet 2"); 
 
                            contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType);
                            status = (HttpStatusCode)(-1); 

                            Exception ex = null;
                            QueryOperationResponse qresponse = null;
                            try 
                            {
                                status = batch.GetStatusCode(); 
 
                                ex = HandleResponse(status, batch.GetResponseVersion(), batch.GetContentStream, false);
                                if (null == ex) 
                                {
                                    DataServiceRequest query = this.Queries[queryCount];

                                    System.Collections.IEnumerable enumerable = query.Materialize(this.Context, contentType, batch.GetContentStream); 
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, enumerable);
                                } 
                            } 
                            catch (ArgumentException e)
                            { 
                                ex = e;
                            }
                            catch (FormatException e)
                            { 
                                ex = e;
                            } 
                            catch (InvalidOperationException e) 
                            {
                                ex = e; 
                            }

                            if (null == qresponse)
                            { 
                                DataServiceRequest query = this.Queries[queryCount];
                                qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, null); 
                                qresponse.Error = ex; 
                            }
 
                            qresponse.StatusCode = (int)status;
                            queryCount++;
                            yield return qresponse;
                            break; 
                        #endregion
 
                        #region ChangeResponse 
                        case BatchStreamState.ChangeResponse:
 
                            if (this.ChangedEntries.Count <= unchecked((uint)this.entryIndex))
                            {
                                Error.ThrowBatchUnexpectedContent(InternalError.TooManyBatchResponse);
                            } 

                            HttpStatusCode statusCode = batch.GetStatusCode(); 
                            Exception error = HandleResponse(statusCode, batch.GetResponseVersion(), batch.GetContentStream, false); 
                            int index = this.ValidateContentID(contentHeaders);
 
                            try
                            {
                                entry = this.ChangedEntries[index];
                                operationCount += this.Context.SaveResultProcessed(entry); 

                                if (null != error) 
                                { 
                                    throw error;
                                } 

                                switch (entry.State)
                                {
                                    #region Post 
                                    case EntityStates.Added:
                                        if (entry.IsResource) 
                                        { 
                                            string mime = null;
                                            Encoding postEncoding = null; 
                                            contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType);
                                            contentHeaders.TryGetValue(XmlConstants.HttpResponseLocation, out location);
                                            contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag);
                                            editLink = (null != location) ? Util.CreateUri(location, UriKind.Absolute) : null; 
                                            ResourceBox box = (ResourceBox)entry;
 
                                            Stream stream = batch.GetContentStream(); 
                                            if (null != stream)
                                            { 
                                                HttpProcessUtility.ReadContentType(contentType, out mime, out postEncoding);
                                                if (!String.Equals(XmlConstants.MimeApplicationAtom, mime, StringComparison.OrdinalIgnoreCase))
                                                {
                                                    throw Error.InvalidOperation(Strings.Deserialize_UnknownMimeTypeSpecified(mime)); 
                                                }
 
                                                XmlReader reader = XmlUtil.CreateXmlReader(stream, postEncoding); 
                                                using (MaterializeAtom atom = new MaterializeAtom(this.Context, reader, box.Resource.GetType(), MergeOption.OverwriteChanges))
                                                { 
                                                    this.Context.HandleResponsePost(box, atom, editLink, etag);
                                                }
                                            }
                                            else 
                                            {
                                                if (null == editLink) 
                                                { 
                                                    string entitySetName = box.Identity.OriginalString;
                                                    editLink = GenerateEditLinkUri(this.Context.baseUriWithSlash, entitySetName, box.Resource); 
                                                }

                                                this.Context.HandleResponsePost(box, null, editLink, etag);
                                            } 
                                        }
                                        else 
                                        { 
                                            HandleResponsePost((RelatedEnd)entry);
                                        } 

                                        break;
                                    #endregion
 
                                    #region Put, Merge
                                    case EntityStates.Modified: 
                                        contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag); 
                                        HandleResponsePut(entry, etag);
                                        break; 
                                    #endregion

                                    #region Delete
                                    case EntityStates.Deleted: 
                                        this.Context.HandleResponseDelete(entry);
                                        break; 
                                    #endregion 
                                }
                            } 
                            catch (Exception e)
                            {
                                this.ChangedEntries[index].SaveError = e;
                                error = e; 
                            }
 
                            ChangeOperationResponse changeOperationResponse = new ChangeOperationResponse(contentHeaders, BuildReturn(this.ChangedEntries[index])); 
                            changeOperationResponse.StatusCode = (int)statusCode;
                            if (error != null) 
                            {
                                changeOperationResponse.Error = error;
                            }
 
                            this.Responses.Add(changeOperationResponse);
                            operationCount++; 
                            this.entryIndex++; 
                            yield return changeOperationResponse;
                            break; 
                        #endregion

                        default:
                            Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState); 
                            break;
                    } 
                } 

                Debug.Assert(batch.State == BatchStreamState.EndBatch, "unexpected batch state"); 

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if (((null == this.Queries) && ((0 == changesetIndex) || 
                                                (0 < queryCount) ||
                            (this.ChangedEntries.Any(o => o.ContentGeneratedForSave != (0 != o.SaveResultWasProcessed)) && 
                             (!IsFlagSet(this.options, SaveChangesOptions.Batch) || 
                               (null == this.ChangedEntries.FirstOrDefault(o => (null != o.SaveError))))))) ||
                    ((null != this.Queries) && (queryCount != this.Queries.Length))) 
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
 
                batch.Dispose();
            } 
 
            /// <summary>
            /// validate the content-id 
            /// </summary>
            /// <param name="contentHeaders">headers</param>
            /// <returns>return the correct ChangedEntries index</returns>
            private int ValidateContentID(Dictionary<string, string> contentHeaders) 
            {
                int contentID = 0; 
                string contentValueID; 

                if (!contentHeaders.TryGetValue(XmlConstants.HttpContentID, out contentValueID) || 
                    !Int32.TryParse(contentValueID, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out contentID))
                {
                    Error.ThrowBatchUnexpectedContent(InternalError.ChangeResponseMissingContentID);
                } 

                for (int i = 0; i < this.ChangedEntries.Count; ++i) 
                { 
                    if (this.ChangedEntries[i].ChangeOrder == contentID)
                    { 
                        return i;
                    }
                }
 
                Error.ThrowBatchUnexpectedContent(InternalError.ChangeResponseUnknownContentID);
                return -1; 
            } 

            #endregion Batch 

            #region callback handlers
            /// <summary>handle request.BeginGetRequestStream with request.EndGetRquestStream and then write out request stream</summary>
            /// <param name="asyncResult">async result</param> 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")]
            private void AsyncEndGetRequestStream(IAsyncResult asyncResult) 
            { 
                PerRequest pereq = asyncResult.AsyncState as PerRequest;
                try 
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndGetRequestCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetRequestStream
 
                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndGetRequestStream);
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndGetRequestStreamRequest); 
 
                    Stream stream = Util.NullCheck(httpWebRequest.EndGetRequestStream(asyncResult), InternalError.InvalidEndGetRequestStreamStream);
                    pereq.RequestStream = stream; 

                    MemoryStream memoryStream = Util.NullCheck(pereq.RequestStreamContent, InternalError.InvalidEndGetRequestStreamContent);
                    byte[] buffer = memoryStream.GetBuffer();
                    int bufferOffset = checked((int)memoryStream.Position); 
                    int bufferLength = checked((int)memoryStream.Length) - bufferOffset;
                    if ((null == buffer) || (0 == bufferLength)) 
                    { 
                        Error.ThrowInternalError(InternalError.InvalidEndGetRequestStreamContentLength);
                    } 

                    // the following is useful in the debugging Immediate Window
                    // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength);
                    asyncResult = stream.BeginWrite(buffer, bufferOffset, bufferLength, this.AsyncEndWrite, pereq); 

                    bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                    pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginWrite 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle reqestStream.BeginWrite with requestStream.EndWrite then BeginGetResponse</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndWrite(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndWriteCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndWrite); 
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndWriteRequest); 

                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndWriteStream); 
                    stream.EndWrite(asyncResult);

                    pereq.RequestStream = null;
                    stream.Close(); 

                    stream = pereq.RequestStreamContent; 
                    if (null != stream) 
                    {
                        pereq.RequestStreamContent = null; 
                        stream.Dispose();
                    }

                    asyncResult = httpWebRequest.BeginGetResponse(this.AsyncEndGetResponse, pereq); 

                    bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                    pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginGetResponse 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle request.BeginGetResponse with request.EndGetResponse and then copy response stream</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndGetResponse(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndGetResponseCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndGetResponse); 
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndGetResponseRequest); 

                    // the httpWebResponse is kept for batching, discarded by non-batch 
                    HttpWebResponse response = null;
                    try
                    {
                        response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                    }
                    catch (WebException e) 
                    { 
                        response = (HttpWebResponse)e.Response;
                    } 

                    pereq.HttpWebResponse = Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse);

                    if (!IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                    {
                        this.HandleOperationResponse(httpWebRequest, response); 
                    } 

                    this.copiedContentLength = 0; 
                    Stream stream = response.GetResponseStream();
                    pereq.ResponseStream = stream;
                    if ((null != stream) && stream.CanRead)
                    { 
                        if (null != this.buildBatchWriter)
                        { 
                            this.buildBatchWriter.Flush(); 
                        }
 
                        if (null == this.buildBatchBuffer)
                        {
                            this.buildBatchBuffer = new byte[8000];
                        } 

                        bool reallyCompletedSynchronously = false; 
                        do 
                        {
                            asyncResult = stream.BeginRead(this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 

                            reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep);
                            pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                        } 
                        while (reallyCompletedSynchronously && !pereq.RequestCompleted && !this.IsCompleted && stream.CanRead);
                    } 
                    else 
                    {
                        pereq.RequestCompleted = true; 

                        // BeginGetResponse could fail and callback still invoked
                        if (!this.IsCompleted)
                        { 
                            this.SaveNextChange(pereq);
                        } 
                    } 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle responseStream.BeginRead with responseStream.EndRead</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndRead(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                int count = 0;
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndReadCompleted); 
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
 
                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead); 
                    Stream stream = Util.NullCheck(pereq.ResponseStream, InternalError.InvalidEndReadStream);
 
                    count = stream.EndRead(asyncResult);
                    if (0 < count)
                    {
                        Stream outputResponse = Util.NullCheck(this.httpWebResponseStream, InternalError.InvalidEndReadCopy); 
                        outputResponse.Write(this.buildBatchBuffer, 0, count);
                        this.copiedContentLength += count; 
 
                        if (!asyncResult.CompletedSynchronously && stream.CanRead)
                        {   // if CompletedSynchronously then caller will call and we reduce risk of stack overflow 
                            bool reallyCompletedSynchronously = false;
                            do
                            {
                                asyncResult = stream.BeginRead(this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 

                                reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                                pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginRead 
                            }
                            while (reallyCompletedSynchronously && !pereq.RequestCompleted && !this.IsCompleted && stream.CanRead); 
                        }
                    }
                    else
                    { 
                        pereq.RequestCompleted = true;
 
                        // BeginRead could fail and callback still invoked 
                        if (!this.IsCompleted)
                        { 
                            this.SaveNextChange(pereq);
                        }
                    }
                } 
                catch (Exception e)
                { 
                    if (this.HandleFailure(pereq, e)) 
                    {
                        throw; 
                    }
                }
                finally
                { 
                    this.HandleCompleted(pereq);
                } 
            } 

            /// <summary>continue with the next change</summary> 
            /// <param name="pereq">the completed per request object</param>
            private void SaveNextChange(PerRequest pereq)
            {
                Debug.Assert(this.executeAsync, "should be async"); 
                if (!pereq.RequestCompleted)
                { 
                    Error.ThrowInternalError(InternalError.SaveNextChangeIncomplete); 
                }
 
                ++pereq.RequestStep;
                EqualRefCheck(this.request, pereq, InternalError.InvalidSaveNextChange);

                if (IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                {
                    this.httpWebResponseStream.Position = 0; 
                    this.request = null; 
                    this.IsCompleted = true;
                } 
                else
                {
                    if (0 == this.copiedContentLength)
                    { 
                        this.HandleOperationResponseNoData();
                    } 
 
                    this.HandleOperationEnd();
 
                    if (!this.procesingMediaLinkEntry)
                    {
                        this.changesCompleted++;
                    } 

                    pereq.Dispose(); 
                    this.request = null; 
                    if (!pereq.RequestCompletedSynchronously)
                    {   // you can't chain synchronously completed responses without risking StackOverflow, caller will loop to next 
                        if (!this.IsCompleted)
                        {
                            this.BeginNextChange(IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate));
                        } 
                    }
                } 
            } 
            #endregion
 
            /// <summary>wrap the full request</summary>
            private sealed class PerRequest
            {
                /// <summary>ctor</summary> 
                internal PerRequest()
                { 
                    this.RequestCompletedSynchronously = true; 
                }
 
                /// <summary>active web request</summary>
                internal HttpWebRequest Request
                {
                    get; 
                    set;
                } 
 
                /// <summary>active web request stream</summary>
                internal Stream RequestStream 
                {
                    get;
                    set;
                } 

                /// <summary>content to write to request stream</summary> 
                internal MemoryStream RequestStreamContent 
                {
                    get; 
                    set;
                }

                /// <summary>web response</summary> 
                internal HttpWebResponse HttpWebResponse
                { 
                    get; 
                    set;
                } 

                /// <summary>async web response stream</summary>
                internal Stream ResponseStream
                { 
                    get;
                    set; 
                } 

                /// <summary>did the request complete all of its steps synchronously?</summary> 
                internal bool RequestCompletedSynchronously
                {
                    get;
                    set; 
                }
 
                /// <summary>did the sequence (BeginGetRequest, EndGetRequest, ... complete</summary> 
                internal bool RequestCompleted
                { 
                    get;
                    set;
                }
 
                /// <summary>
                /// If CompletedSynchronously and requestStep didn't increment, then underlying implementation lied. 
                /// </summary> 
                internal int RequestStep
                { 
                    get;
                    set;
                }
 
                /// <summary>
                /// dispose of the request object 
                /// </summary> 
                internal void Dispose()
                { 
                    Stream stream;

                    if (null != (stream = this.ResponseStream))
                    { 
                        this.ResponseStream = null;
                        stream.Dispose(); 
                    } 

                    if (null != (stream = this.RequestStreamContent)) 
                    {
                        this.RequestStreamContent = null;
                        stream.Dispose();
                    } 

                    if (null != (stream = this.RequestStream)) 
                    { 
                        this.RequestStream = null;
                        stream.Dispose(); 
                    }

                    HttpWebResponse response = this.HttpWebResponse;
                    if (null != response) 
                    {
                        response.Close(); 
                    } 

                    this.Request = null; 
                    this.RequestCompleted = true;
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// <copyright file="DataServiceContext.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary> 
// context
// </summary> 
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client 
{
    using System;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.ObjectModel;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Linq; 
    using System.Linq.Expressions;
#if !ASTORIA_LIGHT // Data.Services http stack
    using System.Net;
#else 
    using System.Data.Services.Http;
#endif 
    using System.Text; 
    using System.Xml;
    using System.Xml.Linq; 

    /// <summary>
    /// context
    /// </summary> 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506", Justification = "Central class of the API, likely to have many cross-references")]
    public class DataServiceContext 
    { 
        /// <summary>represents identity for a resource without one</summary>
        private const Uri NoIdentity = null; 

        /// <summary>represents entityset for a resource without one</summary>
        private const string NoEntitySet = null;
 
        /// <summary>represents empty etag</summary>
        private const string NoETag = null; 
 
        /// <summary>base uri prepended to relative uri</summary>
        private readonly System.Uri baseUri; 

        /// <summary>base uri with guranteed trailing slash</summary>
        private readonly System.Uri baseUriWithSlash;
 
#if !ASTORIA_LIGHT  // Credentials not available
        /// <summary>Authentication interface for retrieving credentials for Web client authentication.</summary> 
        private System.Net.ICredentials credentials; 
#endif
 
        /// <summary>Override the namespace used for the data parts of the ATOM entries</summary>
        private string dataNamespace;

        /// <summary>resolve type from a typename</summary> 
        private Func<Type, string> resolveName;
 
        /// <summary>resolve typename from a type</summary> 
        private Func<string, Type> resolveType;
 
#if !ASTORIA_LIGHT  // Timeout not available
        /// <summary>time-out value in seconds, 0 for default</summary>
        private int timeout;
#endif 

        /// <summary>whether to use post-tunneling for PUT/DELETE</summary> 
        private bool postTunneling; 

        /// <summary>Options when deserializing properties to the target type.</summary> 
        private bool ignoreMissingProperties;

        /// <summary>Used to specify a value synchronization strategy.</summary>
        private MergeOption mergeOption; 

        /// <summary>Default options to be used while doing savechanges.</summary> 
        private SaveChangesOptions saveChangesDefaultOptions; 

        /// <summary>Override the namespace used for the scheme in the category for ATOM entries.</summary> 
        private Uri typeScheme;

        #region Resource state management
 
        /// <summary>change order</summary>
        private uint nextChange; 
 
        /// <summary>Set of tracked resources by ResourceBox.Resource</summary>
        private Dictionary<Object, ResourceBox> objectToResource = new Dictionary<object, ResourceBox>(); 

        /// <summary>Set of tracked resources by ResourceBox.Identity</summary>
        private Dictionary<Uri, ResourceBox> identityToResource;
 
        /// <summary>Set of tracked bindings by ResourceBox.Identity</summary>
        private Dictionary<RelatedEnd, RelatedEnd> bindings = new Dictionary<RelatedEnd, RelatedEnd>(RelatedEnd.EquivalenceComparer); 
 
        #endregion
 
        #region ctor

        /// <summary>
        /// Instantiates a new context with the specified <paramref name="serviceRoot"/> Uri. 
        /// The library expects the Uri to point to the root of a data service,
        /// but does not issue a request to validate it does indeed identify the root of a service. 
        /// If the Uri does not identify the root of the service, the behavior of the client library is undefined. 
        /// </summary>
        /// <param name="serviceRoot"> 
        /// An absolute, well formed http or https URI without a query or fragment which identifies the root of a data service.
        /// A Uri provided with a trailing slash is equivalent to one without such a trailing character
        /// </param>
        /// <exception cref="ArgumentException">if the <paramref name="serviceRoot"/> is not an absolute, well formed http or https URI without a query or fragment</exception> 
        /// <exception cref="ArgumentNullException">when the <paramref name="serviceRoot"/> is null</exception>
        /// <remarks> 
        /// With Silverlight, the <paramref name="serviceRoot"/> can be a relative Uri 
        /// that will be combined with System.Windows.Browser.HtmlPage.Document.DocumentUri.
        /// </remarks> 
        public DataServiceContext(Uri serviceRoot)
        {
            Util.CheckArgumentNull(serviceRoot, "serviceRoot");
 
#if ASTORIA_LIGHT
            if (!serviceRoot.IsAbsoluteUri) 
            { 
                serviceRoot = new Uri(System.Windows.Browser.HtmlPage.Document.DocumentUri, serviceRoot);
            } 
#endif
            if (!serviceRoot.IsAbsoluteUri ||
                !Uri.IsWellFormedUriString(serviceRoot.OriginalString, UriKind.Absolute) ||
                !String.IsNullOrEmpty(serviceRoot.Query) || 
                !string.IsNullOrEmpty(serviceRoot.Fragment) ||
                ((serviceRoot.Scheme != "http") && (serviceRoot.Scheme != "https"))) 
            { 
                throw Error.Argument(Strings.Context_BaseUri, "serviceRoot");
            } 

            this.baseUri = serviceRoot;
            this.baseUriWithSlash = serviceRoot;
            if (!serviceRoot.OriginalString.EndsWith("/", StringComparison.Ordinal)) 
            {
                this.baseUriWithSlash = Util.CreateUri(serviceRoot.OriginalString + "/", UriKind.Absolute); 
            } 

            this.mergeOption = MergeOption.AppendOnly; 
            this.DataNamespace = XmlConstants.DataWebNamespace;
            this.UsePostTunneling = false;
            this.typeScheme = new Uri(XmlConstants.DataWebSchemeNamespace);
        } 
        #endregion
 
#if !ASTORIA_LIGHT // Data.Services http stack 
        /// <summary>
        /// This event is fired before a request it sent to the server, giving 
        /// the handler the opportunity to inspect, adjust and/or replace the
        /// WebRequest object used to perform the request.
        /// </summary>
        /// <remarks> 
        /// When calling BeginSaveChanges and not using SaveChangesOptions.Batch,
        /// this event may be raised from a different thread. 
        /// </remarks> 
        public event EventHandler<SendingRequestEventArgs> SendingRequest;
#endif 

        /// <summary>
        /// This event fires once an entry has been read into a .NET object
        /// but before the serializer returns to the caller, giving handlers 
        /// an opporunity to read further information from the incoming ATOM
        /// entry and updating the object 
        /// </summary> 
        /// <remarks>
        /// This event should only be raised from the thread that was used to 
        /// invoke Execute, EndExecute, SaveChanges, EndSaveChanges.
        /// </remarks>
        public event EventHandler<ReadingWritingEntityEventArgs> ReadingEntity;
 
        /// <summary>
        /// This event fires once an ATOM entry is ready to be written to 
        /// the network for a request, giving handlers an opportunity to 
        /// customize the entry with information from the corresponding
        /// .NET object or the environment. 
        /// </summary>
        /// <remarks>
        /// When calling BeginSaveChanges and not using SaveChangesOptions.Batch,
        /// this event may be raised from a different thread. 
        /// </remarks>
        public event EventHandler<ReadingWritingEntityEventArgs> WritingEntity; 
 
        #region BaseUri, Credentials, MergeOption, Timeout, Links, Entities
        /// <summary> 
        /// Absolute Uri identifying the root of the target data service.
        /// A Uri provided with a trailing slash is equivalent to one without such a trailing character.
        /// </summary>
        /// <remarks> 
        /// Example: http://server/host/myservice.svc
        /// </remarks> 
        public Uri BaseUri 
        {
            get { return this.baseUri; } 
        }

#if !ASTORIA_LIGHT  // Credentials not available
        /// <summary> 
        /// Gets and sets the authentication information used by each query created using the context object.
        /// </summary> 
        public System.Net.ICredentials Credentials 
        {
            get { return this.credentials; } 
            set { this.credentials = value; }
        }
#endif
 
        /// <summary>
        /// Used to specify a synchronization strategy when sending/receiving entities to/from a data service. 
        /// This value is read by the deserialization component of the client prior to materializing objects. 
        /// As such, it is recommended to set this property to the appropriate materialization strategy
        /// before executing any queries/updates to the data service. 
        /// </summary>
        /// <remarks>
        /// The default value is <see cref="MergeOption"/>.AppendOnly.
        /// </remarks> 
        public MergeOption MergeOption
        { 
            get { return this.mergeOption; } 
            set { this.mergeOption = Util.CheckEnumerationValue(value, "MergeOption"); }
        } 

        /// <summary>
        /// Are properties missing from target type ignored?
        /// </summary> 
        /// <remarks>
        /// This also affects responses during SaveChanges. 
        /// </remarks> 
        public bool IgnoreMissingProperties
        { 
            get { return this.ignoreMissingProperties; }
            set { this.ignoreMissingProperties = value; }
        }
 
        /// <summary>Override the namespace used for the data parts of the ATOM entries</summary>
        public string DataNamespace 
        { 
            get
            { 
                return this.dataNamespace;
            }

            set 
            {
                Util.CheckArgumentNull(value, "value"); 
                this.dataNamespace = value; 
            }
        } 

        /// <summary>
        /// Enables one to override the default type resolution strategy used by the client library.
        /// Set this property to a delegate which identifies a function that resolves 
        /// a type within the client application to a namespace-qualified type name.
        /// This enables the client to perform custom mapping between the type name 
        /// provided in a response from the server and a type on the client. 
        /// </summary>
        /// <remarks> 
        /// This method enables one to override the entity name that is serialized
        /// to the target representation (ATOM,JSON, etc) for the specified type.
        /// </remarks>
        public Func<Type, string> ResolveName 
        {
            get { return this.resolveName; } 
            set { this.resolveName = value; } 
        }
 
        /// <summary>
        /// Enables one to override the default type resolution strategy used by the client library.
        /// Set this property to a delegate which identifies a function that resolves a
        /// namespace-qualified type name to type within the client application. 
        /// This enables the client to perform custom mapping between the type name
        /// provided in a response from the server and a type on the client. 
        /// </summary> 
        /// <remarks>
        /// Overriding type resolution enables inserting a custom type name to type mapping strategy. 
        /// It does not enable one to affect how a response is materialized into the identified type.
        /// </remarks>
        public Func<string, Type> ResolveType
        { 
            get { return this.resolveType; }
            set { this.resolveType = value; } 
        } 

#if !ASTORIA_LIGHT  // Timeout not available 
        /// <summary>
        /// Get and sets the timeout span in seconds to use for the underlying HTTP request to the data service.
        /// </summary>
        /// <remarks> 
        /// A value of 0 will use the default timeout of the underlying HTTP request.
        /// This value must be set before executing any query or update operations against 
        /// the target data service for it to have effect on the on the request. 
        /// The value may be changed between requests to a data service and the new value
        /// will be picked up by the next data service request. 
        /// </remarks>
        public int Timeout
        {
            get 
            {
                return this.timeout; 
            } 

            set 
            {
                if (value < 0)
                {
                    throw Error.ArgumentOutOfRange("Timeout"); 
                }
 
                this.timeout = value; 
            }
        } 
#endif

        /// <summary>Gets or sets the URI used to indicate what type scheme is used by the service.</summary>
        public Uri TypeScheme 
        {
            get 
            { 
                return this.typeScheme;
            } 

            set
            {
                Util.CheckArgumentNull(value, "value"); 
                this.typeScheme = value;
            } 
        } 

        /// <summary>whether to use post-tunneling for PUT/DELETE</summary> 
        public bool UsePostTunneling
        {
            get { return this.postTunneling; }
            set { this.postTunneling = value; } 
        }
 
        /// <summary> 
        /// Returns a collection of all the links (ie. associations) currently being tracked by the context.
        /// If no links are being tracked, a collection with 0 elements is returned. 
        /// </summary>
        public ReadOnlyCollection<LinkDescriptor> Links
        {
            get 
            {
                return (from link in this.bindings.Values 
                        orderby link.ChangeOrder 
                        select new LinkDescriptor(link.SourceResource, link.SourceProperty, link.TargetResouce, link.State))
                        .ToList().AsReadOnly(); 
            }
        }

        /// <summary> 
        /// Returns a collection of all the resources currently being tracked by the context.
        /// If no resources are being tracked, a collection with 0 elements is returned. 
        /// </summary> 
        public ReadOnlyCollection<EntityDescriptor> Entities
        { 
            get
            {
                return (from entity in this.objectToResource.Values
                        orderby entity.ChangeOrder 
                        select new EntityDescriptor(entity.Resource, entity.ETag, entity.State))
                        .ToList().AsReadOnly(); 
            } 
        }
 
        /// <summary>
        /// Default SaveChangesOptions that needs to be used when doing SaveChanges.
        /// </summary>
        public SaveChangesOptions SaveChangesDefaultOptions 
        {
            get 
            { 
                return this.saveChangesDefaultOptions;
            } 

            set
            {
                ValidateSaveChangesOptions(value); 
                this.saveChangesDefaultOptions = value;
            } 
        } 

        #endregion 

        /// <summary>base uri with guranteed trailing slash</summary>
        internal Uri BaseUriWithSlash
        { 
            get { return this.baseUriWithSlash; }
        } 
 
        /// <summary>Indicates if there are subscribers for the ReadingEntity event</summary>
        internal bool HasReadingEntityHandlers 
        {
            [DebuggerStepThrough]
            get { return this.ReadingEntity != null; }
        } 

        #region CreateQuery 
        /// <summary> 
        /// create a query based on (BaseUri + relativeUri)
        /// </summary> 
        /// <typeparam name="T">type of object to materialize</typeparam>
        /// <param name="entitySetName">entitySetName</param>
        /// <returns>composible, enumerable query object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "required for this feature")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "required for this feature")]
        public DataServiceQuery<T> CreateQuery<T>(string entitySetName) 
        { 
            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName");
            this.ValidateEntitySetName(ref entitySetName); 

            ResourceSetExpression rse = new ResourceSetExpression(typeof(IOrderedQueryable<T>), null, Expression.Constant(entitySetName), typeof(T), null, null);
            return new DataServiceQuery<T>.DataServiceOrderedQuery(rse, new DataServiceQueryProvider(this));
        } 
        #endregion
 
        #region GetMetadataUri 
        /// <summary>
        /// Given the base URI, resolves the location of the metadata endpoint for the service by using an HTTP OPTIONS request or falling back to convention ($metadata) 
        /// </summary>
        /// <returns>Uri to retrieve metadata from</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "required for this feature")]
        public Uri GetMetadataUri() 
        {
            // 
            Uri metadataUri = Util.CreateUri(this.baseUriWithSlash.OriginalString + XmlConstants.UriMetadataSegment, UriKind.Absolute); 
            return metadataUri;
        } 
        #endregion

        #region LoadProperty
 
        /// <summary>
        /// Begin getting response to load a collection or reference property. 
        /// </summary> 
        /// <remarks>actually doesn't modify the property until EndLoadProperty is called.</remarks>
        /// <param name="entity">entity</param> 
        /// <param name="propertyName">name of collection or reference property to load</param>
        /// <param name="callback">The AsyncCallback delegate.</param>
        /// <param name="state">The state object for this request.</param>
        /// <returns>An IAsyncResult that references the asynchronous request for a response.</returns> 
        public IAsyncResult BeginLoadProperty(object entity, string propertyName, AsyncCallback callback, object state)
        { 
            LoadPropertyAsyncResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state); 
            result.BeginExecute(null);
            return result; 
        }

        /// <summary>
        /// Load a collection or reference property from a async result. 
        /// </summary>
        /// <param name="asyncResult">async result generated by BeginLoadProperty</param> 
        /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
        public QueryOperationResponse EndLoadProperty(IAsyncResult asyncResult)
        { 
            LoadPropertyAsyncResult response = QueryAsyncResult.EndExecute<LoadPropertyAsyncResult>(this, "LoadProperty", asyncResult);
            return response.LoadProperty();
        }
 
#if !ASTORIA_LIGHT // Synchronous methods not available
        /// <summary> 
        /// Load a collection or reference property. 
        /// </summary>
        /// <remarks> 
        /// An entity in detached or added state will throw an InvalidOperationException
        /// since there is nothing it can load from the server.
        ///
        /// An entity in unchanged or modified state will load its collection or 
        /// reference elements as unchanged with unchanged bindings.
        /// 
        /// An entity in deleted state will loads its collection or reference elements 
        /// in the unchanged state with bindings in the deleted state.
        /// </remarks> 
        /// <param name="entity">entity</param>
        /// <param name="propertyName">name of collection or reference property to load</param>
        /// <returns>QueryOperationResponse instance containing information about the response.</returns>
        public QueryOperationResponse LoadProperty(object entity, string propertyName) 
        {
            LoadPropertyAsyncResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null); 
            result.Execute(null); 
            return result.LoadProperty();
        } 
#endif
        #endregion

        #region ExecuteBatch, BeginExecuteBatch, EndExecuteBatch 

        /// <summary> 
        /// Batch multiple queries into a single async request. 
        /// </summary>
        /// <param name="callback">User callback when results from batch are available.</param> 
        /// <param name="state">user state in IAsyncResult</param>
        /// <param name="queries">queries to batch</param>
        /// <returns>async result object</returns>
        public IAsyncResult BeginExecuteBatch(AsyncCallback callback, object state, params DataServiceRequest[] queries) 
        {
            Util.CheckArgumentNotEmpty(queries, "queries"); 
 
            SaveAsyncResult result = new SaveAsyncResult(this, "ExecuteBatch", queries, SaveChangesOptions.Batch, callback, state, true);
            result.BatchBeginRequest(false /*replaceOnUpdate*/); 
            return result;
        }

        /// <summary> 
        /// Call when results from batch are desired.
        /// </summary> 
        /// <param name="asyncResult">async result object returned from BeginExecuteBatch</param> 
        /// <returns>batch response from which query results can be enumerated.</returns>
        public DataServiceResponse EndExecuteBatch(IAsyncResult asyncResult) 
        {
            SaveAsyncResult result = BaseAsyncResult.EndExecute<SaveAsyncResult>(this, "ExecuteBatch", asyncResult);
            return result.EndRequest();
        } 

#if !ASTORIA_LIGHT // Synchronous methods not available 
        /// <summary> 
        /// Batch multiple queries into a single request.
        /// </summary> 
        /// <param name="queries">queries to batch</param>
        /// <returns>batch response from which query results can be enumerated.</returns>
        public DataServiceResponse ExecuteBatch(params DataServiceRequest[] queries)
        { 
            Util.CheckArgumentNotEmpty(queries, "queries");
 
            SaveAsyncResult result = new SaveAsyncResult(this, "ExecuteBatch", queries, SaveChangesOptions.Batch, null, null, false); 
            result.BatchRequest(false /*replaceOnUpdate*/);
            return result.EndRequest(); 
        }
#endif

        #endregion 

        #region Execute(Uri), BeginExecute(Uri), EndExecute(Uri) 
 
        /// <summary>begin the execution of the request uri</summary>
        /// <typeparam name="TElement">element type of the result</typeparam> 
        /// <param name="requestUri">request to execute</param>
        /// <param name="callback">User callback when results from execution are available.</param>
        /// <param name="state">user state in IAsyncResult</param>
        /// <returns>async result object</returns> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")]
        public IAsyncResult BeginExecute<TElement>(Uri requestUri, AsyncCallback callback, object state) 
        { 
            requestUri = Util.CreateUri(this.baseUriWithSlash, requestUri);
            return (new DataServiceRequest<TElement>(requestUri)).BeginExecute(this, this, callback, state); 
        }

        /// <summary>
        /// Call when results from batch are desired. 
        /// </summary>
        /// <typeparam name="TElement">element type of the result</typeparam> 
        /// <param name="asyncResult">async result object returned from BeginExecuteBatch</param> 
        /// <returns>batch response from which query results can be enumerated.</returns>
        /// <exception cref="ArgumentNullException">asyncResult is null</exception> 
        /// <exception cref="ArgumentException">asyncResult did not originate from this instance or End was previously called</exception>
        /// <exception cref="InvalidOperationException">problem in request or materializing results of query into objects</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")]
        public IEnumerable<TElement> EndExecute<TElement>(IAsyncResult asyncResult) 
        {
            QueryAsyncResult response = QueryAsyncResult.EndExecute<QueryAsyncResult>(this, "Execute", asyncResult); 
            IEnumerable<TElement> results = response.ServiceRequest.Materialize(this, response.ContentType, response.GetResponseStream).Cast<TElement>(); 
            return (IEnumerable<TElement>)response.GetResponse(results, typeof(TElement));
        } 

#if !ASTORIA_LIGHT // Synchronous methods not available
        /// <summary>
        /// Execute the requestUri 
        /// </summary>
        /// <typeparam name="TElement">element type of the result</typeparam> 
        /// <param name="requestUri">request uri to execute</param> 
        /// <returns>batch response from which query results can be enumerated.</returns>
        /// <exception cref="ArgumentNullException">null requestUri</exception> 
        /// <exception cref="ArgumentException">!BaseUri.IsBaseOf(requestUri)</exception>
        /// <exception cref="InvalidOperationException">problem materializing results of query into objects</exception>
        /// <exception cref="WebException">failure to get response for requestUri</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Type is used to infer result")] 
        public IEnumerable<TElement> Execute<TElement>(Uri requestUri)
        { 
            requestUri = Util.CreateUri(this.baseUriWithSlash, requestUri); 
            DataServiceRequest request = DataServiceRequest.GetInstance(typeof(TElement), requestUri);
            return request.Execute<TElement>(this, requestUri); 
        }
#endif
        #endregion
 
        #region SaveChanges, BeginSaveChanges, EndSaveChanges
 
        /// <summary> 
        /// submit changes to the server in a single change set
        /// </summary> 
        /// <param name="callback">callback</param>
        /// <param name="state">state</param>
        /// <returns>async result</returns>
        public IAsyncResult BeginSaveChanges(AsyncCallback callback, object state) 
        {
            return this.BeginSaveChanges(this.SaveChangesDefaultOptions, callback, state); 
        } 

        /// <summary> 
        /// begin submitting changes to the server
        /// </summary>
        /// <param name="options">options on how to save changes</param>
        /// <param name="callback">The AsyncCallback delegate.</param> 
        /// <param name="state">The state object for this request.</param>
        /// <returns>An IAsyncResult that references the asynchronous request for a response.</returns> 
        public IAsyncResult BeginSaveChanges(SaveChangesOptions options, AsyncCallback callback, object state) 
        {
            ValidateSaveChangesOptions(options); 
            SaveAsyncResult result = new SaveAsyncResult(this, "SaveChanges", null, options, callback, state, true);
            bool replaceOnUpdate = IsFlagSet(options, SaveChangesOptions.ReplaceOnUpdate);
            if (IsFlagSet(options, SaveChangesOptions.Batch))
            { 
                result.BatchBeginRequest(replaceOnUpdate);
            } 
            else 
            {
                result.BeginNextChange(replaceOnUpdate); // may invoke callback before returning 
            }

            return result;
        } 

        /// <summary> 
        /// done submitting changes to the server 
        /// </summary>
        /// <param name="asyncResult">The pending request for a response. </param> 
        /// <returns>changeset response</returns>
        public DataServiceResponse EndSaveChanges(IAsyncResult asyncResult)
        {
            SaveAsyncResult result = BaseAsyncResult.EndExecute<SaveAsyncResult>(this, "SaveChanges", asyncResult); 
            return result.EndRequest();
        } 
 
#if !ASTORIA_LIGHT // Synchronous methods not available
        /// <summary> 
        /// submit changes to the server in a single change set
        /// </summary>
        /// <returns>changeset response</returns>
        public DataServiceResponse SaveChanges() 
        {
            return this.SaveChanges(this.SaveChangesDefaultOptions); 
        } 

        /// <summary> 
        /// submit changes to the server
        /// </summary>
        /// <param name="options">options on how to save changes</param>
        /// <returns>changeset response</returns> 
        /// <remarks>
        /// MergeOption.NoTracking is tricky but supported because to insert a relationship we need the identity 
        /// of both ends and if one end was an inserted object then its identity is attached, but may not match its value 
        ///
        /// This initial implementation does not do batching. 
        /// Things are sent to the server in the following order
        /// 1) delete relationships
        /// 2) delete objects
        /// 3) update objects 
        /// 4) insert objects
        /// 5) insert relationship 
        /// </remarks> 
        public DataServiceResponse SaveChanges(SaveChangesOptions options)
        { 
            DataServiceResponse errors = null;
            ValidateSaveChangesOptions(options);

            SaveAsyncResult result = new SaveAsyncResult(this, "SaveChanges", null, options, null, null, false); 
            bool replaceOnUpdate = IsFlagSet(options, SaveChangesOptions.ReplaceOnUpdate);
            if (IsFlagSet(options, SaveChangesOptions.Batch)) 
            { 
                result.BatchRequest(replaceOnUpdate);
            } 
            else
            {
                result.BeginNextChange(replaceOnUpdate);
            } 

            errors = result.EndRequest(); 
 
            Debug.Assert(null != errors, "null errors");
            return errors; 
        }
#endif
        #endregion
 
        #region Add, Attach, Delete, Detach, Update, TryGetEntity, TryGetUri
 
        /// <summary> 
        /// Notifies the context that a new link exists between the <paramref name="source"/> and <paramref name="target"/> objects
        /// and that the link is represented via the source.<paramref name="sourceProperty"/> which is a collection. 
        /// The context adds this link to the set of newly created links to be sent to
        /// the data service on the next call to SaveChanges().
        /// </summary>
        /// <remarks> 
        /// Links are one way relationships.  If a back pointer exists (ie. two way association),
        /// this method should be called a second time to notify the context object of the second link. 
        /// </remarks> 
        /// <param name="source">Source object participating in the link.</param>
        /// <param name="sourceProperty">The name of the property on the source object which represents a link from the source to the target object.</param> 
        /// <param name="target">The target object involved in the link which is bound to the source object also specified in this call.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/>, <paramref name="sourceProperty"/> or <paramref name="target"/> are null.</exception>
        /// <exception cref="InvalidOperationException">if link already exists</exception>
        /// <exception cref="InvalidOperationException">if source or target are detached</exception> 
        /// <exception cref="InvalidOperationException">if source or target are in deleted state</exception>
        /// <exception cref="InvalidOperationException">if sourceProperty is not a collection</exception> 
        public void AddLink(object source, string sourceProperty, object target) 
        {
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Added); 

            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.ContainsKey(relation))
            { 
                throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
            } 
 
            relation.State = EntityStates.Added;
            this.bindings.Add(relation, relation); 
            this.objectToResource[source].RelatedLinkCount++;
            this.IncrementChange(relation);
        }
 
        /// <summary>
        /// Notifies the context to start tracking the specified link between source and the specified target entity. 
        /// </summary> 
        /// <param name="source">Source object participating in the link.</param>
        /// <param name="sourceProperty">The name of the property on the source object which represents a link from the source to the target object.</param> 
        /// <param name="target">The target object involved in the link which is bound to the source object also specified in this call.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/>, <paramref name="sourceProperty"/> or <paramref name="target"/> are null.</exception>
        /// <exception cref="InvalidOperationException">if binding already exists</exception>
        /// <exception cref="InvalidOperationException">if source or target are in added state</exception> 
        /// <exception cref="InvalidOperationException">if source or target are in deleted state</exception>
        public void AttachLink(object source, string sourceProperty, object target) 
        { 
            this.AttachLink(source, sourceProperty, target, MergeOption.NoTracking);
        } 

        /// <summary>
        /// Removes the specified link from the list of links being tracked by the context.
        /// Any link being tracked by the context, regardless of its current state, can be detached. 
        /// </summary>
        /// <param name="source">Source object participating in the link.</param> 
        /// <param name="sourceProperty">The name of the property on the source object which represents a link from the source to the target object.</param> 
        /// <param name="target">The target object involved in the link which is bound to the source object also specified in this call.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> or <paramref name="sourceProperty"/> are null.</exception> 
        /// <exception cref="ArgumentException">if sourceProperty is empty</exception>
        /// <returns>true if binding was previously being tracked, false if not</returns>
        public bool DetachLink(object source, string sourceProperty, object target)
        { 
            Util.CheckArgumentNull(source, "source");
            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty"); 
 
            RelatedEnd existing;
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target); 
            if (!this.bindings.TryGetValue(relation, out existing))
            {
                return false;
            } 

            this.DetachExistingLink(existing); 
            return true; 
        }
 
        /// <summary>
        /// Notifies the context that a link exists between the <paramref name="source"/> and <paramref name="target"/> object
        /// and that the link is represented via the source.<paramref name="sourceProperty"/> which is a collection.
        /// The context adds this link to the set of deleted links to be sent to 
        /// the data service on the next call to SaveChanges().
        /// If the specified link exists in the "Added" state, then the link is detached (see DetachLink method) instead. 
        /// </summary> 
        /// <param name="source">Source object participating in the link.</param>
        /// <param name="sourceProperty">The name of the property on the source object which represents a link from the source to the target object.</param> 
        /// <param name="target">The target object involved in the link which is bound to the source object also specified in this call.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/>, <paramref name="sourceProperty"/> or <paramref name="target"/> are null.</exception>
        /// <exception cref="InvalidOperationException">if source or target are detached</exception>
        /// <exception cref="InvalidOperationException">if source or target are in added state</exception> 
        /// <exception cref="InvalidOperationException">if sourceProperty is not a collection</exception>
        public void DeleteLink(object source, string sourceProperty, object target) 
        { 
            bool delay = this.EnsureRelatable(source, sourceProperty, target, EntityStates.Deleted);
 
            RelatedEnd existing = null;
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.TryGetValue(relation, out existing) && (EntityStates.Added == existing.State))
            {   // Added -> Detached 
                this.DetachExistingLink(existing);
            } 
            else 
            {
                if (delay) 
                {   // can't have non-added relationship when source or target is in added state
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithInsertEnd);
                }
 
                if (null == existing)
                {   // detached -> deleted 
                    this.bindings.Add(relation, relation); 
                    this.objectToResource[source].RelatedLinkCount++;
                    existing = relation; 
                }

                if (EntityStates.Deleted != existing.State)
                { 
                    existing.State = EntityStates.Deleted;
 
                    this.IncrementChange(existing); 
                    this.IncrementChange(this.objectToResource[source]);
                    this.IncrementChange(this.objectToResource[target]); 
                }
            }
        }
 
        /// <summary>
        /// Notifies the context that a modified link exists between the <paramref name="source"/> and <paramref name="target"/> objects 
        /// and that the link is represented via the source.<paramref name="sourceProperty"/> which is a reference. 
        /// The context adds this link to the set of modified created links to be sent to
        /// the data service on the next call to SaveChanges(). 
        /// </summary>
        /// <remarks>
        /// Links are one way relationships.  If a back pointer exists (ie. two way association),
        /// this method should be called a second time to notify the context object of the second link. 
        /// </remarks>
        /// <param name="source">Source object participating in the link.</param> 
        /// <param name="sourceProperty">The name of the property on the source object which represents a link from the source to the target object.</param> 
        /// <param name="target">The target object involved in the link which is bound to the source object also specified in this call.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/>, <paramref name="sourceProperty"/> or <paramref name="target"/> are null.</exception> 
        /// <exception cref="InvalidOperationException">if link already exists</exception>
        /// <exception cref="InvalidOperationException">if source or target are detached</exception>
        /// <exception cref="InvalidOperationException">if source or target are in deleted state</exception>
        /// <exception cref="InvalidOperationException">if sourceProperty is not a reference property</exception> 
        public void SetLink(object source, string sourceProperty, object target)
        { 
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Modified); 

            RelatedEnd relation = this.DetachReferenceLink(source, sourceProperty, target, MergeOption.NoTracking); 
            if (null == relation)
            {
                relation = new RelatedEnd(source, sourceProperty, target);
                this.bindings.Add(relation, relation); 
            }
 
            Debug.Assert( 
                0 == relation.State ||
                IncludeLinkState(relation.State), 
                "set link entity state");

            if (EntityStates.Modified != relation.State)
            { 
                relation.State = EntityStates.Modified;
                this.objectToResource[source].RelatedLinkCount++; 
                this.IncrementChange(relation); 
            }
        } 

        #endregion

        #region AddObject, AttachTo, DeleteObject, Detach, TryGetEntity, TryGetUri 
        /// <summary>
        /// Add entity into the context in the Added state for tracking. 
        /// It does not follow the object graph and add related objects. 
        /// </summary>
        /// <param name="entitySetName">EntitySet for the object to be added.</param> 
        /// <param name="entity">entity graph to add</param>
        /// <exception cref="ArgumentNullException">if entitySetName is null</exception>
        /// <exception cref="ArgumentException">if entitySetName is empty</exception>
        /// <exception cref="ArgumentNullException">if entity is null</exception> 
        /// <exception cref="ArgumentException">if entity does not have a key property</exception>
        /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception> 
        /// <remarks> 
        /// Any leading or trailing forward slashes will automatically be trimmed from entitySetName.
        /// Objects in the added state don't have an Identity. 
        /// </remarks>
        public void AddObject(string entitySetName, object entity)
        {
            this.ValidateEntitySetName(ref entitySetName); 
            ValidateEntityWithKey(entity);
 
            Uri editLink = Util.CreateUri(entitySetName, UriKind.Relative); 
            ResourceBox resource = new ResourceBox(NoIdentity, editLink, entity);
            resource.State = EntityStates.Added; 

            try
            {
                this.objectToResource.Add(entity, resource); 
            }
            catch (ArgumentException) 
            { 
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained);
            } 

            this.IncrementChange(resource);
        }
 
        /// <summary>
        /// Attach entity into the context in the Unchanged state for tracking. 
        /// It does not follow the object graph and attach related objects. 
        /// If entity was already being tracked by the context, will be changed to the Unchanged state.
        /// </summary> 
        /// <param name="entitySetName">EntitySet for the object to be attached.</param>
        /// <param name="entity">entity graph to attach</param>
        /// <exception cref="ArgumentNullException">if entitySetName is null</exception>
        /// <exception cref="ArgumentException">if entitySetName is empty</exception> 
        /// <exception cref="ArgumentNullException">if entity is null</exception>
        /// <exception cref="ArgumentException">if entity does not have a key property</exception> 
        /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception> 
        public void AttachTo(string entitySetName, object entity)
        { 
            this.AttachTo(entitySetName, entity, NoETag);
        }

        /// <summary> 
        /// Attach entity into the context in the Unchanged state for tracking.
        /// It does not follow the object graph and attach related objects. 
        /// If entity was already being tracked by the context, will be changed to the Unchanged state. 
        /// </summary>
        /// <param name="entitySetName">EntitySet for the object to be attached.</param> 
        /// <param name="entity">entity graph to attach</param>
        /// <param name="etag">etag</param>
        /// <exception cref="ArgumentNullException">if entitySetName is null</exception>
        /// <exception cref="ArgumentException">if entitySetName is empty</exception> 
        /// <exception cref="ArgumentNullException">if entity is null</exception>
        /// <exception cref="ArgumentException">if entity does not have a key property</exception> 
        /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704", MessageId = "etag", Justification = "represents ETag in request")]
        public void AttachTo(string entitySetName, object entity, string etag) 
        {
            this.ValidateEntitySetName(ref entitySetName);
            ValidateEntityWithKey(entity);
 
            Uri editLink = GenerateEditLinkUri(this.baseUriWithSlash, entitySetName, entity);
 
            // we fake the identity by using the generated edit link 
            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
            Uri identity = Util.ReferenceIdentity(editLink); 

            this.AttachTo(identity, editLink, etag, entity, true);
        }
 
        /// <summary>
        /// Mark an existing object being tracked by the context for deletion. 
        /// </summary> 
        /// <param name="entity">entity to be mark deleted</param>
        /// <exception cref="ArgumentNullException">if entity is null</exception> 
        /// <exception cref="InvalidOperationException">if entity is not being tracked by the context</exception>
        /// <remarks>
        /// Existings objects in the Added state become detached.
        /// </remarks> 
        public void DeleteObject(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity"); 

            ResourceBox resource = null; 
            if (!this.objectToResource.TryGetValue(entity, out resource))
            {   // detached object
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            } 

            EntityStates state = resource.State; 
            if (EntityStates.Added == state) 
            {   // added -> detach
                if ((null != resource.Identity) && 
                    !this.identityToResource.Remove(resource.Identity))
                {   // added objects can have identity via NoTracking
                    Debug.Assert(false, "didn't remove identity");
                } 

                this.DetachRelated(resource); 
 
                resource.State = EntityStates.Detached;
                bool flag = this.objectToResource.Remove(entity); 
                Debug.Assert(flag, "should have removed existing entity");
            }
            else if (EntityStates.Deleted != state)
            { 
                Debug.Assert(
                    IncludeLinkState(state), 
                    "bad state transition to deleted"); 

                this.DeleteRelated(resource); 

                resource.State = EntityStates.Deleted;
                this.IncrementChange(resource);
            } 
        }
 
        /// <summary> 
        /// Detach entity from the context.
        /// </summary> 
        /// <param name="entity">entity to detach.</param>
        /// <returns>true if object was detached</returns>
        /// <exception cref="ArgumentNullException">if entity is null</exception>
        public bool Detach(object entity) 
        {
            Util.CheckArgumentNull(entity, "entity"); 
 
            ResourceBox resource = null;
            if (this.objectToResource.TryGetValue(entity, out resource)) 
            {
                return this.DetachResource(resource);
            }
 
            return false;
        } 
 
        /// <summary>
        /// Mark an existing object for update in the context. 
        /// </summary>
        /// <param name="entity">entity to be mark for update</param>
        /// <exception cref="ArgumentNullException">if entity is null</exception>
        /// <exception cref="ArgumentException">if entity is detached</exception> 
        public void UpdateObject(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity"); 

            ResourceBox resource = null; 
            if (!this.objectToResource.TryGetValue(entity, out resource))
            {
                throw Error.Argument(Strings.Context_EntityNotContained, "entity");
            } 

            if (EntityStates.Unchanged == resource.State) 
            { 
                resource.State = EntityStates.Modified;
                this.IncrementChange(resource); 
            }
        }

        /// <summary> 
        /// Find tracked entity by its identity.
        /// </summary> 
        /// <remarks>entities in added state are not likely to have a identity</remarks> 
        /// <typeparam name="TEntity">entity type</typeparam>
        /// <param name="identity">identity</param> 
        /// <param name="entity">entity being tracked by context</param>
        /// <returns>true if entity was found</returns>
        /// <exception cref="ArgumentNullException">identity is null</exception>
        public bool TryGetEntity<TEntity>(Uri identity, out TEntity entity) where TEntity : class 
        {
            entity = null; 
            Util.CheckArgumentNull(identity, "relativeUri"); 

            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink 
            identity = Util.ReferenceIdentity(identity);

            EntityStates state;
            entity = (TEntity)this.TryGetEntity(identity, null, MergeOption.AppendOnly, out state); 
            return (null != entity);
        } 
 
        /// <summary>
        /// Identity uri for tracked entity. 
        /// Though the identity might use a dereferencable scheme, you MUST NOT assume it can be dereferenced.
        /// </summary>
        /// <remarks>Entities in added state are not likely to have an identity.</remarks>
        /// <param name="entity">entity being tracked by context</param> 
        /// <param name="identity">identity</param>
        /// <returns>true if entity is being tracked and has a identity</returns> 
        /// <exception cref="ArgumentNullException">entity is null</exception> 
        public bool TryGetUri(object entity, out Uri identity)
        { 
            identity = null;
            Util.CheckArgumentNull(entity, "entity");

            ResourceBox resource = null; 
            if (this.objectToResource.TryGetValue(entity, out resource) &&
                (null != resource.Identity)) 
            { 
                // DereferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
                identity = Util.DereferenceIdentity(resource.Identity); 
            }

            return (null != identity);
        } 

        /// <summary> 
        /// Handle response by looking at status and possibly throwing an exception. 
        /// </summary>
        /// <param name="statusCode">response status code</param> 
        /// <param name="responseVersion">Version string on the response header; possibly null.</param>
        /// <param name="getResponseStream">delegate to get response stream</param>
        /// <param name="throwOnFailure">throw or return on failure</param>
        /// <returns>exception on failure</returns> 
        internal static Exception HandleResponse(
            HttpStatusCode statusCode, 
            string responseVersion, 
            Func<Stream> getResponseStream,
            bool throwOnFailure) 
        {
            InvalidOperationException failure = null;
            if (!CanHandleResponseVersion(responseVersion))
            { 
                string description = Strings.Context_VersionNotSupported(
                    responseVersion, 
                    XmlConstants.DataServiceClientVersionCurrentMajor, 
                    XmlConstants.DataServiceClientVersionCurrentMinor);
                failure = Error.InvalidOperation(description); 
            }

            if (failure == null && !WebUtil.SuccessStatusCode(statusCode))
            { 
                failure = GetResponseText(getResponseStream, statusCode);
            } 
 
            if (failure != null && throwOnFailure)
            { 
                throw failure;
            }

            return failure; 
        }
 
        /// <summary>response materialization has an identity to attach to the inserted object</summary> 
        /// <param name="identity">identity of entity</param>
        /// <param name="editLink">edit link of entity</param> 
        /// <param name="entity">inserted object</param>
        /// <param name="etag">etag of attached object</param>
        internal void AttachIdentity(Uri identity, Uri editLink, object entity, string etag)
        {   // insert->unchanged 
            Debug.Assert(null != identity && identity.IsAbsoluteUri, "must have identity");
 
            this.EnsureIdentityToResource(); 

            ResourceBox resource = this.objectToResource[entity]; 
            Debug.Assert(EntityStates.Added == resource.State, "didn't find expected entity in added state");

            if ((null != resource.Identity) &&
                !this.identityToResource.Remove(resource.Identity)) 
            {
                Debug.Assert(false, "didn't remove added identity"); 
            } 

            resource.ETag = etag; 
            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink;

            resource.State = EntityStates.Unchanged; 

            this.identityToResource.Add(identity, resource); 
        } 

        /// <summary>use location from header to generate initial edit and identity</summary> 
        /// <param name="entity">entity in added state</param>
        /// <param name="location">location from post header</param>
        internal void AttachLocation(object entity, string location)
        { 
            Debug.Assert(null != entity, "null != entity");
            Uri editLink = new Uri(location, UriKind.Absolute); 
            Uri identity = Util.ReferenceIdentity(editLink); 

            this.EnsureIdentityToResource(); 

            ResourceBox resource = this.objectToResource[entity];
            Debug.Assert(EntityStates.Added == resource.State, "didn't find expected entity in added state");
 
            if ((null != resource.Identity) &&
                !this.identityToResource.Remove(resource.Identity)) 
            { 
                Debug.Assert(false, "didn't remove added identity");
            } 

            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink;
            this.identityToResource.Add(identity, resource); 
        }
 
        /// <summary> 
        /// Track a binding.
        /// </summary> 
        /// <param name="source">Source resource.</param>
        /// <param name="sourceProperty">Property on the source resource that relates to the target resource.</param>
        /// <param name="target">Target resource.</param>
        /// <param name="linkMerge">merge operation</param> 
        internal void AttachLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        { 
            this.EnsureRelatable(source, sourceProperty, target, EntityStates.Unchanged); 

            RelatedEnd existing = null; 
            RelatedEnd relation = new RelatedEnd(source, sourceProperty, target);
            if (this.bindings.TryGetValue(relation, out existing))
            {
                switch (linkMerge) 
                {
                    case MergeOption.AppendOnly: 
                        break; 

                    case MergeOption.OverwriteChanges: 
                        relation = existing;
                        break;

                    case MergeOption.PreserveChanges: 
                        if ((EntityStates.Added == existing.State) ||
                            (EntityStates.Unchanged == existing.State) || 
                            (EntityStates.Modified == existing.State && null != existing.TargetResouce)) 
                        {
                            relation = existing; 
                        }

                        break;
 
                    case MergeOption.NoTracking: // public API point should throw if link exists
                        throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained); 
                } 
            }
            else 
            {
                bool collectionProperty = (null != ClientType.Create(source.GetType()).GetProperty(sourceProperty, false).CollectionType);
                if (collectionProperty || (null == (existing = this.DetachReferenceLink(source, sourceProperty, target, linkMerge))))
                { 
                    this.bindings.Add(relation, relation);
                    this.objectToResource[source].RelatedLinkCount++; 
                    this.IncrementChange(relation); 
                }
                else if (!((MergeOption.AppendOnly == linkMerge) || 
                           (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State)))
                {
                    // AppendOnly doesn't change state or target
                    // OverWriteChanges changes target and state 
                    // PreserveChanges changes target if unchanged, leaves modified target and state alone
                    relation = existing; 
                } 
            }
 
            relation.State = EntityStates.Unchanged;
        }

        /// <summary> 
        /// Attach entity into the context in the Unchanged state.
        /// </summary> 
        /// <param name="identity">Identity for the object to be attached.</param> 
        /// <param name="editLink">EntitySet for the object to be attached.</param>
        /// <param name="etag">etag for the entity</param> 
        /// <param name="entity">entity graph to attach</param>
        /// <param name="fail">fail for public api else change existing relationship to unchanged</param>
        /// <exception cref="ArgumentException">if entitySetName is empty</exception>
        /// <exception cref="ArgumentNullException">if entitySetName is null</exception> 
        /// <exception cref="ArgumentNullException">if entity is null</exception>
        /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception> 
        internal void AttachTo(Uri identity, Uri editLink, string etag, object entity, bool fail) 
        {
            Debug.Assert((null != identity && identity.IsAbsoluteUri), "must have identity"); 
            Debug.Assert(null != editLink, "must have editLink");
            Debug.Assert(null != entity && ClientType.Create(entity.GetType()).HasKeys, "entity must have keys to attach");

            this.EnsureIdentityToResource(); 

            Debug.Assert(identity.IsAbsoluteUri, "Uri is not absolute"); 
 
            ResourceBox resource;
            this.objectToResource.TryGetValue(entity, out resource); 

            ResourceBox existing;
            this.identityToResource.TryGetValue(identity, out existing);
 
            if (fail && (null != resource))
            { 
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained); 
            }
            else if (resource != existing) 
            {
                throw Error.InvalidOperation(Strings.Context_DifferentEntityAlreadyContained);
            }
            else if (null == resource) 
            {
                resource = new ResourceBox(identity, editLink, entity); 
                this.IncrementChange(resource); 

                this.objectToResource.Add(entity, resource); 
                this.identityToResource.Add(identity, resource);
            }

            resource.State = EntityStates.Unchanged; 
            resource.ETag = etag;
        } 
 
        #endregion
 
        /// <summary>
        /// create the request object
        /// </summary>
        /// <param name="requestUri">requestUri</param> 
        /// <param name="method">updating</param>
        /// <param name="allowAnyType">Whether the request/response should request/assume ATOM or any MIME type</param> 
        /// <param name="contentType">content type for the request</param> 
        /// <returns>a request ready to get a response</returns>
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType) 
        {
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri");
            Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.baseUriWithSlash, requestUri), "context is not base of request uri"); 

            Debug.Assert( 
                Object.ReferenceEquals(XmlConstants.HttpMethodDelete, method) || 
                Object.ReferenceEquals(XmlConstants.HttpMethodGet, method) ||
                Object.ReferenceEquals(XmlConstants.HttpMethodPost, method) || 
                Object.ReferenceEquals(XmlConstants.HttpMethodPut, method) ||
                Object.ReferenceEquals(XmlConstants.HttpMethodMerge, method),
                "unexpected http method string reference");
 
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
 
#if !ASTORIA_LIGHT  // Credentials not available 
            if (null != this.Credentials)
            { 
                request.Credentials = this.Credentials;
            }
#endif
 
#if !ASTORIA_LIGHT  // Timeout not available
            if (0 != this.timeout) 
            { 
                request.Timeout = (int)Math.Min(Int32.MaxValue, new TimeSpan(0, 0, this.timeout).TotalMilliseconds);
            } 
#endif

#if !ASTORIA_LIGHT // KeepAlive not available
            request.KeepAlive = true; 
#endif
 
#if !ASTORIA_LIGHT // UserAgent not available 
            request.UserAgent = "Microsoft ADO.NET Data Services";
#endif 

            if (this.UsePostTunneling &&
                (!Object.ReferenceEquals(XmlConstants.HttpMethodPost, method)) &&
                (!Object.ReferenceEquals(XmlConstants.HttpMethodGet, method))) 
            {
                request.Headers[XmlConstants.HttpXMethod] = method; 
                request.Method = XmlConstants.HttpMethodPost; 
            }
            else 
            {
                request.Method = method;
            }
 
#if !ASTORIA_LIGHT // Data.Services http stack
            // Fires whenever a new HttpWebRequest has been created 
            // The event fires early - before the client library sets many of its required property values. 
            // This ensures the client library has the last say on the value of mandated properties
            // such as the HTTP verb  being used for the request. 
            if (this.SendingRequest != null)
            {
                SendingRequestEventArgs args = new SendingRequestEventArgs(request);
                this.SendingRequest(this, args); 
                if (!Object.ReferenceEquals(args.Request, request))
                { 
                    request = (HttpWebRequest)args.Request; 
                }
            } 
#endif

            request.Accept = allowAnyType ?
                    XmlConstants.MimeAny : 
                    (XmlConstants.MimeApplicationAtom + "," + XmlConstants.MimeApplicationXml);
            request.Headers[HttpRequestHeader.AcceptCharset] = XmlConstants.Utf8Encoding; 
 
            // Always sending the version along allows the server to fail before processing.
            request.Headers[XmlConstants.HttpDataServiceVersion] = XmlConstants.DataServiceClientVersionCurrent; 
            request.Headers[XmlConstants.HttpMaxDataServiceVersion] = XmlConstants.DataServiceClientVersionCurrent;

#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available
            bool allowStreamBuffering = false; 
#endif
            bool removeXMethod = true; 
 
            if (!Object.ReferenceEquals(XmlConstants.HttpMethodGet, method))
            { 
                Debug.Assert(!String.IsNullOrEmpty(contentType), "Content-Type must be specified for non get operation");
                request.ContentType = contentType;
                if (Object.ReferenceEquals(XmlConstants.HttpMethodDelete, method))
                { 
                    request.ContentLength = 0;
                } 
#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available 
                // else
                {   // always set to workaround NullReferenceException in HttpWebRequest.GetResponse when ContentLength = 0 
                    allowStreamBuffering = true;
                }
#endif
 
                if (this.UsePostTunneling && (!Object.ReferenceEquals(XmlConstants.HttpMethodPost, method)))
                { 
                    request.Headers[XmlConstants.HttpXMethod] = method; 
                    method = XmlConstants.HttpMethodPost;
                    removeXMethod = false; 
                }
            }
            else
            { 
                Debug.Assert(contentType == null, "Content-Type for get methods should be null");
            } 
 
#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available
            // When AllowWriteStreamBuffering is true, the data is buffered in memory so it is ready to be resent 
            // in the event of redirections or authentication requests.
            request.AllowWriteStreamBuffering = allowStreamBuffering;
#endif
 
            ICollection<string> headers;
#if !ASTORIA_LIGHT  // alternate Headers.AllKeys 
            headers = request.Headers.AllKeys; 
#else
            headers = request.Headers.Headers; 
#endif

            if (headers.Contains(XmlConstants.HttpRequestIfMatch))
            { 
#if !ASTORIA_LIGHT  // alternate IfMatch header doesn't work
                request.Headers.Remove(HttpRequestHeader.IfMatch); 
#endif 
            }
 
            if (removeXMethod && headers.Contains(XmlConstants.HttpXMethod))
            {
#if !ASTORIA_LIGHT  // alternate HttpXMethod header doesn't work
                request.Headers.Remove(XmlConstants.HttpXMethod); 
#endif
            } 
 
            request.Method = method;
            return request; 
        }

        /// <summary>
        /// get an enumerable materializes the objects the response 
        /// </summary>
        /// <param name="response">http response</param> 
        /// <param name="elementType">base elementType being materialized</param> 
        /// <param name="create">delegate to create the materializer</param>
        /// <returns>an enumerable</returns> 
        internal MaterializeAtom GetMaterializer(QueryAsyncResult response, Type elementType, Func<DataServiceContext, XmlReader, Type, object> create)
        {
            if (HttpStatusCode.NoContent == response.StatusCode)
            {   // object was deleted 
                return null;
            } 
 
            if (HttpStatusCode.Created == response.StatusCode &&
                response.ContentLength == 0) 
            {
                // created but no response back
                return null;
            } 

            if (null != response) 
            { 
                return (MaterializeAtom)this.GetMaterializer(elementType, response.ContentType, response.GetResponseStream, create);
            } 

            return null;
        }
 
        /// <summary>
        /// get an enumerable materializes the objects the response 
        /// </summary> 
        /// <param name="elementType">elementType</param>
        /// <param name="contentType">contentType</param> 
        /// <param name="response">method to get http response stream</param>
        /// <param name="create">method to create a materializer</param>
        /// <returns>an enumerable</returns>
        internal object GetMaterializer( 
            Type elementType,
            string contentType, 
            Func<Stream> response, 
            Func<DataServiceContext, XmlReader, Type, object> create)
        { 
            Debug.Assert(null != create, "null create");

            string mime = null;
            Encoding encoding = null; 
            if (!String.IsNullOrEmpty(contentType))
            { 
                HttpProcessUtility.ReadContentType(contentType, out mime, out encoding); 
            }
 
            if (String.Equals(mime, XmlConstants.MimeApplicationAtom, StringComparison.OrdinalIgnoreCase) ||
                String.Equals(mime, XmlConstants.MimeApplicationXml, StringComparison.OrdinalIgnoreCase))
            {
                System.IO.Stream rstream = response(); 
                if (null != rstream)
                { 
                    XmlReader reader = XmlUtil.CreateXmlReader(rstream, encoding); 
                    return create(this, reader, elementType);
                } 

                return null;
            }
 
            throw Error.InvalidOperation(Strings.Deserialize_UnknownMimeTypeSpecified(mime));
        } 
 
        /// <summary>
        /// Find tracked entity by its resourceUri and update its etag. 
        /// </summary>
        /// <param name="resourceUri">resource id</param>
        /// <param name="etag">updated etag</param>
        /// <param name="merger">merge option</param> 
        /// <param name="state">state of entity</param>
        /// <returns>entity if found else null</returns> 
        internal object TryGetEntity(Uri resourceUri, string etag, MergeOption merger, out EntityStates state) 
        {
            Debug.Assert(null != resourceUri, "null uri"); 
            state = EntityStates.Detached;

            ResourceBox resource = null;
            if ((null != this.identityToResource) && 
                 this.identityToResource.TryGetValue(resourceUri, out resource))
            { 
                state = resource.State; 
                if ((null != etag) && (MergeOption.AppendOnly != merger))
                {   // don't update the etag if AppendOnly 
                    resource.ETag = etag;
                }

                Debug.Assert(null != resource.Resource, "null entity"); 
                return resource.Resource;
            } 
 
            return null;
        } 

        /// <summary>
        /// get the resource box for an entity
        /// </summary> 
        /// <param name="source">entity</param>
        /// <returns>resource box</returns> 
        internal ResourceBox GetEntity(object source) 
        {
            return this.objectToResource[source]; 
        }

        /// <summary>
        /// get the related links ignoring target entity 
        /// </summary>
        /// <param name="source">source entity</param> 
        /// <param name="sourceProperty">source entity's property</param> 
        /// <returns>enumerable of related ends</returns>
        internal IEnumerable<RelatedEnd> GetLinks(object source, string sourceProperty) 
        {
            return this.bindings.Values.Where(o => (o.SourceResource == source) && (o.SourceProperty == sourceProperty));
        }
 
        /// <summary>
        /// user hook to resolve name into a type 
        /// </summary> 
        /// <param name="wireName">name to resolve</param>
        /// <param name="userType">base type associated with name</param> 
        /// <returns>null to skip node</returns>
        /// <exception cref="InvalidOperationException">if ResolveType function returns a type not assignable to the userType</exception>
        internal Type ResolveTypeFromName(string wireName, Type userType)
        { 
            Debug.Assert(null != userType, "null != baseType");
 
            if (String.IsNullOrEmpty(wireName)) 
            {
                return userType; 
            }

            Type payloadType;
            if (!ClientConvert.ToNamedType(wireName, out payloadType)) 
            {
                payloadType = null; 
 
                Func<string, Type> resolve = this.ResolveType;
                if (null != resolve) 
                {
                    // if the ResolveType property is set, call the provided type resultion method
                    payloadType = resolve(wireName);
                } 

                if (null == payloadType) 
                { 
                    // if the type resolution method returns null or the ResolveType property was not set
#if !ASTORIA_LIGHT 
                    payloadType = ClientType.ResolveFromName(wireName, userType);
#else
                    payloadType = ClientType.ResolveFromName(wireName, userType, this.GetType());
#endif 
                }
 
                if ((null != payloadType) && (!userType.IsAssignableFrom(payloadType))) 
                {
                    // throw an exception if the type from the resolver is not assignable to the expected type 
                    throw Error.InvalidOperation(Strings.Deserialize_Current(userType, payloadType));
                }
            }
 
            return payloadType ?? userType;
        } 
 
        /// <summary>
        /// The reverse of ResolveType 
        /// </summary>
        /// <param name="type">client type</param>
        /// <returns>type for the server</returns>
        internal string ResolveNameFromType(Type type) 
        {
            Debug.Assert(null != type, "null type"); 
            Func<Type, string> resolve = this.ResolveName; 
            return ((null != resolve) ? resolve(type) : (String)null);
        } 

        /// <summary>
        /// Fires the ReadingEntity event
        /// </summary> 
        /// <param name="entity">Entity being (de)serialized</param>
        /// <param name="data">XML data of the ATOM entry</param> 
        internal void FireReadingEntityEvent(object entity, XElement data) 
        {
            Debug.Assert(entity != null, "entity != null"); 
            Debug.Assert(data != null, "data != null");

            ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(entity, data);
            this.ReadingEntity(this, args); 
        }
 
        #region Ensure 

        /// <summary>Filter to verify states</summary> 
        /// <param name="x">x</param>
        /// <returns>true if added/updated/deleted</returns>
        private static bool HasModifiedResourceState(Entry x)
        { 
            Debug.Assert(
                (EntityStates.Added == x.State) || 
                (EntityStates.Modified == x.State) || 
                (EntityStates.Unchanged == x.State) ||
                (EntityStates.Deleted == x.State), 
                "entity state is not valid");

            return (EntityStates.Unchanged != x.State);
        } 

        /// <summary>modified or unchanged</summary> 
        /// <param name="x">state to test</param> 
        /// <returns>true if modified or unchanged</returns>
        private static bool IncludeLinkState(EntityStates x) 
        {
            return ((EntityStates.Modified == x) || (EntityStates.Unchanged == x));
        }
 
        #endregion
 
        /// <summary>Checks whether an ADO.NET Data Service version string can be handled.</summary> 
        /// <param name="responseVersion">Version string on the response header; possibly null.</param>
        /// <returns>true if the version can be handled; false otherwise.</returns> 
        private static bool CanHandleResponseVersion(string responseVersion)
        {
            if (!String.IsNullOrEmpty(responseVersion))
            { 
                KeyValuePair<Version, string> version;
                if (!HttpProcessUtility.TryReadVersion(responseVersion, out version)) 
                { 
                    return false;
                } 

                // For the time being, we only handle 1.0 responses.
                if (version.Key.Major != XmlConstants.DataServiceClientVersionCurrentMajor ||
                    version.Key.Minor != XmlConstants.DataServiceClientVersionCurrentMinor) 
                {
                    return false; 
                } 
            }
 
            return true;
        }

        /// <summary>generate a Uri based on key properties of the entity</summary> 
        /// <param name="baseUriWithSlash">baseUri</param>
        /// <param name="entitySetName">entitySetName</param> 
        /// <param name="entity">entity</param> 
        /// <returns>absolute uri</returns>
        private static Uri GenerateEditLinkUri(Uri baseUriWithSlash, string entitySetName, object entity) 
        {
            Debug.Assert(null != baseUriWithSlash && baseUriWithSlash.IsAbsoluteUri && baseUriWithSlash.OriginalString.EndsWith("/", StringComparison.Ordinal), "baseUriWithSlash");
            Debug.Assert(!String.IsNullOrEmpty(entitySetName) && !entitySetName.StartsWith("/", StringComparison.Ordinal), "entitySetName");
            Debug.Assert(null != entity, "entity"); 

            StringBuilder builder = new StringBuilder(); 
            builder.Append(baseUriWithSlash.AbsoluteUri); 
            builder.Append(entitySetName);
            builder.Append("("); 

            string prefix = String.Empty;
            ClientType clientType = ClientType.Create(entity.GetType());
            Debug.Assert(clientType.HasKeys, "requires keys"); 

            ClientType.ClientProperty[] keys = clientType.Properties.Where<ClientType.ClientProperty>(ClientType.ClientProperty.GetKeyProperty).ToArray(); 
            foreach (ClientType.ClientProperty property in keys) 
            {
#if ASTORIA_OPEN_OBJECT 
                Debug.Assert(!property.OpenObjectProperty, "key property values can't be OpenProperties");
#endif

                builder.Append(prefix); 
                if (1 < keys.Length)
                { 
                    builder.Append(property.PropertyName).Append("="); 
                }
 
                object value = property.GetValue(entity);
                if (null == value)
                {
                    throw Error.InvalidOperation(Strings.Serializer_NullKeysAreNotSupported(property.PropertyName)); 
                }
 
                string converted; 
                if (!ClientConvert.TryKeyPrimitiveToString(value, out converted))
                { 
                    throw Error.InvalidOperation(Strings.Deserialize_Current(typeof(string), value.GetType()));
                }

                builder.Append(converted); 
                prefix = ",";
            } 
 
            builder.Append(")");
 
            return Util.CreateUri(builder.ToString(), UriKind.Absolute);
        }

        /// <summary>Get http method string from entity resource state</summary> 
        /// <param name="state">resource state</param>
        /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param> 
        /// <returns>http method string delete, put or post</returns> 
        private static string GetEntityHttpMethod(EntityStates state, bool replaceOnUpdate)
        { 
            switch (state)
            {
                case EntityStates.Deleted:
                    return XmlConstants.HttpMethodDelete; 
                case EntityStates.Modified:
                    if (replaceOnUpdate) 
                    { 
                        return XmlConstants.HttpMethodPut;
                    } 
                    else
                    {
                        return XmlConstants.HttpMethodMerge;
                    } 

                case EntityStates.Added: 
                    return XmlConstants.HttpMethodPost; 
                default:
                    throw Error.InternalError(InternalError.UnvalidatedEntityState); 
            }
        }

        /// <summary>Get http method string from link resource state</summary> 
        /// <param name="link">resource</param>
        /// <returns>http method string put or post</returns> 
        private static string GetLinkHttpMethod(RelatedEnd link) 
        {
            bool collection = (null != ClientType.Create(link.SourceResource.GetType()).GetProperty(link.SourceProperty, false).CollectionType); 
            if (!collection)
            {
                Debug.Assert(EntityStates.Modified == link.State, "not Modified state");
                if (null == link.TargetResouce) 
                {   // REMOVE/DELETE a reference
                    return XmlConstants.HttpMethodDelete; 
                } 
                else
                {   // UPDATE/PUT a reference 
                    return XmlConstants.HttpMethodPut;
                }
            }
            else if (EntityStates.Deleted == link.State) 
            {   // you call DELETE on $links
                return XmlConstants.HttpMethodDelete; 
            } 
            else
            {   // you INSERT/POST into a collection 
                Debug.Assert(EntityStates.Added == link.State, "not Added state");
                return XmlConstants.HttpMethodPost;
            }
        } 

        /// <summary> 
        /// get the response text into a string 
        /// </summary>
        /// <param name="getResponseStream">method to get response stream</param> 
        /// <param name="statusCode">status code</param>
        /// <returns>text</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031", Justification = "Cache exception so user can examine it later")]
        private static DataServiceClientException GetResponseText(Func<Stream> getResponseStream, HttpStatusCode statusCode) 
        {
            string message = null; 
            using (System.IO.Stream stream = getResponseStream()) 
            {
                if ((null != stream) && stream.CanRead) 
                {
                    message = new StreamReader(stream).ReadToEnd();
                }
            } 

            if (String.IsNullOrEmpty(message)) 
            { 
                message = statusCode.ToString();
            } 

            return new DataServiceClientException(message, (int)statusCode);
        }
 
        /// <summary>Handle changeset response.</summary>
        /// <param name="entry">headers of changeset response</param> 
        private static void HandleResponsePost(RelatedEnd entry) 
        {
            if (!((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State && null != entry.TargetResouce))) 
            {
                Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState);
            }
 
            entry.State = EntityStates.Unchanged;
        } 
 
        /// <summary>Handle changeset response.</summary>
        /// <param name="entry">updated entity or link</param> 
        /// <param name="etag">updated etag</param>
        private static void HandleResponsePut(Entry entry, string etag)
        {
            if (entry.IsResource) 
            {
                if (EntityStates.Modified != entry.State) 
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.EntryNotModified);
                } 

                entry.State = EntityStates.Unchanged;
                ((ResourceBox)entry).ETag = etag;
            } 
            else
            { 
                RelatedEnd link = (RelatedEnd)entry; 
                if ((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State))
                { 
                    link.State = EntityStates.Unchanged;
                }
                else
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.LinkBadState);
                } 
            } 
        }
 
        /// <summary>
        /// write out an individual property value which can be a primitive or link
        /// </summary>
        /// <param name="writer">writer</param> 
        /// <param name="namespaceName">namespaceName in which we need to write the property element.</param>
        /// <param name="property">property which contains name, type, is key (if false and null value, will throw)</param> 
        /// <param name="propertyValue">property value</param> 
        private static void WriteContentProperty(XmlWriter writer, string namespaceName, ClientType.ClientProperty property, object propertyValue)
        { 
            writer.WriteStartElement(property.PropertyName, namespaceName);

            string typename = ClientConvert.GetEdmType(property.PropertyType);
            if (null != typename) 
            {
                writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.DataWebMetadataNamespace, typename); 
            } 

            if (null == propertyValue) 
            {   // <d:property adsm:null="true" />
                writer.WriteAttributeString(XmlConstants.AtomNullAttributeName, XmlConstants.DataWebMetadataNamespace, XmlConstants.XmlTrueLiteral);

                if (property.KeyProperty) 
                {
                    throw Error.InvalidOperation(Strings.Serializer_NullKeysAreNotSupported(property.PropertyName)); 
                } 
            }
            else 
            {
                string convertedValue = ClientConvert.ToString(propertyValue);
                if (0 == convertedValue.Length)
                {   // <d:property m:null="false" /> 
                    writer.WriteAttributeString(XmlConstants.AtomNullAttributeName, XmlConstants.DataWebMetadataNamespace, XmlConstants.XmlFalseLiteral);
                } 
                else 
                {   // <d:property>value</property>
                    if (Char.IsWhiteSpace(convertedValue[0]) || 
                        Char.IsWhiteSpace(convertedValue[convertedValue.Length - 1]))
                    {   // xml:space="preserve"
                        writer.WriteAttributeString(XmlConstants.XmlSpaceAttributeName, XmlConstants.XmlNamespacesNamespace, XmlConstants.XmlSpacePreserveValue);
                    } 

                    writer.WriteValue(convertedValue); 
                } 
            }
 
            writer.WriteEndElement();
        }

        /// <summary>validate <paramref name="entity"/></summary> 
        /// <param name="entity">entity to validate</param>
        /// <exception cref="ArgumentNullException">if entity was null</exception> 
        /// <exception cref="ArgumentException">if entity does not have a key property</exception> 
        private static void ValidateEntityWithKey(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity");

            if (!ClientType.Create(entity.GetType()).HasKeys)
            { 
                throw Error.Argument(Strings.Content_EntityWithoutKey, "entity");
            } 
        } 

        /// <summary> 
        /// Validate the SaveChanges Option
        /// </summary>
        /// <param name="options">options as specified by the user.</param>
        private static void ValidateSaveChangesOptions(SaveChangesOptions options) 
        {
            const SaveChangesOptions All = 
                SaveChangesOptions.ContinueOnError | 
                SaveChangesOptions.Batch |
                SaveChangesOptions.ReplaceOnUpdate; 

            // Make sure no higher order bits are set.
            if ((options | All) != All)
            { 
                throw Error.ArgumentOutOfRange("options");
            } 
 
            // Both batch and continueOnError can't be set together
            if (IsFlagSet(options, SaveChangesOptions.Batch | SaveChangesOptions.ContinueOnError)) 
            {
                throw Error.ArgumentOutOfRange("options");
            }
        } 

        /// <summary> 
        /// checks whether the given flag is set on the options 
        /// </summary>
        /// <param name="options">options as specified by the user.</param> 
        /// <param name="flag">whether the given flag is set on the options</param>
        /// <returns>true if the given flag is set, otherwise false.</returns>
        private static bool IsFlagSet(SaveChangesOptions options, SaveChangesOptions flag)
        { 
            return ((options & flag) == flag);
        } 
 
        /// <summary>
        /// Write the batch headers along with the first http header for the batch operation. 
        /// </summary>
        /// <param name="writer">Stream writer which writes to the underlying stream.</param>
        /// <param name="methodName">HTTP method name for the operation.</param>
        /// <param name="uri">uri for the operation.</param> 
        private static void WriteOperationRequestHeaders(StreamWriter writer, string methodName, string uri)
        { 
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationHttp); 
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentTransferEncoding, XmlConstants.BatchRequestContentTransferEncoding);
            writer.WriteLine(); 

            writer.WriteLine("{0} {1} {2}", methodName, uri, XmlConstants.HttpVersionInBatching);
        }
 
        /// <summary>
        /// Write the batch headers along with the first http header for the batch operation. 
        /// </summary> 
        /// <param name="writer">Stream writer which writes to the underlying stream.</param>
        /// <param name="statusCode">status code for the response.</param> 
        private static void WriteOperationResponseHeaders(StreamWriter writer, int statusCode)
        {
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationHttp);
            writer.WriteLine("{0}: {1}", XmlConstants.HttpContentTransferEncoding, XmlConstants.BatchRequestContentTransferEncoding); 
            writer.WriteLine();
 
            writer.WriteLine("{0} {1} {2}", XmlConstants.HttpVersionInBatching, statusCode, (HttpStatusCode)statusCode); 
        }
 
        /// <summary>
        /// Check to see if the resource to be inserted is a media entry, and if so
        /// setup a POST request for the media content first and turn the rest of
        /// the operation into a PUT to update the rest of the properties. 
        /// </summary>
        /// <param name="box">The resource to check/process</param> 
        /// <returns>A web request setup to do POST the media resource</returns> 
        private HttpWebRequest CheckAndProcessMediaEntry(ResourceBox box)
        { 
            //
            ClientType type = ClientType.Create(box.Resource.GetType());

            if (type.MediaDataMember == null) 
            {
                // this is not a media link entry, process normally 
                return null; 
            }
 
            HttpWebRequest mediaRequest = this.CreateRequest(box.GetResourceUri(this.baseUriWithSlash), XmlConstants.HttpMethodPost, true, XmlConstants.MimeApplicationAtom);

            if (type.MediaDataMember.MimeTypeProperty == null)
            { 
                mediaRequest.ContentType = XmlConstants.MimeApplicationOctetStream;
            } 
            else 
            {
                string mimeType = type.MediaDataMember.MimeTypeProperty.GetValue(box.Resource).ToString(); 

                if (string.IsNullOrEmpty(mimeType))
                {
                    throw Error.InvalidOperation( 
                        Strings.Context_NoContentTypeForMediaLink(
                            type.ElementTypeName, 
                            type.MediaDataMember.MimeTypeProperty.PropertyName)); 
                }
 
                mediaRequest.ContentType = mimeType;
            }

            object value = type.MediaDataMember.GetValue(box.Resource); 
            if (value == null)
            { 
                mediaRequest.ContentLength = 0; 
            }
            else 
            {
                byte[] buffer = value as byte[];
                if (buffer == null)
                { 
                    string mime;
                    Encoding encoding; 
                    HttpProcessUtility.ReadContentType(mediaRequest.ContentType, out mime, out encoding); 

                    if (encoding == null) 
                    {
                        encoding = Encoding.UTF8;
                        mediaRequest.ContentType += XmlConstants.MimeTypeUtf8Encoding;
                    } 

                    buffer = encoding.GetBytes(ClientConvert.ToString(value)); 
                } 

                mediaRequest.ContentLength = buffer.Length; 

                using (Stream s = mediaRequest.GetRequestStream())
                {
                    s.Write(buffer, 0, buffer.Length); 
                }
            } 
 
            // Convert the insert into an update for the media link entry we just created
            // (note that the identity still needs to be fixed up on the resbox once 
            // the response comes with the 'location' header; that happens during processing
            // of the response in SavedResource())
            box.State = EntityStates.Modified;
 
            return mediaRequest;
        } 
 
        /// <summary>the work to detach a resource</summary>
        /// <param name="resource">resource to detach</param> 
        /// <returns>true if detached</returns>
        private bool DetachResource(ResourceBox resource)
        {
            this.DetachRelated(resource); 

            resource.ChangeOrder = UInt32.MaxValue; 
            resource.State = EntityStates.Detached; 
            bool flag = this.objectToResource.Remove(resource.Resource);
            Debug.Assert(flag, "should have removed existing entity"); 

            if (null != resource.Identity)
            {
                flag = this.identityToResource.Remove(resource.Identity); 
                Debug.Assert(flag, "should have removed existing identity");
            } 
 
            return true;
        } 

        /// <summary>
        /// write out binding payload using POST with http method override for PUT
        /// </summary> 
        /// <param name="binding">binding</param>
        /// <returns>for non-batching its a request object ready to get a response from else null when batching</returns> 
        private HttpWebRequest CreateRequest(RelatedEnd binding) 
        {
            Debug.Assert(null != binding, "null binding"); 
            if (binding.ContentGeneratedForSave)
            {
                return null;
            } 

            ResourceBox sourceResource = this.objectToResource[binding.SourceResource]; 
            ResourceBox targetResource = (null != binding.TargetResouce) ? this.objectToResource[binding.TargetResouce] : null; 

            // these failures should only with SaveChangesOptions.ContinueOnError 
            if (null == sourceResource.Identity)
            {
                Debug.Assert(!binding.ContentGeneratedForSave, "already saved link");
                binding.ContentGeneratedForSave = true; 
                Debug.Assert(EntityStates.Added == sourceResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, sourceResource.SaveError); 
            } 
            else if ((null != targetResource) && (null == targetResource.Identity))
            { 
                Debug.Assert(!binding.ContentGeneratedForSave, "already saved link");
                binding.ContentGeneratedForSave = true;
                Debug.Assert(EntityStates.Added == targetResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, targetResource.SaveError); 
            }
 
            Debug.Assert(null != sourceResource.Identity, "missing sourceResource.Identity"); 
            return this.CreateRequest(this.CreateRequestUri(sourceResource, binding), GetLinkHttpMethod(binding), false, XmlConstants.MimeApplicationXml);
        } 

        /// <summary>create the uri for a link</summary>
        /// <param name="sourceResource">edit link of source</param>
        /// <param name="binding">link</param> 
        /// <returns>appropriate uri for link state</returns>
        private Uri CreateRequestUri(ResourceBox sourceResource, RelatedEnd binding) 
        { 
            Uri requestUri = Util.CreateUri(sourceResource.GetResourceUri(this.baseUriWithSlash), this.CreateRequestRelativeUri(binding));
            return requestUri; 
        }

        /// <summary>
        /// create the uri for the link relative to its source entity 
        /// </summary>
        /// <param name="binding">link</param> 
        /// <returns>uri</returns> 
        private Uri CreateRequestRelativeUri(RelatedEnd binding)
        { 
            Uri relative;
            bool collection = (null != ClientType.Create(binding.SourceResource.GetType()).GetProperty(binding.SourceProperty, false).CollectionType);
            if (collection && (EntityStates.Added != binding.State))
            {   // you DELETE(PUT NULL) from a collection 
                Debug.Assert(null != binding.TargetResouce, "null target in collection");
                ResourceBox targetResource = this.objectToResource[binding.TargetResouce]; 
                relative = this.baseUriWithSlash.MakeRelativeUri(targetResource.GetResourceLinkUri(this.baseUriWithSlash)); 
            }
            else 
            {   // UPDATE(PUT ID) a reference && INSERT(POST ID) into a collection
                relative = Util.CreateUri(XmlConstants.UriLinkSegment + "/" + binding.SourceProperty, UriKind.Relative);
            }
 
            Debug.Assert(!relative.IsAbsoluteUri, "should be relative uri");
            return relative; 
        } 

        /// <summary> 
        /// write content to batch text stream
        /// </summary>
        /// <param name="binding">link</param>
        /// <param name="text">batch text stream</param> 
        private void CreateRequestBatch(RelatedEnd binding, StreamWriter text)
        { 
            Uri relative = this.CreateRequestRelativeUri(binding); 
            ResourceBox sourceResource = this.objectToResource[binding.SourceResource];
            string requestString; 
            if (null != sourceResource.Identity)
            {
                requestString = this.CreateRequestUri(sourceResource, binding).AbsoluteUri;
            } 
            else
            { 
                requestString = "$" + sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) + "/" + relative.OriginalString; 
            }
 
            WriteOperationRequestHeaders(text, GetLinkHttpMethod(binding), requestString);
            text.WriteLine("{0}: {1}", XmlConstants.HttpDataServiceVersion, XmlConstants.DataServiceClientVersionCurrent);
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, binding.ChangeOrder);
 
            // if (EntityStates.Deleted || (EntityState.Modifed && null == TargetResource))
            // then the server will fail the batch section if content type exists 
            if ((EntityStates.Added == binding.State) || (EntityStates.Modified == binding.State && (null != binding.TargetResouce))) 
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationXml); 
            }
        }

        /// <summary> 
        /// create content memory stream for link
        /// </summary> 
        /// <param name="binding">link</param> 
        /// <param name="newline">should newline be written</param>
        /// <returns>memory stream</returns> 
        private MemoryStream CreateRequestData(RelatedEnd binding, bool newline)
        {
            Debug.Assert(
                (binding.State == EntityStates.Added) || 
                (binding.State == EntityStates.Modified && null != binding.TargetResouce),
                "This method must be called only when a binding is added or put"); 
            MemoryStream stream = new MemoryStream(); 
            XmlWriter writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
            ResourceBox targetResource = this.objectToResource[binding.TargetResouce]; 

            #region <uri xmlns="metadata">
            writer.WriteStartElement(XmlConstants.UriElementName, XmlConstants.DataWebMetadataNamespace);
 
            string id;
            if (null != targetResource.Identity) 
            { 
                id = Util.DereferenceIdentity(targetResource.Identity).AbsoluteUri;
            } 
            else
            {
                id = "$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture);
            } 

            writer.WriteValue(id); 
            writer.WriteEndElement(); // </uri> 
            #endregion
 
            writer.Flush();

            if (newline)
            { 
                // end the xml content stream with a newline
                stream.WriteByte((byte)'\r'); 
                stream.WriteByte((byte)'\n'); 
            }
 
            // strip the preamble.
            stream.Position = 0;
            return stream;
        } 

        /// <summary> 
        /// Create HttpWebRequest from a resource 
        /// </summary>
        /// <param name="box">resource</param> 
        /// <param name="state">resource state</param>
        /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
        /// <returns>web request</returns>
        private HttpWebRequest CreateRequest(ResourceBox box, EntityStates state, bool replaceOnUpdate) 
        {
            Debug.Assert(null != box && ((EntityStates.Added == state) || (EntityStates.Modified == state) || (EntityStates.Deleted == state)), "unexpected entity ResourceState"); 
 
            string httpMethod = GetEntityHttpMethod(state, replaceOnUpdate);
            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash); 
            HttpWebRequest request = this.CreateRequest(requestUri, httpMethod, false, XmlConstants.MimeApplicationAtom);
            if ((null != box.ETag) && ((EntityStates.Deleted == state) || (EntityStates.Modified == state)))
            {
#if !ASTORIA_LIGHT  // different way to write Request headers 
                request.Headers.Set(HttpRequestHeader.IfMatch, box.ETag);
#else 
                request.Headers[XmlConstants.HttpRequestIfMatch] = box.ETag; 
#endif
            } 

            return request;
        }
 
        /// <summary>
        /// generate batch request for entity 
        /// </summary> 
        /// <param name="box">entity</param>
        /// <param name="text">batch stream to write to</param> 
        /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
        private void CreateRequestBatch(ResourceBox box, StreamWriter text, bool replaceOnUpdate)
        {
            Debug.Assert(null != box, "null box"); 
            Debug.Assert(null != text, "null text");
 
            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash); 

            Debug.Assert(null != requestUri, "request uri is null"); 
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri");
            Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.baseUriWithSlash, requestUri), "context is not base of request uri");

            WriteOperationRequestHeaders(text, GetEntityHttpMethod(box.State, replaceOnUpdate), requestUri.AbsoluteUri); 
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, box.ChangeOrder);
            if (EntityStates.Deleted != box.State) 
            { 
                text.WriteLine("{0}: {1};{2}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationAtom, XmlConstants.MimeTypeEntry);
            } 

            if ((null != box.ETag) && (EntityStates.Deleted == box.State || EntityStates.Modified == box.State))
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpRequestIfMatch, box.ETag); 
            }
        } 
 
        /// <summary>
        /// create memory stream with entity data 
        /// </summary>
        /// <param name="box">entity</param>
        /// <param name="newline">should newline be written</param>
        /// <returns>memory stream containing data</returns> 
        private MemoryStream CreateRequestData(ResourceBox box, bool newline)
        { 
            Debug.Assert(null != box, "null box"); 
            MemoryStream stream = null;
            switch (box.State) 
            {
                case EntityStates.Deleted:
                    break;
                case EntityStates.Modified: 
                case EntityStates.Added:
                    stream = new MemoryStream(); 
                    break; 
                default:
                    Error.ThrowInternalError(InternalError.UnvalidatedEntityState); 
                    break;
            }

            if (null != stream) 
            {
                XmlWriter writer; 
                XDocument node = null; 
                if (this.WritingEntity != null)
                { 
                    // if we have to fire the WritingEntity event, buffer the content
                    // in an XElement so we can present the handler with the data
                    node = new XDocument();
                    writer = node.CreateWriter(); 
                }
                else 
                { 
                    writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
                } 

                ClientType type = ClientType.Create(box.Resource.GetType());

                string typeName = this.ResolveNameFromType(type.ElementType); 

                #region <entry xmlns="Atom" xmlns:d="DataWeb", xmlns:m="DataWebMetadata"> 
                writer.WriteStartElement(XmlConstants.AtomEntryElementName, XmlConstants.AtomNamespace); 
                writer.WriteAttributeString(XmlConstants.DataWebNamespacePrefix, XmlConstants.XmlNamespacesNamespace, this.DataNamespace);
                writer.WriteAttributeString(XmlConstants.DataWebMetadataNamespacePrefix, XmlConstants.XmlNamespacesNamespace, XmlConstants.DataWebMetadataNamespace); 

                // <category scheme='http://scheme/' term='typeName' />
                if (!String.IsNullOrEmpty(typeName))
                { 
                    writer.WriteStartElement(XmlConstants.AtomCategoryElementName, XmlConstants.AtomNamespace);
                    writer.WriteAttributeString(XmlConstants.AtomCategorySchemeAttributeName, this.typeScheme.OriginalString); 
                    writer.WriteAttributeString(XmlConstants.AtomCategoryTermAttributeName, typeName); 
                    writer.WriteEndElement();
                } 

                // <title />
                // <updated>2008-05-05T21:44:55Z</updated>
                // <author><name /></author> 
                writer.WriteElementString(XmlConstants.AtomTitleElementName, XmlConstants.AtomNamespace, String.Empty);
                writer.WriteElementString(XmlConstants.AtomUpdatedElementName, XmlConstants.AtomNamespace, XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind)); 
                writer.WriteStartElement(XmlConstants.AtomAuthorElementName, XmlConstants.AtomNamespace); 
                writer.WriteElementString(XmlConstants.AtomNameElementName, XmlConstants.AtomNamespace, String.Empty);
                writer.WriteEndElement(); 

                if (EntityStates.Modified == box.State)
                {
                    // <id>http://host/service/entityset(key)</id> 
                    writer.WriteElementString(XmlConstants.AtomIdElementName, Util.DereferenceIdentity(box.Identity).AbsoluteUri);
                } 
                else 
                {
                    writer.WriteElementString(XmlConstants.AtomIdElementName, XmlConstants.AtomNamespace, String.Empty); 
                }

                #region <link href=”%Identity%” rel=”%DataWebRelatedNamespace%%AssociationName%” type=”application/atom+xml;feed” />
                if (EntityStates.Added == box.State) 
                {
                    this.CreateRequestDataLinks(box, writer); 
                } 
                #endregion
 
                #region <content type="application/xml"><m:Properites> or <m:Properties>
                if (type.MediaDataMember == null)
                {
                    writer.WriteStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); 
                    writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.MimeApplicationXml); // empty namespace
                } 
 
                writer.WriteStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace);
 
                this.WriteContentProperties(writer, type, box.Resource);

                writer.WriteEndElement(); // </adsm:Properties>
 
                if (type.MediaDataMember == null)
                { 
                    writer.WriteEndElement(); // </atom:content> 
                }
 
                writer.WriteEndElement(); // </atom:entry>
                writer.Flush();
                writer.Close();
                #endregion 
                #endregion
 
                if (this.WritingEntity != null) 
                {
                    ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(box.Resource, node.Root); 
                    this.WritingEntity(this, args);

                    // copy the buffered XDocument to the memory stream. no easy way of avoiding
                    // the copy given that we need to know the length before scanning the stream 
                    node.Save(new StreamWriter(stream));    // defaults to UTF8 w/o preamble & Save will Flush
                } 
 
                if (newline)
                { 
                    // end the xml content stream with a newline
                    stream.WriteByte((byte)'\r');
                    stream.WriteByte((byte)'\n');
                } 

                stream.Position = 0; 
            } 

            return stream; 
        }

        /// <summary>
        /// add the related links for new entites to non-new entites 
        /// </summary>
        /// <param name="box">entity in added state</param> 
        /// <param name="writer">writer to add links to</param> 
        private void CreateRequestDataLinks(ResourceBox box, XmlWriter writer)
        { 
            Debug.Assert(EntityStates.Added == box.State, "entity not added state");

            ClientType clientType = null;
            foreach (RelatedEnd end in this.RelatedLinks(box)) 
            {
                Debug.Assert(!end.ContentGeneratedForSave, "already saved link"); 
                end.ContentGeneratedForSave = true; 

                if (null == clientType) 
                {
                    clientType = ClientType.Create(box.Resource.GetType());
                }
 
                string typeAttributeValue;
                if (null != clientType.GetProperty(end.SourceProperty, false).CollectionType) 
                { 
                    typeAttributeValue = XmlConstants.MimeApplicationAtom + ";" + XmlConstants.MimeTypeFeed;
                } 
                else
                {
                    typeAttributeValue = XmlConstants.MimeApplicationAtom + ";" + XmlConstants.MimeTypeEntry;
                } 

                Debug.Assert(null != end.TargetResouce, "null is DELETE"); 
                Uri targetIdentity = Util.DereferenceIdentity(this.objectToResource[end.TargetResouce].Identity); 

                writer.WriteStartElement(XmlConstants.AtomLinkElementName, XmlConstants.AtomNamespace); 
                writer.WriteAttributeString(XmlConstants.AtomHRefAttributeName, targetIdentity.ToString());
                writer.WriteAttributeString(XmlConstants.AtomLinkRelationAttributeName, XmlConstants.DataWebRelatedNamespace + end.SourceProperty);
                writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, typeAttributeValue);
                writer.WriteEndElement(); 
            }
        } 
 
        /// <summary>Handle response to deleted entity.</summary>
        /// <param name="entry">deleted entity</param> 
        private void HandleResponseDelete(Entry entry)
        {
            if (EntityStates.Deleted != entry.State)
            { 
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotDeleted);
            } 
 
            if (entry.IsResource)
            { 
                ResourceBox resource = (ResourceBox)entry;
                this.DetachResource(resource);
            }
            else 
            {
                this.DetachExistingLink((RelatedEnd)entry); 
            } 
        }
 
        /// <summary>Handle changeset response.</summary>
        /// <param name="entry">headers of changeset response</param>
        /// <param name="materializer">changeset response stream</param>
        /// <param name="editLink">editLink of the newly created item (non-null if materialize is null)</param> 
        /// <param name="etag">ETag header value from the server response (or null if no etag or if there is an actual response)</param>
        private void HandleResponsePost(ResourceBox entry, MaterializeAtom materializer, Uri editLink, string etag) 
        { 
            Debug.Assert((materializer != null) || (editLink != null), "must have either materializer or editLink");
 
            if (EntityStates.Added != entry.State)
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotAddedState);
            } 

            ResourceBox box = (ResourceBox)entry; 
 
            if (materializer == null)
            { 
                Uri identity = Util.ReferenceIdentity(editLink);
                this.AttachIdentity(identity, editLink, entry.Resource, etag);
            }
            else 
            {
                materializer.SetInsertingObject(box.Resource); 
 
                foreach (object x in materializer)
                { 
                    Debug.Assert(null != box.Identity, "updated inserted should always gain an identity");
                    Debug.Assert(x == box.Resource, "x == box.Resource, should have same object generated by response");
                    Debug.Assert(EntityStates.Unchanged == box.State, "should have moved out of insert");
                    Debug.Assert((null != this.identityToResource) && this.identityToResource.ContainsKey(box.Identity), "should have identity tracked"); 
                }
            } 
 
            foreach (RelatedEnd end in this.RelatedLinks(box))
            { 
                Debug.Assert(0 != end.SaveResultWasProcessed, "link should have been saved with the enty");
                if (IncludeLinkState(end.SaveResultWasProcessed))
                {
                    HandleResponsePost(end); 
                }
            } 
        } 

        /// <summary>flag results as being processed</summary> 
        /// <param name="entry">result entry being processed</param>
        /// <returns>count of related links that were also processed</returns>
        private int SaveResultProcessed(Entry entry)
        { 
            Debug.Assert(0 == entry.SaveResultWasProcessed, "this entity/link already had a result");
            entry.SaveResultWasProcessed = entry.State; 
 
            int count = 0;
            if (entry.IsResource && (EntityStates.Added == entry.State)) 
            {
                foreach (RelatedEnd end in this.RelatedLinks((ResourceBox)entry))
                {
                    Debug.Assert(end.ContentGeneratedForSave, "link should have been saved with the enty"); 
                    if (end.ContentGeneratedForSave)
                    { 
                        Debug.Assert(0 == end.SaveResultWasProcessed, "this link already had a result"); 
                        end.SaveResultWasProcessed = end.State;
                        count++; 
                    }
                }
            }
 
            return count;
        } 
 
        /// <summary>
        /// enumerate the related Modified/Unchanged links for an added item 
        /// </summary>
        /// <param name="box">entity</param>
        /// <returns>related links</returns>
        private IEnumerable<RelatedEnd> RelatedLinks(ResourceBox box) 
        {
            int related = box.RelatedLinkCount; 
            if (0 < related) 
            {
                foreach (RelatedEnd end in this.bindings.Values) 
                {
                    if (end.SourceResource == box.Resource)
                    {
                        if (null != end.TargetResouce) 
                        {   // null TargetResource is equivalent to Deleted
                            ResourceBox target = this.objectToResource[end.TargetResouce]; 
                            if (IncludeLinkState(target.SaveResultWasProcessed) || ((0 == target.SaveResultWasProcessed) && IncludeLinkState(target.State))) 
                            {
                                Debug.Assert(box.ChangeOrder < end.ChangeOrder, "saving is out of order"); 
                                yield return end;
                            }
                        }
 
                        if (0 == --related)
                        { 
                            break; 
                        }
                    } 
                }
            }

            Debug.Assert(0 == related, "related count mismatch"); 
        }
 
        /// <summary> 
        /// delete related bindings
        /// </summary> 
        /// <param name="entity">entity being deleted</param>
        private void DeleteRelated(ResourceBox entity)
        {
            List<RelatedEnd> detached = null; 
            foreach (RelatedEnd end in this.bindings.Values.Where<RelatedEnd>(entity.IsRelatedEntity))
            { 
                if (EntityStates.Added == end.State) 
                {   // added -> detached
                    (detached ?? (detached = new List<RelatedEnd>())).Add(end); 
                }
                else if (!((EntityStates.Deleted == end.State) || (EntityStates.Modified == end.State && null == end.TargetResouce)))
                {   // modified/unchanged -> deleted
                    end.State = EntityStates.Deleted; 
                    this.IncrementChange(end);
                } 
            } 

            if (null != detached) 
            {
                foreach (RelatedEnd end in detached)
                {
                    this.DetachExistingLink(end); 
                }
            } 
        } 

        /// <summary> 
        /// detach related bindings
        /// </summary>
        /// <param name="entity">detached entity</param>
        private void DetachRelated(ResourceBox entity) 
        {
            foreach (RelatedEnd end in this.bindings.Values.Where(entity.IsRelatedEntity).ToList()) 
            { 
                this.DetachExistingLink(end);
            } 
        }

        /// <summary>
        /// create the load property request 
        /// </summary>
        /// <param name="entity">entity</param> 
        /// <param name="propertyName">name of collection or reference property to load</param> 
        /// <param name="callback">The AsyncCallback delegate.</param>
        /// <param name="state">user state</param> 
        /// <returns>a aync result that you can get a response from</returns>
        private LoadPropertyAsyncResult CreateLoadPropertyRequest(object entity, string propertyName, AsyncCallback callback, object state)
        {
            ResourceBox box = this.EnsureContained(entity, "entity"); 
            Util.CheckArgumentNotEmpty(propertyName, "propertyName");
 
            ClientType type = ClientType.Create(entity.GetType()); 
            Debug.Assert(type.HasKeys, "must have keys to be contained");
 
            if (EntityStates.Added == box.State)
            {
                throw Error.InvalidOperation(Strings.Context_NoLoadWithInsertEnd);
            } 

            ClientType.ClientProperty property = type.GetProperty(propertyName, false); 
            Debug.Assert(null != property, "should have thrown if propertyName didn't exist"); 

            Uri relativeUri; 
            bool allowAnyType = false;
            if (type.MediaDataMember != null && propertyName == type.MediaDataMember.PropertyName)
            {
                // special case for requesting the "media" value of an ATOM media link entry 
                relativeUri = Util.CreateUri(XmlConstants.UriValueSegment, UriKind.Relative);
                allowAnyType = true; // $value can be of any MIME type 
            } 
            else
            { 
                relativeUri = Util.CreateUri(propertyName + (null != property.CollectionType ? "()" : String.Empty), UriKind.Relative);
            }

            Uri requestUri = Util.CreateUri(box.GetResourceUri(this.baseUriWithSlash), relativeUri); 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, allowAnyType, null);
            DataServiceRequest dataServiceRequest = DataServiceRequest.GetInstance(property.PropertyType, requestUri); 
            return new LoadPropertyAsyncResult(entity, propertyName, this, request, callback, state, dataServiceRequest); 
        }
 
        /// <summary>
        /// write the content section of the atom payload
        /// </summary>
        /// <param name="writer">writer</param> 
        /// <param name="type">resource type</param>
        /// <param name="resource">resource value</param> 
        private void WriteContentProperties(XmlWriter writer, ClientType type, object resource) 
        {
            #region <d:property>value</property> 
            foreach (ClientType.ClientProperty property in type.Properties)
            {
                // don't write mime data member or the mime type member for it
                if (property == type.MediaDataMember || 
                    (type.MediaDataMember != null &&
                     type.MediaDataMember.MimeTypeProperty == property)) 
                { 
                    continue;
                } 

                object propertyValue = property.GetValue(resource);

                if (property.IsKnownType) 
                {
                    WriteContentProperty(writer, this.DataNamespace, property, propertyValue); 
                } 
#if ASTORIA_OPEN_OBJECT
                else if (property.OpenObjectProperty) 
                {
                    foreach (KeyValuePair<string, object> pair in (IDictionary<string, object>)propertyValue)
                    {
                        if ((null == pair.Value) || ClientConvert.IsKnownType(pair.Value.GetType())) 
                        {
                            WriteContentProperty(writer, pair.Key, pair.Value, false); 
                        } 
                    }
                } 
#endif
                else if (null == property.CollectionType)
                {
                    ClientType nested = ClientType.Create(property.PropertyType); 
                    if (!nested.HasKeys)
                    { 
                        #region complex type 
                        writer.WriteStartElement(property.PropertyName, this.DataNamespace);
                        string typeName = this.ResolveNameFromType(nested.ElementType); 
                        if (!String.IsNullOrEmpty(typeName))
                        {
                            writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.DataWebMetadataNamespace, typeName);
                        } 

                        this.WriteContentProperties(writer, nested, propertyValue); 
 
                        writer.WriteEndElement();
                        #endregion 
                    }
                }
            }
            #endregion 
        }
 
        /// <summary> 
        /// detach existing link
        /// </summary> 
        /// <param name="existing">link to detach</param>
        private void DetachExistingLink(RelatedEnd existing)
        {
            Debug.Assert(EntityStates.Detached != existing.State, "already detached"); 
            bool flag = this.bindings.Remove(existing);
            Debug.Assert(flag, "didn't detach existing link"); 
 
            existing.State = EntityStates.Detached;
            this.objectToResource[existing.SourceResource].RelatedLinkCount--; 
        }

        /// <summary>
        /// find and detach link for reference property 
        /// </summary>
        /// <param name="source">source entity</param> 
        /// <param name="sourceProperty">source entity property name for target entity</param> 
        /// <param name="target">target entity</param>
        /// <param name="linkMerge">link merge option</param> 
        /// <returns>true if found and not removed</returns>
        private RelatedEnd DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            RelatedEnd existing = this.GetLinks(source, sourceProperty).FirstOrDefault(); 
            if (null != existing)
            { 
                if ((target == existing.TargetResouce) || 
                    (MergeOption.AppendOnly == linkMerge) ||
                    (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State)) 
                {
                    return existing;
                }
 
                this.DetachExistingLink(existing);
                Debug.Assert(!this.bindings.Values.Any(o => (o.SourceResource == source) && (o.SourceProperty == sourceProperty)), "only expecting one"); 
            } 

            return null; 
        }

        /// <summary>
        /// verify the resource being tracked by context 
        /// </summary>
        /// <param name="resource">resource</param> 
        /// <param name="parameterName">parameter name to include in ArgumentException</param> 
        /// <returns>The given resource.</returns>
        /// <exception cref="ArgumentException">if resource is not contained</exception> 
        private ResourceBox EnsureContained(object resource, string parameterName)
        {
            Util.CheckArgumentNull(resource, parameterName);
 
            ResourceBox box = null;
            if (!this.objectToResource.TryGetValue(resource, out box)) 
            { 
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            } 

            return box;
        }
 
        /// <summary>
        /// verify the source and target are relatable 
        /// </summary> 
        /// <param name="source">source Resource</param>
        /// <param name="sourceProperty">source Property</param> 
        /// <param name="target">target Resource</param>
        /// <param name="state">destination state of relationship to evaluate for</param>
        /// <returns>true if DeletedState and one of the ends is in the added state</returns>
        /// <exception cref="ArgumentNullException">if source or target are null</exception> 
        /// <exception cref="ArgumentException">if source or target are not contained</exception>
        /// <exception cref="ArgumentNullException">if source property is null</exception> 
        /// <exception cref="ArgumentException">if source property empty</exception> 
        /// <exception cref="InvalidOperationException">Can only relate ends with keys.</exception>
        /// <exception cref="ArgumentException">If target doesn't match property type.</exception> 
        /// <exception cref="InvalidOperationException">If adding relationship where one of the ends is in the deleted state.</exception>
        /// <exception cref="InvalidOperationException">If attaching relationship where one of the ends is in the added or deleted state.</exception>
        private bool EnsureRelatable(object source, string sourceProperty, object target, EntityStates state)
        { 
            ResourceBox sourceResource = this.EnsureContained(source, "source");
            ResourceBox targetResource = null; 
            if ((null != target) || ((EntityStates.Modified != state) && (EntityStates.Unchanged != state))) 
            {
                targetResource = this.EnsureContained(target, "target"); 
            }

            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty");
 
            ClientType type = ClientType.Create(source.GetType());
            Debug.Assert(type.HasKeys, "should be enforced by just adding an object"); 
 
            // will throw InvalidOperationException if property doesn't exist
            ClientType.ClientProperty property = type.GetProperty(sourceProperty, false); 

            if (property.IsKnownType)
            {
                throw Error.InvalidOperation(Strings.Context_RelationNotRefOrCollection); 
            }
 
            if ((EntityStates.Unchanged == state) && (null == target) && (null != property.CollectionType)) 
            {
                targetResource = this.EnsureContained(target, "target"); 
            }

            if (((EntityStates.Added == state) || (EntityStates.Deleted == state)) && (null == property.CollectionType))
            { 
                throw Error.InvalidOperation(Strings.Context_AddLinkCollectionOnly);
            } 
            else if ((EntityStates.Modified == state) && (null != property.CollectionType)) 
            {
                throw Error.InvalidOperation(Strings.Context_SetLinkReferenceOnly); 
            }

            // if (property.IsCollection) then property.PropertyType is the collection elementType
            // either way you can only have a relation ship between keyed objects 
            type = ClientType.Create(property.CollectionType ?? property.PropertyType);
            Debug.Assert(type.HasKeys, "should be enforced by just adding an object"); 
 
            if ((null != target) && !type.ElementType.IsInstanceOfType(target))
            { 
                // target is not of the correct type
                throw Error.Argument(Strings.Context_RelationNotRefOrCollection, "target");
            }
 
            if ((EntityStates.Added == state) || (EntityStates.Unchanged == state))
            { 
                if ((sourceResource.State == EntityStates.Deleted) || 
                    ((targetResource != null) && (targetResource.State == EntityStates.Deleted)))
                { 
                    // can't add/attach new relationship when source or target in deleted state
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithDeleteEnd);
                }
            } 

            if ((EntityStates.Deleted == state) || (EntityStates.Unchanged == state)) 
            { 
                if ((sourceResource.State == EntityStates.Added) ||
                    ((targetResource != null) && (targetResource.State == EntityStates.Added))) 
                {
                    // can't have non-added relationship when source or target is in added state
                    if (EntityStates.Deleted == state)
                    { 
                        return true;
                    } 
 
                    throw Error.InvalidOperation(Strings.Context_NoRelationWithInsertEnd);
                } 
            }

            return false;
        } 

        /// <summary>validate <paramref name="entitySetName"/> and trim leading and trailing forward slashes</summary> 
        /// <param name="entitySetName">resource name to validate</param> 
        /// <exception cref="ArgumentNullException">if entitySetName was null</exception>
        /// <exception cref="ArgumentException">if entitySetName was empty or contained only forward slash</exception> 
        private void ValidateEntitySetName(ref string entitySetName)
        {
            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName");
            entitySetName = entitySetName.Trim(Util.ForwardSlash); 

            Util.CheckArgumentNotEmpty(entitySetName, "entitySetName"); 
 
            Uri tmp = Util.CreateUri(entitySetName, UriKind.RelativeOrAbsolute);
            if (tmp.IsAbsoluteUri || 
                !String.IsNullOrEmpty(Util.CreateUri(this.baseUriWithSlash, tmp)
                                     .GetComponents(UriComponents.Query | UriComponents.Fragment, UriFormat.SafeUnescaped)))
            {
                throw Error.Argument(Strings.Context_EntitySetName, "entitySetName"); 
            }
        } 
 
        /// <summary>create this.identityToResource when necessary</summary>
        private void EnsureIdentityToResource() 
        {
            if (null == this.identityToResource)
            {
                System.Threading.Interlocked.CompareExchange(ref this.identityToResource, new Dictionary<Uri, ResourceBox>(), null); 
            }
        } 
 
        /// <summary>
        /// increment the resource change for sorting during submit changes 
        /// </summary>
        /// <param name="box">the resource to update the change order</param>
        private void IncrementChange(RelatedEnd box)
        { 
            box.ChangeOrder = ++this.nextChange;
        } 
 
        /// <summary>
        /// increment the resource change for sorting during submit changes 
        /// </summary>
        /// <param name="box">the resource to update the change order</param>
        private void IncrementChange(ResourceBox box)
        { 
            box.ChangeOrder = ++this.nextChange;
        } 
 
        /// <summary>
        /// Entity and LinkDescriptor base class that contains change order and state 
        /// </summary>
        internal abstract class Entry
        {
            /// <summary>change order</summary> 
            private uint changeOrder = UInt32.MaxValue;
 
            /// <summary>was content generated for the entity</summary> 
            private bool saveContentGenerated;
 
            /// <summary>was this entity save result processed</summary>
            /// <remarks>0 - no processed, otherwise reflects the previous state</remarks>
            private EntityStates saveResultProcessed;
 
            /// <summary>state</summary>
            private EntityStates state; 
 
            /// <summary>last save exception per entry</summary>
            private Exception saveError; 

            /// <summary>changeOrder</summary>
            internal uint ChangeOrder
            { 
                get { return this.changeOrder; }
                set { this.changeOrder = value; } 
            } 

            /// <summary>true if resource, false if link</summary> 
            internal abstract bool IsResource
            {
                get;
            } 

            /// <summary>was content generated for the entity</summary> 
            internal bool ContentGeneratedForSave 
            {
                get { return this.saveContentGenerated; } 
                set { this.saveContentGenerated = value; }
            }

            /// <summary>was this entity save result processed</summary> 
            internal EntityStates SaveResultWasProcessed
            { 
                get { return this.saveResultProcessed; } 
                set { this.saveResultProcessed = value; }
            } 

            /// <summary>last save exception per entry</summary>
            internal Exception SaveError
            { 
                get { return this.saveError; }
                set { this.saveError = value; } 
            } 

            /// <summary>state</summary> 
            internal EntityStates State
            {
                get { return this.state; }
                set { this.state = value; } 
            }
        } 
 
        /// <summary>
        /// An untyped container for a resource and its identity 
        /// </summary>
        [DebuggerDisplay("State = {state}, Uri = {editLink}, Element = {resource.GetType().ToString()}")]
        internal class ResourceBox : Entry
        { 
            /// <summary>uri to identitfy the entity</summary>
            /// <remarks><atom:id>identity</id></remarks> 
            private Uri identity; 

            /// <summary>uri to edit the entity</summary> 
            /// <remarks><atom:link rel="edit" href="editLink" /></remarks>
            private Uri editLink;

            // /// <summary>uri to query the entity</summary> 
            // /// <remarks><atom:link rel="self" href="queryLink" /></remarks>
            // private Uri queryLink; 
 
            /// <summary>entity ETag (concurrency token)</summary>
            private string etag; 

            /// <summary>entity</summary>
            private object resource;
 
            /// <summary>count of links for which this entity is the source</summary>
            private int relatedLinkCount; 
 
            /// <summary>constructor</summary>
            /// <param name="identity">resource Uri</param> 
            /// <param name="editLink">resource EntitySet</param>
            /// <param name="resource">non-null resource</param>
            internal ResourceBox(Uri identity, Uri editLink, object resource)
            { 
                Debug.Assert(null == identity || identity.IsAbsoluteUri, "bad identity");
                Debug.Assert(null != editLink, "null editLink"); 
                this.identity = identity; 
                this.editLink = editLink;
                this.resource = resource; 
            }

            /// <summary>this is a entity</summary>
            internal override bool IsResource 
            {
                get { return true; } 
            } 

            /// <summary>uri to edit entity</summary> 
            internal Uri EditLink
            {
                get { return this.editLink; }
                set { this.editLink = value; } 
            }
 
            /// <summary>etag</summary> 
            internal string ETag
            { 
                get { return this.etag; }
                set { this.etag = value; }
            }
 
            /// <summary>entity uri identity</summary>
            internal Uri Identity 
            { 
                get { return this.identity; }
                set { this.identity = Util.CheckArgumentNull(value, "Identity"); } 
            }

            /// <summary>count of links for which this entity is the source</summary>
            internal int RelatedLinkCount 
            {
                get { return this.relatedLinkCount; } 
                set { this.relatedLinkCount = value; } 
            }
 
            /// <summary>entity</summary>
            internal object Resource
            {
                get { return this.resource; } 
            }
 
            /// <summary>uri to edit the entity</summary> 
            /// <param name="baseUriWithSlash">baseUriWithSlash</param>
            /// <returns>absolute uri which can be used to edit the entity</returns> 
            internal Uri GetResourceUri(Uri baseUriWithSlash)
            {
                Uri result = Util.CreateUri(baseUriWithSlash, this.EditLink);
                return result; 
            }
 
            /// <summary> 
            /// uri to edit the link entry
            /// </summary> 
            /// <param name="baseUriWithSlash">baseUriWithSlash</param>
            /// <returns>absolute uri which can be used to edit the link</returns>
            internal Uri GetResourceLinkUri(Uri baseUriWithSlash)
            { 
                Uri result = Util.CreateUri(baseUriWithSlash, new Uri(XmlConstants.UriLinkSegment, UriKind.Relative));
                result = Util.CreateUri(result, this.EditLink); 
                return result; 
            }
 
            /// <summary>is the entity the same as the source or target entity</summary>
            /// <param name="related">related end</param>
            /// <returns>true if same as source or target entity</returns>
            internal bool IsRelatedEntity(RelatedEnd related) 
            {
                return ((this.resource == related.SourceResource) || (this.resource == related.TargetResouce)); 
            } 
        }
 
        /// <summary>
        /// An untyped container for a resource and its related end
        /// </summary>
        [DebuggerDisplay("State = {state}")] 
        internal sealed class RelatedEnd : Entry
        { 
            /// <summary>IEqualityComparer to compare equivalence between to related ends</summary> 
            internal static readonly IEqualityComparer<RelatedEnd> EquivalenceComparer = new EqualityComparer();
 
            /// <summary>source entity</summary>
            private readonly object source;

            /// <summary>name of property on source entity that references the target entity</summary> 
            private readonly string sourceProperty;
 
            /// <summary>target entity</summary> 
            private readonly object target;
 
            // /// <summary>Property on the target resource that relates back to the source resource</summary>
            // internal readonly string ChildProperty;

            /// <summary>constructor</summary> 
            /// <param name="source">parentResource</param>
            /// <param name="property">sourceProperty</param> 
            /// <param name="target">childResource</param> 
            internal RelatedEnd(object source, string property, object target)
            { 
                Debug.Assert(null != source, "null source");
                Debug.Assert(!String.IsNullOrEmpty(property), "null target");

                this.source = source; 
                this.sourceProperty = property;
                this.target = target; 
            } 

            /// <summary>this is a link</summary> 
            internal override bool IsResource
            {
                get { return false; }
            } 

            /// <summary>target resource</summary> 
            internal object TargetResouce 
            {
                get { return this.target; } 
            }

            /// <summary>source resource property name</summary>
            internal string SourceProperty 
            {
                get { return this.sourceProperty; } 
            } 

            /// <summary>source resource</summary> 
            internal object SourceResource
            {
                get { return this.source; }
            } 

            /// <summary> 
            /// Are the two related ends equivalent? 
            /// </summary>
            /// <param name="x">x</param> 
            /// <param name="y">y</param>
            /// <returns>true if the related ends are equivalent</returns>
            public static bool Equals(RelatedEnd x, RelatedEnd y)
            { 
                return ((x.SourceResource == y.SourceResource) &&
                        (x.TargetResouce == y.TargetResouce) && 
                        (x.SourceProperty == y.SourceProperty)); 
            }
 
            /// <summary>test for equivalence</summary>
            private sealed class EqualityComparer : IEqualityComparer<RelatedEnd>
            {
                /// <summary>test for equivalence</summary> 
                /// <param name="x">x</param>
                /// <param name="y">y</param> 
                /// <returns>true if equivalent</returns> 
                bool IEqualityComparer<RelatedEnd>.Equals(RelatedEnd x, RelatedEnd y)
                { 
                    return RelatedEnd.Equals(x, y);
                }

                /// <summary>hash code based on the contained resources</summary> 
                /// <param name="x">x</param>
                /// <returns>hash code</returns> 
                int IEqualityComparer<RelatedEnd>.GetHashCode(RelatedEnd x) 
                {
                    return (x.SourceResource.GetHashCode() ^ 
                            ((null != x.TargetResouce) ? x.TargetResouce.GetHashCode() : 0) ^
                            x.SourceProperty.GetHashCode());
                }
            } 
        }
 
        /// <summary>wrapper around loading a property from a response</summary> 
        private class LoadPropertyAsyncResult : QueryAsyncResult
        { 
            /// <summary>entity whose property is being loaded</summary>
            private readonly object entity;

            /// <summary>name of the property on the entity that is being loaded</summary> 
            private readonly string propertyName;
 
            /// <summary>constructor</summary> 
            /// <param name="entity">entity</param>
            /// <param name="propertyName">name of collection or reference property to load</param> 
            /// <param name="context">Originating context</param>
            /// <param name="request">Originating WebRequest</param>
            /// <param name="callback">user callback</param>
            /// <param name="state">user state</param> 
            /// <param name="dataServiceRequest">request object.</param>
            internal LoadPropertyAsyncResult(object entity, string propertyName, DataServiceContext context, HttpWebRequest request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest) 
                : base(context, "LoadProperty", dataServiceRequest, request, callback, state) 
            {
                this.entity = entity; 
                this.propertyName = propertyName;
            }

            /// <summary> 
            /// loading a property from a response
            /// </summary> 
            /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
            internal QueryOperationResponse LoadProperty()
            { 
                IEnumerable results = null;

                DataServiceContext context = (DataServiceContext)this.Source;
 
                ClientType type = ClientType.Create(this.entity.GetType());
                Debug.Assert(type.HasKeys, "must have keys to be contained"); 
 
                ResourceBox box = context.EnsureContained(this.entity, "entity");
 
                if (EntityStates.Added == box.State)
                {
                    throw Error.InvalidOperation(Strings.Context_NoLoadWithInsertEnd);
                } 

                ClientType.ClientProperty property = type.GetProperty(this.propertyName, false); 
                Type elementType = property.CollectionType ?? property.NullablePropertyType; 
                try
                { 
                    if (type.MediaDataMember == property)
                    {
                        results = this.ReadPropertyFromRawData(property);
                    } 
                    else
                    { 
                        results = this.ReadPropertyFromAtom(box, property); 
                    }
 
                    return this.GetResponse(results, elementType);
                }
                catch (InvalidOperationException ex)
                { 
                    QueryOperationResponse response = this.GetResponse(results, elementType);
                    if (response != null) 
                    { 
                        response.Error = ex;
                        throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, response); 
                    }

                    throw;
                } 
            }
 
            /// <summary> 
            /// Load property data from an ATOM response
            /// </summary> 
            /// <param name="box">Box pointing to the entity to load this to</param>
            /// <param name="property">The property being loaded</param>
            /// <returns>property values as IEnumerable.</returns>
            private IEnumerable ReadPropertyFromAtom(ResourceBox box, ClientType.ClientProperty property) 
            {
                DataServiceContext context = (DataServiceContext)this.Source; 
 
                bool deletedState = (EntityStates.Deleted == box.State);
 
                Type nestedType;
#if ASTORIA_OPEN_OBJECT
                if (property.OpenObjectProperty)
                { 
                    nestedType = typeof(OpenObject);
                } 
                else 
#endif
                { 
                    nestedType = property.CollectionType ?? property.NullablePropertyType;
                }

                ClientType clientType = ClientType.Create(nestedType); 

                // when setting a reference, use the entity 
                // when adding an item to a collection, use the collection object referenced by the entity 
                bool setNestedValue = false;
                object collection = this.entity; 
                if (null != property.CollectionType)
                {   // get the collection that we actually add nested
                    collection = property.GetValue(this.entity);
                    if (null == collection) 
                    {
                        setNestedValue = true; 
                        collection = Activator.CreateInstance(typeof(List<>).MakeGenericType(nestedType)); 
                    }
                } 

                Func<DataServiceContext, XmlReader, Type, object> create = delegate(DataServiceContext ctx, XmlReader reader, Type elmentType)
                {
                    return new MaterializeAtom(ctx, reader, elmentType, ctx.MergeOption); 
                };
 
                // store the results so that they can be there in the response body. 
                Type elementType = property.CollectionType ?? property.NullablePropertyType;
                IList results = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)); 

                // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                using (MaterializeAtom materializer = context.GetMaterializer(this, nestedType, create))
                { 
                    if (null != materializer)
                    { 
                        int count = 0; 
#if ASTORIA_OPEN_OBJECT
                        object openProperties = null; 
#endif
                        foreach (object child in materializer)
                        {
                            results.Add(child); 
                            count++;
#if ASTORIA_OPEN_OBJECT 
                            property.SetValue(collection, child, this.propertyName, ref openProperties, true); 
#else
                            property.SetValue(collection, child, this.propertyName, true); 
#endif

                            // via LoadProperty, you can have a property with <id> and null value
                            if ((null != child) && (MergeOption.NoTracking != materializer.MergeOptionValue) && clientType.HasKeys) 
                            {
                                if (deletedState) 
                                { 
                                    context.DeleteLink(this.entity, this.propertyName, child);
                                } 
                                else
                                {   // put link into unchanged state
                                    context.AttachLink(this.entity, this.propertyName, child, materializer.MergeOptionValue);
                                } 
                            }
                        } 
                    } 

                    // we don't do this because we are loading, not refreshing 
                    // if ((0 == count) && (MergeOption.OverwriteChanges == this.mergeOption))
                    // { property.Clear(entity); }
                }
 
                if (setNestedValue)
                { 
#if ASTORIA_OPEN_OBJECT 
                    object openProperties = null;
                    property.SetValue(this.entity, collection, this.propertyName, ref openProperties, false); 
#else
                    property.SetValue(this.entity, collection, this.propertyName, false);
#endif
                } 

                return results; 
            } 

            /// <summary> 
            /// Load property data form a raw response
            /// </summary>
            /// <param name="property">The property being loaded</param>
            /// <returns>property values as IEnumerable.</returns> 
            private IEnumerable ReadPropertyFromRawData(ClientType.ClientProperty property)
            { 
                // if this is the data property for a media entry, what comes back 
                // is the raw value (no markup)
#if ASTORIA_OPEN_OBJECT 
                object openProps = null;
#endif
                string mimeType = null;
                Encoding encoding = null; 
                Type elementType = property.CollectionType ?? property.NullablePropertyType;
                IList results = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)); 
                HttpProcessUtility.ReadContentType(this.ContentType, out mimeType, out encoding); 

                using (Stream responseStream = this.GetResponseStream()) 
                {
                    // special case byte[], and for everything else let std conversion kick-in
                    if (property.PropertyType == typeof(byte[]))
                    { 
                        int total = checked((int)this.ContentLength);
                        byte[] buffer = new byte[total]; 
                        int read = 0; 
                        while (read < total)
                        { 
                            int r = responseStream.Read(buffer, read, total - read);
                            if (r <= 0)
                            {
                                throw Error.InvalidOperation(Strings.Context_UnexpectedZeroRawRead); 
                            }
 
                            read += r; 
                        }
 
                        results.Add(buffer);

#if ASTORIA_OPEN_OBJECT
                        property.SetValue(this.entity, buffer, this.propertyName, ref openProps, false); 
#else
                        property.SetValue(this.entity, buffer, this.propertyName, false); 
#endif 
                    }
                    else 
                    {
                        StreamReader reader = new StreamReader(responseStream, encoding);
                        object convertedValue = property.PropertyType == typeof(string) ?
                                                    reader.ReadToEnd() : 
                                                    ClientConvert.ChangeType(reader.ReadToEnd(), property.PropertyType);
                        results.Add(convertedValue); 
#if ASTORIA_OPEN_OBJECT 
                        property.SetValue(this.entity, convertedValue, this.propertyName, ref openProps, false);
#else 
                        property.SetValue(this.entity, convertedValue, this.propertyName, false);
#endif
                    }
                } 

#if ASTORIA_OPEN_OBJECT 
                Debug.Assert(openProps == null, "These should not be set in this path"); 
#endif
                if (property.MimeTypeProperty != null) 
                {
                    // an implication of this 3rd-arg-null is that mime type properties cannot be open props
#if ASTORIA_OPEN_OBJECT
                    property.MimeTypeProperty.SetValue(this.entity, mimeType, null, ref openProps, false); 
                    Debug.Assert(openProps == null, "These should not be set in this path");
#else 
                    property.MimeTypeProperty.SetValue(this.entity, mimeType, null, false); 
#endif
                } 

                return results;
            }
        } 

        /// <summary> 
        /// implementation of IAsyncResult for SaveChanges 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Pending")] 
        private class SaveAsyncResult : BaseAsyncResult
        {
            /// <summary>where to pull the changes from</summary>
            private readonly DataServiceContext Context; 

            /// <summary>sorted list of entries by change order</summary> 
            private readonly List<Entry> ChangedEntries; 

            /// <summary>array of queries being executed</summary> 
            private readonly DataServiceRequest[] Queries;

            /// <summary>operations</summary>
            private readonly List<OperationResponse> Responses; 

            /// <summary>boundary used when generating batch boundary</summary> 
            private readonly string batchBoundary; 

            /// <summary>option in use for SaveChanges</summary> 
            private readonly SaveChangesOptions options;

            /// <summary>if true then async, else [....]</summary>
            private readonly bool executeAsync; 

            /// <summary>debugging trick to track number of completed requests</summary> 
            private int changesCompleted; 

            /// <summary>wrapped request</summary> 
            private PerRequest request;

            /// <summary>batch web response</summary>
            private HttpWebResponse batchResponse; 

            /// <summary>response stream for the batch</summary> 
            private Stream httpWebResponseStream; 

            /// <summary>service response</summary> 
            private DataServiceResponse service;

            /// <summary>The ResourceBox or RelatedEnd currently in flight</summary>
            private int entryIndex = -1; 

            /// <summary> 
            /// True if the current in-flight request is a media link entry POST 
            /// that needs to be followed by a PUT for the rest of the properties
            /// </summary> 
            private bool procesingMediaLinkEntry;

            /// <summary>response stream</summary>
            private BatchStream responseBatchStream; 

            /// <summary>temporary buffer when cache results from CUD op in non-batching save changes</summary> 
            private byte[] buildBatchBuffer; 

            /// <summary>temporary writer when cache results from CUD op in non-batching save changes</summary> 
            private StreamWriter buildBatchWriter;

            /// <summary>count of data actually copied</summary>
            private long copiedContentLength; 

            /// <summary>what is the changset boundary</summary> 
            private string changesetBoundary; 

            /// <summary>is a change set being cached</summary> 
            private bool changesetStarted;

            #region constructors
            /// <summary> 
            /// constructor for async operations
            /// </summary> 
            /// <param name="context">context</param> 
            /// <param name="method">method</param>
            /// <param name="queries">queries</param> 
            /// <param name="options">options</param>
            /// <param name="callback">user callback</param>
            /// <param name="state">user state object</param>
            /// <param name="async">async or [....]</param> 
            internal SaveAsyncResult(DataServiceContext context, string method, DataServiceRequest[] queries, SaveChangesOptions options, AsyncCallback callback, object state, bool async)
                : base(context, method, callback, state) 
            { 
                this.executeAsync = async;
                this.Context = context; 
                this.Queries = queries;
                this.options = options;

                this.Responses = new List<OperationResponse>(); 

                if (null == queries) 
                { 
                    #region changed entries
                    this.ChangedEntries = context.objectToResource.Values.Cast<Entry>() 
                                          .Union(context.bindings.Values.Cast<Entry>())
                                          .Where(HasModifiedResourceState)
                                          .OrderBy(o => o.ChangeOrder)
                                          .ToList(); 

                    foreach (Entry e in this.ChangedEntries) 
                    { 
                        e.ContentGeneratedForSave = false;
                        e.SaveResultWasProcessed = 0; 
                        e.SaveError = null;

                        if (!e.IsResource)
                        { 
                            object target = ((RelatedEnd)e).TargetResouce;
                            if (null != target) 
                            { 
                                Entry f = context.objectToResource[target];
                                if (EntityStates.Unchanged == f.State) 
                                {
                                    f.ContentGeneratedForSave = false;
                                    f.SaveResultWasProcessed = 0;
                                    f.SaveError = null; 
                                }
                            } 
                        } 
                    }
                    #endregion 
                }
                else
                {
                    this.ChangedEntries = new List<Entry>(); 
                }
 
                if (IsFlagSet(options, SaveChangesOptions.Batch)) 
                {
                    this.batchBoundary = XmlConstants.HttpMultipartBoundaryBatch + "_" + Guid.NewGuid().ToString(); 
                }
                else
                {
                    this.batchBoundary = XmlConstants.HttpMultipartBoundaryBatchResponse + "_" + Guid.NewGuid().ToString(); 
                    this.DataServiceResponse = new DataServiceResponse(null, -1, this.Responses, false /*batchResponse*/);
                } 
            } 
            #endregion constructor
 
            #region end

            /// <summary>generate the batch request of all changes to save</summary>
            internal DataServiceResponse DataServiceResponse 
            {
                get 
                { 
                    Debug.Assert(null != this.service, "null service");
                    return this.service; 
                }

                set
                { 
                    this.service = value;
                } 
            } 

            /// <summary>process the batch</summary> 
            /// <returns>data service response</returns>
            internal DataServiceResponse EndRequest()
            {
                if ((null != this.responseBatchStream) || (null != this.httpWebResponseStream)) 
                {
                    this.HandleBatchResponse(); 
                } 

                return this.DataServiceResponse; 
            }

            #endregion
 
            #region start a batch
 
            /// <summary>initial the async batch save changeset</summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BatchBeginRequest(bool replaceOnUpdate) 
            {
                PerRequest pereq = null;
                try
                { 
                    MemoryStream memory = this.GenerateBatchRequest(replaceOnUpdate);
                    if (null != memory) 
                    { 
                        HttpWebRequest httpWebRequest = this.CreateBatchRequest(memory);
 
                        this.request = pereq = new PerRequest();
                        pereq.Request = httpWebRequest;
                        pereq.RequestStreamContent = memory;
 
                        this.httpWebResponseStream = new MemoryStream();
 
                        int step = ++pereq.RequestStep; 

                        IAsyncResult asyncResult = httpWebRequest.BeginGetRequestStream(this.AsyncEndGetRequestStream, pereq); 

                        bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep);
                        pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously;
                    } 
                    else
                    { 
                        Debug.Assert(this.CompletedSynchronously, "completedSynchronously"); 
                        Debug.Assert(this.IsCompleted, "completed");
                    } 
                }
                catch (Exception e)
                {
                    this.HandleFailure(pereq, e); 
                    throw; // to user on BeginSaveChangeSet, will still invoke Callback
                } 
                finally 
                {
                    this.HandleCompleted(pereq); // will invoke user callback 
                }

                Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "[....] without complete");
            } 

#if !ASTORIA_LIGHT // Synchronous methods not available 
            /// <summary> 
            /// Synchronous batch request
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BatchRequest(bool replaceOnUpdate)
            {
                MemoryStream memory = this.GenerateBatchRequest(replaceOnUpdate); 
                if ((null != memory) && (0 < memory.Length))
                { 
                    HttpWebRequest httpWebRequest = this.CreateBatchRequest(memory); 
                    using (System.IO.Stream requestStream = httpWebRequest.GetRequestStream())
                    { 
                        byte[] buffer = memory.GetBuffer();
                        int bufferOffset = checked((int)memory.Position);
                        int bufferLength = checked((int)memory.Length) - bufferOffset;
 
                        // the following is useful in the debugging Immediate Window
                        // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength); 
                        requestStream.Write(buffer, bufferOffset, bufferLength); 
                    }
 
                    HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                    this.batchResponse = httpWebResponse;

                    if (null != httpWebResponse) 
                    {
                        this.httpWebResponseStream = httpWebResponse.GetResponseStream(); 
                    } 
                }
            } 
#endif
            #endregion

            #region start a non-batch requests 
            /// <summary>
            /// This starts the next change 
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            internal void BeginNextChange(bool replaceOnUpdate) 
            {
                Debug.Assert(!this.IsCompleted, "why being called if already completed?");

                // SaveCallback can't chain synchronously completed responses, caller will loop the to next change 
                PerRequest pereq = null;
                do 
                { 
                    HttpWebRequest httpWebRequest = null;
                    HttpWebResponse response = null; 
                    try
                    {
                        if (null != this.request)
                        { 
                            this.IsCompleted = true;
                            Error.ThrowInternalError(InternalError.InvalidBeginNextChange); 
                        } 

                        httpWebRequest = this.CreateNextRequest(replaceOnUpdate); 
                        if ((null != httpWebRequest) || (this.entryIndex < this.ChangedEntries.Count))
                        {
                            if (this.ChangedEntries[this.entryIndex].ContentGeneratedForSave)
                            { 
                                Debug.Assert(this.ChangedEntries[this.entryIndex] is RelatedEnd, "only expected RelatedEnd to presave");
                                Debug.Assert( 
                                    this.ChangedEntries[this.entryIndex].State == EntityStates.Added || 
                                    this.ChangedEntries[this.entryIndex].State == EntityStates.Modified,
                                    "only expected added to presave"); 
                                continue;
                            }

                            MemoryStream memoryStream = null; 
                            if (this.executeAsync)
                            { 
                                #region async 
                                this.request = pereq = new PerRequest();
                                pereq.Request = httpWebRequest; 

                                IAsyncResult asyncResult;
                                int step = ++pereq.RequestStep;
                                if (this.procesingMediaLinkEntry || (null == (memoryStream = this.CreateChangeData(this.entryIndex, false)))) 
                                {
                                    asyncResult = httpWebRequest.BeginGetResponse(this.AsyncEndGetResponse, pereq); 
                                } 
                                else
                                { 
                                    httpWebRequest.ContentLength = memoryStream.Length - memoryStream.Position;
                                    pereq.RequestStreamContent = memoryStream;
                                    asyncResult = httpWebRequest.BeginGetRequestStream(this.AsyncEndGetRequestStream, pereq);
                                } 

                                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                                pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; 
                                this.CompletedSynchronously &= reallyCompletedSynchronously;
                                #endregion 
                            }
#if !ASTORIA_LIGHT // Synchronous methods not available
                            else
                            { 
                                #region [....]
                                memoryStream = this.CreateChangeData(this.entryIndex, false); 
                                if (null != memoryStream) 
                                {
                                    byte[] buffer = memoryStream.GetBuffer(); 
                                    int bufferOffset = checked((int)memoryStream.Position);
                                    int bufferLength = checked((int)memoryStream.Length) - bufferOffset;

                                    httpWebRequest.ContentLength = bufferLength; 
                                    using (Stream stream = httpWebRequest.GetRequestStream())
                                    { 
                                        // the following is useful in the debugging Immediate Window 
                                        // string x = System.Text.Encoding.UTF8.GetString(memoryStream.GetBuffer(), bufferOffset, (int)memoryStream.Length);
                                        stream.Write(buffer, bufferOffset, bufferLength); 
                                    }
                                }

                                response = (HttpWebResponse)httpWebRequest.GetResponse(); 
                                if (!this.procesingMediaLinkEntry)
                                { 
                                    this.changesCompleted++; 
                                }
 
                                this.HandleOperationResponse(httpWebRequest, response);
                                this.HandleOperationResponseData(response);
                                this.HandleOperationEnd();
                                this.request = null; 
                                #endregion
                            } 
#endif 
                        }
                        else 
                        {
                            this.IsCompleted = true;

                            if (this.CompletedSynchronously) 
                            {
                                this.HandleCompleted(pereq); 
                            } 
                        }
                    } 
                    catch (InvalidOperationException e)
                    {
                        WebUtil.GetHttpWebResponse(e, ref response);
                        this.HandleOperationException(e, httpWebRequest, response); 
                        this.HandleCompleted(pereq);
                    } 
                    finally 
                    {
                        if (null != response) 
                        {
                            response.Close();
                        }
                    } 

                    // either everything completed synchronously until a change is saved and its state changed 
                    // and we don't return to this loop until then or something was asynchronous 
                    // and we won't continue in this loop, instead letting the inner most loop start the next request
                } 
                while (((null == pereq) || (pereq.RequestCompleted && pereq.RequestCompletedSynchronously)) && !this.IsCompleted);

                Debug.Assert(this.executeAsync || this.CompletedSynchronously, "[....] !CompletedSynchronously");
                Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "[....] without complete"); 
                Debug.Assert(this.entryIndex < this.ChangedEntries.Count || this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links");
            } 
 
            /// <summary>cleanup work to do once the batch / savechanges is complete</summary>
            protected override void CompletedRequest() 
            {
                this.buildBatchBuffer = null;
                if (null != this.buildBatchWriter)
                { 
                    Debug.Assert(!IsFlagSet(this.options, SaveChangesOptions.Batch), "should be non-batch");
                    this.HandleOperationEnd(); 
                    this.buildBatchWriter.WriteLine("--{0}--", this.batchBoundary); 

                    this.buildBatchWriter.Flush(); 
                    Debug.Assert(Object.ReferenceEquals(this.httpWebResponseStream, this.buildBatchWriter.BaseStream), "expected different stream");
                    this.httpWebResponseStream.Position = 0;

                    this.buildBatchWriter = null; 

                    // the following is useful in the debugging Immediate Window 
                    // string x = System.Text.Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); 
                    this.responseBatchStream = new BatchStream(this.httpWebResponseStream, this.batchBoundary, HttpProcessUtility.EncodingUtf8NoPreamble, false);
                } 
            }

            /// <summary>build the *Descriptor object in the ChangeList</summary>
            /// <param name="entry">entry to build from</param> 
            /// <returns>EntityDescriptor or LinkDescriptor</returns>
            private static Descriptor BuildReturn(Entry entry) 
            { 
                if (entry.IsResource)
                { 
                    ResourceBox box = (ResourceBox)entry;
                    EntityDescriptor obj = new EntityDescriptor(box.Resource, box.ETag, box.State);
                    return obj;
                } 
                else
                { 
                    RelatedEnd end = (RelatedEnd)entry; 
                    LinkDescriptor obj = new LinkDescriptor(end.SourceResource, end.SourceProperty, end.TargetResouce, end.State);
                    return obj; 
                }
            }

            /// <summary>verify non-null and not completed</summary> 
            /// <param name="value">the request in progress</param>
            /// <param name="errorcode">error code if null or completed</param> 
            /// <returns>the next step to validate CompletedSyncronously</returns> 
            private static int CompleteCheck(PerRequest value, InternalError errorcode)
            { 
                if ((null == value) || value.RequestCompleted)
                {
                    Error.ThrowInternalError(errorcode);
                } 

                return ++value.RequestStep; 
            } 

            /// <summary>verify they have the same reference</summary> 
            /// <param name="actual">the actual thing</param>
            /// <param name="expected">the expected thing</param>
            /// <param name="errorcode">error code if they are not</param>
            private static void EqualRefCheck(PerRequest actual, PerRequest expected, InternalError errorcode) 
            {
                if (!Object.ReferenceEquals(actual, expected)) 
                { 
                    Error.ThrowInternalError(errorcode);
                } 
            }

            /// <summary>Set the AsyncWait and invoke the user callback.</summary>
            /// <param name="pereq">the request object</param> 
            private void HandleCompleted(PerRequest pereq)
            { 
                if (null != pereq) 
                {
                    this.CompletedSynchronously &= pereq.RequestCompletedSynchronously; 

                    if (pereq.RequestCompleted)
                    {
                        System.Threading.Interlocked.CompareExchange(ref this.request, null, pereq); 
                        if (IsFlagSet(this.options, SaveChangesOptions.Batch))
                        {   // all competing thread must complete this before user calback is invoked 
                            System.Threading.Interlocked.CompareExchange(ref this.batchResponse, pereq.HttpWebResponse, null); 
                            pereq.HttpWebResponse = null;
                        } 

                        pereq.Dispose();
                    }
                } 

                this.HandleCompleted(); 
            } 

            /// <summary>Cache the exception that happened on the background thread for the caller of EndSaveChanges.</summary> 
            /// <param name="pereq">the request object</param>
            /// <param name="e">exception object from background thread</param>
            /// <returns>true if the exception should be rethrown</returns>
            private bool HandleFailure(PerRequest pereq, Exception e) 
            {
                if (null != pereq) 
                { 
                    pereq.RequestCompleted = true;
                } 

                return this.HandleFailure(e);
            }
 
            /// <summary>
            /// Create HttpWebRequest from the next availabe resource 
            /// </summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            /// <returns>web request</returns> 
            private HttpWebRequest CreateNextRequest(bool replaceOnUpdate)
            {
                if (!this.procesingMediaLinkEntry)
                { 
                    this.entryIndex++;
                } 
                else 
                {
                    // if we were creating a media entry before, then the "next change" 
                    // is to do the second step of the creation, a PUT to update
                    // metadata
                    this.procesingMediaLinkEntry = false;
                } 

                if (unchecked((uint)this.entryIndex < (uint)this.ChangedEntries.Count)) 
                { 
                    Entry entry = this.ChangedEntries[this.entryIndex];
                    if (entry.IsResource) 
                    {
                        ResourceBox box = (ResourceBox)entry;

                        HttpWebRequest req; 
                        if ((EntityStates.Added == entry.State) && (null != (req = this.Context.CheckAndProcessMediaEntry(box))))
                        { 
                            this.procesingMediaLinkEntry = true; 
                        }
                        else 
                        {
                            Debug.Assert(!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified");
                            req = this.Context.CreateRequest(box, entry.State, replaceOnUpdate);
                        } 

                        return req; 
                    } 

                    return this.Context.CreateRequest((RelatedEnd)entry); 
                }

                return null;
            } 

            /// <summary> 
            /// create memory stream for entry (entity or link) 
            /// </summary>
            /// <param name="index">index into changed entries</param> 
            /// <param name="newline">include newline in output</param>
            /// <returns>memory stream of data for entry</returns>
            private MemoryStream CreateChangeData(int index, bool newline)
            { 
                Entry entry = this.ChangedEntries[index];
                Debug.Assert(!entry.ContentGeneratedForSave, "already saved entity/link"); 
                entry.ContentGeneratedForSave = true; 

                if (entry.IsResource) 
                {
                    ResourceBox box = (ResourceBox)entry;
                    if (!this.procesingMediaLinkEntry)
                    { 
                        Debug.Assert(!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.procesingMediaLinkEntry || entry.State == EntityStates.Modified");
                        return this.Context.CreateRequestData(box, newline); 
                    } 
                }
                else 
                {
                    RelatedEnd link = (RelatedEnd)entry;
                    if ((EntityStates.Added == link.State) ||
                        ((EntityStates.Modified == link.State) && (null != link.TargetResouce))) 
                    {
                        return this.Context.CreateRequestData(link, newline); 
                    } 
                }
 
                return null;
            }
            #endregion
 
            #region generate batch response from non-batch
 
            /// <summary>basic separator between response</summary> 
            private void HandleOperationStart()
            { 
                this.HandleOperationEnd();

                if (null == this.httpWebResponseStream)
                { 
                    this.httpWebResponseStream = new MemoryStream();
                } 
 
                if (null == this.buildBatchWriter)
                { 
                    this.buildBatchWriter = new StreamWriter(this.httpWebResponseStream);     // defaults to UTF8 w/o preamble
                }

                if (null == this.changesetBoundary) 
                {
                    this.changesetBoundary = XmlConstants.HttpMultipartBoundaryChangesetResponse + "_" + Guid.NewGuid().ToString(); 
                } 

                this.changesetStarted = true; 
                this.buildBatchWriter.WriteLine("--{0}", this.batchBoundary);
                this.buildBatchWriter.WriteLine("{0}: {1}; boundary={2}", XmlConstants.HttpContentType, XmlConstants.MimeMultiPartMixed, this.changesetBoundary);
                this.buildBatchWriter.WriteLine();
                this.buildBatchWriter.WriteLine("--{0}", this.changesetBoundary); 
            }
 
            /// <summary>write the trailing --changesetboundary--</summary> 
            private void HandleOperationEnd()
            { 
                if (this.changesetStarted)
                {
                    Debug.Assert(null != this.buildBatchWriter, "buildBatchWriter");
                    Debug.Assert(null != this.changesetBoundary, "changesetBoundary"); 
                    this.buildBatchWriter.WriteLine();
                    this.buildBatchWriter.WriteLine("--{0}--", this.changesetBoundary); 
                    this.changesetStarted = false; 
                }
            } 

            /// <summary>operation with exception</summary>
            /// <param name="e">exception object</param>
            /// <param name="httpWebRequest">request object</param> 
            /// <param name="response">response object</param>
            private void HandleOperationException(Exception e, HttpWebRequest httpWebRequest, HttpWebResponse response) 
            { 
                if (null != response)
                { 
                    this.HandleOperationResponse(httpWebRequest, response);
                    this.HandleOperationResponseData(response);
                    this.HandleOperationEnd();
                } 
                else
                { 
                    this.HandleOperationStart(); 
                    WriteOperationResponseHeaders(this.buildBatchWriter, 500);
                    this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeTextPlain); 
                    this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentID, this.ChangedEntries[this.entryIndex].ChangeOrder);
                    this.buildBatchWriter.WriteLine();
                    this.buildBatchWriter.WriteLine(e.ToString());
                    this.HandleOperationEnd(); 
                }
 
                this.request = null; 
                if (!IsFlagSet(this.options, SaveChangesOptions.ContinueOnError))
                { 
                    this.IsCompleted = true;

                    // if it was a media link entry don't even try to do a PUT if the POST didn't succeed
                    this.procesingMediaLinkEntry = false; 
                }
            } 
 
            /// <summary>operation with HttpWebResponse</summary>
            /// <param name="httpWebRequest">request object</param> 
            /// <param name="response">response object</param>
            private void HandleOperationResponse(HttpWebRequest httpWebRequest, HttpWebResponse response)
            {
                this.HandleOperationStart(); 
                string location = null;
 
                if (this.ChangedEntries[this.entryIndex].IsResource && 
                    this.ChangedEntries[this.entryIndex].State == EntityStates.Added)
                { 
                    location = response.Headers[XmlConstants.HttpResponseLocation];

                    if (WebUtil.SuccessStatusCode(response.StatusCode))
                    { 
                        if (null != location)
                        { 
                            this.Context.AttachLocation(((ResourceBox)this.ChangedEntries[this.entryIndex]).Resource, location); 
                        }
                        else 
                        {
                            throw Error.NotSupported(Strings.Deserialize_NoLocationHeader);
                        }
                    } 
                }
 
                if ((null == location) && (null != httpWebRequest)) 
                {
                    location = httpWebRequest.RequestUri.OriginalString; 
                }

                WriteOperationResponseHeaders(this.buildBatchWriter, (int)response.StatusCode);
                foreach (string name in response.Headers.AllKeys) 
                {
                    if (XmlConstants.HttpContentLength != name) 
                    { 
                        this.buildBatchWriter.WriteLine("{0}: {1}", name, response.Headers[name]);
                    } 
                }

                this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentID, this.ChangedEntries[this.entryIndex].ChangeOrder);
                this.buildBatchWriter.WriteLine(); 
            }
 
            /// <summary> 
            /// copy the response data
            /// </summary> 
            /// <param name="response">response object</param>
            private void HandleOperationResponseData(HttpWebResponse response)
            {
                using (Stream stream = response.GetResponseStream()) 
                {
                    if (null != stream) 
                    { 
                        this.buildBatchWriter.Flush();
                        if (0 == WebUtil.CopyStream(stream, this.buildBatchWriter.BaseStream, ref this.buildBatchBuffer)) 
                        {
                            this.HandleOperationResponseNoData();
                        }
                    } 
                }
            } 
 
            /// <summary>only call when no data was written to added "Content-Length: 0"</summary>
            private void HandleOperationResponseNoData() 
            {
#if DEBUG
                MemoryStream memory = this.buildBatchWriter.BaseStream as MemoryStream;
                Debug.Assert(null != memory, "expected MemoryStream"); 
                Debug.Assert(
                    (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' && 
                    (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n', 
                    "didn't end with newline");
#endif 
                this.buildBatchWriter.BaseStream.Position -= 2;
                this.buildBatchWriter.WriteLine("{0}: {1}", XmlConstants.HttpContentLength, 0);
                this.buildBatchWriter.WriteLine();
            } 

            #endregion 
 
            /// <summary>
            /// create the web request for a batch 
            /// </summary>
            /// <param name="memory">memory stream for length</param>
            /// <returns>httpweb request</returns>
            private HttpWebRequest CreateBatchRequest(MemoryStream memory) 
            {
                Uri requestUri = Util.CreateUri(this.Context.baseUriWithSlash, Util.CreateUri("$batch", UriKind.Relative)); 
                string contentType = XmlConstants.MimeMultiPartMixed + "; " + XmlConstants.HttpMultipartBoundary + "=" + this.batchBoundary; 
                HttpWebRequest httpWebRequest = this.Context.CreateRequest(requestUri, XmlConstants.HttpMethodPost, false, contentType);
                httpWebRequest.ContentLength = memory.Length - memory.Position; 
                return httpWebRequest;
            }

            /// <summary>generate the batch request of all changes to save</summary> 
            /// <param name="replaceOnUpdate">whether we need to update MERGE or PUT method for update.</param>
            /// <returns>buffer containing data for request stream</returns> 
            private MemoryStream GenerateBatchRequest(bool replaceOnUpdate) 
            {
                this.changesetBoundary = null; 
                if (null != this.Queries)
                {
                }
                else if (0 == this.ChangedEntries.Count) 
                {
                    this.DataServiceResponse = new DataServiceResponse(null, (int)WebExceptionStatus.Success, this.Responses, true /*batchResponse*/); 
                    this.IsCompleted = true; 
                    return null;
                } 
                else
                {
                    this.changesetBoundary = XmlConstants.HttpMultipartBoundaryChangeSet + "_" + Guid.NewGuid().ToString();
                } 

                MemoryStream memory = new MemoryStream(); 
                StreamWriter text = new StreamWriter(memory);     // defaults to UTF8 w/o preamble 

                if (null != this.Queries) 
                {
                    for (int i = 0; i < this.Queries.Length; ++i)
                    {
                        Uri requestUri = Util.CreateUri(this.Context.baseUriWithSlash, this.Queries[i].RequestUri); 

                        Debug.Assert(null != requestUri, "request uri is null"); 
                        Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
                        Debug.Assert(UriUtil.UriInvariantInsensitiveIsBaseOf(this.Context.baseUriWithSlash, requestUri), "context is not base of request uri");
 
                        text.WriteLine("--{0}", this.batchBoundary);
                        WriteOperationRequestHeaders(text, XmlConstants.HttpMethodGet, requestUri.AbsoluteUri);
                        text.WriteLine();
                    } 
                }
                else if (0 < this.ChangedEntries.Count) 
                { 
                    text.WriteLine("--{0}", this.batchBoundary);
                    text.WriteLine("{0}: {1}; boundary={2}", XmlConstants.HttpContentType, XmlConstants.MimeMultiPartMixed, this.changesetBoundary); 
                    text.WriteLine();

                    for (int i = 0; i < this.ChangedEntries.Count; ++i)
                    { 
                        #region validate changeset boundary starts on newline
#if DEBUG 
                        { 
                            text.Flush();
                            Debug.Assert( 
                                (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' &&
                                (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n',
                                "boundary didn't start with newline");
                        } 
#endif
                        #endregion 
 
                        Entry entry = this.ChangedEntries[i];
                        if (entry.ContentGeneratedForSave) 
                        {
                            continue;
                        }
 
                        text.WriteLine("--{0}", this.changesetBoundary);
 
                        MemoryStream stream = this.CreateChangeData(i, true); 
                        if (entry.IsResource)
                        { 
                            ResourceBox box = (ResourceBox)entry;

                            // media link entry creation is not supported in batch mode
                            if (box.State == EntityStates.Added && 
                                ClientType.Create(box.Resource.GetType()).MediaDataMember != null)
                            { 
                                throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink); 
                            }
 
                            this.Context.CreateRequestBatch(box, text, replaceOnUpdate);
                        }
                        else
                        { 
                            this.Context.CreateRequestBatch((RelatedEnd)entry, text);
                        } 
 
                        byte[] buffer = null;
                        int bufferOffset = 0, bufferLength = 0; 
                        if (null != stream)
                        {
                            buffer = stream.GetBuffer();
                            bufferOffset = checked((int)stream.Position); 
                            bufferLength = checked((int)stream.Length) - bufferOffset;
                        } 
 
                        if (0 < bufferLength)
                        { 
                            text.WriteLine("{0}: {1}", XmlConstants.HttpContentLength, bufferLength);
                        }

                        text.WriteLine(); // NewLine separates header from message 

                        if (0 < bufferLength) 
                        { 
                            text.Flush();
                            text.BaseStream.Write(buffer, bufferOffset, bufferLength); 
                        }
                    }

                    #region validate changeset boundary ended with newline 
#if DEBUG
                    { 
                        text.Flush(); 
                        Debug.Assert(
                            (char)memory.GetBuffer()[(int)memory.Length - 2] == '\r' && 
                            (char)memory.GetBuffer()[(int)memory.Length - 1] == '\n',
                            "post CreateRequest boundary didn't start with newline");
                    }
 
#endif
                    #endregion 
 
                    // The boundary delimiter line following the last body part
                    // has two more hyphens after the boundary parameter value. 
                    text.WriteLine("--{0}--", this.changesetBoundary);
                }

                text.WriteLine("--{0}--", this.batchBoundary); 

                text.Flush(); 
                Debug.Assert(Object.ReferenceEquals(text.BaseStream, memory), "should be same"); 
                Debug.Assert(this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links");
 
                #region Validate batch format
#if DEBUG
                int testGetCount = 0;
                int testOpCount = 0; 
                int testBeginSetCount = 0;
                int testEndSetCount = 0; 
                memory.Position = 0; 
                BatchStream testBatch = new BatchStream(memory, this.batchBoundary, HttpProcessUtility.EncodingUtf8NoPreamble, true);
                while (testBatch.MoveNext()) 
                {
                    switch (testBatch.State)
                    {
                        case BatchStreamState.StartBatch: 
                        case BatchStreamState.EndBatch:
                        default: 
                            Debug.Assert(false, "shouldn't happen"); 
                            break;
 
                        case BatchStreamState.Get:
                            testGetCount++;
                            break;
 
                        case BatchStreamState.BeginChangeSet:
                            testBeginSetCount++; 
                            break; 
                        case BatchStreamState.EndChangeSet:
                            testEndSetCount++; 
                            break;
                        case BatchStreamState.Post:
                        case BatchStreamState.Put:
                        case BatchStreamState.Delete: 
                        case BatchStreamState.Merge:
                            testOpCount++; 
                            break; 
                    }
                } 

                Debug.Assert((null == this.Queries && 1 == testBeginSetCount) || (0 == testBeginSetCount), "more than one BeginChangeSet");
                Debug.Assert(testBeginSetCount == testEndSetCount, "more than one EndChangeSet");
                Debug.Assert((null == this.Queries && testGetCount == 0) || this.Queries.Length == testGetCount, "too many get count"); 
                // Debug.Assert(this.ChangedEntries.Count == testOpCount, "too many op count");
                Debug.Assert(BatchStreamState.EndBatch == testBatch.State, "should have ended propertly"); 
#endif 
                #endregion
 
                this.changesetBoundary = null;

                memory.Position = 0;
                return memory; 
            }
 
            #region handle batch response 

            /// <summary> 
            /// process the batch changeset response
            /// </summary>
            private void HandleBatchResponse()
            { 
                string boundary = this.batchBoundary;
                Encoding encoding = Encoding.UTF8; 
                Dictionary<string, string> headers = null; 
                Exception exception = null;
 
                try
                {
                    if (IsFlagSet(this.options, SaveChangesOptions.Batch))
                    { 
                        if ((null == this.batchResponse) || (HttpStatusCode.NoContent == this.batchResponse.StatusCode))
                        {   // we always expect a response to our batch POST request 
                            throw Error.InvalidOperation(Strings.Batch_ExpectedResponse(1)); 
                        }
 
                        headers = WebUtil.WrapResponseHeaders(this.batchResponse);
                        HandleResponse(
                            this.batchResponse.StatusCode,                                      // statusCode
                            this.batchResponse.Headers[XmlConstants.HttpDataServiceVersion],    // responseVersion 
                            delegate() { return this.httpWebResponseStream; },                  // getResponseStream
                            true);                                                              // throwOnFailure 
 
                        if (!BatchStream.GetBoundaryAndEncodingFromMultipartMixedContentType(this.batchResponse.ContentType, out boundary, out encoding))
                        { 
                            string mime;
                            Exception inner = null;
                            HttpProcessUtility.ReadContentType(this.batchResponse.ContentType, out mime, out encoding);
                            if (String.Equals(XmlConstants.MimeTextPlain, mime)) 
                            {
                                inner = GetResponseText(this.batchResponse.GetResponseStream, this.batchResponse.StatusCode); 
                            } 

                            throw Error.InvalidOperation(Strings.Batch_ExpectedContentType(this.batchResponse.ContentType), inner); 
                        }

                        if (null == this.httpWebResponseStream)
                        { 
                            Error.ThrowBatchExpectedResponse(InternalError.NullResponseStream);
                        } 
 
                        this.DataServiceResponse = new DataServiceResponse(headers, (int)this.batchResponse.StatusCode, this.Responses, true /*batchResponse*/);
                    } 

                    bool close = true;
                    BatchStream batchStream = null;
                    try 
                    {
                        batchStream = this.responseBatchStream ?? new BatchStream(this.httpWebResponseStream, boundary, encoding, false); 
                        this.httpWebResponseStream = null; 
                        this.responseBatchStream = null;
 
                        IEnumerable<OperationResponse> responses = this.HandleBatchResponse(batchStream);
                        if (IsFlagSet(this.options, SaveChangesOptions.Batch) && (null != this.Queries))
                        {
                            // ExecuteBatch, EndExecuteBatch 
                            close = false;
                            this.responseBatchStream = batchStream; 
 
                            this.DataServiceResponse = new DataServiceResponse(
                                (Dictionary<string, string>)this.DataServiceResponse.BatchHeaders, 
                                this.DataServiceResponse.BatchStatusCode,
                                responses,
                                true /*batchResponse*/);
                        } 
                        else
                        {   // SaveChanges, EndSaveChanges 
                            // enumerate the entire response 
                            foreach (ChangeOperationResponse response in responses)
                            { 
                                if (exception == null && response.Error != null)
                                {
                                    exception = response.Error;
                                } 
                            }
                        } 
                    } 
                    finally
                    { 
                        if (close && (null != batchStream))
                        {
                            batchStream.Close();
                        } 
                    }
                } 
                catch (InvalidOperationException ex) 
                {
                    exception = ex; 
                }

                if (exception != null)
                { 
                    if (this.DataServiceResponse == null)
                    { 
                        int statusCode = this.batchResponse == null ? (int)HttpStatusCode.InternalServerError : (int)this.batchResponse.StatusCode; 
                        this.DataServiceResponse = new DataServiceResponse(headers, statusCode, null, IsFlagSet(this.options, SaveChangesOptions.Batch));
                    } 

                    throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, exception, this.DataServiceResponse);
                }
            } 

            /// <summary> 
            /// process the batch changeset response 
            /// </summary>
            /// <param name="batch">batch stream</param> 
            /// <returns>enumerable of QueryResponse or null</returns>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506", Justification = "Central method of the API, likely to have many cross-references")]
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031", Justification = "Cache exception so user can examine it later")]
            private IEnumerable<OperationResponse> HandleBatchResponse(BatchStream batch) 
            {
                if (!batch.CanRead) 
                { 
                    yield break;
                } 

                string contentType;
                string location;
                string etag; 

                Uri editLink = null; 
 
                HttpStatusCode status;
                int changesetIndex = 0; 
                int queryCount = 0;
                int operationCount = 0;
                this.entryIndex = 0;
                while (batch.MoveNext()) 
                {
                    var contentHeaders = batch.ContentHeaders; // get the headers before materialize clears them 
 
                    Entry entry;
                    switch (batch.State) 
                    {
                        #region BeginChangeSet
                        case BatchStreamState.BeginChangeSet:
                            if ((IsFlagSet(this.options, SaveChangesOptions.Batch) && (0 != changesetIndex)) || 
                                (!IsFlagSet(this.options, SaveChangesOptions.Batch) && (this.ChangedEntries.Count <= changesetIndex)) ||
                                (0 != operationCount)) 
                            {   // for now, we only send a single batch, single changeset 
                                Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                            } 

                            break;
                        #endregion
 
                        #region EndChangeSet
                        case BatchStreamState.EndChangeSet: 
                            // move forward to next expected changelist 
                            changesetIndex++;
                            operationCount = 0; 
                            break;
                        #endregion

                        #region GetResponse 
                        case BatchStreamState.GetResponse:
                            Debug.Assert(0 == operationCount, "missing an EndChangeSet 2"); 
 
                            contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType);
                            status = (HttpStatusCode)(-1); 

                            Exception ex = null;
                            QueryOperationResponse qresponse = null;
                            try 
                            {
                                status = batch.GetStatusCode(); 
 
                                ex = HandleResponse(status, batch.GetResponseVersion(), batch.GetContentStream, false);
                                if (null == ex) 
                                {
                                    DataServiceRequest query = this.Queries[queryCount];

                                    System.Collections.IEnumerable enumerable = query.Materialize(this.Context, contentType, batch.GetContentStream); 
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, enumerable);
                                } 
                            } 
                            catch (ArgumentException e)
                            { 
                                ex = e;
                            }
                            catch (FormatException e)
                            { 
                                ex = e;
                            } 
                            catch (InvalidOperationException e) 
                            {
                                ex = e; 
                            }

                            if (null == qresponse)
                            { 
                                DataServiceRequest query = this.Queries[queryCount];
                                qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, null); 
                                qresponse.Error = ex; 
                            }
 
                            qresponse.StatusCode = (int)status;
                            queryCount++;
                            yield return qresponse;
                            break; 
                        #endregion
 
                        #region ChangeResponse 
                        case BatchStreamState.ChangeResponse:
 
                            if (this.ChangedEntries.Count <= unchecked((uint)this.entryIndex))
                            {
                                Error.ThrowBatchUnexpectedContent(InternalError.TooManyBatchResponse);
                            } 

                            HttpStatusCode statusCode = batch.GetStatusCode(); 
                            Exception error = HandleResponse(statusCode, batch.GetResponseVersion(), batch.GetContentStream, false); 
                            int index = this.ValidateContentID(contentHeaders);
 
                            try
                            {
                                entry = this.ChangedEntries[index];
                                operationCount += this.Context.SaveResultProcessed(entry); 

                                if (null != error) 
                                { 
                                    throw error;
                                } 

                                switch (entry.State)
                                {
                                    #region Post 
                                    case EntityStates.Added:
                                        if (entry.IsResource) 
                                        { 
                                            string mime = null;
                                            Encoding postEncoding = null; 
                                            contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType);
                                            contentHeaders.TryGetValue(XmlConstants.HttpResponseLocation, out location);
                                            contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag);
                                            editLink = (null != location) ? Util.CreateUri(location, UriKind.Absolute) : null; 
                                            ResourceBox box = (ResourceBox)entry;
 
                                            Stream stream = batch.GetContentStream(); 
                                            if (null != stream)
                                            { 
                                                HttpProcessUtility.ReadContentType(contentType, out mime, out postEncoding);
                                                if (!String.Equals(XmlConstants.MimeApplicationAtom, mime, StringComparison.OrdinalIgnoreCase))
                                                {
                                                    throw Error.InvalidOperation(Strings.Deserialize_UnknownMimeTypeSpecified(mime)); 
                                                }
 
                                                XmlReader reader = XmlUtil.CreateXmlReader(stream, postEncoding); 
                                                using (MaterializeAtom atom = new MaterializeAtom(this.Context, reader, box.Resource.GetType(), MergeOption.OverwriteChanges))
                                                { 
                                                    this.Context.HandleResponsePost(box, atom, editLink, etag);
                                                }
                                            }
                                            else 
                                            {
                                                if (null == editLink) 
                                                { 
                                                    string entitySetName = box.Identity.OriginalString;
                                                    editLink = GenerateEditLinkUri(this.Context.baseUriWithSlash, entitySetName, box.Resource); 
                                                }

                                                this.Context.HandleResponsePost(box, null, editLink, etag);
                                            } 
                                        }
                                        else 
                                        { 
                                            HandleResponsePost((RelatedEnd)entry);
                                        } 

                                        break;
                                    #endregion
 
                                    #region Put, Merge
                                    case EntityStates.Modified: 
                                        contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag); 
                                        HandleResponsePut(entry, etag);
                                        break; 
                                    #endregion

                                    #region Delete
                                    case EntityStates.Deleted: 
                                        this.Context.HandleResponseDelete(entry);
                                        break; 
                                    #endregion 
                                }
                            } 
                            catch (Exception e)
                            {
                                this.ChangedEntries[index].SaveError = e;
                                error = e; 
                            }
 
                            ChangeOperationResponse changeOperationResponse = new ChangeOperationResponse(contentHeaders, BuildReturn(this.ChangedEntries[index])); 
                            changeOperationResponse.StatusCode = (int)statusCode;
                            if (error != null) 
                            {
                                changeOperationResponse.Error = error;
                            }
 
                            this.Responses.Add(changeOperationResponse);
                            operationCount++; 
                            this.entryIndex++; 
                            yield return changeOperationResponse;
                            break; 
                        #endregion

                        default:
                            Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState); 
                            break;
                    } 
                } 

                Debug.Assert(batch.State == BatchStreamState.EndBatch, "unexpected batch state"); 

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if (((null == this.Queries) && ((0 == changesetIndex) || 
                                                (0 < queryCount) ||
                            (this.ChangedEntries.Any(o => o.ContentGeneratedForSave != (0 != o.SaveResultWasProcessed)) && 
                             (!IsFlagSet(this.options, SaveChangesOptions.Batch) || 
                               (null == this.ChangedEntries.FirstOrDefault(o => (null != o.SaveError))))))) ||
                    ((null != this.Queries) && (queryCount != this.Queries.Length))) 
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
 
                batch.Dispose();
            } 
 
            /// <summary>
            /// validate the content-id 
            /// </summary>
            /// <param name="contentHeaders">headers</param>
            /// <returns>return the correct ChangedEntries index</returns>
            private int ValidateContentID(Dictionary<string, string> contentHeaders) 
            {
                int contentID = 0; 
                string contentValueID; 

                if (!contentHeaders.TryGetValue(XmlConstants.HttpContentID, out contentValueID) || 
                    !Int32.TryParse(contentValueID, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out contentID))
                {
                    Error.ThrowBatchUnexpectedContent(InternalError.ChangeResponseMissingContentID);
                } 

                for (int i = 0; i < this.ChangedEntries.Count; ++i) 
                { 
                    if (this.ChangedEntries[i].ChangeOrder == contentID)
                    { 
                        return i;
                    }
                }
 
                Error.ThrowBatchUnexpectedContent(InternalError.ChangeResponseUnknownContentID);
                return -1; 
            } 

            #endregion Batch 

            #region callback handlers
            /// <summary>handle request.BeginGetRequestStream with request.EndGetRquestStream and then write out request stream</summary>
            /// <param name="asyncResult">async result</param> 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")]
            private void AsyncEndGetRequestStream(IAsyncResult asyncResult) 
            { 
                PerRequest pereq = asyncResult.AsyncState as PerRequest;
                try 
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndGetRequestCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetRequestStream
 
                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndGetRequestStream);
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndGetRequestStreamRequest); 
 
                    Stream stream = Util.NullCheck(httpWebRequest.EndGetRequestStream(asyncResult), InternalError.InvalidEndGetRequestStreamStream);
                    pereq.RequestStream = stream; 

                    MemoryStream memoryStream = Util.NullCheck(pereq.RequestStreamContent, InternalError.InvalidEndGetRequestStreamContent);
                    byte[] buffer = memoryStream.GetBuffer();
                    int bufferOffset = checked((int)memoryStream.Position); 
                    int bufferLength = checked((int)memoryStream.Length) - bufferOffset;
                    if ((null == buffer) || (0 == bufferLength)) 
                    { 
                        Error.ThrowInternalError(InternalError.InvalidEndGetRequestStreamContentLength);
                    } 

                    // the following is useful in the debugging Immediate Window
                    // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength);
                    asyncResult = stream.BeginWrite(buffer, bufferOffset, bufferLength, this.AsyncEndWrite, pereq); 

                    bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                    pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginWrite 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle reqestStream.BeginWrite with requestStream.EndWrite then BeginGetResponse</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndWrite(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndWriteCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndWrite); 
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndWriteRequest); 

                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndWriteStream); 
                    stream.EndWrite(asyncResult);

                    pereq.RequestStream = null;
                    stream.Close(); 

                    stream = pereq.RequestStreamContent; 
                    if (null != stream) 
                    {
                        pereq.RequestStreamContent = null; 
                        stream.Dispose();
                    }

                    asyncResult = httpWebRequest.BeginGetResponse(this.AsyncEndGetResponse, pereq); 

                    bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                    pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginGetResponse 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle request.BeginGetResponse with request.EndGetResponse and then copy response stream</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndGetResponse(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndGetResponseCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndGetResponse); 
                    HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndGetResponseRequest); 

                    // the httpWebResponse is kept for batching, discarded by non-batch 
                    HttpWebResponse response = null;
                    try
                    {
                        response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                    }
                    catch (WebException e) 
                    { 
                        response = (HttpWebResponse)e.Response;
                    } 

                    pereq.HttpWebResponse = Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse);

                    if (!IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                    {
                        this.HandleOperationResponse(httpWebRequest, response); 
                    } 

                    this.copiedContentLength = 0; 
                    Stream stream = response.GetResponseStream();
                    pereq.ResponseStream = stream;
                    if ((null != stream) && stream.CanRead)
                    { 
                        if (null != this.buildBatchWriter)
                        { 
                            this.buildBatchWriter.Flush(); 
                        }
 
                        if (null == this.buildBatchBuffer)
                        {
                            this.buildBatchBuffer = new byte[8000];
                        } 

                        bool reallyCompletedSynchronously = false; 
                        do 
                        {
                            asyncResult = stream.BeginRead(this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 

                            reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep);
                            pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                        } 
                        while (reallyCompletedSynchronously && !pereq.RequestCompleted && !this.IsCompleted && stream.CanRead);
                    } 
                    else 
                    {
                        pereq.RequestCompleted = true; 

                        // BeginGetResponse could fail and callback still invoked
                        if (!this.IsCompleted)
                        { 
                            this.SaveNextChange(pereq);
                        } 
                    } 
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e))
                    {
                        throw; 
                    }
                } 
                finally 
                {
                    this.HandleCompleted(pereq); 
                }
            }

            /// <summary>handle responseStream.BeginRead with responseStream.EndRead</summary> 
            /// <param name="asyncResult">async result</param>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
            private void AsyncEndRead(IAsyncResult asyncResult) 
            {
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                int count = 0;
                try
                {
                    int step = CompleteCheck(pereq, InternalError.InvalidEndReadCompleted); 
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
 
                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead); 
                    Stream stream = Util.NullCheck(pereq.ResponseStream, InternalError.InvalidEndReadStream);
 
                    count = stream.EndRead(asyncResult);
                    if (0 < count)
                    {
                        Stream outputResponse = Util.NullCheck(this.httpWebResponseStream, InternalError.InvalidEndReadCopy); 
                        outputResponse.Write(this.buildBatchBuffer, 0, count);
                        this.copiedContentLength += count; 
 
                        if (!asyncResult.CompletedSynchronously && stream.CanRead)
                        {   // if CompletedSynchronously then caller will call and we reduce risk of stack overflow 
                            bool reallyCompletedSynchronously = false;
                            do
                            {
                                asyncResult = stream.BeginRead(this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 

                                reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < pereq.RequestStep); 
                                pereq.RequestCompletedSynchronously &= reallyCompletedSynchronously; // BeginRead 
                            }
                            while (reallyCompletedSynchronously && !pereq.RequestCompleted && !this.IsCompleted && stream.CanRead); 
                        }
                    }
                    else
                    { 
                        pereq.RequestCompleted = true;
 
                        // BeginRead could fail and callback still invoked 
                        if (!this.IsCompleted)
                        { 
                            this.SaveNextChange(pereq);
                        }
                    }
                } 
                catch (Exception e)
                { 
                    if (this.HandleFailure(pereq, e)) 
                    {
                        throw; 
                    }
                }
                finally
                { 
                    this.HandleCompleted(pereq);
                } 
            } 

            /// <summary>continue with the next change</summary> 
            /// <param name="pereq">the completed per request object</param>
            private void SaveNextChange(PerRequest pereq)
            {
                Debug.Assert(this.executeAsync, "should be async"); 
                if (!pereq.RequestCompleted)
                { 
                    Error.ThrowInternalError(InternalError.SaveNextChangeIncomplete); 
                }
 
                ++pereq.RequestStep;
                EqualRefCheck(this.request, pereq, InternalError.InvalidSaveNextChange);

                if (IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                {
                    this.httpWebResponseStream.Position = 0; 
                    this.request = null; 
                    this.IsCompleted = true;
                } 
                else
                {
                    if (0 == this.copiedContentLength)
                    { 
                        this.HandleOperationResponseNoData();
                    } 
 
                    this.HandleOperationEnd();
 
                    if (!this.procesingMediaLinkEntry)
                    {
                        this.changesCompleted++;
                    } 

                    pereq.Dispose(); 
                    this.request = null; 
                    if (!pereq.RequestCompletedSynchronously)
                    {   // you can't chain synchronously completed responses without risking StackOverflow, caller will loop to next 
                        if (!this.IsCompleted)
                        {
                            this.BeginNextChange(IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate));
                        } 
                    }
                } 
            } 
            #endregion
 
            /// <summary>wrap the full request</summary>
            private sealed class PerRequest
            {
                /// <summary>ctor</summary> 
                internal PerRequest()
                { 
                    this.RequestCompletedSynchronously = true; 
                }
 
                /// <summary>active web request</summary>
                internal HttpWebRequest Request
                {
                    get; 
                    set;
                } 
 
                /// <summary>active web request stream</summary>
                internal Stream RequestStream 
                {
                    get;
                    set;
                } 

                /// <summary>content to write to request stream</summary> 
                internal MemoryStream RequestStreamContent 
                {
                    get; 
                    set;
                }

                /// <summary>web response</summary> 
                internal HttpWebResponse HttpWebResponse
                { 
                    get; 
                    set;
                } 

                /// <summary>async web response stream</summary>
                internal Stream ResponseStream
                { 
                    get;
                    set; 
                } 

                /// <summary>did the request complete all of its steps synchronously?</summary> 
                internal bool RequestCompletedSynchronously
                {
                    get;
                    set; 
                }
 
                /// <summary>did the sequence (BeginGetRequest, EndGetRequest, ... complete</summary> 
                internal bool RequestCompleted
                { 
                    get;
                    set;
                }
 
                /// <summary>
                /// If CompletedSynchronously and requestStep didn't increment, then underlying implementation lied. 
                /// </summary> 
                internal int RequestStep
                { 
                    get;
                    set;
                }
 
                /// <summary>
                /// dispose of the request object 
                /// </summary> 
                internal void Dispose()
                { 
                    Stream stream;

                    if (null != (stream = this.ResponseStream))
                    { 
                        this.ResponseStream = null;
                        stream.Dispose(); 
                    } 

                    if (null != (stream = this.RequestStreamContent)) 
                    {
                        this.RequestStreamContent = null;
                        stream.Dispose();
                    } 

                    if (null != (stream = this.RequestStream)) 
                    { 
                        this.RequestStream = null;
                        stream.Dispose(); 
                    }

                    HttpWebResponse response = this.HttpWebResponse;
                    if (null != response) 
                    {
                        response.Close(); 
                    } 

                    this.Request = null; 
                    this.RequestCompleted = true;
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        </pre>

                        </p>
                        <script type="text/javascript">
                            SyntaxHighlighter.all()
                        </script>
                        </pre>
                    </div>
                    <div class="col-sm-3" style="border: 1px solid #81919f;border-radius: 10px;">
                        <h3 style="background-color:#7899a0;margin-bottom: 5%;">Link Menu</h3>
                        <a href="http://www.amazon.com/exec/obidos/ASIN/1555583156/httpnetwoprog-20">
                            <img width="192" height="237" border="0" class="img-responsive" alt="Network programming in C#, Network Programming in VB.NET, Network Programming in .NET" src="/images/book.jpg"></a><br>
                        <span class="copy">

                            This book is available now!<br>

                            <a style="text-decoration: underline; font-family: Verdana,Geneva,Arial,Helvetica,sans-serif; color: Red; font-size: 11px; font-weight: bold;" href="http://www.amazon.com/exec/obidos/ASIN/1555583156/httpnetwoprog-20"> Buy at Amazon US</a> or <br>

                            <a style="text-decoration: underline; font-family: Verdana,Geneva,Arial,Helvetica,sans-serif; color: Red; font-size: 11px; font-weight: bold;" href="http://www.amazon.co.uk/exec/obidos/ASIN/1555583156/wwwxamlnet-21"> Buy at Amazon UK</a> <br>
                            <br>

                            <script type="text/javascript"><!--
                                google_ad_client = "pub-6435000594396515";
                                /* network.programming-in.net */
                                google_ad_slot = "3902760999";
                                google_ad_width = 160;
                                google_ad_height = 600;
                                //-->
                            </script>
                            <script type="text/javascript"
                                    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
                            </script>
                            <ul>
                                
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/Designer/WebForms/System/Web/UI/Design/WebParts/EditorPartDesigner@cs/1/EditorPartDesigner@cs
">
                                                <span style="word-wrap: break-word;">EditorPartDesigner.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/CompMod/System/ComponentModel/Component@cs/1/Component@cs
">
                                                <span style="word-wrap: break-word;">Component.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/untmp/whidbey/QFE/ndp/clr/src/BCL/System/Runtime/CompilerServices/HasCopySemanticsAttribute@cs/1/HasCopySemanticsAttribute@cs
">
                                                <span style="word-wrap: break-word;">HasCopySemanticsAttribute.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/xsp/System/Web/AspNetSynchronizationContext@cs/1/AspNetSynchronizationContext@cs
">
                                                <span style="word-wrap: break-word;">AspNetSynchronizationContext.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Shapes/path@cs/1305600/path@cs
">
                                                <span style="word-wrap: break-word;">path.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Core/CSharp/MS/Internal/Media/ParserStreamGeometryContext@cs/1/ParserStreamGeometryContext@cs
">
                                                <span style="word-wrap: break-word;">ParserStreamGeometryContext.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/untmp/whidbey/QFE/ndp/clr/src/BCL/System/DBNull@cs/1/DBNull@cs
">
                                                <span style="word-wrap: break-word;">DBNull.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/ndp/fx/src/DataEntity/System/Data/Objects/DataClasses/RelatedEnd@cs/2/RelatedEnd@cs
">
                                                <span style="word-wrap: break-word;">RelatedEnd.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/MIT/System/Web/UI/MobileControls/Design/Util/DesignerUtility@cs/1305376/DesignerUtility@cs
">
                                                <span style="word-wrap: break-word;">DesignerUtility.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DataEntity/System/Data/EntityModel/SchemaObjectModel/RelationshipEnd@cs/1305376/RelationshipEnd@cs
">
                                                <span style="word-wrap: break-word;">RelationshipEnd.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Core/CSharp/System/Windows/Media3D/RayHitTestParameters@cs/1/RayHitTestParameters@cs
">
                                                <span style="word-wrap: break-word;">RayHitTestParameters.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/Xml/System/Xml/Serialization/SoapTypeAttribute@cs/1/SoapTypeAttribute@cs
">
                                                <span style="word-wrap: break-word;">SoapTypeAttribute.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/CompMod/System/ComponentModel/ByteConverter@cs/1305376/ByteConverter@cs
">
                                                <span style="word-wrap: break-word;">ByteConverter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/WCF/IdentityModel/System/IdentityModel/CryptoHelper@cs/1305376/CryptoHelper@cs
">
                                                <span style="word-wrap: break-word;">CryptoHelper.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/Environment@cs/1305376/Environment@cs
">
                                                <span style="word-wrap: break-word;">Environment.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/clr/src/BCL/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute@cs/1/CompilerGlobalScopeAttribute@cs
">
                                                <span style="word-wrap: break-word;">CompilerGlobalScopeAttribute.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Framework/System/Windows/Markup/Localizer/BamlLocalizableResource@cs/1/BamlLocalizableResource@cs
">
                                                <span style="word-wrap: break-word;">BamlLocalizableResource.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/WinForms/Managed/System/WinForms/CheckBox@cs/1/CheckBox@cs
">
                                                <span style="word-wrap: break-word;">CheckBox.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Framework/System/Windows/Markup/Localizer/BamlLocalizableResourceKey@cs/1/BamlLocalizableResourceKey@cs
">
                                                <span style="word-wrap: break-word;">BamlLocalizableResourceKey.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Framework/System/Windows/Markup/XamlPointCollectionSerializer@cs/1/XamlPointCollectionSerializer@cs
">
                                                <span style="word-wrap: break-word;">XamlPointCollectionSerializer.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/WCF/WCF/3@5@30729@1/untmp/Orcas/SP/ndp/cdf/src/NetFx35/System@ServiceModel@Web/System/Runtime/Serialization/Json/JsonFormatReaderGenerator@cs/4/JsonFormatReaderGenerator@cs
">
                                                <span style="word-wrap: break-word;">JsonFormatReaderGenerator.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/xsp/System/Web/UI/ClientScriptManager@cs/1/ClientScriptManager@cs
">
                                                <span style="word-wrap: break-word;">ClientScriptManager.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Core/CSharp/System/Windows/Media/StreamGeometryContext@cs/1/StreamGeometryContext@cs
">
                                                <span style="word-wrap: break-word;">StreamGeometryContext.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Core/CSharp/MS/Internal/UIElementHelper@cs/1/UIElementHelper@cs
">
                                                <span style="word-wrap: break-word;">UIElementHelper.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/WinForms/Managed/System/WinForms/DateRangeEvent@cs/1/DateRangeEvent@cs
">
                                                <span style="word-wrap: break-word;">DateRangeEvent.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Core/System/Windows/Media/textformatting/TextFormatterContext@cs/1/TextFormatterContext@cs
">
                                                <span style="word-wrap: break-word;">TextFormatterContext.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/WinForms/Managed/System/WinForms/PropertyGridInternal/CategoryGridEntry@cs/1/CategoryGridEntry@cs
">
                                                <span style="word-wrap: break-word;">CategoryGridEntry.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/Net/System/Net/Mail/DelegatedStream@cs/1/DelegatedStream@cs
">
                                                <span style="word-wrap: break-word;">DelegatedStream.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/Xml/System/Xml/Core/HtmlTernaryTree@cs/1/HtmlTernaryTree@cs
">
                                                <span style="word-wrap: break-word;">HtmlTernaryTree.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/xsp/System/Web/Configuration/FormsAuthenticationUserCollection@cs/1/FormsAuthenticationUserCollection@cs
">
                                                <span style="word-wrap: break-word;">FormsAuthenticationUserCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Core/CSharp/MS/Internal/AppModel/CustomCredentialPolicy@cs/1305600/CustomCredentialPolicy@cs
">
                                                <span style="word-wrap: break-word;">CustomCredentialPolicy.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/DEVDIV/depot/DevDiv/releases/whidbey/QFE/ndp/fx/src/xsp/System/Web/UI/WebControls/DataListCommandEventArgs@cs/1/DataListCommandEventArgs@cs
">
                                                <span style="word-wrap: break-word;">DataListCommandEventArgs.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/DEVDIV/depot/DevDiv/releases/whidbey/QFE/ndp/fx/src/xsp/System/Web/UI/WebParts/WebPartDisplayModeCancelEventArgs@cs/1/WebPartDisplayModeCancelEventArgs@cs
">
                                                <span style="word-wrap: break-word;">WebPartDisplayModeCancelEventArgs.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/clr/src/BCL/System/Runtime/Remoting/DispatchChannelSink@cs/1/DispatchChannelSink@cs
">
                                                <span style="word-wrap: break-word;">DispatchChannelSink.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/UI/WebControls/DataList@cs/1/DataList@cs
">
                                                <span style="word-wrap: break-word;">DataList.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Automation/Peers/TextAutomationPeer@cs/1305600/TextAutomationPeer@cs
">
                                                <span style="word-wrap: break-word;">TextAutomationPeer.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/clr/src/BCL/System/Security/AccessControl/ACE@cs/4/ACE@cs
">
                                                <span style="word-wrap: break-word;">ACE.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/Data/System/Data/Common/SQLTypes/SQLStringStorage@cs/1/SQLStringStorage@cs
">
                                                <span style="word-wrap: break-word;">SQLStringStorage.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Core/CSharp/System/Windows/Media/DrawingCollection@cs/1305600/DrawingCollection@cs
">
                                                <span style="word-wrap: break-word;">DrawingCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/Compilation/BuildManagerHost@cs/3/BuildManagerHost@cs
">
                                                <span style="word-wrap: break-word;">BuildManagerHost.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/Xml/System/Xml/Serialization/XmlElementAttributes@cs/1/XmlElementAttributes@cs
">
                                                <span style="word-wrap: break-word;">XmlElementAttributes.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Core/CSharp/System/Windows/Media/Animation/Generated/VectorAnimationUsingKeyFrames@cs/1/VectorAnimationUsingKeyFrames@cs
">
                                                <span style="word-wrap: break-word;">VectorAnimationUsingKeyFrames.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/clr/src/BCL/System/IO/FileNotFoundException@cs/1/FileNotFoundException@cs
">
                                                <span style="word-wrap: break-word;">FileNotFoundException.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/WinForms/Managed/System/WinForms/Label@cs/2/Label@cs
">
                                                <span style="word-wrap: break-word;">Label.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/MS/Internal/AppModel/Journaling@cs/1305600/Journaling@cs
">
                                                <span style="word-wrap: break-word;">Journaling.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/wpf/src/Base/System/Windows/Rect@cs/1/Rect@cs
">
                                                <span style="word-wrap: break-word;">Rect.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/NetFx40/System@ServiceModel@Activities/System/ServiceModel/Activities/Dispatcher/BufferedReceiveManager@cs/1407647/BufferedReceiveManager@cs
">
                                                <span style="word-wrap: break-word;">BufferedReceiveManager.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/clr/src/BCL/System/Security/Cryptography/AsymmetricKeyExchangeFormatter@cs/1/AsymmetricKeyExchangeFormatter@cs
">
                                                <span style="word-wrap: break-word;">AsymmetricKeyExchangeFormatter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Services/Monitoring/system/Diagnosticts/InstanceData@cs/1305376/InstanceData@cs
">
                                                <span style="word-wrap: break-word;">InstanceData.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/XmlUtils/System/Xml/Xsl/Runtime/XmlILIndex@cs/2/XmlILIndex@cs
">
                                                <span style="word-wrap: break-word;">XmlILIndex.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/Sys/System/Configuration/ConfigXmlElement@cs/1/ConfigXmlElement@cs
">
                                                <span style="word-wrap: break-word;">ConfigXmlElement.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/Xml/System/Xml/schema/XmlSchemaException@cs/1/XmlSchemaException@cs
">
                                                <span style="word-wrap: break-word;">XmlSchemaException.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Core/CSharp/System/Windows/Media/Generated/Transform@cs/1305600/Transform@cs
">
                                                <span style="word-wrap: break-word;">Transform.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/xsp/System/Web/UI/WebControls/DataKeyCollection@cs/1/DataKeyCollection@cs
">
                                                <span style="word-wrap: break-word;">DataKeyCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/xsp/System/Web/UI/WebControls/RoleGroup@cs/1/RoleGroup@cs
">
                                                <span style="word-wrap: break-word;">RoleGroup.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/WinForms/Managed/System/WinForms/LayoutEvent@cs/1/LayoutEvent@cs
">
                                                <span style="word-wrap: break-word;">LayoutEvent.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/Designer/Drawing/System/Drawing/Design/IconEditor@cs/1/IconEditor@cs
">
                                                <span style="word-wrap: break-word;">IconEditor.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/XmlUtils/System/Xml/Xsl/XsltOld/VariableAction@cs/1305376/VariableAction@cs
">
                                                <span style="word-wrap: break-word;">VariableAction.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/WCF/WCF/3@5@30729@1/untmp/Orcas/SP/ndp/cdf/src/WCF/ServiceModel/System/ServiceModel/Channels/MsmqMessageProperty@cs/1/MsmqMessageProperty@cs
">
                                                <span style="word-wrap: break-word;">MsmqMessageProperty.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/Services/Timers/System/Timers/ElapsedEventArgs@cs/1/ElapsedEventArgs@cs
">
                                                <span style="word-wrap: break-word;">ElapsedEventArgs.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Services/Web/System/Web/Services/Discovery/DiscoveryDocumentLinksPattern@cs/1305376/DiscoveryDocumentLinksPattern@cs
">
                                                <span style="word-wrap: break-word;">DiscoveryDocumentLinksPattern.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/WF/Common/Shared/ValidationHelpers@cs/1305376/ValidationHelpers@cs
">
                                                <span style="word-wrap: break-word;">ValidationHelpers.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/CompMod/System/Diagnostics/SourceElementsCollection@cs/1/SourceElementsCollection@cs
">
                                                <span style="word-wrap: break-word;">SourceElementsCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Controls/DateTimeHelper@cs/1305600/DateTimeHelper@cs
">
                                                <span style="word-wrap: break-word;">DateTimeHelper.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Framework/System/Windows/ResourceDictionaryCollection@cs/1/ResourceDictionaryCollection@cs
">
                                                <span style="word-wrap: break-word;">ResourceDictionaryCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/CompMod/System/ComponentModel/PropertyDescriptor@cs/1/PropertyDescriptor@cs
">
                                                <span style="word-wrap: break-word;">PropertyDescriptor.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/WinForms/Managed/System/WinForms/ButtonInternal/CheckBoxPopupAdapter@cs/1/CheckBoxPopupAdapter@cs
">
                                                <span style="word-wrap: break-word;">CheckBoxPopupAdapter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/clr/src/BCL/System/IO/BinaryReader@cs/1/BinaryReader@cs
">
                                                <span style="word-wrap: break-word;">BinaryReader.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/CompMod/System/CodeDOM/CodeCompileUnit@cs/1/CodeCompileUnit@cs
">
                                                <span style="word-wrap: break-word;">CodeCompileUnit.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/WF/Common/AuthoringOM/Compiler/XomlCompilerResults@cs/1305376/XomlCompilerResults@cs
">
                                                <span style="word-wrap: break-word;">XomlCompilerResults.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/UI/WebControls/DataGridItemCollection@cs/1/DataGridItemCollection@cs
">
                                                <span style="word-wrap: break-word;">DataGridItemCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/WinForms/Managed/System/WinForms/DataGridViewSelectedCellCollection@cs/1/DataGridViewSelectedCellCollection@cs
">
                                                <span style="word-wrap: break-word;">DataGridViewSelectedCellCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/Designer/WinForms/System/WinForms/Design/TextBoxDesigner@cs/1/TextBoxDesigner@cs
">
                                                <span style="word-wrap: break-word;">TextBoxDesigner.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/WF/Common/AuthoringOM/Serializer/DependencyStoreSurrogate@cs/1305376/DependencyStoreSurrogate@cs
">
                                                <span style="word-wrap: break-word;">DependencyStoreSurrogate.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Documents/TextTreeRootNode@cs/1305600/TextTreeRootNode@cs
">
                                                <span style="word-wrap: break-word;">TextTreeRootNode.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Core/System/Windows/FontWeight@cs/1/FontWeight@cs
">
                                                <span style="word-wrap: break-word;">FontWeight.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Shared/MS/Internal/Generated/GradientSpreadMethodValidation@cs/1/GradientSpreadMethodValidation@cs
">
                                                <span style="word-wrap: break-word;">GradientSpreadMethodValidation.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DLinq/Dlinq/SqlClient/Query/ContainsRowNumberChecker@cs/1305376/ContainsRowNumberChecker@cs
">
                                                <span style="word-wrap: break-word;">ContainsRowNumberChecker.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Base/System/Windows/Markup/ReflectionHelper@cs/1305600/ReflectionHelper@cs
">
                                                <span style="word-wrap: break-word;">ReflectionHelper.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Shared/MS/Win32/SafeNativeMethodsCLR@cs/1305600/SafeNativeMethodsCLR@cs
">
                                                <span style="word-wrap: break-word;">SafeNativeMethodsCLR.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Data/System/Data/Odbc/OdbcHandle@cs/1305376/OdbcHandle@cs
">
                                                <span style="word-wrap: break-word;">OdbcHandle.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/WCF/WCF/3@5@30729@1/untmp/Orcas/SP/ndp/cdf/src/WCF/Tools/xws_reg/System/ServiceModel/Install/Configuration/WasHttpModulesInstallComponent@cs/1/WasHttpModulesInstallComponent@cs
">
                                                <span style="word-wrap: break-word;">WasHttpModulesInstallComponent.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Framework/System/Windows/Documents/FixedSOMFixedBlock@cs/1/FixedSOMFixedBlock@cs
">
                                                <span style="word-wrap: break-word;">FixedSOMFixedBlock.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/UI/WebControls/TableRow@cs/2/TableRow@cs
">
                                                <span style="word-wrap: break-word;">TableRow.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/CompMod/System/ComponentModel/PasswordPropertyTextAttribute@cs/1/PasswordPropertyTextAttribute@cs
">
                                                <span style="word-wrap: break-word;">PasswordPropertyTextAttribute.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Core/CSharp/System/Windows/Media/Generated/PathFigure@cs/1/PathFigure@cs
">
                                                <span style="word-wrap: break-word;">PathFigure.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Core/CSharp/System/Windows/Media/Generated/PathFigureCollection@cs/2/PathFigureCollection@cs
">
                                                <span style="word-wrap: break-word;">PathFigureCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DataEntity/System/Data/Mapping/StorageAssociationTypeMapping@cs/1305376/StorageAssociationTypeMapping@cs
">
                                                <span style="word-wrap: break-word;">StorageAssociationTypeMapping.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/clr/src/BCL/System/Text/GB18030Encoding@cs/1/GB18030Encoding@cs
">
                                                <span style="word-wrap: break-word;">GB18030Encoding.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/WCF/WCF/3@5@30729@1/untmp/Orcas/SP/ndp/cdf/src/WCF/ServiceModel/System/ServiceModel/Configuration/PolicyVersionConverter@cs/1/PolicyVersionConverter@cs
">
                                                <span style="word-wrap: break-word;">PolicyVersionConverter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/Data/System/Data/DataViewManagerListItemTypeDescriptor@cs/1/DataViewManagerListItemTypeDescriptor@cs
">
                                                <span style="word-wrap: break-word;">DataViewManagerListItemTypeDescriptor.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/xsp/System/Web/UI/WebControls/CreateUserWizard@cs/1/CreateUserWizard@cs
">
                                                <span style="word-wrap: break-word;">CreateUserWizard.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/clr/src/BCL/System/Security/Policy/HashMembershipCondition@cs/1/HashMembershipCondition@cs
">
                                                <span style="word-wrap: break-word;">HashMembershipCondition.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/UI/WebControls/TableRow@cs/2/TableRow@cs
">
                                                <span style="word-wrap: break-word;">TableRow.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/xsp/System/Web/Abstractions/HttpResponseBase@cs/1503810/HttpResponseBase@cs
">
                                                <span style="word-wrap: break-word;">HttpResponseBase.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Framework/System/Windows/SharedDp@cs/1/SharedDp@cs
">
                                                <span style="word-wrap: break-word;">SharedDp.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/DEVDIV/depot/DevDiv/releases/whidbey/QFE/ndp/fx/src/xsp/System/Web/Configuration/ClientTargetSection@cs/3/ClientTargetSection@cs
">
                                                <span style="word-wrap: break-word;">ClientTargetSection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/clr/src/BCL/System/Runtime/Remoting/CrossAppDomainChannel@cs/1/CrossAppDomainChannel@cs
">
                                                <span style="word-wrap: break-word;">CrossAppDomainChannel.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/ndp/fx/src/DataEntity/System/Data/Map/Update/Internal/Graph@cs/2/Graph@cs
">
                                                <span style="word-wrap: break-word;">Graph.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Core/System/Windows/Media/Visual@cs/8/Visual@cs
">
                                                <span style="word-wrap: break-word;">Visual.cs
</span>
                                            </a></li>

                                    
                            </ul>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-sm-12" id="footer">
                    <p>Copyright © 2010-2021 <a href="http://www.infiniteloop.ie">Infinite Loop Ltd</a> </p>
                   
                </div>

            </div>
            <script type="text/javascript">
                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
            </script>
            <script type="text/javascript">
                var pageTracker = _gat._getTracker("UA-3658396-9");
                pageTracker._trackPageview();
            </script>
        </div>
    </div>
</div>
</body>
</html>