DataServiceContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / DataServiceContext.cs / 2 / 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;
 
                    // It is the users responsibility to delete the link 
                    // before deleting the entity when required.
                    this.IncrementChange(existing); 
                }
            }
        }
 
        /// 
        /// 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.
        ///  
        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. 
        ///  
        /// 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. 
        /// 
        /// 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"); 

                // Leave related links alone which means we can have a link in the Added 
                // or Modified state referencing a source/target entity in the Deleted state. 
                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 if (EntityStates.Detached != entry.State) 
                {   // this link may have been previously detached by a detaching entity
                    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];
 
                // For collections, we need to generate the uri with the property name followed by the keys.
                // GenerateEditLinkUri generates an absolute uri 
                //      First parameters is the base service uri 
                //      Second parameter is the segment name (in this case, navigation property name)
                //      Third parameter is the resource whose key values need to be appended after the segment 
                // For e.g. If the navigation property name is "Purchases" and the resource type is Order with key '1', then this method will generate 'baseuri/Purchases(1)'
                Uri navigationPropertyUri = this.BaseUriWithSlash.MakeRelativeUri(DataServiceContext.GenerateEditLinkUri(this.BaseUriWithSlash, binding.SourceProperty, targetResource.Resource));

                // Get the relative uri and appends links segment at the start. 
                relative = Util.CreateUri(XmlConstants.UriLinkSegment + "/" + navigationPropertyUri.OriginalString, UriKind.Relative);
            } 
            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>
        /// <remarks>
        /// During a non-batch SaveChanges, an Added entity can become an Unchanged entity
        /// and should be included in the set of related links for the second Added entity. 
        /// </remarks>
        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];
 
                            // assumption: the source entity started in the Added state
                            // note: SaveChanges operates with two passes
                            //      a) first send the request and then attach identity and append the result into a batch response  (Example: BeginSaveChanges)
                            //      b) process the batch response (shared code with SaveChanges(Batch))  (Example: EndSaveChanges) 
                            // note: SaveResultWasProcessed is set when to the pre-save state when the save result is sucessfully processed
 
                            // scenario #1 when target entity started in modified or unchanged state 
                            // 1) the link target entity was modified and now implicitly assumed to be unchanged (this is true in second pass)
                            // 2) or link target entity has not been saved is in the modified or unchanged state (this is true in first pass) 

                            // scenario #2 when target entity started in added state
                            // 1) target entity has an identity (true in first pass for non-batch)
                            // 2) target entity is processed before source to qualify (1) better during the second pass 
                            // 3) the link target has not been saved and is in the added state
                            // 4) or the link target has been saved and was in the added state 
                            if (IncludeLinkState(target.SaveResultWasProcessed) || ((0 == target.SaveResultWasProcessed) && IncludeLinkState(target.State)) || 
                                ((null != target.Identity) && (target.ChangeOrder < box.ChangeOrder) &&
                                 ((0 == target.SaveResultWasProcessed && EntityStates.Added == target.State) || 
                                  (EntityStates.Added == target.SaveResultWasProcessed))))
                            {
                                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>
        /// 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)
        { 
            if (this.bindings.Remove(existing))
            {   // this link may have been previously detached by a detaching entity 
                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>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;
 
                    // It is the users responsibility to delete the link 
                    // before deleting the entity when required.
                    this.IncrementChange(existing); 
                }
            }
        }
 
        /// <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.
        /// </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. 
        /// </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. 
        /// </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"); 

                // Leave related links alone which means we can have a link in the Added 
                // or Modified state referencing a source/target entity in the Deleted state. 
                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 if (EntityStates.Detached != entry.State) 
                {   // this link may have been previously detached by a detaching entity
                    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];
 
                // For collections, we need to generate the uri with the property name followed by the keys.
                // GenerateEditLinkUri generates an absolute uri 
                //      First parameters is the base service uri 
                //      Second parameter is the segment name (in this case, navigation property name)
                //      Third parameter is the resource whose key values need to be appended after the segment 
                // For e.g. If the navigation property name is "Purchases" and the resource type is Order with key '1', then this method will generate 'baseuri/Purchases(1)'
                Uri navigationPropertyUri = this.BaseUriWithSlash.MakeRelativeUri(DataServiceContext.GenerateEditLinkUri(this.BaseUriWithSlash, binding.SourceProperty, targetResource.Resource));

                // Get the relative uri and appends links segment at the start. 
                relative = Util.CreateUri(XmlConstants.UriLinkSegment + "/" + navigationPropertyUri.OriginalString, UriKind.Relative);
            } 
            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>
        /// <remarks>
        /// During a non-batch SaveChanges, an Added entity can become an Unchanged entity
        /// and should be included in the set of related links for the second Added entity. 
        /// </remarks>
        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];
 
                            // assumption: the source entity started in the Added state
                            // note: SaveChanges operates with two passes
                            //      a) first send the request and then attach identity and append the result into a batch response  (Example: BeginSaveChanges)
                            //      b) process the batch response (shared code with SaveChanges(Batch))  (Example: EndSaveChanges) 
                            // note: SaveResultWasProcessed is set when to the pre-save state when the save result is sucessfully processed
 
                            // scenario #1 when target entity started in modified or unchanged state 
                            // 1) the link target entity was modified and now implicitly assumed to be unchanged (this is true in second pass)
                            // 2) or link target entity has not been saved is in the modified or unchanged state (this is true in first pass) 

                            // scenario #2 when target entity started in added state
                            // 1) target entity has an identity (true in first pass for non-batch)
                            // 2) target entity is processed before source to qualify (1) better during the second pass 
                            // 3) the link target has not been saved and is in the added state
                            // 4) or the link target has been saved and was in the added state 
                            if (IncludeLinkState(target.SaveResultWasProcessed) || ((0 == target.SaveResultWasProcessed) && IncludeLinkState(target.State)) || 
                                ((null != target.Identity) && (target.ChangeOrder < box.ChangeOrder) &&
                                 ((0 == target.SaveResultWasProcessed && EntityStates.Added == target.State) || 
                                  (EntityStates.Added == target.SaveResultWasProcessed))))
                            {
                                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>
        /// 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)
        { 
            if (this.bindings.Remove(existing))
            {   // this link may have been previously detached by a detaching entity 
                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>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/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/Orcas/NetFXw7/wpf/src/Base/System/ComponentModel/CurrentChangingEventArgs@cs/1/CurrentChangingEventArgs@cs
">
                                                <span style="word-wrap: break-word;">CurrentChangingEventArgs.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/Reflection/Emit/TypeToken@cs/1/TypeToken@cs
">
                                                <span style="word-wrap: break-word;">TypeToken.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/Compilation/BrowserCapabilitiesCompiler@cs/1/BrowserCapabilitiesCompiler@cs
">
                                                <span style="word-wrap: break-word;">BrowserCapabilitiesCompiler.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/StringStorage@cs/1/StringStorage@cs
">
                                                <span style="word-wrap: break-word;">StringStorage.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/System/Windows/Media/CultureSpecificStringDictionary@cs/1305600/CultureSpecificStringDictionary@cs
">
                                                <span style="word-wrap: break-word;">CultureSpecificStringDictionary.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/Xml/System/Xml/Core/XmlValidatingReaderImpl@cs/1305376/XmlValidatingReaderImpl@cs
">
                                                <span style="word-wrap: break-word;">XmlValidatingReaderImpl.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/Net/System/Net/Mail/SevenBitStream@cs/1/SevenBitStream@cs
">
                                                <span style="word-wrap: break-word;">SevenBitStream.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/Xml/System/Xml/XPath/Internal/XPathSingletonIterator@cs/1/XPathSingletonIterator@cs
">
                                                <span style="word-wrap: break-word;">XPathSingletonIterator.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/Media3D/Light@cs/1/Light@cs
">
                                                <span style="word-wrap: break-word;">Light.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/Sys/System/Configuration/ConfigXmlWhitespace@cs/1/ConfigXmlWhitespace@cs
">
                                                <span style="word-wrap: break-word;">ConfigXmlWhitespace.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/clr/src/BCL/System/Runtime/CompilerServices/NativeCppClassAttribute@cs/1305376/NativeCppClassAttribute@cs
">
                                                <span style="word-wrap: break-word;">NativeCppClassAttribute.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/ArcSegment@cs/1/ArcSegment@cs
">
                                                <span style="word-wrap: break-word;">ArcSegment.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/Serialization/System/Xml/XmlDictionaryReader@cs/2/XmlDictionaryReader@cs
">
                                                <span style="word-wrap: break-word;">XmlDictionaryReader.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@Activities@DurableInstancing/System/Activities/DurableInstancing/ExtendLockCommand@cs/1305376/ExtendLockCommand@cs
">
                                                <span style="word-wrap: break-word;">ExtendLockCommand.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/WinForms/Managed/System/WinForms/LinkLabelLinkClickedEvent@cs/1305376/LinkLabelLinkClickedEvent@cs
">
                                                <span style="word-wrap: break-word;">LinkLabelLinkClickedEvent.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/Globalization/ThaiBuddhistCalendar@cs/1/ThaiBuddhistCalendar@cs
">
                                                <span style="word-wrap: break-word;">ThaiBuddhistCalendar.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/UIAutomation/UIAutomationClient/MS/Internal/Automation/ClickablePoint@cs/1305600/ClickablePoint@cs
">
                                                <span style="word-wrap: break-word;">ClickablePoint.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/xsp/System/Web/Security/ADMembershipProvider@cs/5/ADMembershipProvider@cs
">
                                                <span style="word-wrap: break-word;">ADMembershipProvider.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/CommonUI/System/Drawing/Printing/PrintEvent@cs/1/PrintEvent@cs
">
                                                <span style="word-wrap: break-word;">PrintEvent.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/Markup/RoutedEventValueSerializer@cs/1305600/RoutedEventValueSerializer@cs
">
                                                <span style="word-wrap: break-word;">RoutedEventValueSerializer.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/Design/PropertyTabAttribute@cs/1/PropertyTabAttribute@cs
">
                                                <span style="word-wrap: break-word;">PropertyTabAttribute.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/RunTime/Tracking/TrackingRecord@cs/1305376/TrackingRecord@cs
">
                                                <span style="word-wrap: break-word;">TrackingRecord.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/clr/src/ManagedLibraries/Security/System/Security/Cryptography/BigInt@cs/1305376/BigInt@cs
">
                                                <span style="word-wrap: break-word;">BigInt.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/Security/Cryptography/HMAC@cs/1305376/HMAC@cs
">
                                                <span style="word-wrap: break-word;">HMAC.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/Base/System/Windows/Markup/WhitespaceSignificantCollectionAttribute@cs/1/WhitespaceSignificantCollectionAttribute@cs
">
                                                <span style="word-wrap: break-word;">WhitespaceSignificantCollectionAttribute.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/SchemaCollectionPreprocessor@cs/1/SchemaCollectionPreprocessor@cs
">
                                                <span style="word-wrap: break-word;">SchemaCollectionPreprocessor.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/Themes/Aero/Microsoft/Windows/Themes/ProgressBarHighlightConverter@cs/1305600/ProgressBarHighlightConverter@cs
">
                                                <span style="word-wrap: break-word;">ProgressBarHighlightConverter.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/ContextStaticAttribute@cs/1/ContextStaticAttribute@cs
">
                                                <span style="word-wrap: break-word;">ContextStaticAttribute.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/NetFx40/Tools/System@Activities@Presentation/System/Activities/Presentation/Model/DictionaryEditChange@cs/1305376/DictionaryEditChange@cs
">
                                                <span style="word-wrap: break-word;">DictionaryEditChange.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/CodeDOM/CodeParameterDeclarationExpressionCollection@cs/1/CodeParameterDeclarationExpressionCollection@cs
">
                                                <span style="word-wrap: break-word;">CodeParameterDeclarationExpressionCollection.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/PerfCounters@cs/1/PerfCounters@cs
">
                                                <span style="word-wrap: break-word;">PerfCounters.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/Sys/System/Runtime/InteropServices/DefaultParameterValueAttribute@cs/1/DefaultParameterValueAttribute@cs
">
                                                <span style="word-wrap: break-word;">DefaultParameterValueAttribute.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/System/Windows/Media/Generated/PolyLineSegmentFigureLogic@cs/1305600/PolyLineSegmentFigureLogic@cs
">
                                                <span style="word-wrap: break-word;">PolyLineSegmentFigureLogic.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/CompMod/System/ComponentModel/ListBindableAttribute@cs/1/ListBindableAttribute@cs
">
                                                <span style="word-wrap: break-word;">ListBindableAttribute.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/CompMod/Microsoft/Win32/UserPreferenceChangedEventArgs@cs/1/UserPreferenceChangedEventArgs@cs
">
                                                <span style="word-wrap: break-word;">UserPreferenceChangedEventArgs.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/SourceChangedEventArgs@cs/1305600/SourceChangedEventArgs@cs
">
                                                <span style="word-wrap: break-word;">SourceChangedEventArgs.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/Configuration/RemoteWebConfigurationHost@cs/2/RemoteWebConfigurationHost@cs
">
                                                <span style="word-wrap: break-word;">RemoteWebConfigurationHost.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/GridViewPageEventArgs@cs/1/GridViewPageEventArgs@cs
">
                                                <span style="word-wrap: break-word;">GridViewPageEventArgs.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/Base/System/Windows/Input/ModifierKeysConverter@cs/1305600/ModifierKeysConverter@cs
">
                                                <span style="word-wrap: break-word;">ModifierKeysConverter.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/Core/System/Linq/Parallel/Utils/ExceptionAggregator@cs/1305376/ExceptionAggregator@cs
">
                                                <span style="word-wrap: break-word;">ExceptionAggregator.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/Xml/System/Xml/XPath/Internal/XPathChildIterator@cs/1/XPathChildIterator@cs
">
                                                <span style="word-wrap: break-word;">XPathChildIterator.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/infocard/Service/managed/Microsoft/InfoCards/LifetimeMonitor@cs/1/LifetimeMonitor@cs
">
                                                <span style="word-wrap: break-word;">LifetimeMonitor.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/MS/Internal/Annotations/AnnotationObservableCollection@cs/1/AnnotationObservableCollection@cs
">
                                                <span style="word-wrap: break-word;">AnnotationObservableCollection.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/untmp/whidbey/QFE/ndp/fx/src/xsp/System/Web/UI/ParseChildrenAsPropertiesAttribute@cs/1/ParseChildrenAsPropertiesAttribute@cs
">
                                                <span style="word-wrap: break-word;">ParseChildrenAsPropertiesAttribute.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/Data/System/Data/XmlKeywords@cs/1305376/XmlKeywords@cs
">
                                                <span style="word-wrap: break-word;">XmlKeywords.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/Animation/Generated/Timeline@cs/1/Timeline@cs
">
                                                <span style="word-wrap: break-word;">Timeline.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/System/Windows/Media3D/Generated/QuaternionConverter@cs/1305600/QuaternionConverter@cs
">
                                                <span style="word-wrap: break-word;">QuaternionConverter.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/ValueType@cs/1/ValueType@cs
">
                                                <span style="word-wrap: break-word;">ValueType.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/Security/AccessControl/CommonObjectSecurity@cs/1/CommonObjectSecurity@cs
">
                                                <span style="word-wrap: break-word;">CommonObjectSecurity.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/xsp/System/Web/UI/WebControls/DataGridLinkButton@cs/1305376/DataGridLinkButton@cs
">
                                                <span style="word-wrap: break-word;">DataGridLinkButton.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/xsp/System/Extensions/Compilation/WCFModel/ProxyGenerationError@cs/1305376/ProxyGenerationError@cs
">
                                                <span style="word-wrap: break-word;">ProxyGenerationError.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/DLinq/Dlinq/SqlClient/Common/SqlNodeAnnotations@cs/1/SqlNodeAnnotations@cs
">
                                                <span style="word-wrap: break-word;">SqlNodeAnnotations.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/System/Windows/InterOp/HwndTarget@cs/1661220/HwndTarget@cs
">
                                                <span style="word-wrap: break-word;">HwndTarget.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/SaveFileDialog@cs/1/SaveFileDialog@cs
">
                                                <span style="word-wrap: break-word;">SaveFileDialog.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/BamlWriter@cs/1/BamlWriter@cs
">
                                                <span style="word-wrap: break-word;">BamlWriter.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/ButtonInternal/ButtonPopupAdapter@cs/1/ButtonPopupAdapter@cs
">
                                                <span style="word-wrap: break-word;">ButtonPopupAdapter.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/Designer/CompMod/System/ComponentModel/Design/MenuCommandsChangedEventArgs@cs/1/MenuCommandsChangedEventArgs@cs
">
                                                <span style="word-wrap: break-word;">MenuCommandsChangedEventArgs.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/Automation/Peers/DocumentPageViewAutomationPeer@cs/1305600/DocumentPageViewAutomationPeer@cs
">
                                                <span style="word-wrap: break-word;">DocumentPageViewAutomationPeer.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/Web/System/Web/Services/Protocols/MimeParameterWriter@cs/1305376/MimeParameterWriter@cs
">
                                                <span style="word-wrap: break-word;">MimeParameterWriter.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/MS/Internal/PtsHost/Section@cs/1/Section@cs
">
                                                <span style="word-wrap: break-word;">Section.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/WebParts/Part@cs/1/Part@cs
">
                                                <span style="word-wrap: break-word;">Part.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/Compilation/BuildProvider@cs/1/BuildProvider@cs
">
                                                <span style="word-wrap: break-word;">BuildProvider.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/CommonUI/System/Drawing/Advanced/ColorBlend@cs/1/ColorBlend@cs
">
                                                <span style="word-wrap: break-word;">ColorBlend.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/Net/System/Net/_BufferOffsetSize@cs/1/_BufferOffsetSize@cs
">
                                                <span style="word-wrap: break-word;">_BufferOffsetSize.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/Xml/System/Xml/schema/XmlSchemaAnyAttribute@cs/1/XmlSchemaAnyAttribute@cs
">
                                                <span style="word-wrap: break-word;">XmlSchemaAnyAttribute.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/ndp/fx/src/DataEntity/System/Data/EntityModel/SchemaObjectModel/Documentation@cs/1/Documentation@cs
">
                                                <span style="word-wrap: break-word;">Documentation.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/WinForms/Managed/System/Resources/ResXResourceWriter@cs/1305376/ResXResourceWriter@cs
">
                                                <span style="word-wrap: break-word;">ResXResourceWriter.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/LinkLabelLinkClickedEvent@cs/1/LinkLabelLinkClickedEvent@cs
">
                                                <span style="word-wrap: break-word;">LinkLabelLinkClickedEvent.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/ndp/fx/src/DataEntity/System/Data/SqlClient/SqlGen/Sql8ConformanceChecker@cs/1/Sql8ConformanceChecker@cs
">
                                                <span style="word-wrap: break-word;">Sql8ConformanceChecker.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/WinForms/Managed/System/WinForms/MainMenu@cs/1305376/MainMenu@cs
">
                                                <span style="word-wrap: break-word;">MainMenu.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/ndp/fx/src/DataEntity/System/Data/Common/CommandTrees/AbstractExpressions@cs/4/AbstractExpressions@cs
">
                                                <span style="word-wrap: break-word;">AbstractExpressions.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/GridViewUpdateEventArgs@cs/1/GridViewUpdateEventArgs@cs
">
                                                <span style="word-wrap: break-word;">GridViewUpdateEventArgs.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/WebPageTraceListener@cs/1/WebPageTraceListener@cs
">
                                                <span style="word-wrap: break-word;">WebPageTraceListener.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/ToolStripRenderer@cs/1/ToolStripRenderer@cs
">
                                                <span style="word-wrap: break-word;">ToolStripRenderer.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/Net/System/Net/IPEndPoint@cs/1/IPEndPoint@cs
">
                                                <span style="word-wrap: break-word;">IPEndPoint.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/Threading/ExecutionContext@cs/2/ExecutionContext@cs
">
                                                <span style="word-wrap: break-word;">ExecutionContext.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/DataWeb/Client/System/Data/Services/Client/BaseAsyncResult@cs/1/BaseAsyncResult@cs
">
                                                <span style="word-wrap: break-word;">BaseAsyncResult.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/Themes/Shared/Microsoft/Windows/Themes/KnownTypeHelper@cs/1305600/KnownTypeHelper@cs
">
                                                <span style="word-wrap: break-word;">KnownTypeHelper.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/UI/WebControls/DataListItemEventArgs@cs/1305376/DataListItemEventArgs@cs
">
                                                <span style="word-wrap: break-word;">DataListItemEventArgs.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/ArgumentNullException@cs/1/ArgumentNullException@cs
">
                                                <span style="word-wrap: break-word;">ArgumentNullException.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/Core/Microsoft/Scripting/Actions/ConvertBinder@cs/1305376/ConvertBinder@cs
">
                                                <span style="word-wrap: break-word;">ConvertBinder.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/XPath/XPathNavigatorReader@cs/1/XPathNavigatorReader@cs
">
                                                <span style="word-wrap: break-word;">XPathNavigatorReader.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/xsp/System/Web/UI/WebControls/DataGridPagerStyle@cs/1/DataGridPagerStyle@cs
">
                                                <span style="word-wrap: break-word;">DataGridPagerStyle.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/CodeDOM/CodeDirectionExpression@cs/1/CodeDirectionExpression@cs
">
                                                <span style="word-wrap: break-word;">CodeDirectionExpression.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/WebPageTraceListener@cs/1/WebPageTraceListener@cs
">
                                                <span style="word-wrap: break-word;">WebPageTraceListener.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/DataWeb/Client/System/Data/Services/Client/Binding/DataServiceCollectionOfT@cs/1305376/DataServiceCollectionOfT@cs
">
                                                <span style="word-wrap: break-word;">DataServiceCollectionOfT.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/Configuration/System/Configuration/Internal/FileVersion@cs/1305376/FileVersion@cs
">
                                                <span style="word-wrap: break-word;">FileVersion.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/Globalization/TextElementEnumerator@cs/1/TextElementEnumerator@cs
">
                                                <span style="word-wrap: break-word;">TextElementEnumerator.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/FederatedMessageSecurityOverHttp@cs/1/FederatedMessageSecurityOverHttp@cs
">
                                                <span style="word-wrap: break-word;">FederatedMessageSecurityOverHttp.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/Xml/System/Xml/Serialization/SoapAttributes@cs/1/SoapAttributes@cs
">
                                                <span style="word-wrap: break-word;">SoapAttributes.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/Compiler/Executor@cs/1/Executor@cs
">
                                                <span style="word-wrap: break-word;">Executor.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/Configuration/WebPartsSection@cs/2/WebPartsSection@cs
">
                                                <span style="word-wrap: break-word;">WebPartsSection.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/ndp/fx/src/DataEntity/System/Data/Common/EntitySql/CqlQuery@cs/1/CqlQuery@cs
">
                                                <span style="word-wrap: break-word;">CqlQuery.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/ValueType@cs/1305376/ValueType@cs
">
                                                <span style="word-wrap: break-word;">ValueType.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/DataWeb/Design/system/Data/EntityModel/Emitters/NamespaceEmitter@cs/1/NamespaceEmitter@cs
">
                                                <span style="word-wrap: break-word;">NamespaceEmitter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/untmp/whidbey/QFE/ndp/fx/src/xsp/System/Web/UI/WebControls/MenuItemBinding@cs/1/MenuItemBinding@cs
">
                                                <span style="word-wrap: break-word;">MenuItemBinding.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/StatusStrip@cs/1/StatusStrip@cs
">
                                                <span style="word-wrap: break-word;">StatusStrip.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/CompMod/System/ComponentModel/Design/CheckoutException@cs/1/CheckoutException@cs
">
                                                <span style="word-wrap: break-word;">CheckoutException.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/ndp/fx/src/SystemNet/Net/PeerToPeer/Collaboration/PeerInvitationResponse@cs/1/PeerInvitationResponse@cs
">
                                                <span style="word-wrap: break-word;">PeerInvitationResponse.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/AccessibleTech/longhorn/Automation/UIAutomationClient/MS/Internal/Automation/input@cs/1/input@cs
">
                                                <span style="word-wrap: break-word;">input.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>