DataServiceContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / DataServiceContext.cs / 1676519 / DataServiceContext.cs

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

// #define TESTUNIXNEWLINE 

namespace System.Data.Services.Client
{
    #region Namespaces. 

    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;
    using System.Data.Services.Common; 
#if !ASTORIA_LIGHT 
    using System.Net;
#else // Data.Services http stack 
    using System.Data.Services.Http;
#endif
    using System.Text;
    using System.Xml; 
    using System.Xml.Linq;
 
    #endregion Namespaces. 

    ///  
    /// context
    /// 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506", Justification = "Central class of the API, likely to have many cross-references")]
    public class DataServiceContext 
    {
#if !TESTUNIXNEWLINE 
        /// cache NewLine string 
        private static readonly string NewLine = System.Environment.NewLine;
#else 
        /// cache NewLine string
        private const string NewLine = "\n";
#endif
 
        /// 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; 

        /// Client will ignore 404 resource not found exception and return an empty set when this is set to true 
        private bool ignoreResourceNotFoundException;

#if ASTORIA_LIGHT // Multiple HTTP stacks for Silverlight
        /// The HTTP stack to use for requests. 
        private HttpStack httpStack;
#endif 
 
        #region Resource state management
 
        /// change order
        private uint nextChange;

        /// Set of tracked resources 
        private Dictionary entityDescriptors = new Dictionary(EqualityComparer.Default);
 
        /// Set of tracked resources by Identity 
        private Dictionary identityToDescriptor;
 
        /// Set of tracked bindings
        private Dictionary bindings = new Dictionary(LinkDescriptor.EquivalenceComparer);

        ///  
        /// A flag indicating if the data service context is applying changes
        ///  
        private bool applyingChanges; 

        #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. 
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public DataServiceContext(Uri serviceRoot)
        { 
            Util.CheckArgumentNull(serviceRoot, "serviceRoot");
 
#if ASTORIA_LIGHT 
            if (!serviceRoot.IsAbsoluteUri)
            { 
                // If we can use XHR, we will and thus we should use the old (V1) way of determining our
                //   base URI. That is, use the uri of the HTML page
                if (XHRHttpWebRequest.IsAvailable())
                { 
                    serviceRoot = new Uri(System.Windows.Browser.HtmlPage.Document.DocumentUri, serviceRoot);
                } 
                else 
                {
                    // Otherwise we are going to use the new Client stack. In this case there might not be any 
                    //   HTML page hosting us, or it might not be accessible, so the only base uri we can use
                    //   is the base uri of the xap we're running in.
                    System.Net.WebClient webClient = new System.Net.WebClient();
                    serviceRoot = new Uri(new Uri(webClient.BaseAddress), 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; 
#if ASTORIA_LIGHT
            this.UsePostTunneling = true; 
#else
            this.UsePostTunneling = false;
#endif
            this.typeScheme = new Uri(XmlConstants.DataWebSchemeNamespace); 
#if ASTORIA_LIGHT
            this.httpStack = HttpStack.Auto; 
#endif 
        }
 
        #endregion

        /// 
        /// 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;
 
        /// 
        /// 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; 

        /// 
        /// This event fires when SaveChanges or EndSaveChanges is called
        ///  
        internal event EventHandler ChangesSaved;
 
        #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"); } 
        }
 
        /// 
        /// A flag indicating if the data service context is applying changes
        /// 
        public bool ApplyingChanges 
        {
            get { return this.applyingChanges; } 
            internal set { this.applyingChanges = value; } 
        }
 
        /// 
        /// 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 this.bindings.Values.OrderBy(l => l.ChangeOrder).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 this.entityDescriptors.Values.OrderBy(d => d.ChangeOrder).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

        ///  
        /// When set to true, client will return an empty set instead of throwing when the
        /// server generates a HTTP 404: Resource Not Found exception 
        ///  
        public bool IgnoreResourceNotFoundException
        { 
            get { return this.ignoreResourceNotFoundException; }
            set { this.ignoreResourceNotFoundException = value; }
        }
 
#if ASTORIA_LIGHT // Multiple HTTP stacks in Silverlight
        ///  
        /// The HTTP stack to use in Silverlight. 
        /// Default value is HttpStack.Auto.
        ///  
        public HttpStack HttpStack
        {
            get { return this.httpStack; }
            set { this.httpStack = Util.CheckEnumerationValue(value, "HttpStack"); } 
        }
#endif 
 
        /// 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 Entity and Link Tracking
 
        /// Gets the entity descriptor corresponding to a particular entity
        /// Entity for which to find the entity descriptor 
        /// EntityDescriptor for the  or null if not found 
        public EntityDescriptor GetEntityDescriptor(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity");

            EntityDescriptor descriptor;
            if (this.entityDescriptors.TryGetValue(entity, out descriptor)) 
            {
                return descriptor; 
            } 
            else
            { 
                return null;
            }
        }
 
        /// 
        /// Gets the link descriptor corresponding to a particular link b/w source and target objects 
        ///  
        /// Source entity
        /// Property of  
        /// Target entity
        /// LinkDescriptor for the relationship b/w source and target entities or null if not found
        public LinkDescriptor GetLinkDescriptor(object source, string sourceProperty, object target)
        { 
            Util.CheckArgumentNull(source, "source");
            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty"); 
            Util.CheckArgumentNull(target, "target"); 

            LinkDescriptor link; 

            if (this.bindings.TryGetValue(new LinkDescriptor(source, sourceProperty, target), out link))
            {
                return link; 
            }
            else 
            { 
                return null;
            } 
        }

        #endregion
 
        #region CancelRequest
        /// Best effort to abort the outstand request 
        /// the current async request to cancel 
        /// DataServiceContext is not safe to use until asyncResult.IsCompleted is true.
        public void CancelRequest(IAsyncResult asyncResult) 
        {
            Util.CheckArgumentNull(asyncResult, "asyncResult");
            BaseAsyncResult result = asyncResult as BaseAsyncResult;
 
            // verify this asyncResult orginated from this context or via query from this context
            if ((null == result) || (this != result.Source)) 
            { 
                object context = null;
                DataServiceQuery query = null; 
                if (null != result)
                {
                    query = result.Source as DataServiceQuery;
 
                    if (null != query)
                    { 
                        DataServiceQueryProvider provider = query.Provider as DataServiceQueryProvider; 
                        if (null != provider)
                        { 
                            context = provider.Context;
                        }
                    }
                } 

                if (this != context) 
                { 
                    throw Error.Argument(Strings.Context_DidNotOriginateAsync, "asyncResult");
                } 
            }

            // at this point the result originated from this context or a query from this context
            if (!result.IsCompletedInternally) 
            {
                result.SetAborted(); 
 
                WebRequest request = result.Abortable;
                if (null != request) 
                {
                    // with Silverlight we can't wait around to check if the request was aborted
                    // because that would block callbacks for the abort from actually running.
                    request.Abort(); 
                }
            } 
        } 
        #endregion
 
        #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, CountOption.None, 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) 
        {
            return this.BeginLoadProperty(entity, propertyName, (Uri)null, callback, state);
        }
 
        /// 
        /// Begin getting response to load a page for a collection. 
        ///  
        /// The entity
        /// name of collection or reference property to load 
        /// load the page from this URI
        /// 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, Uri nextLinkUri, AsyncCallback callback, object state)
        { 
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state, nextLinkUri, null); 
            result.BeginExecute();
            return result; 
        }

        /// 
        /// Begin getting response to load a page for a collection. 
        /// 
        /// The entity 
        /// name of collection or reference property to load 
        /// Continuation from which the property should be loaded.
        /// 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, DataServiceQueryContinuation continuation, AsyncCallback callback, object state)
        { 
            Util.CheckArgumentNull(continuation, "continuation");
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state, null, continuation); 
            result.BeginExecute(); 
            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) 
        {
            LoadPropertyResult response = QueryResult.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)
        { 
            return this.LoadProperty(entity, propertyName, (Uri)null);
        } 
 
        /// 
        /// Load a page for collection from an uri 
        /// 
        /// 
        /// 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 
        /// The uri to load the page from; possibly null.
        /// QueryOperationResponse instance containing information about the response. 
        public QueryOperationResponse LoadProperty(object entity, string propertyName, Uri nextLinkUri) 
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, nextLinkUri, null); 
            result.Execute();
            return result.LoadProperty();
        }
 
        /// 
        /// Load a page for collection from an uri 
        ///  
        /// 
        /// 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.
        /// The continuation object from a previous response.
        /// QueryOperationResponse instance containing information about the response.
        public QueryOperationResponse LoadProperty(object entity, string propertyName, DataServiceQueryContinuation continuation) 
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, null, continuation); 
            result.Execute(); 
            return result.LoadProperty();
        } 

        /// Loads a page for a collection from a continuation object..
        /// 
        /// 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.
        /// 
        /// Element type of collection to load. 
        /// entity
        /// name of collection or reference property to load 
        /// The continuation object from a previous response. 
        /// QueryOperationResponse instance containing information about the response.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011", Justification = "allows compiler to infer 'T'")] 
        public QueryOperationResponse LoadProperty(object entity, string propertyName, DataServiceQueryContinuation continuation)
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, null, continuation);
            result.Execute(); 
            return (QueryOperationResponse)result.LoadProperty();
        } 
 
#endif
        #endregion 

        #region GetReadStreamUri
        /// 
        /// If the specified entity is a Media Link Entry, this method will return 
        /// an URI which can be used to access the content of the Media Resource.
        /// This URI should only be used to GET/Read the content of the MR. It may not respond to POST/PUT/DELETE requests. 
        ///  
        /// The entity to lookup the MR URI for.
        /// The read URI of the MR. 
        /// If the entity specified is null.
        /// If the entity specified is not being tracked.
        public Uri GetReadStreamUri(object entity)
        { 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            return box.GetMediaResourceUri(this.baseUriWithSlash); 
        } 
        #endregion
 
        #region GetReadStream, BeginGetReadStream, EndGetReadStream

        /// 
        /// This method begins a request to get the read stream for a Media Resource 
        /// associated with the media link entry represented by the entity object.
        ///  
        /// The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state.
        /// Instance of  class with additional metadata for the request. 
        /// Must not be null.
        /// User defined callback to be called when results are available. Can be null.
        /// User state in IAsyncResult. Can be null.
        /// The async result object to track the request. 
        /// Either entity or args parameters are null.
        /// The specified entity is either not tracked, is in the added state or it's not an MLE. 
        public IAsyncResult BeginGetReadStream(object entity, DataServiceRequestArgs args, AsyncCallback callback, object state) 
        {
            GetReadStreamResult result; 
            result = this.CreateGetReadStreamResult(entity, args, callback, state);
            result.Begin();
            return result;
        } 

        ///  
        /// Call this method when the results from the request for the Media Resource are required. 
        /// The method will block if the request have not finished yet.
        ///  
        /// Async result object returned from BeginGetReadStream.
        /// An instance of  which contains the response stream
        /// as well as its metadata.
        public DataServiceStreamResponse EndGetReadStream(IAsyncResult asyncResult) 
        {
            GetReadStreamResult result = BaseAsyncResult.EndExecute(this, "GetReadStream", asyncResult); 
            return result.End(); 
        }
 
#if !ASTORIA_LIGHT
        /// 
        /// This method executes synchronously a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object. 
        /// 
        /// The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state. 
        /// An instance of  which represents the response.
        /// entity parameter are null. 
        /// The specified entity is either not tracked, is in the added state or it's not an MLE.
        public DataServiceStreamResponse GetReadStream(object entity)
        {
            DataServiceRequestArgs args = new DataServiceRequestArgs(); 
            return this.GetReadStream(entity, args);
        } 
 
        /// 
        /// This method executes synchronously a request to get the read stream for a Media Resource 
        /// associated with the Media Link Entry represented by the entity object.
        /// 
        /// The entity which is the Media Link Entry for the requested Media Resource. Thist must specify
        /// a tracked entity in a non-added state. 
        /// The content type which should be requested from the server.
        /// An instance of  which represents the response. 
        /// Either entity or contentType parameters are null. 
        /// The specified entity is either not tracked, is in the added state or it's not an MLE.
        /// Or the contentType is an empty string. 
        public DataServiceStreamResponse GetReadStream(object entity, string acceptContentType)
        {
            Util.CheckArgumentNotEmpty(acceptContentType, "acceptContentType");
            DataServiceRequestArgs args = new DataServiceRequestArgs(); 
            args.AcceptContentType = acceptContentType;
            return this.GetReadStream(entity, args); 
        } 

        ///  
        /// This method executes synchronously a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object.
        /// 
        /// The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state.
        /// Instance of  class with additional metadata for the request. 
        /// Must not be null. 
        /// An instance of  which represents the response.
        /// Either entity or args parameters are null. 
        /// The specified entity is either not tracked, is in the added state or it's not an MLE.
        public DataServiceStreamResponse GetReadStream(object entity, DataServiceRequestArgs args)
        {
            GetReadStreamResult result = this.CreateGetReadStreamResult(entity, args, null, null); 
            return result.Execute();
        } 
 
#endif
        #endregion 

        #region SetSaveStream

        ///  
        /// Sets a new content for a Media Resource associated with the specified Media Link Entry entity.
        ///  
        /// The entity (MLE) for which to set the MR content. 
        /// The stream from which to read the content. The stream will be read to its end.
        /// No Seek operation will be tried on the stream. 
        /// If set to true SaveChanges will close the stream before it returns. It will close the stream
        /// even if it failed (throws) and even if it didn't get to use the stream.
        /// The Content-Type header value to set for the MR request. The value is not validated
        /// in any way and it's the responsibility of the user to make sure it's a valid value for Content-Type header. 
        /// The Slug header value to set for the MR request. The value is not validated in any way
        /// and it's the responsibility of the user to make usre it's a valid value for Slug header. 
        /// Calling this method marks the entity as media link resource (MLE). It also marks the entity as modified 
        /// so that it will participate in the next call to SaveChanges.
        /// The entity is not being tracked or the contentType is an empty string. 
        /// The entity has the MediaEntry attribute marking it to use the older way of handling MRs.
        /// Any of the arguments is null.
        public void SetSaveStream(object entity, Stream stream, bool closeStream, string contentType, string slug)
        { 
            Util.CheckArgumentNull(contentType, "contentType");
            Util.CheckArgumentNull(slug, "slug"); 
 
            DataServiceRequestArgs args = new DataServiceRequestArgs();
            args.ContentType = contentType; 
            args.Slug = slug;
            this.SetSaveStream(entity, stream, closeStream, args);
        }
 
        /// 
        /// Sets a new content for a Media Resource associated with the specified Media Link Entry entity. 
        ///  
        /// The entity (MLE) for which to set the MR content.
        /// The stream from which to read the content. The stream will be read to its end. 
        /// No Seek operation will be tried on the stream.
        /// If set to true SaveChanges will close the stream before it returns. It will close the stream
        /// even if it failed (throws) and even if it didn't get to use the stream.
        /// Instance of  class with additional metadata for the MR request. 
        /// Must not be null.
        /// Calling this method marks the entity as media link resource (MLE). It also marks the entity as modified 
        /// so that it will participate in the next call to SaveChanges. 
        /// The entity is not being tracked. The entity has the MediaEntry attribute
        /// marking it to use the older way of handling MRs. 
        /// Any of the arguments is null.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public void SetSaveStream(object entity, Stream stream, bool closeStream, DataServiceRequestArgs args)
        { 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNull(stream, "stream"); 
            Util.CheckArgumentNull(args, "args"); 

            ClientType clientType = ClientType.Create(entity.GetType()); 
            if (clientType.MediaDataMember != null)
            {
                throw new ArgumentException(
                    Strings.Context_SetSaveStreamOnMediaEntryProperty(clientType.ElementTypeName), 
                    "entity");
            } 
 
            box.SaveStream = new DataServiceSaveStream(stream, closeStream, args);
 
            Debug.Assert(box.State != EntityStates.Detached, "We should never have a detached entity in the entityDescriptor dictionary.");
            switch (box.State)
            {
                case EntityStates.Added: 
                    box.StreamState = StreamStates.Added;
                    break; 
 
                case EntityStates.Modified:
                case EntityStates.Unchanged: 
                    box.StreamState = StreamStates.Modified;
                    break;

                case EntityStates.Deleted: 
                default:
                    // 
 
                    throw new DataServiceClientException(Strings.DataServiceException_GeneralError);
            } 

            // Note that there's no need to mark the entity as updated because we consider the presense
            // of the save stream as the mark that the MR for this MLE has been updated.
        } 

        #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");

            SaveResult result = new SaveResult(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) 
        {
            SaveResult 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"); 

            SaveResult result = new SaveResult(this, "ExecuteBatch", queries, SaveChangesOptions.Batch, null, null, false);
            result.BatchRequest(false /*replaceOnUpdate*/);
            return result.EndRequest(); 
        }
#endif 
 
        #endregion
 
        #region Execute(Uri), BeginExecute(Uri), EndExecute(Uri)

        /// Begins 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);
            QueryComponents qc = new QueryComponents(requestUri, Util.DataServiceVersionEmpty, typeof(TElement), null, null); 
            return (new DataServiceRequest(qc, null)).BeginExecute(this, this, callback, state);
        } 
 
        /// Begins the execution of spscified continuation.
        /// Element type of the result 
        /// Conti----ation 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")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")] 
        public IAsyncResult BeginExecute(DataServiceQueryContinuation continuation, AsyncCallback callback, object state) 
        {
            Util.CheckArgumentNull(continuation, "continuation"); 
            QueryComponents qc = continuation.CreateQueryComponents();
            return (new DataServiceRequest(qc, continuation.Plan)).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) 
        { 
            Util.CheckArgumentNull(asyncResult, "asyncResult");
            return DataServiceRequest.EndExecute(this, this, asyncResult); 
        }

#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);
            QueryComponents qc = new QueryComponents(requestUri, Util.DataServiceVersionEmpty, typeof(TElement), null, null); 
            DataServiceRequest request = new DataServiceRequest(qc, null);
            return request.Execute(this, qc);
        }
 
        /// Executes the specified .
        /// Element type for response. 
        /// Continuation for query to execute. 
        /// The response for the specified .
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")] 
        public QueryOperationResponse Execute(DataServiceQueryContinuation continuation)
        {
            Util.CheckArgumentNull(continuation, "continuation");
            QueryComponents qc = continuation.CreateQueryComponents(); 
            DataServiceRequest request = new DataServiceRequest(qc, continuation.Plan);
            return request.Execute(this, qc); 
        } 
#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.
        ///  
        /// BeginSaveChanges will asynchronously attach identity Uri returned by server to sucessfully added entites.
        /// EndSaveChanges will apply updated values to entities, raise ReadingEntity events and change entity states. 
        ///  
        public IAsyncResult BeginSaveChanges(SaveChangesOptions options, AsyncCallback callback, object state)
        { 
            ValidateSaveChangesOptions(options);
            SaveResult result = new SaveResult(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)
        { 
            SaveResult result = BaseAsyncResult.EndExecute(this, "SaveChanges", asyncResult);
 
            DataServiceResponse errors = result.EndRequest(); 

            if (this.ChangesSaved != null) 
            {
                this.ChangesSaved(this, new SaveChangesEventArgs(errors));
            }
 
            return errors;
        } 
 
#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);

            SaveResult result = new SaveResult(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");
 
            if (this.ChangesSaved != null)
            {
                this.ChangesSaved(this, new SaveChangesEventArgs(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); 
 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target);
            if (this.bindings.ContainsKey(relation)) 
            {
                throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
            }
 
            relation.State = EntityStates.Added;
            this.bindings.Add(relation, relation); 
            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");

            LinkDescriptor existing; 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target);
            if (!this.bindings.TryGetValue(relation, out existing)) 
            { 
                return false;
            } 

            this.DetachExistingLink(existing, false);
            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); 

            LinkDescriptor existing = null; 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target); 
            if (this.bindings.TryGetValue(relation, out existing) && (EntityStates.Added == existing.State))
            {   // Added -> Detached 
                this.DetachExistingLink(existing, false);
            }
            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);
                    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);

            LinkDescriptor relation = this.DetachReferenceLink(source, sourceProperty, target, MergeOption.NoTracking); 
            if (null == relation)
            { 
                relation = new LinkDescriptor(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.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); 
            ValidateEntityType(entity); 

            EntityDescriptor resource = new EntityDescriptor(null, null /*selfLink*/, null /*editLink*/, entity, null, null, entitySetName, null, EntityStates.Added); 

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

            this.IncrementChange(resource);
        }
 
        /// 
        /// This API enables adding the target object and setting the link between the source object and target object in one request. 
        ///  
        /// the parent object which is already tracked by the context.
        /// The name of the navigation property which forms the association between the source and target. 
        /// the target object which needs to be added.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "parameters are validated against null via CheckArgumentNull")]
        public void AddRelatedObject(object source, string sourceProperty, object target) 
        {
            Util.CheckArgumentNull(source, "source"); 
            Util.CheckArgumentNotEmpty(sourceProperty, "propertyName"); 
            Util.CheckArgumentNull(target, "target");
 
            // Validate that the source is an entity and is already tracked by the context.
            ValidateEntityType(source);

            EntityDescriptor sourceResource = this.EnsureContained(source, "source"); 

            // Check for deleted source entity 
            if (sourceResource.State == EntityStates.Deleted) 
            {
                throw Error.InvalidOperation(Strings.Context_AddRelatedObjectSourceDeleted); 
            }

            // Validate that the property is valid and exists on the source
            ClientType parentType = ClientType.Create(source.GetType()); 
            ClientType.ClientProperty property = parentType.GetProperty(sourceProperty, false);
            if (property.IsKnownType || property.CollectionType == null) 
            { 
                throw Error.InvalidOperation(Strings.Context_AddRelatedObjectCollectionOnly);
            } 

            // Validate that the target is an entity
            ClientType childType = ClientType.Create(target.GetType());
            ValidateEntityType(target); 

            // Validate that the property type matches with the target type 
            ClientType propertyElementType = ClientType.Create(property.CollectionType); 
            if (!propertyElementType.ElementType.IsAssignableFrom(childType.ElementType))
            { 
                // target is not of the correct type
                throw Error.Argument(Strings.Context_RelationNotRefOrCollection, "target");
            }
 
            EntityDescriptor targetResource = new EntityDescriptor(null, null, null, target, sourceResource, sourceProperty, null /*entitySetName*/, null, EntityStates.Added);
 
            try 
            {
                this.entityDescriptors.Add(target, targetResource); 
            }
            catch (ArgumentException)
            {
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained); 
            }
 
            // Add the link in the added state. 
            LinkDescriptor end = targetResource.GetRelatedEnd();
            end.State = EntityStates.Added; 
            this.bindings.Add(end, end);

            this.IncrementChange(targetResource);
        } 

        ///  
        /// 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, null);
        }

        ///  
        /// 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);
            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
            String identity = Util.ReferenceIdentity(editLink.AbsoluteUri); 
 
            // EntitySetName need to be cached only when the entity is in added state. For all other states, entities self/edit link must be used.
            EntityDescriptor descriptor = new EntityDescriptor(identity, null /* selfLink */, editLink, entity, null /* parent */, null /* parent property */, null /*entitySetName*/, etag, EntityStates.Unchanged); 
            this.InternalAttachEntityDescriptor(descriptor, 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"); 
 
            EntityDescriptor resource = null;
            if (!this.entityDescriptors.TryGetValue(entity, out resource)) 
            {   // detached object
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            }
 
            EntityStates state = resource.State;
            if (EntityStates.Added == state) 
            {   // added -> detach 
                this.DetachResource(resource);
            } 
            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"); 

            EntityDescriptor resource = null; 
            if (this.entityDescriptors.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");
 
            EntityDescriptor resource = null; 
            if (!this.entityDescriptors.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
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public bool TryGetEntity(Uri identity, out TEntity entity) where TEntity : class
        { 
            entity = null;
            Util.CheckArgumentNull(identity, "relativeUri"); 
 
            EntityStates state;
 
            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
            entity = (TEntity)this.TryGetEntity(Util.ReferenceIdentity(identity.ToString()), 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"); 

            // if the entity's identity does not map back to the entity, don't return it
            EntityDescriptor resource = null;
            if ((null != this.identityToDescriptor) && 
                this.entityDescriptors.TryGetValue(entity, out resource) &&
                (null != resource.Identity) && 
                Object.ReferenceEquals(resource, this.identityToDescriptor[resource.Identity])) 
            {
                // DereferenceIdentity is a test hook to help verify we dont' use identity instead of editLink 
                string identityUri = Util.DereferenceIdentity(resource.Identity);
                identity = Util.CreateUri(identityUri, UriKind.Absolute);
            }
 
            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,
                    SerializeSupportedVersions()); 

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

            return failure; 
        } 

        ///  
        /// 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")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "underlying stream is disposed so wrapping StreamReader doesn't need to be disposed")] 
        internal static DataServiceClientException GetResponseText(Func getResponseStream, HttpStatusCode statusCode)
        { 
            string message = null;
            using (System.IO.Stream stream = getResponseStream())
            {
                if ((null != stream) && stream.CanRead) 
                {
                    // this StreamReader can go out of scope without dispose because the underly stream is disposed of 
                    message = new StreamReader(stream).ReadToEnd(); 
                }
            } 

            if (String.IsNullOrEmpty(message))
            {
                message = statusCode.ToString(); 
            }
 
            return new DataServiceClientException(message, (int)statusCode); 
        }
 
        /// response materialization has an identity to attach to the inserted object
        /// identity of entity
        /// query link of entity
        /// edit link of entity 
        /// inserted object
        /// etag of attached object 
        internal void AttachIdentity(String identity, Uri selfLink, Uri editLink, object entity, string etag) 
        {   // insert->unchanged
            Debug.Assert(null != identity, "must have identity"); 

            this.EnsureIdentityToResource();

            // resource.State == EntityState.Added or Unchanged for second pass of media link 
            EntityDescriptor resource = this.entityDescriptors[entity];
 
            this.DetachResourceIdentity(resource); 

            // While processing the response, we need to find out if the given resource was inserted deep 
            // If it was, then we need to change the link state from added to unchanged
            if (resource.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[resource.GetRelatedEnd()]; 
                end.State = EntityStates.Unchanged;
            } 
 
            resource.ETag = etag;
            resource.Identity = identity; // always attach the identity 
            resource.SelfLink = selfLink;
            resource.EditLink = editLink;

            resource.State = EntityStates.Unchanged; 

            // scenario: sucessfully (1) delete an existing entity and (2) add a new entity where the new entity has the same identity as deleted entity 
            // where the SaveChanges pass1 will now associate existing identity with new entity 
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity
            this.identityToDescriptor[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); 
            String identity = Util.ReferenceIdentity(editLink.ToString());

            this.EnsureIdentityToResource();
 
            // resource.State == EntityState.Added or Unchanged for second pass of media link
            EntityDescriptor resource = this.entityDescriptors[entity]; 
            this.DetachResourceIdentity(resource); 

            // While processing the response, we need to find out if the given resource was inserted deep 
            // If it was, then we need to change the link state from added to unchanged
            if (resource.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[resource.GetRelatedEnd()]; 
                end.State = EntityStates.Unchanged;
            } 
 
            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink; 

            // scenario: sucessfully batch (1) add a new entity and (2) delete an existing entity where the new entity has the same identity as deleted entity
            // where the SaveChanges pass1 will now associate existing identity with new entity
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity 
            this.identityToDescriptor[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);
 
            LinkDescriptor existing = null;
            LinkDescriptor relation = new LinkDescriptor(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.Target))
                        { 
                            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.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.
        ///  
        /// the descriptor to add 
        /// fail for public api else change existing relationship to unchanged
        /// Caller should validate descriptor instance. 
        /// The attached descriptor, if one already exists in the context and failIfDuplicated is set to false, then the existing instance is returned
        /// if entity is already being tracked by the context
        /// if identity is pointing to another entity
        internal EntityDescriptor InternalAttachEntityDescriptor(EntityDescriptor descriptor, bool failIfDuplicated) 
        {
            Debug.Assert((null != descriptor.Identity), "must have identity"); 
            Debug.Assert(null != descriptor.Entity && ClientType.Create(descriptor.Entity.GetType()).IsEntityType, "must be entity type to attach"); 

            this.EnsureIdentityToResource(); 

            EntityDescriptor resource;
            this.entityDescriptors.TryGetValue(descriptor.Entity, out resource);
 
            EntityDescriptor existing;
            this.identityToDescriptor.TryGetValue(descriptor.Identity, out existing); 
 
            // identity existing & pointing to something else
            if (failIfDuplicated && (null != resource)) 
            {
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained);
            }
            else if (resource != existing) 
            {
                throw Error.InvalidOperation(Strings.Context_DifferentEntityAlreadyContained); 
            } 
            else if (null == resource)
            { 
                resource = descriptor;

                // if resource doesn't exist...
                this.IncrementChange(descriptor); 
                this.entityDescriptors.Add(descriptor.Entity, descriptor);
                this.identityToDescriptor.Add(descriptor.Identity, descriptor); 
            } 

            // DEVNOTE([....]): 
            // we used to mark the descriptor as Unchanged
            // but it's now up to the caller to do that
            return resource;
        } 

        #endregion 
 
#if ASTORIA_LIGHT
        ///  
        /// create the request object
        /// 
        /// requestUri
        /// updating 
        /// Whether the request/response should request/assume ATOM or any MIME type
        /// content type for the request 
        /// The version associated with this request 
        /// Set to true if the request body should be sent using chunked encoding.
        /// a request ready to get a response 
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked)
        {
            return CreateRequest(requestUri, method, allowAnyType, contentType, requestVersion, sendChunked, HttpStack.Auto);
        } 
#endif
 
#if !ASTORIA_LIGHT 
        /// 
        /// create the request object 
        /// 
        /// requestUri
        /// updating
        /// Whether the request/response should request/assume ATOM or any MIME type 
        /// content type for the request. Can be null which means don't set the header.
        /// The version associated with this request 
        /// Set to true if the request body should be sent using chunked encoding. 
        /// a request ready to get a response
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked) 
#else
        /// 
        /// create the request object
        ///  
        /// requestUri
        /// updating 
        /// Whether the request/response should request/assume ATOM or any MIME type 
        /// content type for the request
        /// The version associated with this request 
        /// Set to true if the request body should be sent using chunked encoding.
        /// If set to non-Auto it forces usage of that http stack in SL regardless of the context settings.
        /// a request ready to get a response
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "sendChunked", Justification = "common parameter not used in silverlight")] 
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked, HttpStack httpStackArg)
#endif 
        { 
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
            Debug.Assert(
                requestUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) ||
                    requestUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase),
                "request uri is not for HTTP"); 

            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");
 
#if !ASTORIA_LIGHT
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); 
#else 
            if (httpStackArg == HttpStack.Auto)
            { 
                httpStackArg = this.httpStack;
            }
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri, httpStackArg);
#endif 

#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;
            }

            // Always sending the version along allows the server to fail before processing. 
            // devnote([....]): this needs to be set before SendingRequest is fired, so client has a chance to modify them
            if (requestVersion != null && requestVersion.Major > 0) 
            { 
                // if request version is 0.x, then we don't put a DSV header
                // in this case it's up to the server to decide what version this request is 
                request.Headers[XmlConstants.HttpDataServiceVersion] = requestVersion.ToString() + Util.VersionSuffix;
            }

            request.Headers[XmlConstants.HttpMaxDataServiceVersion] = Util.MaxResponseVersion.ToString() + Util.VersionSuffix; 

#if !ASTORIA_LIGHT // Silverlight doesn't support chunked encoding yet - so just ignore it 
            if (sendChunked) 
            {
                request.SendChunked = true; 
            }
#endif

            // 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)
            { 
                System.Net.WebHeaderCollection requestHeaders;
#if !ASTORIA_LIGHT
                requestHeaders = request.Headers;
                SendingRequestEventArgs args = new SendingRequestEventArgs(request, requestHeaders); 
#else
                requestHeaders = request.CreateEmptyWebHeaderCollection(); 
                SendingRequestEventArgs args = new SendingRequestEventArgs(null, requestHeaders); 
#endif
                this.SendingRequest(this, args); 

#if !ASTORIA_LIGHT
                if (!Object.ReferenceEquals(args.Request, request))
                { 
                    request = (System.Net.HttpWebRequest)args.Request;
                } 
#else 
                // apply all headers to the request
                foreach (string key in requestHeaders.AllKeys) 
                {
                    request.Headers[key] = requestHeaders[key];
                }
#endif 
            }
 
            request.Accept = allowAnyType ? 
                    XmlConstants.MimeAny :
                    (XmlConstants.MimeApplicationAtom + "," + XmlConstants.MimeApplicationXml); 

            request.Headers[HttpRequestHeader.AcceptCharset] = XmlConstants.Utf8Encoding;

#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available 
            bool allowStreamBuffering = false;
            bool removeXMethod = true; 
#endif 

            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; 
#if !ASTORIA_LIGHT
                    removeXMethod = false;
#endif
                } 
            }
            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;
            headers = request.Headers.AllKeys; 

#if !ASTORIA_LIGHT  // alternate IfMatch header doesn't work
            if (headers.Contains(XmlConstants.HttpRequestIfMatch))
            { 
                request.Headers.Remove(HttpRequestHeader.IfMatch);
            } 
#endif 

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

        /// 
        /// 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(String resourceUri, string etag, MergeOption merger, out EntityStates state)
        {
            Debug.Assert(null != resourceUri, "null uri");
            state = EntityStates.Detached; 

            EntityDescriptor resource = null; 
            if ((null != this.identityToDescriptor) && 
                 this.identityToDescriptor.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.Entity, "null entity"); 
                return resource.Entity;
            } 

            return null;
        }
 
        /// 
        /// 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.Source == source) && (o.SourceProperty == sourceProperty)); 
        }
 
        ///  
        /// user hook to resolve name into a type
        ///  
        /// name to resolve
        /// base type associated with name
        /// Whether to check that the resulting type is assignable.
        /// null to skip node 
        /// if ResolveType function returns a type not assignable to the userType
        internal Type ResolveTypeFromName(string wireName, Type userType, bool checkAssignable) 
        { 
            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 (checkAssignable && (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, use for complex types and LINQ query expression building
        ///  
        /// 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);
        }
 
        /// 
        /// Get from entity descriptor or resolve the server type name for the entitydescriptor 
        ///  
        /// The entity descriptor
        /// The server type name for the entity 
        internal string GetServerTypeName(EntityDescriptor descriptor)
        {
            Debug.Assert(descriptor != null && descriptor.Entity != null, "Null descriptor or no entity in descriptor");
 
            if (this.resolveName != null)
            { 
                // is resolveName the code-gen resolver? 
                Type entityType = descriptor.Entity.GetType();
                var codegenAttr = this.resolveName.Method.GetCustomAttributes(false).OfType().FirstOrDefault(); 
                if (codegenAttr == null || codegenAttr.Tool != Util.CodeGeneratorToolName)
                {
                    // User-supplied resolver, must call first
                    return this.resolveName(entityType) ?? descriptor.ServerTypeName; 
                }
                else 
                { 
                    // V2+ codegen resolver, called last
                    return descriptor.ServerTypeName ?? this.resolveName(entityType); 
                }
            }
            else
            { 
                return descriptor.ServerTypeName;
            } 
        } 

        ///  
        /// 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
 
        /// 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 a WCF 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; 
                }

                if (!Util.SupportedResponseVersions.Contains(version.Key))
                { 
                    return false;
                } 
            } 

            return true; 
        }

        /// 
        /// Serialize supported data service versions to a string that will be used in the exception message. 
        /// The string contains versions in single quotes separated by comma followed by a single space (e.g. "'1.0', '2.0'").
        ///  
        /// Supported data service versions in single quotes separated by comma followed by a space. 
        private static string SerializeSupportedVersions()
        { 
            Debug.Assert(Util.SupportedResponseVersions.Length > 0, "At least one supported version must exist.");

            StringBuilder supportedVersions = new StringBuilder("'").Append(Util.SupportedResponseVersions[0].ToString());
            for (int versionIdx = 1; versionIdx < Util.SupportedResponseVersions.Length; versionIdx++) 
            {
                supportedVersions.Append("', '"); 
                supportedVersions.Append(Util.SupportedResponseVersions[versionIdx].ToString()); 
            }
 
            supportedVersions.Append("'");

            return supportedVersions.ToString();
        } 

        /// 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");
 
            // to generate the edit link uri, we need keys 
            // this also checks for null
            ValidateEntityTypeHasKeys(entity); 

            StringBuilder builder = new StringBuilder();
            builder.Append(baseUriWithSlash.AbsoluteUri);
            builder.Append(entitySetName); 
            builder.Append("(");
 
            string prefix = String.Empty; 
            ClientType clientType = ClientType.Create(entity.GetType());
 
            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.Context_CannotConvertKey(value));
                } 
 
                builder.Append(System.Uri.EscapeDataString(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(LinkDescriptor link)
        {
            bool collection = (null != ClientType.Create(link.Source.GetType()).GetProperty(link.SourceProperty, false).CollectionType); 
            if (!collection)
            { 
                Debug.Assert(EntityStates.Modified == link.State, "not Modified state"); 
                if (null == link.Target)
                {   // 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; 
            } 
        }
 
        /// Handle changeset response.
        /// headers of changeset response
        private static void HandleResponsePost(LinkDescriptor entry)
        { 
            if (!((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State && null != entry.Target)))
            { 
                Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState); 
            }
 
            entry.State = EntityStates.Unchanged;
        }

        /// Handle changeset response. 
        /// updated entity or link
        /// updated etag 
        private static void HandleResponsePut(Descriptor entry, string etag) 
        {
            if (entry.IsResource) 
            {
                EntityDescriptor descriptor = (EntityDescriptor)entry;
                if (EntityStates.Modified != descriptor.State && StreamStates.Modified != descriptor.StreamState)
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.EntryNotModified);
                } 
 
                // We MUST process the MR before the MLE since we always issue the requests in that order.
                if (descriptor.StreamState == StreamStates.Modified) 
                {
                    descriptor.StreamETag = etag;
                    descriptor.StreamState = StreamStates.NoStream;
                } 
                else
                { 
                    Debug.Assert(descriptor.State == EntityStates.Modified, "descriptor.State == EntityStates.Modified"); 
                    descriptor.ETag = etag;
                    descriptor.State = EntityStates.Unchanged; 
                }
            }
            else
            { 
                LinkDescriptor link = (LinkDescriptor)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, false /* atomDateConstruct */); 
                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  is entity type
        /// entity to validate
        /// if entity was null 
        /// if entity does not have a key property
        private static void ValidateEntityType(object entity) 
        { 
            Util.CheckArgumentNull(entity, "entity");
 
            if (!ClientType.Create(entity.GetType()).IsEntityType)
            {
                throw Error.Argument(Strings.Content_EntityIsNotEntityType, "entity");
            } 
        }
 
        /// validate  has key properties 
        /// entity to validate
        /// if entity was null 
        /// if entity does not have a key property
        private static void ValidateEntityTypeHasKeys(object entity)
        {
            Util.CheckArgumentNull(entity, "entity"); 

            if (ClientType.Create(entity.GetType()).KeyCount <= 0) 
            { 
                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. 
        /// version for the request
        private static void WriteOperationRequestHeaders(StreamWriter writer, string methodName, string uri, Version requestVersion) 
        {
            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); 
            if (requestVersion != Util.DataServiceVersion1 && requestVersion != Util.DataServiceVersionEmpty) 
            {
                writer.WriteLine("{0}: {1}{2}", XmlConstants.HttpDataServiceVersion, requestVersion, Util.VersionSuffix); 
            }
        }

        ///  
        /// 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); 
        } 

        /// the work to detach a resource 
        /// resource to detach
        /// true if detached
        private bool DetachResource(EntityDescriptor resource)
        { 
            // Since we are changing the list on the fly, we need to convert it into a list first
            // so that enumeration won't get effected. 
            foreach (LinkDescriptor end in this.bindings.Values.Where(resource.IsRelatedEntity).ToList()) 
            {
                this.DetachExistingLink( 
                        end,
                        end.Target == resource.Entity && resource.State == EntityStates.Added);
            }
 
            resource.ChangeOrder = UInt32.MaxValue;
            resource.State = EntityStates.Detached; 
            bool flag = this.entityDescriptors.Remove(resource.Entity); 
            Debug.Assert(flag, "should have removed existing entity");
            this.DetachResourceIdentity(resource); 

            return true;
        }
 
        /// remove the identity attached to the resource
        /// resource with an identity to detach to detach 
        private void DetachResourceIdentity(EntityDescriptor resource) 
        {
            EntityDescriptor existing = null; 
            if ((null != resource.Identity) &&
                this.identityToDescriptor.TryGetValue(resource.Identity, out existing) &&
                Object.ReferenceEquals(existing, resource))
            { 
                bool removed = this.identityToDescriptor.Remove(resource.Identity);
                Debug.Assert(removed, "should have removed existing identity"); 
            } 
        }
 
        /// 
        /// 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(LinkDescriptor binding) 
        { 
            Debug.Assert(null != binding, "null binding");
            if (binding.ContentGeneratedForSave) 
            {
                return null;
            }
 
            EntityDescriptor sourceResource = this.entityDescriptors[binding.Source];
            EntityDescriptor targetResource = (null != binding.Target) ? this.entityDescriptors[binding.Target] : 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, Util.DataServiceVersion1, false); 
        }
 
        /// create the uri for a link
        /// edit link of source
        /// link
        /// appropriate uri for link state 
        private Uri CreateRequestUri(EntityDescriptor sourceResource, LinkDescriptor binding)
        { 
            Uri requestUri = Util.CreateUri(sourceResource.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/), this.CreateRequestRelativeUri(binding)); 
            return requestUri;
        } 

        /// 
        /// create the uri for the link relative to its source entity
        ///  
        /// link
        /// uri 
        private Uri CreateRequestRelativeUri(LinkDescriptor binding) 
        {
            Uri relative; 
            bool collection = (null != ClientType.Create(binding.Source.GetType()).GetProperty(binding.SourceProperty, false).CollectionType);
            if (collection && (EntityStates.Added != binding.State))
            {   // you DELETE(PUT NULL) from a collection
                Debug.Assert(null != binding.Target, "null target in collection"); 
                EntityDescriptor targetResource = this.entityDescriptors[binding.Target];
 
                // 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.Entity)); 

                // 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(LinkDescriptor binding, StreamWriter text)
        { 
            EntityDescriptor sourceResource = this.entityDescriptors[binding.Source]; 
            string requestString;
            if (null != sourceResource.Identity) 
            {
                requestString = this.CreateRequestUri(sourceResource, binding).AbsoluteUri;
            }
            else 
            {
                Uri relative = this.CreateRequestRelativeUri(binding); 
                requestString = "$" + sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) + "/" + relative.OriginalString; 
            }
 
            WriteOperationRequestHeaders(text, GetLinkHttpMethod(binding), requestString, Util.DataServiceVersion1);
            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.Target))) 
            { 
                text.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.MimeApplicationXml);
            } 
        }

        /// 
        /// create content memory stream for link 
        /// 
        /// link 
        /// should newline be written 
        /// memory stream
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MemoryStream which doesn't require disposal")] 
        private MemoryStream CreateRequestData(LinkDescriptor binding, bool newline)
        {
            Debug.Assert(
                (binding.State == EntityStates.Added) || 
                (binding.State == EntityStates.Modified && null != binding.Target),
                "This method must be called only when a binding is added or put"); 
            MemoryStream stream = new MemoryStream(); 
            XmlWriter writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
            EntityDescriptor targetResource = this.entityDescriptors[binding.Target]; 

            #region 
            writer.WriteStartElement(XmlConstants.UriElementName, XmlConstants.DataWebMetadataNamespace);
 
            string id;
            if (null != targetResource.Identity) 
            { 
                // When we write the uri in the payload, we need to make sure that we write the edit
                // link in the payload, since the request uri is the edit link of the parent entity. 
                // Think of a read/write service - since the uri is the target link to the parent entity
                // its better than we write the edit link of the child entity in the payload.
                id = targetResource.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/).OriginalString;
            } 
            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 
                for (int kk = 0; kk < NewLine.Length; ++kk)
                {
                    stream.WriteByte((byte)NewLine[kk]);
                } 
            }
 
            // 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(EntityDescriptor 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, false /*queryLink*/); 
 
            Version requestVersion = ClientType.Create(box.Entity.GetType()).EpmIsV1Compatible ? Util.DataServiceVersion1 : Util.DataServiceVersion2;
            HttpWebRequest request = this.CreateRequest(requestUri, httpMethod, false, XmlConstants.MimeApplicationAtom, requestVersion, false); 
            if ((null != box.ETag) && ((EntityStates.Deleted == state) || (EntityStates.Modified == state)))
            {
                request.Headers.Set(HttpRequestHeader.IfMatch, box.ETag);
            } 

            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(EntityDescriptor box, StreamWriter text, bool replaceOnUpdate) 
        { 
            Debug.Assert(null != box, "null box");
            Debug.Assert(null != text, "null text"); 
            Debug.Assert(box.State == EntityStates.Added || box.State == EntityStates.Deleted || box.State == EntityStates.Modified, "the entity must be in one of the 3 possible states");

            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/);
 
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
 
            Version requestVersion = ClientType.Create(box.Entity.GetType()).EpmIsV1Compatible ? Util.DataServiceVersion1 : Util.DataServiceVersion2;
            WriteOperationRequestHeaders(text, GetEntityHttpMethod(box.State, replaceOnUpdate), requestUri.AbsoluteUri, requestVersion); 
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, box.ChangeOrder);
            if (EntityStates.Deleted != box.State)
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.LinkMimeTypeEntry); 
            }
 
            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 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MemoryStream which doesn't require disposal")]
        private MemoryStream CreateRequestData(EntityDescriptor 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.Entity.GetType());
 
                string typeName = this.GetServerTypeName(box);

                #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();
                } 
 
                if (type.HasEntityPropertyMappings)
                { 
                    using (EpmSyndicationContentSerializer s = new EpmSyndicationContentSerializer(type.EpmTargetTree, box.Entity, writer))
                    {
                        s.Serialize();
                    } 
                }
                else 
                { 
                    // 
                    // <updated>2008-05-05T21:44:55Z</updated> 
                    // <author><name /></author>
                    writer.WriteElementString(XmlConstants.AtomTitleElementName, XmlConstants.AtomNamespace, String.Empty);
                    writer.WriteStartElement(XmlConstants.AtomAuthorElementName, XmlConstants.AtomNamespace);
                    writer.WriteElementString(XmlConstants.AtomNameElementName, XmlConstants.AtomNamespace, String.Empty); 
                    writer.WriteEndElement();
 
                    writer.WriteElementString(XmlConstants.AtomUpdatedElementName, XmlConstants.AtomNamespace, XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind)); 
                }
 
                if (EntityStates.Modified == box.State)
                {
                    // <id>http://host/service/entityset(key)</id>
                    writer.WriteElementString(XmlConstants.AtomIdElementName, Util.DereferenceIdentity(box.Identity)); 
                }
                else 
                { 
                    writer.WriteElementString(XmlConstants.AtomIdElementName, XmlConstants.AtomNamespace, String.Empty);
                } 

                #region <link href=”%EditLink%” 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> 
                // For MLE we need to write the properties to the entry level, we also omit the content element completely
                //   as the server will ignore it anyway.
                if (!type.IsMediaLinkEntry && !box.IsMediaLinkEntry)
                { 
                    writer.WriteStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); // <atom:content>
                    writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.MimeApplicationXml); // empty namespace 
                } 

                writer.WriteStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace); // <m:Properties> 

                bool propertiesWritten;
                this.WriteContentProperties(writer, type, box.Entity, type.HasEntityPropertyMappings ? type.EpmSourceTree.Root : null, out propertiesWritten);
 
                writer.WriteEndElement(); // </m:Properties>
 
                if (!type.IsMediaLinkEntry && !box.IsMediaLinkEntry) 
                {
                    writer.WriteEndElement(); // </atom:content> 
                }

                if (type.HasEntityPropertyMappings)
                { 
                    using (EpmCustomContentSerializer s = new EpmCustomContentSerializer(type.EpmTargetTree, box.Entity, writer))
                    { 
                        s.Serialize(); 
                    }
                } 

                writer.WriteEndElement(); // </atom:entry>
                writer.Flush();
                writer.Close(); 
                #endregion
                #endregion 
 
                if (this.WritingEntity != null)
                { 
                    ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(box.Entity, 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
                    XmlWriterSettings settings = XmlUtil.CreateXmlWriterSettings(HttpProcessUtility.EncodingUtf8NoPreamble); 
                    settings.ConformanceLevel = ConformanceLevel.Auto; 
                    using (XmlWriter streamWriter = XmlWriter.Create(stream, settings))
                    { 
                        node.Save(streamWriter);
                    }
                }
 
                if (newline)
                { 
                    // end the xml content stream with a newline 
                    for (int kk = 0; kk < NewLine.Length; ++kk)
                    { 
                        stream.WriteByte((byte)NewLine[kk]);
                    }
                }
 
                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(EntityDescriptor box, XmlWriter writer) 
        {
            Debug.Assert(EntityStates.Added == box.State, "entity not added state"); 

            ClientType clientType = null;
            foreach (LinkDescriptor end in this.RelatedLinks(box))
            { 
                Debug.Assert(!end.ContentGeneratedForSave, "already saved link");
                end.ContentGeneratedForSave = true; 
 
                if (null == clientType)
                { 
                    clientType = ClientType.Create(box.Entity.GetType());
                }

                string typeAttributeValue; 
                if (null != clientType.GetProperty(end.SourceProperty, false).CollectionType)
                { 
                    typeAttributeValue = XmlConstants.LinkMimeTypeFeed; 
                }
                else 
                {
                    typeAttributeValue = XmlConstants.LinkMimeTypeEntry;
                }
 
                Debug.Assert(null != end.Target, "null is DELETE");
                String targetEditLink = this.entityDescriptors[end.Target].EditLink.ToString(); 
 
                writer.WriteStartElement(XmlConstants.AtomLinkElementName, XmlConstants.AtomNamespace);
                writer.WriteAttributeString(XmlConstants.AtomHRefAttributeName, targetEditLink); 
                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(Descriptor entry) 
        {
            if (EntityStates.Deleted != entry.State)
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotDeleted); 
            }
 
            if (entry.IsResource) 
            {
                EntityDescriptor resource = (EntityDescriptor)entry; 
                this.DetachResource(resource);
            }
            else
            { 
                this.DetachExistingLink((LinkDescriptor)entry, false);
            } 
        } 

        /// <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(EntityDescriptor entry, MaterializeAtom materializer, Uri editLink, string etag)
        { 
            Debug.Assert(editLink != null, "location header must be specified in POST responses."); 

            if (EntityStates.Added != entry.State && StreamStates.Added != entry.StreamState) 
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotAddedState);
            }
 
            if (materializer == null)
            { 
                // If the materializer is null, that means the POST request didn't send a response back. Hence we will use 
                // the location header as the self and edit links.
                String identity = Util.ReferenceIdentity(editLink.ToString()); 
                this.AttachIdentity(identity, null /*queryLink*/, editLink, entry.Entity, etag);
            }
            else
            { 
                materializer.SetInsertingObject(entry.Entity);
 
                foreach (object x in materializer) 
                {
                    Debug.Assert(null != entry.Identity, "updated inserted should always gain an identity"); 
                    Debug.Assert(x == entry.Entity, "x == box.Entity, should have same object generated by response");
                    Debug.Assert(EntityStates.Unchanged == entry.State, "should have moved out of insert");
                    Debug.Assert((null != this.identityToDescriptor) && this.identityToDescriptor.ContainsKey(entry.Identity), "should have identity tracked");
 
                    // If there was no edit link specified in the payload, then we need to set the location header as the edit link
                    if (entry.EditLink == null) 
                    { 
                        entry.EditLink = editLink;
                    } 

                    // If there was no etag specified in the payload, then we need to set the etag from the header
                    if (entry.ETag == null)
                    { 
                        entry.ETag = etag;
                    } 
                } 
            }
 
            foreach (LinkDescriptor end in this.RelatedLinks(entry))
            {
                Debug.Assert(0 != end.SaveResultWasProcessed, "link should have been saved with the enty");
 
                // Since we allow link folding on collection properties also, we need to check if the link
                // was in added state also, and make sure we put that link in unchanged state. 
                if (IncludeLinkState(end.SaveResultWasProcessed) || end.SaveResultWasProcessed == EntityStates.Added) 
                {
                    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(Descriptor entry)
        { 
            // media links will be processed twice
            entry.SaveResultWasProcessed = entry.State;

            int count = 0; 
            if (entry.IsResource && (EntityStates.Added == entry.State))
            { 
                foreach (LinkDescriptor end in this.RelatedLinks((EntityDescriptor)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<LinkDescriptor> RelatedLinks(EntityDescriptor box) 
        {
            foreach (LinkDescriptor end in this.bindings.Values) 
            { 
                if (end.Source == box.Entity)
                { 
                    if (null != end.Target)
                    {   // null TargetResource is equivalent to Deleted
                        EntityDescriptor target = this.entityDescriptors[end.Target];
 
                        // 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;
                        } 
                    }
                }
            }
        } 

        /// <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>
        /// <param name="requestUri">The request uri, or null if one is to be constructed</param> 
        /// <param name="continuation">Continuation, if one is available.</param>
        /// <returns>a aync result that you can get a response from</returns> 
        private LoadPropertyResult CreateLoadPropertyRequest(object entity, string propertyName, AsyncCallback callback, object state, Uri requestUri, DataServiceQueryContinuation continuation) 
        {
            Debug.Assert(continuation == null || requestUri == null, "continuation == null || requestUri == null -- only one or the either (or neither) may be passed in"); 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNotEmpty(propertyName, "propertyName");

            ClientType type = ClientType.Create(entity.GetType()); 
            Debug.Assert(type.IsEntityType, "must be entity type 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"); 

            ProjectionPlan plan; 
            if (continuation == null) 
            {
                plan = null; 
            }
            else
            {
                plan = continuation.Plan; 
                requestUri = continuation.NextLinkUri;
            } 
 
            bool mediaLink = (type.MediaDataMember != null && propertyName == type.MediaDataMember.PropertyName);
            Version requestVersion; 
            if (requestUri == null)
            {
                Uri relativeUri;
                if (mediaLink) 
                {
                    // special case for requesting the "media" value of an ATOM media link entry 
                    relativeUri = Util.CreateUri(XmlConstants.UriValueSegment, UriKind.Relative); 
                }
                else 
                {
                    relativeUri = Util.CreateUri(propertyName + (null != property.CollectionType ? "()" : String.Empty), UriKind.Relative);
                }
 
                requestUri = Util.CreateUri(box.GetResourceUri(this.baseUriWithSlash, true /*queryLink*/), relativeUri);
                requestVersion = Util.DataServiceVersion1; 
            } 
            else
            { 
                // if we specify an URI, we need to keep the Execute<T> behaviour
                requestVersion = Util.DataServiceVersionEmpty;
            }
 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, mediaLink, null, requestVersion, false);
            DataServiceRequest dataServiceRequest = DataServiceRequest.GetInstance(property.PropertyType, requestUri); 
            return new LoadPropertyResult(entity, propertyName, this, request, callback, state, dataServiceRequest, plan); 
        }
 
        /// <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> 
        /// <param name="currentSegment">Source EPM tree segment corresponding to <paramref name="type"/></param> 
        /// <param name="propertiesWritten">True if we have written any property to the writer.</param>
        private void WriteContentProperties(XmlWriter writer, ClientType type, object resource, EpmSourcePathSegment currentSegment, out bool propertiesWritten) 
        {
            #region <d:property>value</property>
            propertiesWritten = false;
            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);
 
                EpmSourcePathSegment matchedSegment = currentSegment != null ? currentSegment.SubProperties.SingleOrDefault(s => s.PropertyName == property.PropertyName) : null; 

                if (property.IsKnownType) 
                {
                    if (propertyValue == null || matchedSegment == null || matchedSegment.EpmInfo.Attribute.KeepInContent)
                    {
                        WriteContentProperty(writer, this.DataNamespace, property, propertyValue); 
                        propertiesWritten = true;
                    } 
                } 
#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())) 
                        {
                            Type valueType = pair.Value != null ? pair.Value.GetType() : typeof(string); 
                            ClientType.ClientProperty openProperty = new ClientType.ClientProperty(null, valueType, false, true); 
                            WriteContentProperty(writer, this.DataNamespace, openProperty, pair.Value);
                            propertiesWritten = true; 
                        }
                    }
                }
#endif 
                else if (null == property.CollectionType)
                { 
                    ClientType nested = ClientType.Create(property.PropertyType); 
                    if (!nested.IsEntityType)
                    { 
                        #region complex type
                        XElement complexProperty = new XElement(((XNamespace)this.DataNamespace) + property.PropertyName);
                        bool shouldWriteComplexProperty = false;
                        string typeName = this.ResolveNameFromType(nested.ElementType); 
                        if (!String.IsNullOrEmpty(typeName))
                        { 
                            complexProperty.Add(new XAttribute(((XNamespace)XmlConstants.DataWebMetadataNamespace) + XmlConstants.AtomTypeAttributeName, typeName)); 
                        }
 
                        // Handle null values for complex types by putting m:null="true"
                        if (null == propertyValue)
                        {
                            complexProperty.Add(new XAttribute(((XNamespace)XmlConstants.DataWebMetadataNamespace) + XmlConstants.AtomNullAttributeName, XmlConstants.XmlTrueLiteral)); 
                            shouldWriteComplexProperty = true;
                        } 
                        else 
                        {
                            using (XmlWriter complexPropertyWriter = complexProperty.CreateWriter()) 
                            {
                                this.WriteContentProperties(complexPropertyWriter, nested, propertyValue, matchedSegment, out shouldWriteComplexProperty);
                            }
                        } 

                        if (shouldWriteComplexProperty) 
                        { 
                            complexProperty.WriteTo(writer);
                            propertiesWritten = true; 
                        }
                        #endregion
                    }
                } 
            }
            #endregion 
        } 

        /// <summary>Detach existing link</summary> 
        /// <param name="existingLink">link to detach</param>
        /// <param name="targetDelete">true if target is being deleted, false otherwise</param>
        private void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
        { 
            // The target can be null in which case we don't need this check
            if (existingLink.Target != null) 
            { 
                // Identify the target resource for the link
                EntityDescriptor targetResource = this.entityDescriptors[existingLink.Target]; 

                // Check if there is a dependency relationship b/w the source and target objects i.e. target can not exist without source link
                // Deep insert requires this check to be made but skip the check if the target object is being deleted
                if (targetResource.IsDeepInsert && !targetDelete) 
                {
                    EntityDescriptor parentOfTarget = targetResource.ParentForInsert; 
                    if (Object.ReferenceEquals(targetResource.ParentEntity, existingLink.Source) && 
                       (parentOfTarget.State != EntityStates.Deleted ||
                        parentOfTarget.State != EntityStates.Detached)) 
                    {
                        throw new InvalidOperationException(Strings.Context_ChildResourceExists);
                    }
                } 
            }
 
            if (this.bindings.Remove(existingLink)) 
            {   // this link may have been previously detached by a detaching entity
                existingLink.State = EntityStates.Detached; 
            }
        }

        /// <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 LinkDescriptor DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        { 
            LinkDescriptor existing = this.GetLinks(source, sourceProperty).FirstOrDefault();
            if (null != existing) 
            { 
                if ((target == existing.Target) ||
                    (MergeOption.AppendOnly == linkMerge) || 
                    (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State))
                {
                    return existing;
                } 

                // Since we don't support deep insert on reference property, no need to check for deep insert. 
                this.DetachExistingLink(existing, false); 
                Debug.Assert(!this.bindings.Values.Any(o => (o.Source == 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 EntityDescriptor EnsureContained(object resource, string parameterName)
        { 
            Util.CheckArgumentNull(resource, parameterName);
 
            EntityDescriptor box = null; 
            if (!this.entityDescriptors.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)
        { 
            EntityDescriptor sourceResource = this.EnsureContained(source, "source"); 
            EntityDescriptor 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.IsEntityType, "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.IsEntityType, "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.identityToDescriptor) 
            {
                System.Threading.Interlocked.CompareExchange(ref this.identityToDescriptor, new Dictionary<String, EntityDescriptor>(EqualityComparer<String>.Default), null); 
            } 
        }
 
        /// <summary>
        /// increment the resource change for sorting during submit changes
        /// </summary>
        /// <param name="descriptor">the resource to update the change order</param> 
        private void IncrementChange(Descriptor descriptor)
        { 
            descriptor.ChangeOrder = ++this.nextChange; 
        }
 
        /// <summary>
        /// This method creates an async result object around a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object.
        /// </summary> 
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify
        /// a tracked entity in a non-added state.</param> 
        /// <param name="args">Instance of <see cref="DataServiceRequestArgs"/> class with additional metadata for the request. 
        /// Must not be null.</param>
        /// <param name="callback">User defined callback to be called when results are available. Can be null.</param> 
        /// <param name="state">User state in IAsyncResult. Can be null.</param>
        /// <returns>The async result object for the request, the request hasn't been started yet.</returns>
        /// <exception cref="ArgumentNullException">Either entity or args parameters are null.</exception>
        /// <exception cref="ArgumentException">The specified entity is either not tracked, 
        /// is in the added state or it's not an MLE.</exception>
        private GetReadStreamResult CreateGetReadStreamResult( 
            object entity, 
            DataServiceRequestArgs args,
            AsyncCallback callback, 
            object state)
        {
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNull(args, "args"); 

            Uri requestUri = box.GetMediaResourceUri(this.baseUriWithSlash); 
            if (requestUri == null) 
            {
                throw new ArgumentException(Strings.Context_EntityNotMediaLinkEntry, "entity"); 
            }

#if ASTORIA_LIGHT
            // For MR requests always use the ClientHtpp stack as the XHR doesn't support binary content 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, true, null, null, false, HttpStack.ClientHttp);
#else 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, true, null, null, false); 
#endif
 
            WebUtil.ApplyHeadersToRequest(args.Headers, request, false);

            return new GetReadStreamResult(this, "GetReadStream", request, callback, state);
        } 

        /// <summary>Stream wrapper for MR POST/PUT which also holds the information if the stream should be closed or not.</summary> 
        internal class DataServiceSaveStream 
        {
            /// <summary>The stream we are wrapping. 
            /// Can be null in which case we didn't open it yet.</summary>
            private readonly Stream stream;

            // This class would one day hold a Func<Stream> to open the stream when needed 
            //   instead of specifying the stream up front.
 
            /// <summary>Set to true if the stream should be closed once we're done with it.</summary> 
            private readonly bool close;
 
            /// <summary>Arguments for the request when POST/PUT of the stream is issued.</summary>
            private readonly DataServiceRequestArgs args;

            /// <summary> 
            /// Constructor
            /// </summary> 
            /// <param name="stream">The stream to use.</param> 
            /// <param name="close">Should the stream be closed before SaveChanges returns.</param>
            /// <param name="args">Additional arguments to apply to the request before sending it.</param> 
            internal DataServiceSaveStream(Stream stream, bool close, DataServiceRequestArgs args)
            {
                Debug.Assert(stream != null, "stream must not be null.");
 
                this.stream = stream;
                this.close = close; 
                this.args = args; 
            }
 
            /// <summary>The stream to use.</summary>
            internal Stream Stream
            {
                get 
                {
                    return this.stream; 
                } 
            }
 
            /// <summary>
            /// Arguments to be used for creation of the HTTP request when POST/PUT for the MR is issued.
            /// </summary>
            internal DataServiceRequestArgs Args 
            {
                get { return this.args; } 
            } 

            /// <summary> 
            /// Close the stream if required.
            /// This is so that callers can simply call this method and don't have to care about the settings.
            /// </summary>
            internal void Close() 
            {
                if (this.stream != null && this.close) 
                { 
                    this.stream.Close();
                } 
            }
        }

        /// <summary>wrapper around loading a property from a response</summary> 
        private class LoadPropertyResult : QueryResult
        { 
            #region Private fields. 

            /// <summary>entity whose property is being loaded</summary> 
            private readonly object entity;

            /// <summary>Projection plan for loading results; possibly null.</summary>
            private readonly ProjectionPlan plan; 

            /// <summary>name of the property on the entity that is being loaded</summary> 
            private readonly string propertyName; 

            #endregion Private fields. 

            /// <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> 
            /// <param name="plan">Projection plan for materialization; possibly null.</param>
            internal LoadPropertyResult(object entity, string propertyName, DataServiceContext context, HttpWebRequest request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest, ProjectionPlan plan)
                : base(context, "LoadProperty", dataServiceRequest, request, callback, state)
            { 
                this.entity = entity;
                this.propertyName = propertyName; 
                this.plan = plan; 
            }
 
            /// <summary>
            /// loading a property from a response
            /// </summary>
            /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
            internal QueryOperationResponse LoadProperty()
            { 
                MaterializeAtom results = null; 

                DataServiceContext context = (DataServiceContext)this.Source; 

                ClientType type = ClientType.Create(this.entity.GetType());
                Debug.Assert(type.IsEntityType, "must be entity type to be contained");
 
                EntityDescriptor 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.GetResponseWithType(results, elementType); 
                }
                catch (InvalidOperationException ex) 
                {
                    QueryOperationResponse response = this.GetResponseWithType(results, elementType);
                    if (response != null)
                    { 
                        response.Error = ex;
                        throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, response); 
                    } 

                    throw; 
                }
            }

            /// <summary> 
            /// Reads the data from the response stream into a buffer using the content length.
            /// </summary> 
            /// <param name="responseStream">Response stream.</param> 
            /// <param name="totalLength">Length of data to read.</param>
            /// <returns>byte array containing read data.</returns> 
            private static byte[] ReadByteArrayWithContentLength(Stream responseStream, int totalLength)
            {
                byte[] buffer = new byte[totalLength];
                int read = 0; 
                while (read < totalLength)
                { 
                    int r = responseStream.Read(buffer, read, totalLength - read); 
                    if (r <= 0)
                    { 
                        throw Error.InvalidOperation(Strings.Context_UnexpectedZeroRawRead);
                    }

                    read += r; 
                }
 
                return buffer; 
            }
 
            /// <summary>Reads the data from the response stream in chunks.</summary>
            /// <param name="responseStream">Response stream.</param>
            /// <returns>byte array containing read data.</returns>
            private static byte[] ReadByteArrayChunked(Stream responseStream) 
            {
                byte[] completeBuffer = null; 
                using (MemoryStream m = new MemoryStream()) 
                {
                    byte[] buffer = new byte[4096]; 
                    int numRead = 0;
                    int totalRead = 0;
                    while (true)
                    { 
                        numRead = responseStream.Read(buffer, 0, buffer.Length);
                        if (numRead <= 0) 
                        { 
                            break;
                        } 

                        m.Write(buffer, 0, numRead);
                        totalRead += numRead;
                    } 

                    completeBuffer = new byte[totalRead]; 
                    m.Position = 0; 
                    numRead = m.Read(completeBuffer, 0, completeBuffer.Length);
                } 

                return completeBuffer;
            }
 
            /// <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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MaterializeAtom, caller will dispose")]
            private MaterializeAtom ReadPropertyFromAtom(EntityDescriptor box, ClientType.ClientProperty property)
            { 
                DataServiceContext context = (DataServiceContext)this.Source;
 
                bool merging = context.ApplyingChanges; 

                try 
                {
                    context.ApplyingChanges = true;

                    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;
                            if (BindingEntityInfo.IsDataServiceCollection(property.PropertyType))
                            { 
                                Debug.Assert(WebUtil.GetDataServiceCollectionOfT(nestedType) != null, "DataServiceCollection<> must be available here.");
 
                                // new DataServiceCollection<nestedType>(null, TrackingMode.None) 
                                collection = Activator.CreateInstance(
                                    WebUtil.GetDataServiceCollectionOfT(nestedType), 
                                    null,
                                    TrackingMode.None);
                            }
                            else 
                            {
                                collection = Activator.CreateInstance(typeof(List<>).MakeGenericType(nestedType)); 
                            } 
                        }
                    } 

                    // 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)); 

                    DataServiceQueryContinuation continuation = null; 
 
                    // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                    using (MaterializeAtom materializer = this.GetMaterializer(context, this.plan)) 
                    {
                        Debug.Assert(materializer != null, "materializer != null -- otherwise GetMaterializer() returned null rather than empty");
                        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.IsEntityType) 
                            {
                                if (deletedState)
                                {
                                    context.DeleteLink(this.entity, this.propertyName, child); 
                                }
                                else 
                                {   // put link into unchanged state 
                                    context.AttachLink(this.entity, this.propertyName, child, materializer.MergeOptionValue);
                                } 
                            }
                        }

                        // LoadProperty should only deal with single level collections 
                        continuation = materializer.GetContinuation(null);
                        Util.SetNextLinkForCollection(collection, continuation); 
 
                        // 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 MaterializeAtom.CreateWrapper(results, continuation);
                } 
                finally 
                {
                    context.ApplyingChanges = merging; 
                }
            }

            /// <summary> 
            /// Load property data form a raw response
            /// </summary> 
            /// <param name="property">The property being loaded</param> 
            /// <returns>property values as IEnumerable.</returns>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MaterializeAtom, caller will dispose")] 
            private MaterializeAtom ReadPropertyFromRawData(ClientType.ClientProperty property)
            {
                DataServiceContext context = (DataServiceContext)this.Source;
 
                bool merging = context.ApplyingChanges;
 
                try 
                {
                    context.ApplyingChanges = true; 

                    // 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 = null;
                            if (total >= 0)
                            {
                                buffer = LoadPropertyResult.ReadByteArrayWithContentLength(responseStream, total); 
                            }
                            else 
                            { 
                                buffer = LoadPropertyResult.ReadByteArrayChunked(responseStream);
                            } 

                            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 
                        {
                            // responseStream will disposed, StreamReader doesn't need to dispose of it.
                            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 MaterializeAtom.CreateWrapper(results);
                } 
                finally
                { 
                    context.ApplyingChanges = merging; 
                }
            } 
        }

        /// <summary>
        /// implementation of IAsyncResult for SaveChanges 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Pending")] 
        private class SaveResult : 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<Descriptor> 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 an MR POST or PUT 
            /// that might need to be followed by a PUT for the MLE
            /// </summary> 
            private bool processingMediaLinkEntry; 

            /// <summary> 
            /// True if the current in-flight request is an MR PUT
            /// that might need to be followed by a PUT for the MLE
            /// </summary>
            private bool processingMediaLinkEntryPut; 

            /// <summary> 
            /// If the <see cref="processingMediaLinkEntry"/> is set to true 
            /// this field holds a stream which contains the body of the MR POST request
            /// to be sent. 
            /// This can be null in the case where the content of MR is empty. (In which case
            /// we will not try to open the request stream and thus avoid additional async call).
            /// </summary>
            private Stream mediaResourceRequestStream; 

            /// <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 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 SaveResult(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.entityDescriptors.Values.Cast<Descriptor>()
                                          .Union(context.bindings.Values.Cast<Descriptor>()) 
                                          .Where(o => o.IsModified && o.ChangeOrder != UInt32.MaxValue)
                                          .OrderBy(o => o.ChangeOrder) 
                                          .ToList(); 

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

                        if (!e.IsResource) 
                        { 
                            object target = ((LinkDescriptor)e).Target;
                            if (null != target) 
                            {
                                Descriptor f = context.entityDescriptors[target];
                                if (EntityStates.Unchanged == f.State)
                                { 
                                    f.ContentGeneratedForSave = false;
                                    f.SaveResultWasProcessed = 0; 
                                    f.SaveError = null; 
                                }
                            } 
                        }
                    }
                    #endregion
                } 
                else
                { 
                    this.ChangedEntries = new List<Descriptor>(); 
                }
 
                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 
                {
                    return this.service;
                }
 
                set
                { 
                    this.service = value; 
                }
            } 

            /// <summary>process the batch</summary>
            /// <returns>data service response</returns>
            internal DataServiceResponse EndRequest() 
            {
                // Close all Save streams before we return (and do this before we throw for any errors below) 
                foreach (EntityDescriptor box in this.ChangedEntries.Where(e => e.IsResource).Cast<EntityDescriptor>()) 
                {
                    box.CloseSaveStream(); 
                }

                // This will process the responses and throw if failure was detected
                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.Abortable = httpWebRequest; 

                        this.request = pereq = new PerRequest();
                        pereq.Request = httpWebRequest;
                        pereq.RequestContentStream = new PerRequest.ContentStream(memory, true); 

                        this.httpWebResponseStream = new MemoryStream(); 
 
                        IAsyncResult asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetRequestStream, this.AsyncEndGetRequestStream, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                    }
                    else
                    {
                        Debug.Assert(this.CompletedSynchronously, "completedSynchronously"); 
                        Debug.Assert(this.IsCompletedInternally, "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.IsCompletedInternally, "why being called if already completed?");
 
                // SaveCallback can't chain synchronously completed responses, caller will loop the to next change
                PerRequest pereq = null;
                IAsyncResult asyncResult = null;
                do 
                {
                    HttpWebRequest httpWebRequest = null; 
                    HttpWebResponse response = null; 
                    try
                    { 
                        if (null != this.request)
                        {
                            this.SetCompleted();
                            Error.ThrowInternalError(InternalError.InvalidBeginNextChange); 
                        }
 
                        this.Abortable = 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 LinkDescriptor, "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;
                            } 

                            PerRequest.ContentStream contentStream = this.CreateChangeData(this.entryIndex, false);
                            if (this.executeAsync)
                            { 
                                #region async
                                this.request = pereq = new PerRequest(); 
                                pereq.Request = httpWebRequest; 

                                if (null == contentStream || null == contentStream.Stream) 
                                {
                                    asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetResponse, this.AsyncEndGetResponse, pereq);
                                }
                                else 
                                {
                                    if (contentStream.IsKnownMemoryStream) 
                                    { 
                                        httpWebRequest.ContentLength = contentStream.Stream.Length - contentStream.Stream.Position;
                                    } 

                                    pereq.RequestContentStream = contentStream;
                                    asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetRequestStream, this.AsyncEndGetRequestStream, pereq);
                                } 

                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                                this.CompletedSynchronously &= asyncResult.CompletedSynchronously; 
                                #endregion
                            } 
#if !ASTORIA_LIGHT // Synchronous methods not available
                            else
                            {
                                #region [....] 
                                if (null != contentStream && null != contentStream.Stream)
                                { 
                                    if (contentStream.IsKnownMemoryStream) 
                                    {
                                        httpWebRequest.ContentLength = contentStream.Stream.Length - contentStream.Stream.Position; 
                                    }

                                    using (Stream stream = httpWebRequest.GetRequestStream())
                                    { 
                                        byte[] buffer = new byte[64 * 1024];
                                        int read; 
                                        do 
                                        {
                                            read = contentStream.Stream.Read(buffer, 0, buffer.Length); 
                                            if (read > 0)
                                            {
                                                stream.Write(buffer, 0, read);
                                            } 
                                        }
                                        while (read > 0); 
                                    } 
                                }
 
                                response = (HttpWebResponse)httpWebRequest.GetResponse();
                                if (!this.processingMediaLinkEntry)
                                {
                                    this.changesCompleted++; 
                                }
 
                                this.HandleOperationResponse(response); 
                                this.HandleOperationResponseData(response);
                                this.HandleOperationEnd(); 
                                this.request = null;
                                #endregion
                            }
#endif 
                        }
                        else 
                        { 
                            this.SetCompleted();
 
                            if (this.CompletedSynchronously)
                            {
                                this.HandleCompleted(pereq);
                            } 
                        }
                    } 
                    catch (InvalidOperationException e) 
                    {
                        WebUtil.GetHttpWebResponse(e, ref response); 
                        this.HandleOperationException(e, 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 && asyncResult != null && asyncResult.CompletedSynchronously)) && !this.IsCompletedInternally); 

                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 generate 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>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>
            private static void CompleteCheck(PerRequest value, InternalError errorcode)
            { 
                if ((null == value) || value.RequestCompleted)
                { 
                    // since PerRequest is nested, it won't get set true during Abort unlike BaseAsyncResult 
                    // but like QueryAsyncResult, when the request is aborted it it lets the request throw on next operation
                    Error.ThrowInternalError(errorcode); 
                }
            }

            /// <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)
                {
                    if (IsAborted)
                    { 
                        pereq.SetAborted();
                    } 
                    else 
                    {
                        pereq.SetComplete(); 
                    }
                }

                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.processingMediaLinkEntry)
                { 
                    this.entryIndex++; 
                }
                else 
                {
                    // If the previous request was an MR request the next one might be a PUT for the MLE
                    //   but if the entity was not changed (just the MR changed) no PUT for MLE should be sent
                    Debug.Assert(this.ChangedEntries[this.entryIndex].IsResource, "Only resources can have MR's."); 
                    EntityDescriptor box = (EntityDescriptor)this.ChangedEntries[this.entryIndex];
                    if (this.processingMediaLinkEntryPut && EntityStates.Unchanged == box.State) 
                    { 
                        // Only the MR changed. In this case we also need to mark the entry as processed to notify
                        //   that the content for save has been generated as there's not going to be another request for it. 
                        box.ContentGeneratedForSave = true;
                        this.entryIndex++;
                    }
 
                    this.processingMediaLinkEntry = false;
                    this.processingMediaLinkEntryPut = false; 
 
                    // In any case also close the save stream if there's any and forget about it
                    // for POST this is just a good practice to do so as soon as possible 
                    // for PUT it's actually required for us to recognize that we already processed the MR part of the change
                    box.CloseSaveStream();
                }
 
                if (unchecked((uint)this.entryIndex < (uint)this.ChangedEntries.Count))
                { 
                    Descriptor entry = this.ChangedEntries[this.entryIndex]; 
                    if (entry.IsResource)
                    { 
                        EntityDescriptor box = (EntityDescriptor)entry;

                        HttpWebRequest req;
                        if (((EntityStates.Unchanged == entry.State) || (EntityStates.Modified == entry.State)) && 
                            (null != (req = this.CheckAndProcessMediaEntryPut(box))))
                        { 
                            this.processingMediaLinkEntry = true; 
                            this.processingMediaLinkEntryPut = true;
                        } 
                        else if ((EntityStates.Added == entry.State) && (null != (req = this.CheckAndProcessMediaEntryPost(box))))
                        {
                            this.processingMediaLinkEntry = true;
                            this.processingMediaLinkEntryPut = false; 
                        }
                        else 
                        { 
                            Debug.Assert(!this.processingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.processingMediaLinkEntry || entry.State == EntityStates.Modified");
                            req = this.Context.CreateRequest(box, entry.State, replaceOnUpdate); 
                        }

                        return req;
                    } 

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

                return null; 
            }

            /// <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="entityDescriptor">The resource to check/process</param>
            /// <returns>A web request setup to do POST the media resource</returns> 
            private HttpWebRequest CheckAndProcessMediaEntryPost(EntityDescriptor entityDescriptor)
            {
                //
                ClientType type = ClientType.Create(entityDescriptor.Entity.GetType()); 

                if (!type.IsMediaLinkEntry && !entityDescriptor.IsMediaLinkEntry) 
                { 
                    // this is not a media link entry, process normally
                    return null; 
                }

                if (type.MediaDataMember == null && entityDescriptor.SaveStream == null)
                { 
                    // The entity is marked as MLE but we don't have the content property
                    //   and the user didn't set the save stream. 
                    throw Error.InvalidOperation(Strings.Context_MLEWithoutSaveStream(type.ElementTypeName)); 
                }
 
                Debug.Assert(
                    (type.MediaDataMember != null && entityDescriptor.SaveStream == null) ||
                    (type.MediaDataMember == null && entityDescriptor.SaveStream != null),
                    "Only one way of specifying the MR content is allowed."); 

                HttpWebRequest mediaRequest = this.CreateMediaResourceRequest( 
                    entityDescriptor.GetResourceUri(this.Context.baseUriWithSlash, false /*queryLink*/), 
                    XmlConstants.HttpMethodPost,
                    type.MediaDataMember == null); 

                if (type.MediaDataMember != null)
                {
                    if (type.MediaDataMember.MimeTypeProperty == null) 
                    {
                        mediaRequest.ContentType = XmlConstants.MimeApplicationOctetStream; 
                    } 
                    else
                    { 
                        object mimeTypeValue = type.MediaDataMember.MimeTypeProperty.GetValue(entityDescriptor.Entity);
                        String mimeType = mimeTypeValue != null ? mimeTypeValue.ToString() : null;

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

                        mediaRequest.ContentType = mimeType;
                    } 

                    object value = type.MediaDataMember.GetValue(entityDescriptor.Entity); 
                    if (value == null) 
                    {
                        mediaRequest.ContentLength = 0; 
                        this.mediaResourceRequestStream = null;
                    }
                    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, false /* atomDateConstruct */)); 
                        }

                        mediaRequest.ContentLength = buffer.Length;
 
                        // Need to specify that the buffer is publicly visible as we need to access it later on
                        this.mediaResourceRequestStream = new MemoryStream(buffer, 0, buffer.Length, false, true); 
                    } 
                }
                else 
                {
                    this.SetupMediaResourceRequest(mediaRequest, entityDescriptor);
                }
 
                // 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())
                entityDescriptor.State = EntityStates.Modified; 

                return mediaRequest;
            }
 
            /// <summary>
            /// Checks if the resource box represents an MLE with modified MR and if so creates a PUT request 
            ///   to update the MR. 
            /// </summary>
            /// <param name="box">The resource box for the entity to be checked.</param> 
            /// <returns>Newly created MR PUT request or null if the entity is not MLE or its MR hasn't changed.</returns>
            private HttpWebRequest CheckAndProcessMediaEntryPut(EntityDescriptor box)
            {
                // If there's no save stream associated with the entity it's not MLE or its MR hasn't changed 
                //  (which for purposes of PUT is the same anyway)
                if (box.SaveStream == null) 
                { 
                    return null;
                } 

                Uri requestUri = box.GetEditMediaResourceUri(this.Context.baseUriWithSlash);
                if (requestUri == null)
                { 
                    throw Error.InvalidOperation(
                        Strings.Context_SetSaveStreamWithoutEditMediaLink); 
                } 

                HttpWebRequest mediaResourceRequest = this.CreateMediaResourceRequest(requestUri, XmlConstants.HttpMethodPut, true); 
                this.SetupMediaResourceRequest(mediaResourceRequest, box);

                if (box.StreamETag != null)
                { 
                    mediaResourceRequest.Headers.Set(HttpRequestHeader.IfMatch, box.StreamETag);
                } 
 
                return mediaResourceRequest;
            } 

            /// <summary>
            /// Creates HTTP request for the media resource (MR)
            /// </summary> 
            /// <param name="requestUri">The URI to request</param>
            /// <param name="method">The HTTP method to use (POST or PUT)</param> 
            /// <param name="sendChunked">Send the request using chunked encoding to avoid buffering.</param> 
            /// <returns>The newly created HTTP request object.</returns>
            private HttpWebRequest CreateMediaResourceRequest(Uri requestUri, string method, bool sendChunked) 
            {
#if ASTORIA_LIGHT
                // For MR requests always use the ClientHtpp stack as the XHR doesn't support binary content
                HttpWebRequest mediaResourceRequest = this.Context.CreateRequest( 
                    requestUri,
                    method, 
                    false, 
                    XmlConstants.MimeAny,
                    Util.DataServiceVersion1, 
                    sendChunked,
                    HttpStack.ClientHttp);
#else
                HttpWebRequest mediaResourceRequest = this.Context.CreateRequest( 
                    requestUri,
                    method, 
                    false, 
                    XmlConstants.MimeAny,
                    Util.DataServiceVersion1, 
                    sendChunked);
#endif
                return mediaResourceRequest;
            } 

            /// <summary> 
            /// Sets the content and the headers of the media resource request 
            /// </summary>
            /// <param name="mediaResourceRequest">The request to setup</param> 
            /// <param name="box">The resource box for the entity with the MT</param>
            /// <remarks>This only works with the V2 MR support (SetSaveStream), this will not setup
            /// the request for V1 property based MRs.</remarks>
            private void SetupMediaResourceRequest(HttpWebRequest mediaResourceRequest, EntityDescriptor box) 
            {
                // Get the write stream for this MR 
                this.mediaResourceRequestStream = box.SaveStream.Stream; 

                // Apply the arguments for the request 
                WebUtil.ApplyHeadersToRequest(box.SaveStream.Args.Headers, mediaResourceRequest, true);

                // Do NOT set the ContentLength since we don't know if the stream even supports reporting its length
            } 

            /// <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>stream of data for entry</returns>
            private PerRequest.ContentStream CreateChangeData(int index, bool newline)
            { 
                Descriptor entry = this.ChangedEntries[index];
                Debug.Assert(!entry.ContentGeneratedForSave, "already saved entity/link"); 
 
                if (entry.IsResource)
                { 
                    EntityDescriptor box = (EntityDescriptor)entry;
                    if (this.processingMediaLinkEntry)
                    {
                        Debug.Assert( 
                            this.processingMediaLinkEntryPut || entry.State == EntityStates.Modified,
                            "We should have modified the MLE state to Modified when we've created the MR POST request."); 
                        Debug.Assert( 
                            !this.processingMediaLinkEntryPut || (entry.State == EntityStates.Unchanged || entry.State == EntityStates.Modified),
                            "If we're processing MR PUT the entity must be either in Unchanged or Modified state."); 

                        // media resource request - we already precreated the body of the request
                        // in the CheckAndProcessMediaEntryPost or CheckAndProcessMediaEntryPut method.
                        Debug.Assert(this.mediaResourceRequestStream != null, "We should have precreated the MR stream already."); 
                        return new PerRequest.ContentStream(this.mediaResourceRequestStream, false);
                    } 
                    else 
                    {
                        // either normal entity or second call for media link entity, generate content payload 
                        // else first call of media link entry where we only send the default value
                        entry.ContentGeneratedForSave = true;
                        return new PerRequest.ContentStream(this.Context.CreateRequestData(box, newline), true);
                    } 
                }
                else 
                { 
                    entry.ContentGeneratedForSave = true;
                    LinkDescriptor link = (LinkDescriptor)entry; 
                    if ((EntityStates.Added == link.State) ||
                        ((EntityStates.Modified == link.State) && (null != link.Target)))
                    {
                        return new PerRequest.ContentStream(this.Context.CreateRequestData(link, newline), true); 
                    }
                } 
 
                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 TESTUNIXNEWLINE 
                    this.buildBatchWriter.NewLine = NewLine;
#endif
                }
 
                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="response">response object</param>
            private void HandleOperationException(Exception e, HttpWebResponse response) 
            { 
                if (null != response)
                { 
                    this.HandleOperationResponse(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.SetCompleted();

                    // if it was a media link entry don't even try to do a PUT if the POST didn't succeed
                    this.processingMediaLinkEntry = false; 

                    // Need to set this to true since we check this even on error cases, but we're here 
                    //   because exception was thrown during preparation of the request, so we might not have a chance 
                    //   to generate the content for save yet.
                    this.ChangedEntries[this.entryIndex].ContentGeneratedForSave = true; 
                }
            }

            /// <summary>operation with HttpWebResponse</summary> 
            /// <param name="response">response object</param>
            private void HandleOperationResponse(HttpWebResponse response) 
            { 
                this.HandleOperationStart();
 
                Descriptor entry = this.ChangedEntries[this.entryIndex];

                // in the first pass, the http response is packaged into a batch response (which is then processed in second pass).
                // in this first pass, (all added entities and first call of modified media link entities) update their edit location 
                // added entities - so entities that have not sent content yet w/ reference links can inline those reference links in their payload
                // media entities - because they can change edit location which is then necessary for second call that includes property content 
                if (entry.IsResource) 
                {
                    EntityDescriptor entityDescriptor = (EntityDescriptor)entry; 

                    if (entry.State == EntityStates.Added ||
                         (entry.State == EntityStates.Modified &&
                          this.processingMediaLinkEntry && !this.processingMediaLinkEntryPut)) 
                    {
                        string location = response.Headers[XmlConstants.HttpResponseLocation]; 
 
                        if (WebUtil.SuccessStatusCode(response.StatusCode))
                        { 
                            if (null != location)
                            {
                                this.Context.AttachLocation(entityDescriptor.Entity, location);
                            } 
                            else
                            { 
                                throw Error.NotSupported(Strings.Deserialize_NoLocationHeader); 
                            }
                        } 
                    }

                    if (this.processingMediaLinkEntry)
                    { 
                        if (!WebUtil.SuccessStatusCode(response.StatusCode))
                        { 
                            // If the request failed and it was the MR request we should not try to send the PUT MLE after it 
                            //   for one we don't have the location to send it to (if it was POST MR)
 
                            // Just reset the processMLE flag - that means that we will not try to PUT the MLE and instead skip over
                            //   to the next change (if we are to ignore errors that is)
                            this.processingMediaLinkEntry = false;
 
                            if (!this.processingMediaLinkEntryPut)
                            { 
                                // If this was the POST MR it means we tried to add the entity. Now its state is Modified but we need 
                                //   to revert back to Added so that user can retry by calling SaveChanges again.
                                Debug.Assert(entry.State == EntityStates.Modified, "Entity state should be set to Modified once we've sent the POST MR"); 
                                entry.State = EntityStates.Added;
                                this.processingMediaLinkEntryPut = false;
                            }
 
                            // And we also need to mark it such that we generated the save content (which we did before the POST request in fact)
                            // to workaround the fact that we use the same entry object to track two requests. 
                            entry.ContentGeneratedForSave = true; 
                        }
                        else if (response.StatusCode == HttpStatusCode.Created) 
                        {
                            // We just finished a POST MR request and the PUT MLE coming immediately after it will
                            // need the new etag value from the server to succeed.
                            entityDescriptor.ETag = response.Headers[XmlConstants.HttpResponseETag]; 

                            // else is not interesting and we intentionally do nothing. 
                        } 
                    }
                } 

                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, entry.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()
            { 
                Debug.Assert(null != this.buildBatchWriter, "null buildBatchWriter");
                this.buildBatchWriter.Flush();
#if DEBUG
                MemoryStream memory = this.buildBatchWriter.BaseStream as MemoryStream; 
                Debug.Assert(null != memory, "expected MemoryStream");
                Debug.Assert(this.buildBatchWriter.NewLine == NewLine, "mismatch NewLine"); 
                for (int kk = 0; kk < NewLine.Length; ++kk) 
                {
                    Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "didn't end with newline"); 
                }
#endif
                this.buildBatchWriter.BaseStream.Position -= NewLine.Length;
                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, Util.DataServiceVersion1, false);
                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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposal not required for MemoryStream which is being returned")] 
            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.SetCompleted();
                    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 TESTUNIXNEWLINE
                text.NewLine = NewLine;
#endif 

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

                        Debug.Assert(null != requestUri, "request uri is null");
                        Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 

                        text.WriteLine("--{0}", this.batchBoundary); 
                        WriteOperationRequestHeaders(text, XmlConstants.HttpMethodGet, requestUri.AbsoluteUri, this.Queries[i].QueryComponents.Version); 
                        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(); 
                            for (int kk = 0; kk < NewLine.Length; ++kk)
                            { 
                                Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "boundary didn't start with newline"); 
                            }
                        } 
#endif
                        #endregion

                        Descriptor entry = this.ChangedEntries[i]; 
                        if (entry.ContentGeneratedForSave)
                        { 
                            continue; 
                        }
 
                        text.WriteLine("--{0}", this.changesetBoundary);

                        EntityDescriptor entityDescriptor = entry as EntityDescriptor;
                        if (entry.IsResource) 
                        {
                            if (entityDescriptor.State == EntityStates.Added) 
                            { 
                                // We don't support adding MLE/MR in batch mode
                                ClientType type = ClientType.Create(entityDescriptor.Entity.GetType()); 
                                if (type.IsMediaLinkEntry || entityDescriptor.IsMediaLinkEntry)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                } 
                            }
                            else if (entityDescriptor.State == EntityStates.Unchanged || entityDescriptor.State == EntityStates.Modified) 
                            { 
                                // We don't support PUT for the MR in batch mode
                                // It's OK to PUT the MLE alone inside a batch mode though 
                                if (entityDescriptor.SaveStream != null)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                } 
                            }
                        } 
 
                        PerRequest.ContentStream contentStream = this.CreateChangeData(i, true);
                        MemoryStream stream = null; 
                        if (null != contentStream)
                        {
                            Debug.Assert(contentStream.IsKnownMemoryStream, "Batch requests don't support MRs yet");
                            stream = contentStream.Stream as MemoryStream; 
                        }
 
                        if (entry.IsResource) 
                        {
                            this.Context.CreateRequestBatch(entityDescriptor, text, replaceOnUpdate); 
                        }
                        else
                        {
                            this.Context.CreateRequestBatch((LinkDescriptor)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(); 
 
                        for (int kk = 0; kk < NewLine.Length; ++kk)
                        { 
                            Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "BatchStream will be disposed after user iterates through final response enumerator")]
            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 takes ownership of the httpWebResponseStream (which may be a network stream) 
                        // BatchStream will be disposed after user iterates through enumerator 
                        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")]
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "MaterializeAtom is responsible for closing XmlReader which will close the stream")] 
            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 

                    Descriptor entry;
                    switch (batch.State)
                    { 
                        #region BeginChangeSet
                        case BatchStreamState.BeginChangeSet: 
                            if ((IsFlagSet(this.options, SaveChangesOptions.Batch) && (0 != 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]; 
                                    MaterializeAtom materializer = DataServiceRequest.Materialize(this.Context, query.QueryComponents, null, contentType, batch.GetContentStream());
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, materializer); 
                                } 
                            }
                            catch (ArgumentException e) 
                            {
                                ex = e;
                            }
                            catch (FormatException e) 
                            {
                                ex = e; 
                            } 
                            catch (InvalidOperationException e)
                            { 
                                ex = e;
                            }

                            if (null == qresponse) 
                            {
                                if (null != this.Queries) 
                                { 
                                    // this is the normal ExecuteBatch response
                                    DataServiceRequest query = this.Queries[queryCount]; 

                                    if (this.Context.ignoreResourceNotFoundException && status == HttpStatusCode.NotFound)
                                    {
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, MaterializeAtom.EmptyResults); 
                                    }
                                    else 
                                    { 
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, MaterializeAtom.EmptyResults);
                                        qresponse.Error = ex; 
                                    }
                                }
                                else
                                { 
                                    // This is top-level failure SaveChanges(SaveChangesOptions.Batch) response
                                    // example: server doesn't support batching or number of batch objects exceeded an allowed limit. 
                                    // ex could be null if the server responded to SaveChanges with an unexpected success with 
                                    // response of batched GETS that did not correspond the original POST/MERGE/PUT/DELETE requests.
                                    // we expect non-null since server should have failed with a non-success code 
                                    // and HandleResponse(status, ...) should generate the exception object
                                    throw ex;
                                }
                            } 

                            qresponse.StatusCode = (int)status; 
                            queryCount++; 
                            yield return qresponse;
                            break; 
                        #endregion

                        #region ChangeResponse
                        case BatchStreamState.ChangeResponse: 

                            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;
                                } 

                                StreamStates streamState = StreamStates.NoStream;
                                if (entry.IsResource)
                                { 
                                    EntityDescriptor descriptor = (EntityDescriptor)entry;
                                    streamState = descriptor.StreamState; 
#if DEBUG 
                                    if (descriptor.StreamState == StreamStates.Added)
                                    { 
                                        Debug.Assert(
                                            statusCode == HttpStatusCode.Created && entry.State == EntityStates.Modified && descriptor.IsMediaLinkEntry,
                                            "statusCode == HttpStatusCode.Created && entry.State == EntityStates.Modified && descriptor.IsMediaLinkEntry -- Processing Post MR");
                                    } 
                                    else if (descriptor.StreamState == StreamStates.Modified)
                                    { 
                                        Debug.Assert( 
                                            statusCode == HttpStatusCode.NoContent && descriptor.IsMediaLinkEntry,
                                            "statusCode == HttpStatusCode.NoContent && descriptor.IsMediaLinkEntry -- Processing Put MR"); 
                                    }
#endif
                                }
 
                                if (streamState == StreamStates.Added || entry.State == EntityStates.Added)
                                { 
                                    #region Post 
                                    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);
                                        EntityDescriptor entityDescriptor = (EntityDescriptor)entry; 
 
                                        // If the location header is specified, we need to set the edit link
                                        // for the entity descriptor to that value. 
                                        if (location != null)
                                        {
                                            editLink = Util.CreateUri(location, UriKind.Absolute);
                                        } 
                                        else
                                        { 
                                            throw Error.NotSupported(Strings.Deserialize_NoLocationHeader); 
                                        }
 
                                        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);
                                            QueryComponents qc = new QueryComponents(null, Util.DataServiceVersionEmpty, entityDescriptor.Entity.GetType(), null, null);
                                            EntityDescriptor descriptor = (EntityDescriptor)entry;
                                            MergeOption mergeOption = MergeOption.OverwriteChanges; 

                                            // If we are processing a POST MR, we want to materialize the payload to get the metadata for the stream. 
                                            // However we must not modify the MLE properties with the server initialized properties.  The next request 
                                            // will be a Put MLE operation and we will set the server properties with values from the client entity.
                                            if (descriptor.StreamState == StreamStates.Added) 
                                            {
                                                mergeOption = MergeOption.PreserveChanges;
                                                Debug.Assert(descriptor.State == EntityStates.Modified, "The MLE state must be Modified.");
                                            } 

                                            try 
                                            { 
                                                using (MaterializeAtom atom = new MaterializeAtom(this.Context, reader, qc, null, mergeOption))
                                                { 
                                                    this.Context.HandleResponsePost(entityDescriptor, atom, editLink, etag);
                                                }
                                            }
                                            finally 
                                            {
                                                if (descriptor.StreamState == StreamStates.Added) 
                                                { 
                                                    // The materializer will always set the entity state to Unchanged.  We just processed Post MR, we
                                                    // need to restore the entity state to Modified to process the Put MLE. 
                                                    Debug.Assert(descriptor.State == EntityStates.Unchanged, "The materializer should always set the entity state to Unchanged.");
                                                    descriptor.State = EntityStates.Modified;

                                                    // Need to clear the stream state so the next iteration we will always process the Put MLE operation. 
                                                    descriptor.StreamState = StreamStates.NoStream;
                                                } 
                                            } 
                                        }
                                        else 
                                        {
                                            this.Context.HandleResponsePost(entityDescriptor, null /*materializer*/, editLink, etag);
                                        }
                                    } 
                                    else
                                    { 
                                        HandleResponsePost((LinkDescriptor)entry); 
                                    }
                                    #endregion 
                                }
                                else if (streamState == StreamStates.Modified || entry.State == EntityStates.Modified)
                                {
                                    #region Put, Merge 
                                    contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag);
                                    HandleResponsePut(entry, etag); 
                                    #endregion 
                                }
                                else if (entry.State == EntityStates.Deleted) 
                                {
                                    #region Delete
                                    this.Context.HandleResponseDelete(entry);
                                    #endregion 
                                }
 
                                // else condition is not interesting here and we intentionally do nothing. 
                            }
                            catch (Exception e) 
                            {
                                this.ChangedEntries[index].SaveError = e;
                                error = e;
                            } 

                            ChangeOperationResponse changeOperationResponse = 
                                new ChangeOperationResponse(contentHeaders, 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) 
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest;
                try
                {
                    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;

                    PerRequest.ContentStream contentStream = pereq.RequestContentStream; 
                    Util.NullCheck(contentStream, InternalError.InvalidEndGetRequestStreamContent);
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndGetRequestStreamContent); 
                    if (contentStream.IsKnownMemoryStream) 
                    {
                        MemoryStream memoryStream = contentStream.Stream as MemoryStream; 
                        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); 
                        } 
                    }
 
                    // Start the Read on the request content stream.
                    // Note that we don't deal with synchronous results here.
                    // If the read finishes synchronously the AsyncRequestContentEndRead will be called from inside the BeginRead
                    //   call below. In there we will call BeginWrite. If that completes synchronously we will loop 
                    //   and call BeginRead again. If that completes synchronously as well we will call BeginWrite and so on.
                    //   AsyncEndWrite will return immedially if it finished synchronously (otherwise it calls BeginRead). 
                    // So in the worst case we will have a stack like this: 
                    //   AsyncEndGetRequestStream
                    //     AsyncRequestContentEndRead 
                    //       AsyncRequestContentEndRead or AsyncEndWrite

                    // We just need to differentiate between the first AsyncRequestContentEndRead and the others (the first one
                    //   must not return even if it completed synchronously, otherwise we would have to do the loop here as well). 
                    //   We'll use the RequestContentBufferValidLength as the notification. It will start with -1 which means
                    //   we didn't read anything at all and thus it's the first read ending. 
                    pereq.RequestContentBufferValidLength = -1; 

                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetRequestStream_BeforeBeginRead"); 
                    asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e)) 
                    { 
                        throw;
                    } 
                }
                finally
                {
                    this.HandleCompleted(pereq); 
                }
            } 
 
            /// <summary>
            /// Callback for Stream.BeginRead on the request content input stream. Calls request content output stream BeginWrite 
            /// and in case of synchronous also the next BeginRead.
            /// </summary>
            /// <param name="asyncResult">The asynchronous result associated with the completed operation.</param>
            private void AsyncRequestContentEndRead(IAsyncResult asyncResult) 
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest; 
                try
                { 
                    CompleteCheck(pereq, InternalError.InvalidEndReadCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead); 
                    PerRequest.ContentStream contentStream = pereq.RequestContentStream;
                    Util.NullCheck(contentStream, InternalError.InvalidEndReadStream); 
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndReadStream); 
                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndReadStream);
 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeEndRead");
                    int count = contentStream.Stream.EndRead(asyncResult);
                    if (0 < count)
                    { 
                        bool firstEndRead = (pereq.RequestContentBufferValidLength == -1);
                        pereq.RequestContentBufferValidLength = count; 
 
                        // If we completed synchronously then just return. Our caller will take care of processing the results.
                        // First EndRead must not return even if completed synchronously. 
                        if (!asyncResult.CompletedSynchronously || firstEndRead)
                        {
                            do
                            { 
                                // Write the data we've read to the request stream
                                Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeBeginWrite"); 
                                asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginWrite, pereq.RequestContentBuffer, 0, pereq.RequestContentBufferValidLength, this.AsyncEndWrite, pereq); 
                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
 
                                // If the write above completed synchronously
                                //   immediately start the next read so that we loop instead of recursion.
                                // If it completed asynchronously we just return as we will deal with the results in the EndWrite
                                if (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally) 
                                {
                                    Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeBeginRead"); 
                                    asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq); 
                                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
                                } 

                                // If the read completed synchronously as well we loop to write the data to the request stream without recursion.
                                // Only loop if there's actually some data to be processed. If there's no more data then return.
                                // The request will continue inside the inner call to AsyncRequestContentEndRead (which will get 0 data 
                                //   and will end up in the else branch of the big if).
                            } 
                            while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && 
                                pereq.RequestContentBufferValidLength > 0);
                        } 
                    }
                    else
                    {
                        // Done reading data (and writing them) 
                        pereq.RequestContentBufferValidLength = 0;
                        pereq.RequestStream = null; 
                        stream.Close(); 

                        HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndWriteRequest); 
                        asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetResponse, this.AsyncEndGetResponse, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse
                    }
                } 
                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)
            { 
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest; 
                try 
                {
                    CompleteCheck(pereq, InternalError.InvalidEndWriteCompleted); 
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndWrite);
 
                    PerRequest.ContentStream contentStream = pereq.RequestContentStream;
                    Util.NullCheck(contentStream, InternalError.InvalidEndWriteStream); 
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndWriteStream); 
                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndWriteStream);
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndWrite_BeforeEndWrite"); 
                    stream.EndWrite(asyncResult);

                    // If the write completed synchronously just return. The caller (AsyncRequestContentEndRead)
                    //   will loop and initiate the next read. 
                    // If the write completed asynchronously we need to start the next read here. Note that we start the read
                    //   regardless if the stream has other data to offer or not. This is to avoid dealing with the end 
                    //   of the read/write loop in several places. We simply issue a read which (if the stream is at the end) 
                    //   will return 0 bytes and we will deal with that in the AsyncRequestContentEndRead method.
                    if (!asyncResult.CompletedSynchronously) 
                    {
                        Util.DebugInjectFault("SaveAsyncResult::AsyncEndWrite_BeforeBeginRead");
                        asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                    }
                } 
                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)
            { 
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest;
                try 
                {
                    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
                    {
                        Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse::BeforeEndGetResponse");
                        response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                    }
                    catch (WebException e) 
                    { 
                        response = (HttpWebResponse)e.Response;
                        if (null == response) 
                        {
                            throw;
                        }
                    } 

                    pereq.HttpWebResponse = Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse); 
 
                    if (!IsFlagSet(this.options, SaveChangesOptions.Batch))
                    { 
                        this.HandleOperationResponse(response);
                    }

                    this.copiedContentLength = 0; 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse_BeforeGetStream");
                    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];
                        } 

                        do
                        {
                            Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse_BeforeBeginRead"); 
                            asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginRead, this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq);
                            pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead 
                        } 
                        while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && stream.CanRead);
                    } 
                    else
                    {
                        pereq.SetComplete();
 
                        // BeginGetResponse could fail and callback still invoked
                        if (!this.IsCompletedInternally) 
                        { 
                            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)
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                int count = 0;
                try 
                { 
                    CompleteCheck(pereq, InternalError.InvalidEndReadCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead);
                    Stream stream = Util.NullCheck(pereq.ResponseStream, InternalError.InvalidEndReadStream);
 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndRead_BeforeEndRead");
                    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 
                            do 
                            {
                                asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginRead, this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 
                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
                            }
                            while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && stream.CanRead);
                        } 
                    }
                    else 
                    { 
                        pereq.SetComplete();
 
                        // BeginRead could fail and callback still invoked
                        if (!this.IsCompletedInternally)
                        {
                            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);
                }

                EqualRefCheck(this.request, pereq, InternalError.InvalidSaveNextChange); 

                if (IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                { 
                    this.httpWebResponseStream.Position = 0;
                    this.request = null; 
                    this.SetCompleted();
                }
                else
                { 
                    if (0 == this.copiedContentLength)
                    { 
                        this.HandleOperationResponseNoData(); 
                    }
 
                    this.HandleOperationEnd();

                    if (!this.processingMediaLinkEntry)
                    { 
                        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.IsCompletedInternally)
                        { 
                            this.BeginNextChange(IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate));
                        } 
                    } 
                }
            } 
            #endregion

            /// <summary>wrap the full request</summary>
            private sealed class PerRequest 
            {
                /// <summary> 
                /// did the sequence (BeginGetRequest, EndGetRequest, ... complete. 0 = In Progress, 1 = Completed, 2 = Aborted 
                /// </summary>
                private int requestStatus; 

                /// <summary>
                /// Buffer used when pumping data from the write stream to the request content stream
                /// </summary> 
                private byte[] requestContentBuffer;
 
                /// <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 ContentStream RequestContentStream
                {
                    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>
                /// Short cut for testing if request has finished (either completed or aborted)
                /// </summary>
                internal bool RequestCompleted 
                {
                    get { return this.requestStatus != 0; } 
                } 

                /// <summary> 
                /// Short cut for testing request status is 2 (Aborted)
                /// </summary>
                internal bool RequestAborted
                { 
                    get { return this.requestStatus == 2; }
                } 
 
                /// <summary>
                /// Buffer used when pumping data from the write stream to the request content stream 
                /// </summary>
                internal byte[] RequestContentBuffer
                {
                    get 
                    {
                        if (this.requestContentBuffer == null) 
                        { 
                            this.requestContentBuffer = new byte[64 * 1024];
                        } 

                        return this.requestContentBuffer;
                    }
                } 

                /// <summary> 
                /// The length of the valid content in the RequestContentBuffer 
                /// Once the data is read from the request content stream into the RequestContent buffer
                /// this length is set to the amount of data read. 
                /// When the data is written into the request stream it is set back to 0.
                /// </summary>
                internal int RequestContentBufferValidLength
                { 
                    get;
                    set; 
                } 

                /// <summary> 
                /// Change the request status to completed
                /// </summary>
                internal void SetComplete()
                { 
                    System.Threading.Interlocked.CompareExchange(ref this.requestStatus, 1, 0);
                } 
 
                /// <summary>
                /// Change the request status to aborted 
                /// </summary>
                internal void SetAborted()
                {
                    System.Threading.Interlocked.Exchange(ref this.requestStatus, 2); 
                }
 
                /// <summary> 
                /// dispose of the request object
                /// </summary> 
                internal void Dispose()
                {
                    Stream stream = null;
 
                    if (null != (stream = this.ResponseStream))
                    { 
                        this.ResponseStream = null; 
                        stream.Dispose();
                    } 

                    if (null != this.RequestContentStream)
                    {
                        if (this.RequestContentStream.Stream != null && this.RequestContentStream.IsKnownMemoryStream) 
                        {
                            this.RequestContentStream.Stream.Dispose(); 
                        } 

                        // We must not dispose the stream which came from outside 
                        //   the disposing/closing of that stream depends on parameter passed to us and is dealt with
                        //   at the end of SaveChanges process.
                        this.RequestContentStream = null;
                    } 

                    if (null != (stream = this.RequestStream)) 
                    { 
                        this.RequestStream = null;
                        try 
                        {
                            Util.DebugInjectFault("PerRequest::Dispose_BeforeRequestStreamDisposed");
                            stream.Dispose();
                        } 
                        catch (WebException)
                        { 
                            // if the request is aborted, then the connect stream 
                            // cannot be disposed - since not all bytes are written to it yet
                            // In this case, we eat the exception 
                            // Otherwise, keep throwing
                            if (!this.RequestAborted)
                            {
                                throw; 
                            }
 
                            // Call Injector to report the exception so test code can verify it is thrown 
                            Util.DebugInjectFault("PerRequest::Dispose_WebExceptionThrown");
                        } 
                    }

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

                    this.Request = null; 
                    this.SetComplete();
                }

                /// <summary> 
                /// Helper class to wrap the stream with the content of the request.
                /// We need to remember if the stream came from us (IsKnownMemoryStream is true) 
                /// or if it came from outside. For backward compatibility we set the Content-Length for our streams 
                /// since they are always MemoryStream and thus know their length.
                /// For outside streams (content of the MR requests) we don't set Content-Length since the stream 
                /// might not be able to answer to the Length call.
                /// </summary>
                internal class ContentStream
                { 
                    /// <summary>
                    /// The stream with the content of the request 
                    /// </summary> 
                    private readonly Stream stream;
 
                    /// <summary>
                    /// Set to true if the stream is a MemoryStream and we produced it (so it does have the buffer accesible)
                    /// </summary>
                    private readonly bool isKnownMemoryStream; 

                    /// <summary> 
                    /// Constructor 
                    /// </summary>
                    /// <param name="stream">The stream with the request content</param> 
                    /// <param name="isKnownMemoryStream">The stream was create by us and it's a MemoryStream</param>
                    public ContentStream(Stream stream, bool isKnownMemoryStream)
                    {
                        this.stream = stream; 
                        this.isKnownMemoryStream = isKnownMemoryStream;
                    } 
 
                    /// <summary>
                    /// The stream with the content of the request 
                    /// </summary>
                    public Stream Stream
                    {
                        get { return this.stream; } 
                    }
 
                    /// <summary> 
                    /// Set to true if the stream is a MemoryStream and we produced it (so it does have the buffer accesible)
                    /// </summary> 
                    public bool IsKnownMemoryStream
                    {
                        get { return this.isKnownMemoryStream; }
                    } 
                }
            } 
        } 
    }
} 

// 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> 
//--------------------------------------------------------------------- 

// #define TESTUNIXNEWLINE 

namespace System.Data.Services.Client
{
    #region Namespaces. 

    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;
    using System.Data.Services.Common; 
#if !ASTORIA_LIGHT 
    using System.Net;
#else // Data.Services http stack 
    using System.Data.Services.Http;
#endif
    using System.Text;
    using System.Xml; 
    using System.Xml.Linq;
 
    #endregion Namespaces. 

    /// <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 
    {
#if !TESTUNIXNEWLINE 
        /// <summary>cache NewLine string</summary> 
        private static readonly string NewLine = System.Environment.NewLine;
#else 
        /// <summary>cache NewLine string</summary>
        private const string NewLine = "\n";
#endif
 
        /// <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; 

        /// <summary>Client will ignore 404 resource not found exception and return an empty set when this is set to true</summary> 
        private bool ignoreResourceNotFoundException;

#if ASTORIA_LIGHT // Multiple HTTP stacks for Silverlight
        /// <summary>The HTTP stack to use for requests.</summary> 
        private HttpStack httpStack;
#endif 
 
        #region Resource state management
 
        /// <summary>change order</summary>
        private uint nextChange;

        /// <summary>Set of tracked resources</summary> 
        private Dictionary<object, EntityDescriptor> entityDescriptors = new Dictionary<object, EntityDescriptor>(EqualityComparer<object>.Default);
 
        /// <summary>Set of tracked resources by Identity</summary> 
        private Dictionary<String, EntityDescriptor> identityToDescriptor;
 
        /// <summary>Set of tracked bindings</summary>
        private Dictionary<LinkDescriptor, LinkDescriptor> bindings = new Dictionary<LinkDescriptor, LinkDescriptor>(LinkDescriptor.EquivalenceComparer);

        /// <summary> 
        /// A flag indicating if the data service context is applying changes
        /// </summary> 
        private bool applyingChanges; 

        #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>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public DataServiceContext(Uri serviceRoot)
        { 
            Util.CheckArgumentNull(serviceRoot, "serviceRoot");
 
#if ASTORIA_LIGHT 
            if (!serviceRoot.IsAbsoluteUri)
            { 
                // If we can use XHR, we will and thus we should use the old (V1) way of determining our
                //   base URI. That is, use the uri of the HTML page
                if (XHRHttpWebRequest.IsAvailable())
                { 
                    serviceRoot = new Uri(System.Windows.Browser.HtmlPage.Document.DocumentUri, serviceRoot);
                } 
                else 
                {
                    // Otherwise we are going to use the new Client stack. In this case there might not be any 
                    //   HTML page hosting us, or it might not be accessible, so the only base uri we can use
                    //   is the base uri of the xap we're running in.
                    System.Net.WebClient webClient = new System.Net.WebClient();
                    serviceRoot = new Uri(new Uri(webClient.BaseAddress), 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; 
#if ASTORIA_LIGHT
            this.UsePostTunneling = true; 
#else
            this.UsePostTunneling = false;
#endif
            this.typeScheme = new Uri(XmlConstants.DataWebSchemeNamespace); 
#if ASTORIA_LIGHT
            this.httpStack = HttpStack.Auto; 
#endif 
        }
 
        #endregion

        /// <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;
 
        /// <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; 

        /// <summary>
        /// This event fires when SaveChanges or EndSaveChanges is called
        /// </summary> 
        internal event EventHandler<SaveChangesEventArgs> ChangesSaved;
 
        #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>
        /// A flag indicating if the data service context is applying changes
        /// </summary>
        public bool ApplyingChanges 
        {
            get { return this.applyingChanges; } 
            internal set { this.applyingChanges = value; } 
        }
 
        /// <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 this.bindings.Values.OrderBy(l => l.ChangeOrder).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 this.entityDescriptors.Values.OrderBy(d => d.ChangeOrder).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> 
        /// When set to true, client will return an empty set instead of throwing when the
        /// server generates a HTTP 404: Resource Not Found exception 
        /// </summary> 
        public bool IgnoreResourceNotFoundException
        { 
            get { return this.ignoreResourceNotFoundException; }
            set { this.ignoreResourceNotFoundException = value; }
        }
 
#if ASTORIA_LIGHT // Multiple HTTP stacks in Silverlight
        /// <summary> 
        /// The HTTP stack to use in Silverlight. 
        /// Default value is HttpStack.Auto.
        /// </summary> 
        public HttpStack HttpStack
        {
            get { return this.httpStack; }
            set { this.httpStack = Util.CheckEnumerationValue(value, "HttpStack"); } 
        }
#endif 
 
        /// <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 Entity and Link Tracking
 
        /// <summary>Gets the entity descriptor corresponding to a particular entity</summary>
        /// <param name="entity">Entity for which to find the entity descriptor</param> 
        /// <returns>EntityDescriptor for the <paramref name="entity"/> or null if not found</returns> 
        public EntityDescriptor GetEntityDescriptor(object entity)
        { 
            Util.CheckArgumentNull(entity, "entity");

            EntityDescriptor descriptor;
            if (this.entityDescriptors.TryGetValue(entity, out descriptor)) 
            {
                return descriptor; 
            } 
            else
            { 
                return null;
            }
        }
 
        /// <summary>
        /// Gets the link descriptor corresponding to a particular link b/w source and target objects 
        /// </summary> 
        /// <param name="source">Source entity</param>
        /// <param name="sourceProperty">Property of <paramref name="source"/></param> 
        /// <param name="target">Target entity</param>
        /// <returns>LinkDescriptor for the relationship b/w source and target entities or null if not found</returns>
        public LinkDescriptor GetLinkDescriptor(object source, string sourceProperty, object target)
        { 
            Util.CheckArgumentNull(source, "source");
            Util.CheckArgumentNotEmpty(sourceProperty, "sourceProperty"); 
            Util.CheckArgumentNull(target, "target"); 

            LinkDescriptor link; 

            if (this.bindings.TryGetValue(new LinkDescriptor(source, sourceProperty, target), out link))
            {
                return link; 
            }
            else 
            { 
                return null;
            } 
        }

        #endregion
 
        #region CancelRequest
        /// <summary>Best effort to abort the outstand request</summary> 
        /// <param name="asyncResult">the current async request to cancel</param> 
        /// <remarks>DataServiceContext is not safe to use until asyncResult.IsCompleted is true.</remarks>
        public void CancelRequest(IAsyncResult asyncResult) 
        {
            Util.CheckArgumentNull(asyncResult, "asyncResult");
            BaseAsyncResult result = asyncResult as BaseAsyncResult;
 
            // verify this asyncResult orginated from this context or via query from this context
            if ((null == result) || (this != result.Source)) 
            { 
                object context = null;
                DataServiceQuery query = null; 
                if (null != result)
                {
                    query = result.Source as DataServiceQuery;
 
                    if (null != query)
                    { 
                        DataServiceQueryProvider provider = query.Provider as DataServiceQueryProvider; 
                        if (null != provider)
                        { 
                            context = provider.Context;
                        }
                    }
                } 

                if (this != context) 
                { 
                    throw Error.Argument(Strings.Context_DidNotOriginateAsync, "asyncResult");
                } 
            }

            // at this point the result originated from this context or a query from this context
            if (!result.IsCompletedInternally) 
            {
                result.SetAborted(); 
 
                WebRequest request = result.Abortable;
                if (null != request) 
                {
                    // with Silverlight we can't wait around to check if the request was aborted
                    // because that would block callbacks for the abort from actually running.
                    request.Abort(); 
                }
            } 
        } 
        #endregion
 
        #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, CountOption.None, 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) 
        {
            return this.BeginLoadProperty(entity, propertyName, (Uri)null, callback, state);
        }
 
        /// <summary>
        /// Begin getting response to load a page for a collection. 
        /// </summary> 
        /// <param name="entity">The entity</param>
        /// <param name="propertyName">name of collection or reference property to load</param> 
        /// <param name="nextLinkUri">load the page from this URI</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, Uri nextLinkUri, AsyncCallback callback, object state)
        { 
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state, nextLinkUri, null); 
            result.BeginExecute();
            return result; 
        }

        /// <summary>
        /// Begin getting response to load a page for a collection. 
        /// </summary>
        /// <param name="entity">The entity</param> 
        /// <param name="propertyName">name of collection or reference property to load</param> 
        /// <param name="continuation">Continuation from which the property should be loaded.</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, DataServiceQueryContinuation continuation, AsyncCallback callback, object state)
        { 
            Util.CheckArgumentNull(continuation, "continuation");
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, callback, state, null, continuation); 
            result.BeginExecute(); 
            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) 
        {
            LoadPropertyResult response = QueryResult.EndExecute<LoadPropertyResult>(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)
        { 
            return this.LoadProperty(entity, propertyName, (Uri)null);
        } 
 
        /// <summary>
        /// Load a page for collection from an uri 
        /// </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> 
        /// <param name="nextLinkUri">The uri to load the page from; possibly null.</param>
        /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
        public QueryOperationResponse LoadProperty(object entity, string propertyName, Uri nextLinkUri) 
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, nextLinkUri, null); 
            result.Execute();
            return result.LoadProperty();
        }
 
        /// <summary>
        /// Load a page for collection from an uri 
        /// </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>
        /// <param name="continuation">The continuation object from a previous response.</param>
        /// <returns>QueryOperationResponse instance containing information about the response.</returns>
        public QueryOperationResponse LoadProperty(object entity, string propertyName, DataServiceQueryContinuation continuation) 
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, null, continuation); 
            result.Execute(); 
            return result.LoadProperty();
        } 

        /// <summary>Loads a page for a collection from a continuation object..</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>
        /// <typeparam name='T'>Element type of collection to load.</typeparam> 
        /// <param name="entity">entity</param>
        /// <param name="propertyName">name of collection or reference property to load</param> 
        /// <param name="continuation">The continuation object from a previous response.</param> 
        /// <returns>QueryOperationResponse instance containing information about the response.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011", Justification = "allows compiler to infer 'T'")] 
        public QueryOperationResponse<T> LoadProperty<T>(object entity, string propertyName, DataServiceQueryContinuation<T> continuation)
        {
            LoadPropertyResult result = this.CreateLoadPropertyRequest(entity, propertyName, null, null, null, continuation);
            result.Execute(); 
            return (QueryOperationResponse<T>)result.LoadProperty();
        } 
 
#endif
        #endregion 

        #region GetReadStreamUri
        /// <summary>
        /// If the specified entity is a Media Link Entry, this method will return 
        /// an URI which can be used to access the content of the Media Resource.
        /// This URI should only be used to GET/Read the content of the MR. It may not respond to POST/PUT/DELETE requests. 
        /// </summary> 
        /// <param name="entity">The entity to lookup the MR URI for.</param>
        /// <returns>The read URI of the MR.</returns> 
        /// <exception cref="ArgumentNullException">If the entity specified is null.</exception>
        /// <exception cref="ArgumentException">If the entity specified is not being tracked.</exception>
        public Uri GetReadStreamUri(object entity)
        { 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            return box.GetMediaResourceUri(this.baseUriWithSlash); 
        } 
        #endregion
 
        #region GetReadStream, BeginGetReadStream, EndGetReadStream

        /// <summary>
        /// This method begins a request to get the read stream for a Media Resource 
        /// associated with the media link entry represented by the entity object.
        /// </summary> 
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state.</param>
        /// <param name="args">Instance of <see cref="DataServiceRequestArgs"/> class with additional metadata for the request. 
        /// Must not be null.</param>
        /// <param name="callback">User defined callback to be called when results are available. Can be null.</param>
        /// <param name="state">User state in IAsyncResult. Can be null.</param>
        /// <returns>The async result object to track the request.</returns> 
        /// <exception cref="ArgumentNullException">Either entity or args parameters are null.</exception>
        /// <exception cref="ArgumentException">The specified entity is either not tracked, is in the added state or it's not an MLE.</exception> 
        public IAsyncResult BeginGetReadStream(object entity, DataServiceRequestArgs args, AsyncCallback callback, object state) 
        {
            GetReadStreamResult result; 
            result = this.CreateGetReadStreamResult(entity, args, callback, state);
            result.Begin();
            return result;
        } 

        /// <summary> 
        /// Call this method when the results from the request for the Media Resource are required. 
        /// The method will block if the request have not finished yet.
        /// </summary> 
        /// <param name="asyncResult">Async result object returned from BeginGetReadStream.</param>
        /// <returns>An instance of <see cref="DataServiceStreamResponse"/> which contains the response stream
        /// as well as its metadata.</returns>
        public DataServiceStreamResponse EndGetReadStream(IAsyncResult asyncResult) 
        {
            GetReadStreamResult result = BaseAsyncResult.EndExecute<GetReadStreamResult>(this, "GetReadStream", asyncResult); 
            return result.End(); 
        }
 
#if !ASTORIA_LIGHT
        /// <summary>
        /// This method executes synchronously a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object. 
        /// </summary>
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state.</param> 
        /// <returns>An instance of <see cref="DataServiceStreamResponse"/> which represents the response.</returns>
        /// <exception cref="ArgumentNullException">entity parameter are null.</exception> 
        /// <exception cref="ArgumentException">The specified entity is either not tracked, is in the added state or it's not an MLE.</exception>
        public DataServiceStreamResponse GetReadStream(object entity)
        {
            DataServiceRequestArgs args = new DataServiceRequestArgs(); 
            return this.GetReadStream(entity, args);
        } 
 
        /// <summary>
        /// This method executes synchronously a request to get the read stream for a Media Resource 
        /// associated with the Media Link Entry represented by the entity object.
        /// </summary>
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify
        /// a tracked entity in a non-added state.</param> 
        /// <param name="acceptContentType">The content type which should be requested from the server.</param>
        /// <returns>An instance of <see cref="DataServiceStreamResponse"/> which represents the response.</returns> 
        /// <exception cref="ArgumentNullException">Either entity or contentType parameters are null.</exception> 
        /// <exception cref="ArgumentException">The specified entity is either not tracked, is in the added state or it's not an MLE.
        /// Or the contentType is an empty string.</exception> 
        public DataServiceStreamResponse GetReadStream(object entity, string acceptContentType)
        {
            Util.CheckArgumentNotEmpty(acceptContentType, "acceptContentType");
            DataServiceRequestArgs args = new DataServiceRequestArgs(); 
            args.AcceptContentType = acceptContentType;
            return this.GetReadStream(entity, args); 
        } 

        /// <summary> 
        /// This method executes synchronously a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object.
        /// </summary>
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify 
        /// a tracked entity in a non-added state.</param>
        /// <param name="args">Instance of <see cref="DataServiceRequestArgs"/> class with additional metadata for the request. 
        /// Must not be null.</param> 
        /// <returns>An instance of <see cref="DataServiceStreamResponse"/> which represents the response.</returns>
        /// <exception cref="ArgumentNullException">Either entity or args parameters are null.</exception> 
        /// <exception cref="ArgumentException">The specified entity is either not tracked, is in the added state or it's not an MLE.</exception>
        public DataServiceStreamResponse GetReadStream(object entity, DataServiceRequestArgs args)
        {
            GetReadStreamResult result = this.CreateGetReadStreamResult(entity, args, null, null); 
            return result.Execute();
        } 
 
#endif
        #endregion 

        #region SetSaveStream

        /// <summary> 
        /// Sets a new content for a Media Resource associated with the specified Media Link Entry entity.
        /// </summary> 
        /// <param name="entity">The entity (MLE) for which to set the MR content.</param> 
        /// <param name="stream">The stream from which to read the content. The stream will be read to its end.
        /// No Seek operation will be tried on the stream.</param> 
        /// <param name="closeStream">If set to true SaveChanges will close the stream before it returns. It will close the stream
        /// even if it failed (throws) and even if it didn't get to use the stream.</param>
        /// <param name="contentType">The Content-Type header value to set for the MR request. The value is not validated
        /// in any way and it's the responsibility of the user to make sure it's a valid value for Content-Type header.</param> 
        /// <param name="slug">The Slug header value to set for the MR request. The value is not validated in any way
        /// and it's the responsibility of the user to make usre it's a valid value for Slug header.</param> 
        /// <remarks>Calling this method marks the entity as media link resource (MLE). It also marks the entity as modified 
        /// so that it will participate in the next call to SaveChanges.</remarks>
        /// <exception cref="ArgumentException">The entity is not being tracked or the contentType is an empty string. 
        /// The entity has the MediaEntry attribute marking it to use the older way of handling MRs.</exception>
        /// <exception cref="ArgumentNullException">Any of the arguments is null.</exception>
        public void SetSaveStream(object entity, Stream stream, bool closeStream, string contentType, string slug)
        { 
            Util.CheckArgumentNull(contentType, "contentType");
            Util.CheckArgumentNull(slug, "slug"); 
 
            DataServiceRequestArgs args = new DataServiceRequestArgs();
            args.ContentType = contentType; 
            args.Slug = slug;
            this.SetSaveStream(entity, stream, closeStream, args);
        }
 
        /// <summary>
        /// Sets a new content for a Media Resource associated with the specified Media Link Entry entity. 
        /// </summary> 
        /// <param name="entity">The entity (MLE) for which to set the MR content.</param>
        /// <param name="stream">The stream from which to read the content. The stream will be read to its end. 
        /// No Seek operation will be tried on the stream.</param>
        /// <param name="closeStream">If set to true SaveChanges will close the stream before it returns. It will close the stream
        /// even if it failed (throws) and even if it didn't get to use the stream.</param>
        /// <param name="args">Instance of <see cref="DataServiceRequestArgs"/> class with additional metadata for the MR request. 
        /// Must not be null.</param>
        /// <remarks>Calling this method marks the entity as media link resource (MLE). It also marks the entity as modified 
        /// so that it will participate in the next call to SaveChanges.</remarks> 
        /// <exception cref="ArgumentException">The entity is not being tracked. The entity has the MediaEntry attribute
        /// marking it to use the older way of handling MRs.</exception> 
        /// <exception cref="ArgumentNullException">Any of the arguments is null.</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public void SetSaveStream(object entity, Stream stream, bool closeStream, DataServiceRequestArgs args)
        { 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNull(stream, "stream"); 
            Util.CheckArgumentNull(args, "args"); 

            ClientType clientType = ClientType.Create(entity.GetType()); 
            if (clientType.MediaDataMember != null)
            {
                throw new ArgumentException(
                    Strings.Context_SetSaveStreamOnMediaEntryProperty(clientType.ElementTypeName), 
                    "entity");
            } 
 
            box.SaveStream = new DataServiceSaveStream(stream, closeStream, args);
 
            Debug.Assert(box.State != EntityStates.Detached, "We should never have a detached entity in the entityDescriptor dictionary.");
            switch (box.State)
            {
                case EntityStates.Added: 
                    box.StreamState = StreamStates.Added;
                    break; 
 
                case EntityStates.Modified:
                case EntityStates.Unchanged: 
                    box.StreamState = StreamStates.Modified;
                    break;

                case EntityStates.Deleted: 
                default:
                    // 
 
                    throw new DataServiceClientException(Strings.DataServiceException_GeneralError);
            } 

            // Note that there's no need to mark the entity as updated because we consider the presense
            // of the save stream as the mark that the MR for this MLE has been updated.
        } 

        #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");

            SaveResult result = new SaveResult(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) 
        {
            SaveResult result = BaseAsyncResult.EndExecute<SaveResult>(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"); 

            SaveResult result = new SaveResult(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>Begins 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);
            QueryComponents qc = new QueryComponents(requestUri, Util.DataServiceVersionEmpty, typeof(TElement), null, null); 
            return (new DataServiceRequest<TElement>(qc, null)).BeginExecute(this, this, callback, state);
        } 
 
        /// <summary>Begins the execution of spscified continuation.</summary>
        /// <typeparam name="T">Element type of the result</typeparam> 
        /// <param name="continuation">Conti----ation 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")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")] 
        public IAsyncResult BeginExecute<T>(DataServiceQueryContinuation<T> continuation, AsyncCallback callback, object state) 
        {
            Util.CheckArgumentNull(continuation, "continuation"); 
            QueryComponents qc = continuation.CreateQueryComponents();
            return (new DataServiceRequest<T>(qc, continuation.Plan)).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) 
        { 
            Util.CheckArgumentNull(asyncResult, "asyncResult");
            return DataServiceRequest.EndExecute<TElement>(this, this, asyncResult); 
        }

#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);
            QueryComponents qc = new QueryComponents(requestUri, Util.DataServiceVersionEmpty, typeof(TElement), null, null); 
            DataServiceRequest request = new DataServiceRequest<TElement>(qc, null);
            return request.Execute<TElement>(this, qc);
        }
 
        /// <summary>Executes the specified <paramref name="continuation"/>.</summary>
        /// <typeparam name="T">Element type for response.</typeparam> 
        /// <param name="continuation">Continuation for query to execute.</param> 
        /// <returns>The response for the specified <paramref name="continuation"/>.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")] 
        public QueryOperationResponse<T> Execute<T>(DataServiceQueryContinuation<T> continuation)
        {
            Util.CheckArgumentNull(continuation, "continuation");
            QueryComponents qc = continuation.CreateQueryComponents(); 
            DataServiceRequest request = new DataServiceRequest<T>(qc, continuation.Plan);
            return request.Execute<T>(this, qc); 
        } 
#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>
        /// <remarks> 
        /// BeginSaveChanges will asynchronously attach identity Uri returned by server to sucessfully added entites.
        /// EndSaveChanges will apply updated values to entities, raise ReadingEntity events and change entity states. 
        /// </remarks> 
        public IAsyncResult BeginSaveChanges(SaveChangesOptions options, AsyncCallback callback, object state)
        { 
            ValidateSaveChangesOptions(options);
            SaveResult result = new SaveResult(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)
        { 
            SaveResult result = BaseAsyncResult.EndExecute<SaveResult>(this, "SaveChanges", asyncResult);
 
            DataServiceResponse errors = result.EndRequest(); 

            if (this.ChangesSaved != null) 
            {
                this.ChangesSaved(this, new SaveChangesEventArgs(errors));
            }
 
            return errors;
        } 
 
#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);

            SaveResult result = new SaveResult(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");
 
            if (this.ChangesSaved != null)
            {
                this.ChangesSaved(this, new SaveChangesEventArgs(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); 
 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target);
            if (this.bindings.ContainsKey(relation)) 
            {
                throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
            }
 
            relation.State = EntityStates.Added;
            this.bindings.Add(relation, relation); 
            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");

            LinkDescriptor existing; 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target);
            if (!this.bindings.TryGetValue(relation, out existing)) 
            { 
                return false;
            } 

            this.DetachExistingLink(existing, false);
            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); 

            LinkDescriptor existing = null; 
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target); 
            if (this.bindings.TryGetValue(relation, out existing) && (EntityStates.Added == existing.State))
            {   // Added -> Detached 
                this.DetachExistingLink(existing, false);
            }
            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);
                    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);

            LinkDescriptor relation = this.DetachReferenceLink(source, sourceProperty, target, MergeOption.NoTracking); 
            if (null == relation)
            { 
                relation = new LinkDescriptor(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.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); 
            ValidateEntityType(entity); 

            EntityDescriptor resource = new EntityDescriptor(null, null /*selfLink*/, null /*editLink*/, entity, null, null, entitySetName, null, EntityStates.Added); 

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

            this.IncrementChange(resource);
        }
 
        /// <summary>
        /// This API enables adding the target object and setting the link between the source object and target object in one request. 
        /// </summary> 
        /// <param name="source">the parent object which is already tracked by the context.</param>
        /// <param name="sourceProperty">The name of the navigation property which forms the association between the source and target.</param> 
        /// <param name="target">the target object which needs to be added.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "parameters are validated against null via CheckArgumentNull")]
        public void AddRelatedObject(object source, string sourceProperty, object target) 
        {
            Util.CheckArgumentNull(source, "source"); 
            Util.CheckArgumentNotEmpty(sourceProperty, "propertyName"); 
            Util.CheckArgumentNull(target, "target");
 
            // Validate that the source is an entity and is already tracked by the context.
            ValidateEntityType(source);

            EntityDescriptor sourceResource = this.EnsureContained(source, "source"); 

            // Check for deleted source entity 
            if (sourceResource.State == EntityStates.Deleted) 
            {
                throw Error.InvalidOperation(Strings.Context_AddRelatedObjectSourceDeleted); 
            }

            // Validate that the property is valid and exists on the source
            ClientType parentType = ClientType.Create(source.GetType()); 
            ClientType.ClientProperty property = parentType.GetProperty(sourceProperty, false);
            if (property.IsKnownType || property.CollectionType == null) 
            { 
                throw Error.InvalidOperation(Strings.Context_AddRelatedObjectCollectionOnly);
            } 

            // Validate that the target is an entity
            ClientType childType = ClientType.Create(target.GetType());
            ValidateEntityType(target); 

            // Validate that the property type matches with the target type 
            ClientType propertyElementType = ClientType.Create(property.CollectionType); 
            if (!propertyElementType.ElementType.IsAssignableFrom(childType.ElementType))
            { 
                // target is not of the correct type
                throw Error.Argument(Strings.Context_RelationNotRefOrCollection, "target");
            }
 
            EntityDescriptor targetResource = new EntityDescriptor(null, null, null, target, sourceResource, sourceProperty, null /*entitySetName*/, null, EntityStates.Added);
 
            try 
            {
                this.entityDescriptors.Add(target, targetResource); 
            }
            catch (ArgumentException)
            {
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained); 
            }
 
            // Add the link in the added state. 
            LinkDescriptor end = targetResource.GetRelatedEnd();
            end.State = EntityStates.Added; 
            this.bindings.Add(end, end);

            this.IncrementChange(targetResource);
        } 

        /// <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, null);
        }

        /// <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);
            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
            String identity = Util.ReferenceIdentity(editLink.AbsoluteUri); 
 
            // EntitySetName need to be cached only when the entity is in added state. For all other states, entities self/edit link must be used.
            EntityDescriptor descriptor = new EntityDescriptor(identity, null /* selfLink */, editLink, entity, null /* parent */, null /* parent property */, null /*entitySetName*/, etag, EntityStates.Unchanged); 
            this.InternalAttachEntityDescriptor(descriptor, 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"); 
 
            EntityDescriptor resource = null;
            if (!this.entityDescriptors.TryGetValue(entity, out resource)) 
            {   // detached object
                throw Error.InvalidOperation(Strings.Context_EntityNotContained);
            }
 
            EntityStates state = resource.State;
            if (EntityStates.Added == state) 
            {   // added -> detach 
                this.DetachResource(resource);
            } 
            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"); 

            EntityDescriptor resource = null; 
            if (this.entityDescriptors.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");
 
            EntityDescriptor resource = null; 
            if (!this.entityDescriptors.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>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "parameters are validated against null via CheckArgumentNull")]
        public bool TryGetEntity<TEntity>(Uri identity, out TEntity entity) where TEntity : class
        { 
            entity = null;
            Util.CheckArgumentNull(identity, "relativeUri"); 
 
            EntityStates state;
 
            // ReferenceIdentity is a test hook to help verify we dont' use identity instead of editLink
            entity = (TEntity)this.TryGetEntity(Util.ReferenceIdentity(identity.ToString()), 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"); 

            // if the entity's identity does not map back to the entity, don't return it
            EntityDescriptor resource = null;
            if ((null != this.identityToDescriptor) && 
                this.entityDescriptors.TryGetValue(entity, out resource) &&
                (null != resource.Identity) && 
                Object.ReferenceEquals(resource, this.identityToDescriptor[resource.Identity])) 
            {
                // DereferenceIdentity is a test hook to help verify we dont' use identity instead of editLink 
                string identityUri = Util.DereferenceIdentity(resource.Identity);
                identity = Util.CreateUri(identityUri, UriKind.Absolute);
            }
 
            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,
                    SerializeSupportedVersions()); 

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

            return failure; 
        } 

        /// <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")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "underlying stream is disposed so wrapping StreamReader doesn't need to be disposed")] 
        internal static DataServiceClientException GetResponseText(Func<Stream> getResponseStream, HttpStatusCode statusCode)
        { 
            string message = null;
            using (System.IO.Stream stream = getResponseStream())
            {
                if ((null != stream) && stream.CanRead) 
                {
                    // this StreamReader can go out of scope without dispose because the underly stream is disposed of 
                    message = new StreamReader(stream).ReadToEnd(); 
                }
            } 

            if (String.IsNullOrEmpty(message))
            {
                message = statusCode.ToString(); 
            }
 
            return new DataServiceClientException(message, (int)statusCode); 
        }
 
        /// <summary>response materialization has an identity to attach to the inserted object</summary>
        /// <param name="identity">identity of entity</param>
        /// <param name="selfLink">query link 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(String identity, Uri selfLink, Uri editLink, object entity, string etag) 
        {   // insert->unchanged
            Debug.Assert(null != identity, "must have identity"); 

            this.EnsureIdentityToResource();

            // resource.State == EntityState.Added or Unchanged for second pass of media link 
            EntityDescriptor resource = this.entityDescriptors[entity];
 
            this.DetachResourceIdentity(resource); 

            // While processing the response, we need to find out if the given resource was inserted deep 
            // If it was, then we need to change the link state from added to unchanged
            if (resource.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[resource.GetRelatedEnd()]; 
                end.State = EntityStates.Unchanged;
            } 
 
            resource.ETag = etag;
            resource.Identity = identity; // always attach the identity 
            resource.SelfLink = selfLink;
            resource.EditLink = editLink;

            resource.State = EntityStates.Unchanged; 

            // scenario: sucessfully (1) delete an existing entity and (2) add a new entity where the new entity has the same identity as deleted entity 
            // where the SaveChanges pass1 will now associate existing identity with new entity 
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity
            this.identityToDescriptor[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); 
            String identity = Util.ReferenceIdentity(editLink.ToString());

            this.EnsureIdentityToResource();
 
            // resource.State == EntityState.Added or Unchanged for second pass of media link
            EntityDescriptor resource = this.entityDescriptors[entity]; 
            this.DetachResourceIdentity(resource); 

            // While processing the response, we need to find out if the given resource was inserted deep 
            // If it was, then we need to change the link state from added to unchanged
            if (resource.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[resource.GetRelatedEnd()]; 
                end.State = EntityStates.Unchanged;
            } 
 
            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink; 

            // scenario: sucessfully batch (1) add a new entity and (2) delete an existing entity where the new entity has the same identity as deleted entity
            // where the SaveChanges pass1 will now associate existing identity with new entity
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity 
            this.identityToDescriptor[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);
 
            LinkDescriptor existing = null;
            LinkDescriptor relation = new LinkDescriptor(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.Target))
                        { 
                            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.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="descriptor">the descriptor to add</param> 
        /// <param name="failIfDuplicated">fail for public api else change existing relationship to unchanged</param>
        /// <remarks>Caller should validate descriptor instance.</remarks> 
        /// <returns>The attached descriptor, if one already exists in the context and failIfDuplicated is set to false, then the existing instance is returned</returns>
        /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception>
        /// <exception cref="InvalidOperationException">if identity is pointing to another entity</exception>
        internal EntityDescriptor InternalAttachEntityDescriptor(EntityDescriptor descriptor, bool failIfDuplicated) 
        {
            Debug.Assert((null != descriptor.Identity), "must have identity"); 
            Debug.Assert(null != descriptor.Entity && ClientType.Create(descriptor.Entity.GetType()).IsEntityType, "must be entity type to attach"); 

            this.EnsureIdentityToResource(); 

            EntityDescriptor resource;
            this.entityDescriptors.TryGetValue(descriptor.Entity, out resource);
 
            EntityDescriptor existing;
            this.identityToDescriptor.TryGetValue(descriptor.Identity, out existing); 
 
            // identity existing & pointing to something else
            if (failIfDuplicated && (null != resource)) 
            {
                throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained);
            }
            else if (resource != existing) 
            {
                throw Error.InvalidOperation(Strings.Context_DifferentEntityAlreadyContained); 
            } 
            else if (null == resource)
            { 
                resource = descriptor;

                // if resource doesn't exist...
                this.IncrementChange(descriptor); 
                this.entityDescriptors.Add(descriptor.Entity, descriptor);
                this.identityToDescriptor.Add(descriptor.Identity, descriptor); 
            } 

            // DEVNOTE([....]): 
            // we used to mark the descriptor as Unchanged
            // but it's now up to the caller to do that
            return resource;
        } 

        #endregion 
 
#if ASTORIA_LIGHT
        /// <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> 
        /// <param name="requestVersion">The version associated with this request</param> 
        /// <param name="sendChunked">Set to true if the request body should be sent using chunked encoding.</param>
        /// <returns>a request ready to get a response</returns> 
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked)
        {
            return CreateRequest(requestUri, method, allowAnyType, contentType, requestVersion, sendChunked, HttpStack.Auto);
        } 
#endif
 
#if !ASTORIA_LIGHT 
        /// <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. Can be null which means don't set the header.</param>
        /// <param name="requestVersion">The version associated with this request</param> 
        /// <param name="sendChunked">Set to true if the request body should be sent using chunked encoding.</param> 
        /// <returns>a request ready to get a response</returns>
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked) 
#else
        /// <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>
        /// <param name="requestVersion">The version associated with this request</param> 
        /// <param name="sendChunked">Set to true if the request body should be sent using chunked encoding.</param>
        /// <param name="httpStackArg">If set to non-Auto it forces usage of that http stack in SL regardless of the context settings.</param>
        /// <returns>a request ready to get a response</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "sendChunked", Justification = "common parameter not used in silverlight")] 
        internal HttpWebRequest CreateRequest(Uri requestUri, string method, bool allowAnyType, string contentType, Version requestVersion, bool sendChunked, HttpStack httpStackArg)
#endif 
        { 
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
            Debug.Assert(
                requestUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) ||
                    requestUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase),
                "request uri is not for HTTP"); 

            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");
 
#if !ASTORIA_LIGHT
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); 
#else 
            if (httpStackArg == HttpStack.Auto)
            { 
                httpStackArg = this.httpStack;
            }
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri, httpStackArg);
#endif 

#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;
            }

            // Always sending the version along allows the server to fail before processing. 
            // devnote([....]): this needs to be set before SendingRequest is fired, so client has a chance to modify them
            if (requestVersion != null && requestVersion.Major > 0) 
            { 
                // if request version is 0.x, then we don't put a DSV header
                // in this case it's up to the server to decide what version this request is 
                request.Headers[XmlConstants.HttpDataServiceVersion] = requestVersion.ToString() + Util.VersionSuffix;
            }

            request.Headers[XmlConstants.HttpMaxDataServiceVersion] = Util.MaxResponseVersion.ToString() + Util.VersionSuffix; 

#if !ASTORIA_LIGHT // Silverlight doesn't support chunked encoding yet - so just ignore it 
            if (sendChunked) 
            {
                request.SendChunked = true; 
            }
#endif

            // 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)
            { 
                System.Net.WebHeaderCollection requestHeaders;
#if !ASTORIA_LIGHT
                requestHeaders = request.Headers;
                SendingRequestEventArgs args = new SendingRequestEventArgs(request, requestHeaders); 
#else
                requestHeaders = request.CreateEmptyWebHeaderCollection(); 
                SendingRequestEventArgs args = new SendingRequestEventArgs(null, requestHeaders); 
#endif
                this.SendingRequest(this, args); 

#if !ASTORIA_LIGHT
                if (!Object.ReferenceEquals(args.Request, request))
                { 
                    request = (System.Net.HttpWebRequest)args.Request;
                } 
#else 
                // apply all headers to the request
                foreach (string key in requestHeaders.AllKeys) 
                {
                    request.Headers[key] = requestHeaders[key];
                }
#endif 
            }
 
            request.Accept = allowAnyType ? 
                    XmlConstants.MimeAny :
                    (XmlConstants.MimeApplicationAtom + "," + XmlConstants.MimeApplicationXml); 

            request.Headers[HttpRequestHeader.AcceptCharset] = XmlConstants.Utf8Encoding;

#if !ASTORIA_LIGHT // AllowWriteStreamBuffering not available 
            bool allowStreamBuffering = false;
            bool removeXMethod = true; 
#endif 

            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; 
#if !ASTORIA_LIGHT
                    removeXMethod = false;
#endif
                } 
            }
            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;
            headers = request.Headers.AllKeys; 

#if !ASTORIA_LIGHT  // alternate IfMatch header doesn't work
            if (headers.Contains(XmlConstants.HttpRequestIfMatch))
            { 
                request.Headers.Remove(HttpRequestHeader.IfMatch);
            } 
#endif 

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

        /// <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(String resourceUri, string etag, MergeOption merger, out EntityStates state)
        {
            Debug.Assert(null != resourceUri, "null uri");
            state = EntityStates.Detached; 

            EntityDescriptor resource = null; 
            if ((null != this.identityToDescriptor) && 
                 this.identityToDescriptor.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.Entity, "null entity"); 
                return resource.Entity;
            } 

            return null;
        }
 
        /// <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<LinkDescriptor> GetLinks(object source, string sourceProperty)
        {
            return this.bindings.Values.Where(o => (o.Source == 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>
        /// <param name="checkAssignable">Whether to check that the resulting type is assignable.</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, bool checkAssignable) 
        { 
            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 (checkAssignable && (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, use for complex types and LINQ query expression building
        /// </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>
        /// Get from entity descriptor or resolve the server type name for the entitydescriptor 
        /// </summary> 
        /// <param name="descriptor">The entity descriptor</param>
        /// <returns>The server type name for the entity</returns> 
        internal string GetServerTypeName(EntityDescriptor descriptor)
        {
            Debug.Assert(descriptor != null && descriptor.Entity != null, "Null descriptor or no entity in descriptor");
 
            if (this.resolveName != null)
            { 
                // is resolveName the code-gen resolver? 
                Type entityType = descriptor.Entity.GetType();
                var codegenAttr = this.resolveName.Method.GetCustomAttributes(false).OfType<System.CodeDom.Compiler.GeneratedCodeAttribute>().FirstOrDefault(); 
                if (codegenAttr == null || codegenAttr.Tool != Util.CodeGeneratorToolName)
                {
                    // User-supplied resolver, must call first
                    return this.resolveName(entityType) ?? descriptor.ServerTypeName; 
                }
                else 
                { 
                    // V2+ codegen resolver, called last
                    return descriptor.ServerTypeName ?? this.resolveName(entityType); 
                }
            }
            else
            { 
                return descriptor.ServerTypeName;
            } 
        } 

        /// <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>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 a WCF 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; 
                }

                if (!Util.SupportedResponseVersions.Contains(version.Key))
                { 
                    return false;
                } 
            } 

            return true; 
        }

        /// <summary>
        /// Serialize supported data service versions to a string that will be used in the exception message. 
        /// The string contains versions in single quotes separated by comma followed by a single space (e.g. "'1.0', '2.0'").
        /// </summary> 
        /// <returns>Supported data service versions in single quotes separated by comma followed by a space.</returns> 
        private static string SerializeSupportedVersions()
        { 
            Debug.Assert(Util.SupportedResponseVersions.Length > 0, "At least one supported version must exist.");

            StringBuilder supportedVersions = new StringBuilder("'").Append(Util.SupportedResponseVersions[0].ToString());
            for (int versionIdx = 1; versionIdx < Util.SupportedResponseVersions.Length; versionIdx++) 
            {
                supportedVersions.Append("', '"); 
                supportedVersions.Append(Util.SupportedResponseVersions[versionIdx].ToString()); 
            }
 
            supportedVersions.Append("'");

            return supportedVersions.ToString();
        } 

        /// <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");
 
            // to generate the edit link uri, we need keys 
            // this also checks for null
            ValidateEntityTypeHasKeys(entity); 

            StringBuilder builder = new StringBuilder();
            builder.Append(baseUriWithSlash.AbsoluteUri);
            builder.Append(entitySetName); 
            builder.Append("(");
 
            string prefix = String.Empty; 
            ClientType clientType = ClientType.Create(entity.GetType());
 
            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.Context_CannotConvertKey(value));
                } 
 
                builder.Append(System.Uri.EscapeDataString(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(LinkDescriptor link)
        {
            bool collection = (null != ClientType.Create(link.Source.GetType()).GetProperty(link.SourceProperty, false).CollectionType); 
            if (!collection)
            { 
                Debug.Assert(EntityStates.Modified == link.State, "not Modified state"); 
                if (null == link.Target)
                {   // 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>Handle changeset response.</summary>
        /// <param name="entry">headers of changeset response</param>
        private static void HandleResponsePost(LinkDescriptor entry)
        { 
            if (!((EntityStates.Added == entry.State) || (EntityStates.Modified == entry.State && null != entry.Target)))
            { 
                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(Descriptor entry, string etag) 
        {
            if (entry.IsResource) 
            {
                EntityDescriptor descriptor = (EntityDescriptor)entry;
                if (EntityStates.Modified != descriptor.State && StreamStates.Modified != descriptor.StreamState)
                { 
                    Error.ThrowBatchUnexpectedContent(InternalError.EntryNotModified);
                } 
 
                // We MUST process the MR before the MLE since we always issue the requests in that order.
                if (descriptor.StreamState == StreamStates.Modified) 
                {
                    descriptor.StreamETag = etag;
                    descriptor.StreamState = StreamStates.NoStream;
                } 
                else
                { 
                    Debug.Assert(descriptor.State == EntityStates.Modified, "descriptor.State == EntityStates.Modified"); 
                    descriptor.ETag = etag;
                    descriptor.State = EntityStates.Unchanged; 
                }
            }
            else
            { 
                LinkDescriptor link = (LinkDescriptor)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, false /* atomDateConstruct */); 
                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"/> is entity type</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 ValidateEntityType(object entity) 
        { 
            Util.CheckArgumentNull(entity, "entity");
 
            if (!ClientType.Create(entity.GetType()).IsEntityType)
            {
                throw Error.Argument(Strings.Content_EntityIsNotEntityType, "entity");
            } 
        }
 
        /// <summary>validate <paramref name="entity"/> has key properties</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 ValidateEntityTypeHasKeys(object entity)
        {
            Util.CheckArgumentNull(entity, "entity"); 

            if (ClientType.Create(entity.GetType()).KeyCount <= 0) 
            { 
                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> 
        /// <param name="requestVersion">version for the request</param>
        private static void WriteOperationRequestHeaders(StreamWriter writer, string methodName, string uri, Version requestVersion) 
        {
            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); 
            if (requestVersion != Util.DataServiceVersion1 && requestVersion != Util.DataServiceVersionEmpty) 
            {
                writer.WriteLine("{0}: {1}{2}", XmlConstants.HttpDataServiceVersion, requestVersion, Util.VersionSuffix); 
            }
        }

        /// <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>the work to detach a resource</summary> 
        /// <param name="resource">resource to detach</param>
        /// <returns>true if detached</returns>
        private bool DetachResource(EntityDescriptor resource)
        { 
            // Since we are changing the list on the fly, we need to convert it into a list first
            // so that enumeration won't get effected. 
            foreach (LinkDescriptor end in this.bindings.Values.Where(resource.IsRelatedEntity).ToList()) 
            {
                this.DetachExistingLink( 
                        end,
                        end.Target == resource.Entity && resource.State == EntityStates.Added);
            }
 
            resource.ChangeOrder = UInt32.MaxValue;
            resource.State = EntityStates.Detached; 
            bool flag = this.entityDescriptors.Remove(resource.Entity); 
            Debug.Assert(flag, "should have removed existing entity");
            this.DetachResourceIdentity(resource); 

            return true;
        }
 
        /// <summary>remove the identity attached to the resource</summary>
        /// <param name="resource">resource with an identity to detach to detach</param> 
        private void DetachResourceIdentity(EntityDescriptor resource) 
        {
            EntityDescriptor existing = null; 
            if ((null != resource.Identity) &&
                this.identityToDescriptor.TryGetValue(resource.Identity, out existing) &&
                Object.ReferenceEquals(existing, resource))
            { 
                bool removed = this.identityToDescriptor.Remove(resource.Identity);
                Debug.Assert(removed, "should have removed existing identity"); 
            } 
        }
 
        /// <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(LinkDescriptor binding) 
        { 
            Debug.Assert(null != binding, "null binding");
            if (binding.ContentGeneratedForSave) 
            {
                return null;
            }
 
            EntityDescriptor sourceResource = this.entityDescriptors[binding.Source];
            EntityDescriptor targetResource = (null != binding.Target) ? this.entityDescriptors[binding.Target] : 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, Util.DataServiceVersion1, false); 
        }
 
        /// <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(EntityDescriptor sourceResource, LinkDescriptor binding)
        { 
            Uri requestUri = Util.CreateUri(sourceResource.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/), 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(LinkDescriptor binding) 
        {
            Uri relative; 
            bool collection = (null != ClientType.Create(binding.Source.GetType()).GetProperty(binding.SourceProperty, false).CollectionType);
            if (collection && (EntityStates.Added != binding.State))
            {   // you DELETE(PUT NULL) from a collection
                Debug.Assert(null != binding.Target, "null target in collection"); 
                EntityDescriptor targetResource = this.entityDescriptors[binding.Target];
 
                // 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.Entity)); 

                // 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(LinkDescriptor binding, StreamWriter text)
        { 
            EntityDescriptor sourceResource = this.entityDescriptors[binding.Source]; 
            string requestString;
            if (null != sourceResource.Identity) 
            {
                requestString = this.CreateRequestUri(sourceResource, binding).AbsoluteUri;
            }
            else 
            {
                Uri relative = this.CreateRequestRelativeUri(binding); 
                requestString = "$" + sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) + "/" + relative.OriginalString; 
            }
 
            WriteOperationRequestHeaders(text, GetLinkHttpMethod(binding), requestString, Util.DataServiceVersion1);
            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.Target))) 
            { 
                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>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MemoryStream which doesn't require disposal")] 
        private MemoryStream CreateRequestData(LinkDescriptor binding, bool newline)
        {
            Debug.Assert(
                (binding.State == EntityStates.Added) || 
                (binding.State == EntityStates.Modified && null != binding.Target),
                "This method must be called only when a binding is added or put"); 
            MemoryStream stream = new MemoryStream(); 
            XmlWriter writer = XmlUtil.CreateXmlWriterAndWriteProcessingInstruction(stream, HttpProcessUtility.EncodingUtf8NoPreamble);
            EntityDescriptor targetResource = this.entityDescriptors[binding.Target]; 

            #region <uri xmlns="metadata">
            writer.WriteStartElement(XmlConstants.UriElementName, XmlConstants.DataWebMetadataNamespace);
 
            string id;
            if (null != targetResource.Identity) 
            { 
                // When we write the uri in the payload, we need to make sure that we write the edit
                // link in the payload, since the request uri is the edit link of the parent entity. 
                // Think of a read/write service - since the uri is the target link to the parent entity
                // its better than we write the edit link of the child entity in the payload.
                id = targetResource.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/).OriginalString;
            } 
            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 
                for (int kk = 0; kk < NewLine.Length; ++kk)
                {
                    stream.WriteByte((byte)NewLine[kk]);
                } 
            }
 
            // 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(EntityDescriptor 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, false /*queryLink*/); 
 
            Version requestVersion = ClientType.Create(box.Entity.GetType()).EpmIsV1Compatible ? Util.DataServiceVersion1 : Util.DataServiceVersion2;
            HttpWebRequest request = this.CreateRequest(requestUri, httpMethod, false, XmlConstants.MimeApplicationAtom, requestVersion, false); 
            if ((null != box.ETag) && ((EntityStates.Deleted == state) || (EntityStates.Modified == state)))
            {
                request.Headers.Set(HttpRequestHeader.IfMatch, box.ETag);
            } 

            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(EntityDescriptor box, StreamWriter text, bool replaceOnUpdate) 
        { 
            Debug.Assert(null != box, "null box");
            Debug.Assert(null != text, "null text"); 
            Debug.Assert(box.State == EntityStates.Added || box.State == EntityStates.Deleted || box.State == EntityStates.Modified, "the entity must be in one of the 3 possible states");

            Uri requestUri = box.GetResourceUri(this.baseUriWithSlash, false /*queryLink*/);
 
            Debug.Assert(null != requestUri, "request uri is null");
            Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 
 
            Version requestVersion = ClientType.Create(box.Entity.GetType()).EpmIsV1Compatible ? Util.DataServiceVersion1 : Util.DataServiceVersion2;
            WriteOperationRequestHeaders(text, GetEntityHttpMethod(box.State, replaceOnUpdate), requestUri.AbsoluteUri, requestVersion); 
            text.WriteLine("{0}: {1}", XmlConstants.HttpContentID, box.ChangeOrder);
            if (EntityStates.Deleted != box.State)
            {
                text.WriteLine("{0}: {1}", XmlConstants.HttpContentType, XmlConstants.LinkMimeTypeEntry); 
            }
 
            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> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MemoryStream which doesn't require disposal")]
        private MemoryStream CreateRequestData(EntityDescriptor 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.Entity.GetType());
 
                string typeName = this.GetServerTypeName(box);

                #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();
                } 
 
                if (type.HasEntityPropertyMappings)
                { 
                    using (EpmSyndicationContentSerializer s = new EpmSyndicationContentSerializer(type.EpmTargetTree, box.Entity, writer))
                    {
                        s.Serialize();
                    } 
                }
                else 
                { 
                    // <title />
                    // <updated>2008-05-05T21:44:55Z</updated> 
                    // <author><name /></author>
                    writer.WriteElementString(XmlConstants.AtomTitleElementName, XmlConstants.AtomNamespace, String.Empty);
                    writer.WriteStartElement(XmlConstants.AtomAuthorElementName, XmlConstants.AtomNamespace);
                    writer.WriteElementString(XmlConstants.AtomNameElementName, XmlConstants.AtomNamespace, String.Empty); 
                    writer.WriteEndElement();
 
                    writer.WriteElementString(XmlConstants.AtomUpdatedElementName, XmlConstants.AtomNamespace, XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind)); 
                }
 
                if (EntityStates.Modified == box.State)
                {
                    // <id>http://host/service/entityset(key)</id>
                    writer.WriteElementString(XmlConstants.AtomIdElementName, Util.DereferenceIdentity(box.Identity)); 
                }
                else 
                { 
                    writer.WriteElementString(XmlConstants.AtomIdElementName, XmlConstants.AtomNamespace, String.Empty);
                } 

                #region <link href=”%EditLink%” 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> 
                // For MLE we need to write the properties to the entry level, we also omit the content element completely
                //   as the server will ignore it anyway.
                if (!type.IsMediaLinkEntry && !box.IsMediaLinkEntry)
                { 
                    writer.WriteStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); // <atom:content>
                    writer.WriteAttributeString(XmlConstants.AtomTypeAttributeName, XmlConstants.MimeApplicationXml); // empty namespace 
                } 

                writer.WriteStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace); // <m:Properties> 

                bool propertiesWritten;
                this.WriteContentProperties(writer, type, box.Entity, type.HasEntityPropertyMappings ? type.EpmSourceTree.Root : null, out propertiesWritten);
 
                writer.WriteEndElement(); // </m:Properties>
 
                if (!type.IsMediaLinkEntry && !box.IsMediaLinkEntry) 
                {
                    writer.WriteEndElement(); // </atom:content> 
                }

                if (type.HasEntityPropertyMappings)
                { 
                    using (EpmCustomContentSerializer s = new EpmCustomContentSerializer(type.EpmTargetTree, box.Entity, writer))
                    { 
                        s.Serialize(); 
                    }
                } 

                writer.WriteEndElement(); // </atom:entry>
                writer.Flush();
                writer.Close(); 
                #endregion
                #endregion 
 
                if (this.WritingEntity != null)
                { 
                    ReadingWritingEntityEventArgs args = new ReadingWritingEntityEventArgs(box.Entity, 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
                    XmlWriterSettings settings = XmlUtil.CreateXmlWriterSettings(HttpProcessUtility.EncodingUtf8NoPreamble); 
                    settings.ConformanceLevel = ConformanceLevel.Auto; 
                    using (XmlWriter streamWriter = XmlWriter.Create(stream, settings))
                    { 
                        node.Save(streamWriter);
                    }
                }
 
                if (newline)
                { 
                    // end the xml content stream with a newline 
                    for (int kk = 0; kk < NewLine.Length; ++kk)
                    { 
                        stream.WriteByte((byte)NewLine[kk]);
                    }
                }
 
                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(EntityDescriptor box, XmlWriter writer) 
        {
            Debug.Assert(EntityStates.Added == box.State, "entity not added state"); 

            ClientType clientType = null;
            foreach (LinkDescriptor end in this.RelatedLinks(box))
            { 
                Debug.Assert(!end.ContentGeneratedForSave, "already saved link");
                end.ContentGeneratedForSave = true; 
 
                if (null == clientType)
                { 
                    clientType = ClientType.Create(box.Entity.GetType());
                }

                string typeAttributeValue; 
                if (null != clientType.GetProperty(end.SourceProperty, false).CollectionType)
                { 
                    typeAttributeValue = XmlConstants.LinkMimeTypeFeed; 
                }
                else 
                {
                    typeAttributeValue = XmlConstants.LinkMimeTypeEntry;
                }
 
                Debug.Assert(null != end.Target, "null is DELETE");
                String targetEditLink = this.entityDescriptors[end.Target].EditLink.ToString(); 
 
                writer.WriteStartElement(XmlConstants.AtomLinkElementName, XmlConstants.AtomNamespace);
                writer.WriteAttributeString(XmlConstants.AtomHRefAttributeName, targetEditLink); 
                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(Descriptor entry) 
        {
            if (EntityStates.Deleted != entry.State)
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotDeleted); 
            }
 
            if (entry.IsResource) 
            {
                EntityDescriptor resource = (EntityDescriptor)entry; 
                this.DetachResource(resource);
            }
            else
            { 
                this.DetachExistingLink((LinkDescriptor)entry, false);
            } 
        } 

        /// <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(EntityDescriptor entry, MaterializeAtom materializer, Uri editLink, string etag)
        { 
            Debug.Assert(editLink != null, "location header must be specified in POST responses."); 

            if (EntityStates.Added != entry.State && StreamStates.Added != entry.StreamState) 
            {
                Error.ThrowBatchUnexpectedContent(InternalError.EntityNotAddedState);
            }
 
            if (materializer == null)
            { 
                // If the materializer is null, that means the POST request didn't send a response back. Hence we will use 
                // the location header as the self and edit links.
                String identity = Util.ReferenceIdentity(editLink.ToString()); 
                this.AttachIdentity(identity, null /*queryLink*/, editLink, entry.Entity, etag);
            }
            else
            { 
                materializer.SetInsertingObject(entry.Entity);
 
                foreach (object x in materializer) 
                {
                    Debug.Assert(null != entry.Identity, "updated inserted should always gain an identity"); 
                    Debug.Assert(x == entry.Entity, "x == box.Entity, should have same object generated by response");
                    Debug.Assert(EntityStates.Unchanged == entry.State, "should have moved out of insert");
                    Debug.Assert((null != this.identityToDescriptor) && this.identityToDescriptor.ContainsKey(entry.Identity), "should have identity tracked");
 
                    // If there was no edit link specified in the payload, then we need to set the location header as the edit link
                    if (entry.EditLink == null) 
                    { 
                        entry.EditLink = editLink;
                    } 

                    // If there was no etag specified in the payload, then we need to set the etag from the header
                    if (entry.ETag == null)
                    { 
                        entry.ETag = etag;
                    } 
                } 
            }
 
            foreach (LinkDescriptor end in this.RelatedLinks(entry))
            {
                Debug.Assert(0 != end.SaveResultWasProcessed, "link should have been saved with the enty");
 
                // Since we allow link folding on collection properties also, we need to check if the link
                // was in added state also, and make sure we put that link in unchanged state. 
                if (IncludeLinkState(end.SaveResultWasProcessed) || end.SaveResultWasProcessed == EntityStates.Added) 
                {
                    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(Descriptor entry)
        { 
            // media links will be processed twice
            entry.SaveResultWasProcessed = entry.State;

            int count = 0; 
            if (entry.IsResource && (EntityStates.Added == entry.State))
            { 
                foreach (LinkDescriptor end in this.RelatedLinks((EntityDescriptor)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<LinkDescriptor> RelatedLinks(EntityDescriptor box) 
        {
            foreach (LinkDescriptor end in this.bindings.Values) 
            { 
                if (end.Source == box.Entity)
                { 
                    if (null != end.Target)
                    {   // null TargetResource is equivalent to Deleted
                        EntityDescriptor target = this.entityDescriptors[end.Target];
 
                        // 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;
                        } 
                    }
                }
            }
        } 

        /// <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>
        /// <param name="requestUri">The request uri, or null if one is to be constructed</param> 
        /// <param name="continuation">Continuation, if one is available.</param>
        /// <returns>a aync result that you can get a response from</returns> 
        private LoadPropertyResult CreateLoadPropertyRequest(object entity, string propertyName, AsyncCallback callback, object state, Uri requestUri, DataServiceQueryContinuation continuation) 
        {
            Debug.Assert(continuation == null || requestUri == null, "continuation == null || requestUri == null -- only one or the either (or neither) may be passed in"); 
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNotEmpty(propertyName, "propertyName");

            ClientType type = ClientType.Create(entity.GetType()); 
            Debug.Assert(type.IsEntityType, "must be entity type 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"); 

            ProjectionPlan plan; 
            if (continuation == null) 
            {
                plan = null; 
            }
            else
            {
                plan = continuation.Plan; 
                requestUri = continuation.NextLinkUri;
            } 
 
            bool mediaLink = (type.MediaDataMember != null && propertyName == type.MediaDataMember.PropertyName);
            Version requestVersion; 
            if (requestUri == null)
            {
                Uri relativeUri;
                if (mediaLink) 
                {
                    // special case for requesting the "media" value of an ATOM media link entry 
                    relativeUri = Util.CreateUri(XmlConstants.UriValueSegment, UriKind.Relative); 
                }
                else 
                {
                    relativeUri = Util.CreateUri(propertyName + (null != property.CollectionType ? "()" : String.Empty), UriKind.Relative);
                }
 
                requestUri = Util.CreateUri(box.GetResourceUri(this.baseUriWithSlash, true /*queryLink*/), relativeUri);
                requestVersion = Util.DataServiceVersion1; 
            } 
            else
            { 
                // if we specify an URI, we need to keep the Execute<T> behaviour
                requestVersion = Util.DataServiceVersionEmpty;
            }
 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, mediaLink, null, requestVersion, false);
            DataServiceRequest dataServiceRequest = DataServiceRequest.GetInstance(property.PropertyType, requestUri); 
            return new LoadPropertyResult(entity, propertyName, this, request, callback, state, dataServiceRequest, plan); 
        }
 
        /// <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> 
        /// <param name="currentSegment">Source EPM tree segment corresponding to <paramref name="type"/></param> 
        /// <param name="propertiesWritten">True if we have written any property to the writer.</param>
        private void WriteContentProperties(XmlWriter writer, ClientType type, object resource, EpmSourcePathSegment currentSegment, out bool propertiesWritten) 
        {
            #region <d:property>value</property>
            propertiesWritten = false;
            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);
 
                EpmSourcePathSegment matchedSegment = currentSegment != null ? currentSegment.SubProperties.SingleOrDefault(s => s.PropertyName == property.PropertyName) : null; 

                if (property.IsKnownType) 
                {
                    if (propertyValue == null || matchedSegment == null || matchedSegment.EpmInfo.Attribute.KeepInContent)
                    {
                        WriteContentProperty(writer, this.DataNamespace, property, propertyValue); 
                        propertiesWritten = true;
                    } 
                } 
#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())) 
                        {
                            Type valueType = pair.Value != null ? pair.Value.GetType() : typeof(string); 
                            ClientType.ClientProperty openProperty = new ClientType.ClientProperty(null, valueType, false, true); 
                            WriteContentProperty(writer, this.DataNamespace, openProperty, pair.Value);
                            propertiesWritten = true; 
                        }
                    }
                }
#endif 
                else if (null == property.CollectionType)
                { 
                    ClientType nested = ClientType.Create(property.PropertyType); 
                    if (!nested.IsEntityType)
                    { 
                        #region complex type
                        XElement complexProperty = new XElement(((XNamespace)this.DataNamespace) + property.PropertyName);
                        bool shouldWriteComplexProperty = false;
                        string typeName = this.ResolveNameFromType(nested.ElementType); 
                        if (!String.IsNullOrEmpty(typeName))
                        { 
                            complexProperty.Add(new XAttribute(((XNamespace)XmlConstants.DataWebMetadataNamespace) + XmlConstants.AtomTypeAttributeName, typeName)); 
                        }
 
                        // Handle null values for complex types by putting m:null="true"
                        if (null == propertyValue)
                        {
                            complexProperty.Add(new XAttribute(((XNamespace)XmlConstants.DataWebMetadataNamespace) + XmlConstants.AtomNullAttributeName, XmlConstants.XmlTrueLiteral)); 
                            shouldWriteComplexProperty = true;
                        } 
                        else 
                        {
                            using (XmlWriter complexPropertyWriter = complexProperty.CreateWriter()) 
                            {
                                this.WriteContentProperties(complexPropertyWriter, nested, propertyValue, matchedSegment, out shouldWriteComplexProperty);
                            }
                        } 

                        if (shouldWriteComplexProperty) 
                        { 
                            complexProperty.WriteTo(writer);
                            propertiesWritten = true; 
                        }
                        #endregion
                    }
                } 
            }
            #endregion 
        } 

        /// <summary>Detach existing link</summary> 
        /// <param name="existingLink">link to detach</param>
        /// <param name="targetDelete">true if target is being deleted, false otherwise</param>
        private void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
        { 
            // The target can be null in which case we don't need this check
            if (existingLink.Target != null) 
            { 
                // Identify the target resource for the link
                EntityDescriptor targetResource = this.entityDescriptors[existingLink.Target]; 

                // Check if there is a dependency relationship b/w the source and target objects i.e. target can not exist without source link
                // Deep insert requires this check to be made but skip the check if the target object is being deleted
                if (targetResource.IsDeepInsert && !targetDelete) 
                {
                    EntityDescriptor parentOfTarget = targetResource.ParentForInsert; 
                    if (Object.ReferenceEquals(targetResource.ParentEntity, existingLink.Source) && 
                       (parentOfTarget.State != EntityStates.Deleted ||
                        parentOfTarget.State != EntityStates.Detached)) 
                    {
                        throw new InvalidOperationException(Strings.Context_ChildResourceExists);
                    }
                } 
            }
 
            if (this.bindings.Remove(existingLink)) 
            {   // this link may have been previously detached by a detaching entity
                existingLink.State = EntityStates.Detached; 
            }
        }

        /// <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 LinkDescriptor DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        { 
            LinkDescriptor existing = this.GetLinks(source, sourceProperty).FirstOrDefault();
            if (null != existing) 
            { 
                if ((target == existing.Target) ||
                    (MergeOption.AppendOnly == linkMerge) || 
                    (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State))
                {
                    return existing;
                } 

                // Since we don't support deep insert on reference property, no need to check for deep insert. 
                this.DetachExistingLink(existing, false); 
                Debug.Assert(!this.bindings.Values.Any(o => (o.Source == 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 EntityDescriptor EnsureContained(object resource, string parameterName)
        { 
            Util.CheckArgumentNull(resource, parameterName);
 
            EntityDescriptor box = null; 
            if (!this.entityDescriptors.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)
        { 
            EntityDescriptor sourceResource = this.EnsureContained(source, "source"); 
            EntityDescriptor 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.IsEntityType, "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.IsEntityType, "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.identityToDescriptor) 
            {
                System.Threading.Interlocked.CompareExchange(ref this.identityToDescriptor, new Dictionary<String, EntityDescriptor>(EqualityComparer<String>.Default), null); 
            } 
        }
 
        /// <summary>
        /// increment the resource change for sorting during submit changes
        /// </summary>
        /// <param name="descriptor">the resource to update the change order</param> 
        private void IncrementChange(Descriptor descriptor)
        { 
            descriptor.ChangeOrder = ++this.nextChange; 
        }
 
        /// <summary>
        /// This method creates an async result object around a request to get the read stream for a Media Resource
        /// associated with the Media Link Entry represented by the entity object.
        /// </summary> 
        /// <param name="entity">The entity which is the Media Link Entry for the requested Media Resource. Thist must specify
        /// a tracked entity in a non-added state.</param> 
        /// <param name="args">Instance of <see cref="DataServiceRequestArgs"/> class with additional metadata for the request. 
        /// Must not be null.</param>
        /// <param name="callback">User defined callback to be called when results are available. Can be null.</param> 
        /// <param name="state">User state in IAsyncResult. Can be null.</param>
        /// <returns>The async result object for the request, the request hasn't been started yet.</returns>
        /// <exception cref="ArgumentNullException">Either entity or args parameters are null.</exception>
        /// <exception cref="ArgumentException">The specified entity is either not tracked, 
        /// is in the added state or it's not an MLE.</exception>
        private GetReadStreamResult CreateGetReadStreamResult( 
            object entity, 
            DataServiceRequestArgs args,
            AsyncCallback callback, 
            object state)
        {
            EntityDescriptor box = this.EnsureContained(entity, "entity");
            Util.CheckArgumentNull(args, "args"); 

            Uri requestUri = box.GetMediaResourceUri(this.baseUriWithSlash); 
            if (requestUri == null) 
            {
                throw new ArgumentException(Strings.Context_EntityNotMediaLinkEntry, "entity"); 
            }

#if ASTORIA_LIGHT
            // For MR requests always use the ClientHtpp stack as the XHR doesn't support binary content 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, true, null, null, false, HttpStack.ClientHttp);
#else 
            HttpWebRequest request = this.CreateRequest(requestUri, XmlConstants.HttpMethodGet, true, null, null, false); 
#endif
 
            WebUtil.ApplyHeadersToRequest(args.Headers, request, false);

            return new GetReadStreamResult(this, "GetReadStream", request, callback, state);
        } 

        /// <summary>Stream wrapper for MR POST/PUT which also holds the information if the stream should be closed or not.</summary> 
        internal class DataServiceSaveStream 
        {
            /// <summary>The stream we are wrapping. 
            /// Can be null in which case we didn't open it yet.</summary>
            private readonly Stream stream;

            // This class would one day hold a Func<Stream> to open the stream when needed 
            //   instead of specifying the stream up front.
 
            /// <summary>Set to true if the stream should be closed once we're done with it.</summary> 
            private readonly bool close;
 
            /// <summary>Arguments for the request when POST/PUT of the stream is issued.</summary>
            private readonly DataServiceRequestArgs args;

            /// <summary> 
            /// Constructor
            /// </summary> 
            /// <param name="stream">The stream to use.</param> 
            /// <param name="close">Should the stream be closed before SaveChanges returns.</param>
            /// <param name="args">Additional arguments to apply to the request before sending it.</param> 
            internal DataServiceSaveStream(Stream stream, bool close, DataServiceRequestArgs args)
            {
                Debug.Assert(stream != null, "stream must not be null.");
 
                this.stream = stream;
                this.close = close; 
                this.args = args; 
            }
 
            /// <summary>The stream to use.</summary>
            internal Stream Stream
            {
                get 
                {
                    return this.stream; 
                } 
            }
 
            /// <summary>
            /// Arguments to be used for creation of the HTTP request when POST/PUT for the MR is issued.
            /// </summary>
            internal DataServiceRequestArgs Args 
            {
                get { return this.args; } 
            } 

            /// <summary> 
            /// Close the stream if required.
            /// This is so that callers can simply call this method and don't have to care about the settings.
            /// </summary>
            internal void Close() 
            {
                if (this.stream != null && this.close) 
                { 
                    this.stream.Close();
                } 
            }
        }

        /// <summary>wrapper around loading a property from a response</summary> 
        private class LoadPropertyResult : QueryResult
        { 
            #region Private fields. 

            /// <summary>entity whose property is being loaded</summary> 
            private readonly object entity;

            /// <summary>Projection plan for loading results; possibly null.</summary>
            private readonly ProjectionPlan plan; 

            /// <summary>name of the property on the entity that is being loaded</summary> 
            private readonly string propertyName; 

            #endregion Private fields. 

            /// <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> 
            /// <param name="plan">Projection plan for materialization; possibly null.</param>
            internal LoadPropertyResult(object entity, string propertyName, DataServiceContext context, HttpWebRequest request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest, ProjectionPlan plan)
                : base(context, "LoadProperty", dataServiceRequest, request, callback, state)
            { 
                this.entity = entity;
                this.propertyName = propertyName; 
                this.plan = plan; 
            }
 
            /// <summary>
            /// loading a property from a response
            /// </summary>
            /// <returns>QueryOperationResponse instance containing information about the response.</returns> 
            internal QueryOperationResponse LoadProperty()
            { 
                MaterializeAtom results = null; 

                DataServiceContext context = (DataServiceContext)this.Source; 

                ClientType type = ClientType.Create(this.entity.GetType());
                Debug.Assert(type.IsEntityType, "must be entity type to be contained");
 
                EntityDescriptor 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.GetResponseWithType(results, elementType); 
                }
                catch (InvalidOperationException ex) 
                {
                    QueryOperationResponse response = this.GetResponseWithType(results, elementType);
                    if (response != null)
                    { 
                        response.Error = ex;
                        throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, response); 
                    } 

                    throw; 
                }
            }

            /// <summary> 
            /// Reads the data from the response stream into a buffer using the content length.
            /// </summary> 
            /// <param name="responseStream">Response stream.</param> 
            /// <param name="totalLength">Length of data to read.</param>
            /// <returns>byte array containing read data.</returns> 
            private static byte[] ReadByteArrayWithContentLength(Stream responseStream, int totalLength)
            {
                byte[] buffer = new byte[totalLength];
                int read = 0; 
                while (read < totalLength)
                { 
                    int r = responseStream.Read(buffer, read, totalLength - read); 
                    if (r <= 0)
                    { 
                        throw Error.InvalidOperation(Strings.Context_UnexpectedZeroRawRead);
                    }

                    read += r; 
                }
 
                return buffer; 
            }
 
            /// <summary>Reads the data from the response stream in chunks.</summary>
            /// <param name="responseStream">Response stream.</param>
            /// <returns>byte array containing read data.</returns>
            private static byte[] ReadByteArrayChunked(Stream responseStream) 
            {
                byte[] completeBuffer = null; 
                using (MemoryStream m = new MemoryStream()) 
                {
                    byte[] buffer = new byte[4096]; 
                    int numRead = 0;
                    int totalRead = 0;
                    while (true)
                    { 
                        numRead = responseStream.Read(buffer, 0, buffer.Length);
                        if (numRead <= 0) 
                        { 
                            break;
                        } 

                        m.Write(buffer, 0, numRead);
                        totalRead += numRead;
                    } 

                    completeBuffer = new byte[totalRead]; 
                    m.Position = 0; 
                    numRead = m.Read(completeBuffer, 0, completeBuffer.Length);
                } 

                return completeBuffer;
            }
 
            /// <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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MaterializeAtom, caller will dispose")]
            private MaterializeAtom ReadPropertyFromAtom(EntityDescriptor box, ClientType.ClientProperty property)
            { 
                DataServiceContext context = (DataServiceContext)this.Source;
 
                bool merging = context.ApplyingChanges; 

                try 
                {
                    context.ApplyingChanges = true;

                    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;
                            if (BindingEntityInfo.IsDataServiceCollection(property.PropertyType))
                            { 
                                Debug.Assert(WebUtil.GetDataServiceCollectionOfT(nestedType) != null, "DataServiceCollection<> must be available here.");
 
                                // new DataServiceCollection<nestedType>(null, TrackingMode.None) 
                                collection = Activator.CreateInstance(
                                    WebUtil.GetDataServiceCollectionOfT(nestedType), 
                                    null,
                                    TrackingMode.None);
                            }
                            else 
                            {
                                collection = Activator.CreateInstance(typeof(List<>).MakeGenericType(nestedType)); 
                            } 
                        }
                    } 

                    // 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)); 

                    DataServiceQueryContinuation continuation = null; 
 
                    // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                    using (MaterializeAtom materializer = this.GetMaterializer(context, this.plan)) 
                    {
                        Debug.Assert(materializer != null, "materializer != null -- otherwise GetMaterializer() returned null rather than empty");
                        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.IsEntityType) 
                            {
                                if (deletedState)
                                {
                                    context.DeleteLink(this.entity, this.propertyName, child); 
                                }
                                else 
                                {   // put link into unchanged state 
                                    context.AttachLink(this.entity, this.propertyName, child, materializer.MergeOptionValue);
                                } 
                            }
                        }

                        // LoadProperty should only deal with single level collections 
                        continuation = materializer.GetContinuation(null);
                        Util.SetNextLinkForCollection(collection, continuation); 
 
                        // 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 MaterializeAtom.CreateWrapper(results, continuation);
                } 
                finally 
                {
                    context.ApplyingChanges = merging; 
                }
            }

            /// <summary> 
            /// Load property data form a raw response
            /// </summary> 
            /// <param name="property">The property being loaded</param> 
            /// <returns>property values as IEnumerable.</returns>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning MaterializeAtom, caller will dispose")] 
            private MaterializeAtom ReadPropertyFromRawData(ClientType.ClientProperty property)
            {
                DataServiceContext context = (DataServiceContext)this.Source;
 
                bool merging = context.ApplyingChanges;
 
                try 
                {
                    context.ApplyingChanges = true; 

                    // 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 = null;
                            if (total >= 0)
                            {
                                buffer = LoadPropertyResult.ReadByteArrayWithContentLength(responseStream, total); 
                            }
                            else 
                            { 
                                buffer = LoadPropertyResult.ReadByteArrayChunked(responseStream);
                            } 

                            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 
                        {
                            // responseStream will disposed, StreamReader doesn't need to dispose of it.
                            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 MaterializeAtom.CreateWrapper(results);
                } 
                finally
                { 
                    context.ApplyingChanges = merging; 
                }
            } 
        }

        /// <summary>
        /// implementation of IAsyncResult for SaveChanges 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Pending")] 
        private class SaveResult : 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<Descriptor> 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 an MR POST or PUT 
            /// that might need to be followed by a PUT for the MLE
            /// </summary> 
            private bool processingMediaLinkEntry; 

            /// <summary> 
            /// True if the current in-flight request is an MR PUT
            /// that might need to be followed by a PUT for the MLE
            /// </summary>
            private bool processingMediaLinkEntryPut; 

            /// <summary> 
            /// If the <see cref="processingMediaLinkEntry"/> is set to true 
            /// this field holds a stream which contains the body of the MR POST request
            /// to be sent. 
            /// This can be null in the case where the content of MR is empty. (In which case
            /// we will not try to open the request stream and thus avoid additional async call).
            /// </summary>
            private Stream mediaResourceRequestStream; 

            /// <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 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 SaveResult(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.entityDescriptors.Values.Cast<Descriptor>()
                                          .Union(context.bindings.Values.Cast<Descriptor>()) 
                                          .Where(o => o.IsModified && o.ChangeOrder != UInt32.MaxValue)
                                          .OrderBy(o => o.ChangeOrder) 
                                          .ToList(); 

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

                        if (!e.IsResource) 
                        { 
                            object target = ((LinkDescriptor)e).Target;
                            if (null != target) 
                            {
                                Descriptor f = context.entityDescriptors[target];
                                if (EntityStates.Unchanged == f.State)
                                { 
                                    f.ContentGeneratedForSave = false;
                                    f.SaveResultWasProcessed = 0; 
                                    f.SaveError = null; 
                                }
                            } 
                        }
                    }
                    #endregion
                } 
                else
                { 
                    this.ChangedEntries = new List<Descriptor>(); 
                }
 
                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 
                {
                    return this.service;
                }
 
                set
                { 
                    this.service = value; 
                }
            } 

            /// <summary>process the batch</summary>
            /// <returns>data service response</returns>
            internal DataServiceResponse EndRequest() 
            {
                // Close all Save streams before we return (and do this before we throw for any errors below) 
                foreach (EntityDescriptor box in this.ChangedEntries.Where(e => e.IsResource).Cast<EntityDescriptor>()) 
                {
                    box.CloseSaveStream(); 
                }

                // This will process the responses and throw if failure was detected
                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.Abortable = httpWebRequest; 

                        this.request = pereq = new PerRequest();
                        pereq.Request = httpWebRequest;
                        pereq.RequestContentStream = new PerRequest.ContentStream(memory, true); 

                        this.httpWebResponseStream = new MemoryStream(); 
 
                        IAsyncResult asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetRequestStream, this.AsyncEndGetRequestStream, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                    }
                    else
                    {
                        Debug.Assert(this.CompletedSynchronously, "completedSynchronously"); 
                        Debug.Assert(this.IsCompletedInternally, "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.IsCompletedInternally, "why being called if already completed?");
 
                // SaveCallback can't chain synchronously completed responses, caller will loop the to next change
                PerRequest pereq = null;
                IAsyncResult asyncResult = null;
                do 
                {
                    HttpWebRequest httpWebRequest = null; 
                    HttpWebResponse response = null; 
                    try
                    { 
                        if (null != this.request)
                        {
                            this.SetCompleted();
                            Error.ThrowInternalError(InternalError.InvalidBeginNextChange); 
                        }
 
                        this.Abortable = 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 LinkDescriptor, "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;
                            } 

                            PerRequest.ContentStream contentStream = this.CreateChangeData(this.entryIndex, false);
                            if (this.executeAsync)
                            { 
                                #region async
                                this.request = pereq = new PerRequest(); 
                                pereq.Request = httpWebRequest; 

                                if (null == contentStream || null == contentStream.Stream) 
                                {
                                    asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetResponse, this.AsyncEndGetResponse, pereq);
                                }
                                else 
                                {
                                    if (contentStream.IsKnownMemoryStream) 
                                    { 
                                        httpWebRequest.ContentLength = contentStream.Stream.Length - contentStream.Stream.Position;
                                    } 

                                    pereq.RequestContentStream = contentStream;
                                    asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetRequestStream, this.AsyncEndGetRequestStream, pereq);
                                } 

                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                                this.CompletedSynchronously &= asyncResult.CompletedSynchronously; 
                                #endregion
                            } 
#if !ASTORIA_LIGHT // Synchronous methods not available
                            else
                            {
                                #region [....] 
                                if (null != contentStream && null != contentStream.Stream)
                                { 
                                    if (contentStream.IsKnownMemoryStream) 
                                    {
                                        httpWebRequest.ContentLength = contentStream.Stream.Length - contentStream.Stream.Position; 
                                    }

                                    using (Stream stream = httpWebRequest.GetRequestStream())
                                    { 
                                        byte[] buffer = new byte[64 * 1024];
                                        int read; 
                                        do 
                                        {
                                            read = contentStream.Stream.Read(buffer, 0, buffer.Length); 
                                            if (read > 0)
                                            {
                                                stream.Write(buffer, 0, read);
                                            } 
                                        }
                                        while (read > 0); 
                                    } 
                                }
 
                                response = (HttpWebResponse)httpWebRequest.GetResponse();
                                if (!this.processingMediaLinkEntry)
                                {
                                    this.changesCompleted++; 
                                }
 
                                this.HandleOperationResponse(response); 
                                this.HandleOperationResponseData(response);
                                this.HandleOperationEnd(); 
                                this.request = null;
                                #endregion
                            }
#endif 
                        }
                        else 
                        { 
                            this.SetCompleted();
 
                            if (this.CompletedSynchronously)
                            {
                                this.HandleCompleted(pereq);
                            } 
                        }
                    } 
                    catch (InvalidOperationException e) 
                    {
                        WebUtil.GetHttpWebResponse(e, ref response); 
                        this.HandleOperationException(e, 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 && asyncResult != null && asyncResult.CompletedSynchronously)) && !this.IsCompletedInternally); 

                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 generate 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>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>
            private static void CompleteCheck(PerRequest value, InternalError errorcode)
            { 
                if ((null == value) || value.RequestCompleted)
                { 
                    // since PerRequest is nested, it won't get set true during Abort unlike BaseAsyncResult 
                    // but like QueryAsyncResult, when the request is aborted it it lets the request throw on next operation
                    Error.ThrowInternalError(errorcode); 
                }
            }

            /// <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)
                {
                    if (IsAborted)
                    { 
                        pereq.SetAborted();
                    } 
                    else 
                    {
                        pereq.SetComplete(); 
                    }
                }

                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.processingMediaLinkEntry)
                { 
                    this.entryIndex++; 
                }
                else 
                {
                    // If the previous request was an MR request the next one might be a PUT for the MLE
                    //   but if the entity was not changed (just the MR changed) no PUT for MLE should be sent
                    Debug.Assert(this.ChangedEntries[this.entryIndex].IsResource, "Only resources can have MR's."); 
                    EntityDescriptor box = (EntityDescriptor)this.ChangedEntries[this.entryIndex];
                    if (this.processingMediaLinkEntryPut && EntityStates.Unchanged == box.State) 
                    { 
                        // Only the MR changed. In this case we also need to mark the entry as processed to notify
                        //   that the content for save has been generated as there's not going to be another request for it. 
                        box.ContentGeneratedForSave = true;
                        this.entryIndex++;
                    }
 
                    this.processingMediaLinkEntry = false;
                    this.processingMediaLinkEntryPut = false; 
 
                    // In any case also close the save stream if there's any and forget about it
                    // for POST this is just a good practice to do so as soon as possible 
                    // for PUT it's actually required for us to recognize that we already processed the MR part of the change
                    box.CloseSaveStream();
                }
 
                if (unchecked((uint)this.entryIndex < (uint)this.ChangedEntries.Count))
                { 
                    Descriptor entry = this.ChangedEntries[this.entryIndex]; 
                    if (entry.IsResource)
                    { 
                        EntityDescriptor box = (EntityDescriptor)entry;

                        HttpWebRequest req;
                        if (((EntityStates.Unchanged == entry.State) || (EntityStates.Modified == entry.State)) && 
                            (null != (req = this.CheckAndProcessMediaEntryPut(box))))
                        { 
                            this.processingMediaLinkEntry = true; 
                            this.processingMediaLinkEntryPut = true;
                        } 
                        else if ((EntityStates.Added == entry.State) && (null != (req = this.CheckAndProcessMediaEntryPost(box))))
                        {
                            this.processingMediaLinkEntry = true;
                            this.processingMediaLinkEntryPut = false; 
                        }
                        else 
                        { 
                            Debug.Assert(!this.processingMediaLinkEntry || entry.State == EntityStates.Modified, "!this.processingMediaLinkEntry || entry.State == EntityStates.Modified");
                            req = this.Context.CreateRequest(box, entry.State, replaceOnUpdate); 
                        }

                        return req;
                    } 

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

                return null; 
            }

            /// <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="entityDescriptor">The resource to check/process</param>
            /// <returns>A web request setup to do POST the media resource</returns> 
            private HttpWebRequest CheckAndProcessMediaEntryPost(EntityDescriptor entityDescriptor)
            {
                //
                ClientType type = ClientType.Create(entityDescriptor.Entity.GetType()); 

                if (!type.IsMediaLinkEntry && !entityDescriptor.IsMediaLinkEntry) 
                { 
                    // this is not a media link entry, process normally
                    return null; 
                }

                if (type.MediaDataMember == null && entityDescriptor.SaveStream == null)
                { 
                    // The entity is marked as MLE but we don't have the content property
                    //   and the user didn't set the save stream. 
                    throw Error.InvalidOperation(Strings.Context_MLEWithoutSaveStream(type.ElementTypeName)); 
                }
 
                Debug.Assert(
                    (type.MediaDataMember != null && entityDescriptor.SaveStream == null) ||
                    (type.MediaDataMember == null && entityDescriptor.SaveStream != null),
                    "Only one way of specifying the MR content is allowed."); 

                HttpWebRequest mediaRequest = this.CreateMediaResourceRequest( 
                    entityDescriptor.GetResourceUri(this.Context.baseUriWithSlash, false /*queryLink*/), 
                    XmlConstants.HttpMethodPost,
                    type.MediaDataMember == null); 

                if (type.MediaDataMember != null)
                {
                    if (type.MediaDataMember.MimeTypeProperty == null) 
                    {
                        mediaRequest.ContentType = XmlConstants.MimeApplicationOctetStream; 
                    } 
                    else
                    { 
                        object mimeTypeValue = type.MediaDataMember.MimeTypeProperty.GetValue(entityDescriptor.Entity);
                        String mimeType = mimeTypeValue != null ? mimeTypeValue.ToString() : null;

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

                        mediaRequest.ContentType = mimeType;
                    } 

                    object value = type.MediaDataMember.GetValue(entityDescriptor.Entity); 
                    if (value == null) 
                    {
                        mediaRequest.ContentLength = 0; 
                        this.mediaResourceRequestStream = null;
                    }
                    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, false /* atomDateConstruct */)); 
                        }

                        mediaRequest.ContentLength = buffer.Length;
 
                        // Need to specify that the buffer is publicly visible as we need to access it later on
                        this.mediaResourceRequestStream = new MemoryStream(buffer, 0, buffer.Length, false, true); 
                    } 
                }
                else 
                {
                    this.SetupMediaResourceRequest(mediaRequest, entityDescriptor);
                }
 
                // 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())
                entityDescriptor.State = EntityStates.Modified; 

                return mediaRequest;
            }
 
            /// <summary>
            /// Checks if the resource box represents an MLE with modified MR and if so creates a PUT request 
            ///   to update the MR. 
            /// </summary>
            /// <param name="box">The resource box for the entity to be checked.</param> 
            /// <returns>Newly created MR PUT request or null if the entity is not MLE or its MR hasn't changed.</returns>
            private HttpWebRequest CheckAndProcessMediaEntryPut(EntityDescriptor box)
            {
                // If there's no save stream associated with the entity it's not MLE or its MR hasn't changed 
                //  (which for purposes of PUT is the same anyway)
                if (box.SaveStream == null) 
                { 
                    return null;
                } 

                Uri requestUri = box.GetEditMediaResourceUri(this.Context.baseUriWithSlash);
                if (requestUri == null)
                { 
                    throw Error.InvalidOperation(
                        Strings.Context_SetSaveStreamWithoutEditMediaLink); 
                } 

                HttpWebRequest mediaResourceRequest = this.CreateMediaResourceRequest(requestUri, XmlConstants.HttpMethodPut, true); 
                this.SetupMediaResourceRequest(mediaResourceRequest, box);

                if (box.StreamETag != null)
                { 
                    mediaResourceRequest.Headers.Set(HttpRequestHeader.IfMatch, box.StreamETag);
                } 
 
                return mediaResourceRequest;
            } 

            /// <summary>
            /// Creates HTTP request for the media resource (MR)
            /// </summary> 
            /// <param name="requestUri">The URI to request</param>
            /// <param name="method">The HTTP method to use (POST or PUT)</param> 
            /// <param name="sendChunked">Send the request using chunked encoding to avoid buffering.</param> 
            /// <returns>The newly created HTTP request object.</returns>
            private HttpWebRequest CreateMediaResourceRequest(Uri requestUri, string method, bool sendChunked) 
            {
#if ASTORIA_LIGHT
                // For MR requests always use the ClientHtpp stack as the XHR doesn't support binary content
                HttpWebRequest mediaResourceRequest = this.Context.CreateRequest( 
                    requestUri,
                    method, 
                    false, 
                    XmlConstants.MimeAny,
                    Util.DataServiceVersion1, 
                    sendChunked,
                    HttpStack.ClientHttp);
#else
                HttpWebRequest mediaResourceRequest = this.Context.CreateRequest( 
                    requestUri,
                    method, 
                    false, 
                    XmlConstants.MimeAny,
                    Util.DataServiceVersion1, 
                    sendChunked);
#endif
                return mediaResourceRequest;
            } 

            /// <summary> 
            /// Sets the content and the headers of the media resource request 
            /// </summary>
            /// <param name="mediaResourceRequest">The request to setup</param> 
            /// <param name="box">The resource box for the entity with the MT</param>
            /// <remarks>This only works with the V2 MR support (SetSaveStream), this will not setup
            /// the request for V1 property based MRs.</remarks>
            private void SetupMediaResourceRequest(HttpWebRequest mediaResourceRequest, EntityDescriptor box) 
            {
                // Get the write stream for this MR 
                this.mediaResourceRequestStream = box.SaveStream.Stream; 

                // Apply the arguments for the request 
                WebUtil.ApplyHeadersToRequest(box.SaveStream.Args.Headers, mediaResourceRequest, true);

                // Do NOT set the ContentLength since we don't know if the stream even supports reporting its length
            } 

            /// <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>stream of data for entry</returns>
            private PerRequest.ContentStream CreateChangeData(int index, bool newline)
            { 
                Descriptor entry = this.ChangedEntries[index];
                Debug.Assert(!entry.ContentGeneratedForSave, "already saved entity/link"); 
 
                if (entry.IsResource)
                { 
                    EntityDescriptor box = (EntityDescriptor)entry;
                    if (this.processingMediaLinkEntry)
                    {
                        Debug.Assert( 
                            this.processingMediaLinkEntryPut || entry.State == EntityStates.Modified,
                            "We should have modified the MLE state to Modified when we've created the MR POST request."); 
                        Debug.Assert( 
                            !this.processingMediaLinkEntryPut || (entry.State == EntityStates.Unchanged || entry.State == EntityStates.Modified),
                            "If we're processing MR PUT the entity must be either in Unchanged or Modified state."); 

                        // media resource request - we already precreated the body of the request
                        // in the CheckAndProcessMediaEntryPost or CheckAndProcessMediaEntryPut method.
                        Debug.Assert(this.mediaResourceRequestStream != null, "We should have precreated the MR stream already."); 
                        return new PerRequest.ContentStream(this.mediaResourceRequestStream, false);
                    } 
                    else 
                    {
                        // either normal entity or second call for media link entity, generate content payload 
                        // else first call of media link entry where we only send the default value
                        entry.ContentGeneratedForSave = true;
                        return new PerRequest.ContentStream(this.Context.CreateRequestData(box, newline), true);
                    } 
                }
                else 
                { 
                    entry.ContentGeneratedForSave = true;
                    LinkDescriptor link = (LinkDescriptor)entry; 
                    if ((EntityStates.Added == link.State) ||
                        ((EntityStates.Modified == link.State) && (null != link.Target)))
                    {
                        return new PerRequest.ContentStream(this.Context.CreateRequestData(link, newline), true); 
                    }
                } 
 
                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 TESTUNIXNEWLINE 
                    this.buildBatchWriter.NewLine = NewLine;
#endif
                }
 
                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="response">response object</param>
            private void HandleOperationException(Exception e, HttpWebResponse response) 
            { 
                if (null != response)
                { 
                    this.HandleOperationResponse(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.SetCompleted();

                    // if it was a media link entry don't even try to do a PUT if the POST didn't succeed
                    this.processingMediaLinkEntry = false; 

                    // Need to set this to true since we check this even on error cases, but we're here 
                    //   because exception was thrown during preparation of the request, so we might not have a chance 
                    //   to generate the content for save yet.
                    this.ChangedEntries[this.entryIndex].ContentGeneratedForSave = true; 
                }
            }

            /// <summary>operation with HttpWebResponse</summary> 
            /// <param name="response">response object</param>
            private void HandleOperationResponse(HttpWebResponse response) 
            { 
                this.HandleOperationStart();
 
                Descriptor entry = this.ChangedEntries[this.entryIndex];

                // in the first pass, the http response is packaged into a batch response (which is then processed in second pass).
                // in this first pass, (all added entities and first call of modified media link entities) update their edit location 
                // added entities - so entities that have not sent content yet w/ reference links can inline those reference links in their payload
                // media entities - because they can change edit location which is then necessary for second call that includes property content 
                if (entry.IsResource) 
                {
                    EntityDescriptor entityDescriptor = (EntityDescriptor)entry; 

                    if (entry.State == EntityStates.Added ||
                         (entry.State == EntityStates.Modified &&
                          this.processingMediaLinkEntry && !this.processingMediaLinkEntryPut)) 
                    {
                        string location = response.Headers[XmlConstants.HttpResponseLocation]; 
 
                        if (WebUtil.SuccessStatusCode(response.StatusCode))
                        { 
                            if (null != location)
                            {
                                this.Context.AttachLocation(entityDescriptor.Entity, location);
                            } 
                            else
                            { 
                                throw Error.NotSupported(Strings.Deserialize_NoLocationHeader); 
                            }
                        } 
                    }

                    if (this.processingMediaLinkEntry)
                    { 
                        if (!WebUtil.SuccessStatusCode(response.StatusCode))
                        { 
                            // If the request failed and it was the MR request we should not try to send the PUT MLE after it 
                            //   for one we don't have the location to send it to (if it was POST MR)
 
                            // Just reset the processMLE flag - that means that we will not try to PUT the MLE and instead skip over
                            //   to the next change (if we are to ignore errors that is)
                            this.processingMediaLinkEntry = false;
 
                            if (!this.processingMediaLinkEntryPut)
                            { 
                                // If this was the POST MR it means we tried to add the entity. Now its state is Modified but we need 
                                //   to revert back to Added so that user can retry by calling SaveChanges again.
                                Debug.Assert(entry.State == EntityStates.Modified, "Entity state should be set to Modified once we've sent the POST MR"); 
                                entry.State = EntityStates.Added;
                                this.processingMediaLinkEntryPut = false;
                            }
 
                            // And we also need to mark it such that we generated the save content (which we did before the POST request in fact)
                            // to workaround the fact that we use the same entry object to track two requests. 
                            entry.ContentGeneratedForSave = true; 
                        }
                        else if (response.StatusCode == HttpStatusCode.Created) 
                        {
                            // We just finished a POST MR request and the PUT MLE coming immediately after it will
                            // need the new etag value from the server to succeed.
                            entityDescriptor.ETag = response.Headers[XmlConstants.HttpResponseETag]; 

                            // else is not interesting and we intentionally do nothing. 
                        } 
                    }
                } 

                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, entry.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()
            { 
                Debug.Assert(null != this.buildBatchWriter, "null buildBatchWriter");
                this.buildBatchWriter.Flush();
#if DEBUG
                MemoryStream memory = this.buildBatchWriter.BaseStream as MemoryStream; 
                Debug.Assert(null != memory, "expected MemoryStream");
                Debug.Assert(this.buildBatchWriter.NewLine == NewLine, "mismatch NewLine"); 
                for (int kk = 0; kk < NewLine.Length; ++kk) 
                {
                    Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "didn't end with newline"); 
                }
#endif
                this.buildBatchWriter.BaseStream.Position -= NewLine.Length;
                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, Util.DataServiceVersion1, false);
                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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposal not required for MemoryStream which is being returned")] 
            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.SetCompleted();
                    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 TESTUNIXNEWLINE
                text.NewLine = NewLine;
#endif 

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

                        Debug.Assert(null != requestUri, "request uri is null");
                        Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri"); 

                        text.WriteLine("--{0}", this.batchBoundary); 
                        WriteOperationRequestHeaders(text, XmlConstants.HttpMethodGet, requestUri.AbsoluteUri, this.Queries[i].QueryComponents.Version); 
                        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(); 
                            for (int kk = 0; kk < NewLine.Length; ++kk)
                            { 
                                Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "boundary didn't start with newline"); 
                            }
                        } 
#endif
                        #endregion

                        Descriptor entry = this.ChangedEntries[i]; 
                        if (entry.ContentGeneratedForSave)
                        { 
                            continue; 
                        }
 
                        text.WriteLine("--{0}", this.changesetBoundary);

                        EntityDescriptor entityDescriptor = entry as EntityDescriptor;
                        if (entry.IsResource) 
                        {
                            if (entityDescriptor.State == EntityStates.Added) 
                            { 
                                // We don't support adding MLE/MR in batch mode
                                ClientType type = ClientType.Create(entityDescriptor.Entity.GetType()); 
                                if (type.IsMediaLinkEntry || entityDescriptor.IsMediaLinkEntry)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                } 
                            }
                            else if (entityDescriptor.State == EntityStates.Unchanged || entityDescriptor.State == EntityStates.Modified) 
                            { 
                                // We don't support PUT for the MR in batch mode
                                // It's OK to PUT the MLE alone inside a batch mode though 
                                if (entityDescriptor.SaveStream != null)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                } 
                            }
                        } 
 
                        PerRequest.ContentStream contentStream = this.CreateChangeData(i, true);
                        MemoryStream stream = null; 
                        if (null != contentStream)
                        {
                            Debug.Assert(contentStream.IsKnownMemoryStream, "Batch requests don't support MRs yet");
                            stream = contentStream.Stream as MemoryStream; 
                        }
 
                        if (entry.IsResource) 
                        {
                            this.Context.CreateRequestBatch(entityDescriptor, text, replaceOnUpdate); 
                        }
                        else
                        {
                            this.Context.CreateRequestBatch((LinkDescriptor)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(); 
 
                        for (int kk = 0; kk < NewLine.Length; ++kk)
                        { 
                            Debug.Assert((char)memory.GetBuffer()[memory.Length - (NewLine.Length - kk)] == NewLine[kk], "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>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "BatchStream will be disposed after user iterates through final response enumerator")]
            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 takes ownership of the httpWebResponseStream (which may be a network stream) 
                        // BatchStream will be disposed after user iterates through enumerator 
                        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")]
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "MaterializeAtom is responsible for closing XmlReader which will close the stream")] 
            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 

                    Descriptor entry;
                    switch (batch.State)
                    { 
                        #region BeginChangeSet
                        case BatchStreamState.BeginChangeSet: 
                            if ((IsFlagSet(this.options, SaveChangesOptions.Batch) && (0 != 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]; 
                                    MaterializeAtom materializer = DataServiceRequest.Materialize(this.Context, query.QueryComponents, null, contentType, batch.GetContentStream());
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, materializer); 
                                } 
                            }
                            catch (ArgumentException e) 
                            {
                                ex = e;
                            }
                            catch (FormatException e) 
                            {
                                ex = e; 
                            } 
                            catch (InvalidOperationException e)
                            { 
                                ex = e;
                            }

                            if (null == qresponse) 
                            {
                                if (null != this.Queries) 
                                { 
                                    // this is the normal ExecuteBatch response
                                    DataServiceRequest query = this.Queries[queryCount]; 

                                    if (this.Context.ignoreResourceNotFoundException && status == HttpStatusCode.NotFound)
                                    {
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, MaterializeAtom.EmptyResults); 
                                    }
                                    else 
                                    { 
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, contentHeaders, query, MaterializeAtom.EmptyResults);
                                        qresponse.Error = ex; 
                                    }
                                }
                                else
                                { 
                                    // This is top-level failure SaveChanges(SaveChangesOptions.Batch) response
                                    // example: server doesn't support batching or number of batch objects exceeded an allowed limit. 
                                    // ex could be null if the server responded to SaveChanges with an unexpected success with 
                                    // response of batched GETS that did not correspond the original POST/MERGE/PUT/DELETE requests.
                                    // we expect non-null since server should have failed with a non-success code 
                                    // and HandleResponse(status, ...) should generate the exception object
                                    throw ex;
                                }
                            } 

                            qresponse.StatusCode = (int)status; 
                            queryCount++; 
                            yield return qresponse;
                            break; 
                        #endregion

                        #region ChangeResponse
                        case BatchStreamState.ChangeResponse: 

                            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;
                                } 

                                StreamStates streamState = StreamStates.NoStream;
                                if (entry.IsResource)
                                { 
                                    EntityDescriptor descriptor = (EntityDescriptor)entry;
                                    streamState = descriptor.StreamState; 
#if DEBUG 
                                    if (descriptor.StreamState == StreamStates.Added)
                                    { 
                                        Debug.Assert(
                                            statusCode == HttpStatusCode.Created && entry.State == EntityStates.Modified && descriptor.IsMediaLinkEntry,
                                            "statusCode == HttpStatusCode.Created && entry.State == EntityStates.Modified && descriptor.IsMediaLinkEntry -- Processing Post MR");
                                    } 
                                    else if (descriptor.StreamState == StreamStates.Modified)
                                    { 
                                        Debug.Assert( 
                                            statusCode == HttpStatusCode.NoContent && descriptor.IsMediaLinkEntry,
                                            "statusCode == HttpStatusCode.NoContent && descriptor.IsMediaLinkEntry -- Processing Put MR"); 
                                    }
#endif
                                }
 
                                if (streamState == StreamStates.Added || entry.State == EntityStates.Added)
                                { 
                                    #region Post 
                                    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);
                                        EntityDescriptor entityDescriptor = (EntityDescriptor)entry; 
 
                                        // If the location header is specified, we need to set the edit link
                                        // for the entity descriptor to that value. 
                                        if (location != null)
                                        {
                                            editLink = Util.CreateUri(location, UriKind.Absolute);
                                        } 
                                        else
                                        { 
                                            throw Error.NotSupported(Strings.Deserialize_NoLocationHeader); 
                                        }
 
                                        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);
                                            QueryComponents qc = new QueryComponents(null, Util.DataServiceVersionEmpty, entityDescriptor.Entity.GetType(), null, null);
                                            EntityDescriptor descriptor = (EntityDescriptor)entry;
                                            MergeOption mergeOption = MergeOption.OverwriteChanges; 

                                            // If we are processing a POST MR, we want to materialize the payload to get the metadata for the stream. 
                                            // However we must not modify the MLE properties with the server initialized properties.  The next request 
                                            // will be a Put MLE operation and we will set the server properties with values from the client entity.
                                            if (descriptor.StreamState == StreamStates.Added) 
                                            {
                                                mergeOption = MergeOption.PreserveChanges;
                                                Debug.Assert(descriptor.State == EntityStates.Modified, "The MLE state must be Modified.");
                                            } 

                                            try 
                                            { 
                                                using (MaterializeAtom atom = new MaterializeAtom(this.Context, reader, qc, null, mergeOption))
                                                { 
                                                    this.Context.HandleResponsePost(entityDescriptor, atom, editLink, etag);
                                                }
                                            }
                                            finally 
                                            {
                                                if (descriptor.StreamState == StreamStates.Added) 
                                                { 
                                                    // The materializer will always set the entity state to Unchanged.  We just processed Post MR, we
                                                    // need to restore the entity state to Modified to process the Put MLE. 
                                                    Debug.Assert(descriptor.State == EntityStates.Unchanged, "The materializer should always set the entity state to Unchanged.");
                                                    descriptor.State = EntityStates.Modified;

                                                    // Need to clear the stream state so the next iteration we will always process the Put MLE operation. 
                                                    descriptor.StreamState = StreamStates.NoStream;
                                                } 
                                            } 
                                        }
                                        else 
                                        {
                                            this.Context.HandleResponsePost(entityDescriptor, null /*materializer*/, editLink, etag);
                                        }
                                    } 
                                    else
                                    { 
                                        HandleResponsePost((LinkDescriptor)entry); 
                                    }
                                    #endregion 
                                }
                                else if (streamState == StreamStates.Modified || entry.State == EntityStates.Modified)
                                {
                                    #region Put, Merge 
                                    contentHeaders.TryGetValue(XmlConstants.HttpResponseETag, out etag);
                                    HandleResponsePut(entry, etag); 
                                    #endregion 
                                }
                                else if (entry.State == EntityStates.Deleted) 
                                {
                                    #region Delete
                                    this.Context.HandleResponseDelete(entry);
                                    #endregion 
                                }
 
                                // else condition is not interesting here and we intentionally do nothing. 
                            }
                            catch (Exception e) 
                            {
                                this.ChangedEntries[index].SaveError = e;
                                error = e;
                            } 

                            ChangeOperationResponse changeOperationResponse = 
                                new ChangeOperationResponse(contentHeaders, 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) 
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest;
                try
                {
                    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;

                    PerRequest.ContentStream contentStream = pereq.RequestContentStream; 
                    Util.NullCheck(contentStream, InternalError.InvalidEndGetRequestStreamContent);
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndGetRequestStreamContent); 
                    if (contentStream.IsKnownMemoryStream) 
                    {
                        MemoryStream memoryStream = contentStream.Stream as MemoryStream; 
                        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); 
                        } 
                    }
 
                    // Start the Read on the request content stream.
                    // Note that we don't deal with synchronous results here.
                    // If the read finishes synchronously the AsyncRequestContentEndRead will be called from inside the BeginRead
                    //   call below. In there we will call BeginWrite. If that completes synchronously we will loop 
                    //   and call BeginRead again. If that completes synchronously as well we will call BeginWrite and so on.
                    //   AsyncEndWrite will return immedially if it finished synchronously (otherwise it calls BeginRead). 
                    // So in the worst case we will have a stack like this: 
                    //   AsyncEndGetRequestStream
                    //     AsyncRequestContentEndRead 
                    //       AsyncRequestContentEndRead or AsyncEndWrite

                    // We just need to differentiate between the first AsyncRequestContentEndRead and the others (the first one
                    //   must not return even if it completed synchronously, otherwise we would have to do the loop here as well). 
                    //   We'll use the RequestContentBufferValidLength as the notification. It will start with -1 which means
                    //   we didn't read anything at all and thus it's the first read ending. 
                    pereq.RequestContentBufferValidLength = -1; 

                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetRequestStream_BeforeBeginRead"); 
                    asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
                }
                catch (Exception e) 
                {
                    if (this.HandleFailure(pereq, e)) 
                    { 
                        throw;
                    } 
                }
                finally
                {
                    this.HandleCompleted(pereq); 
                }
            } 
 
            /// <summary>
            /// Callback for Stream.BeginRead on the request content input stream. Calls request content output stream BeginWrite 
            /// and in case of synchronous also the next BeginRead.
            /// </summary>
            /// <param name="asyncResult">The asynchronous result associated with the completed operation.</param>
            private void AsyncRequestContentEndRead(IAsyncResult asyncResult) 
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest; 
                try
                { 
                    CompleteCheck(pereq, InternalError.InvalidEndReadCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead); 
                    PerRequest.ContentStream contentStream = pereq.RequestContentStream;
                    Util.NullCheck(contentStream, InternalError.InvalidEndReadStream); 
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndReadStream); 
                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndReadStream);
 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeEndRead");
                    int count = contentStream.Stream.EndRead(asyncResult);
                    if (0 < count)
                    { 
                        bool firstEndRead = (pereq.RequestContentBufferValidLength == -1);
                        pereq.RequestContentBufferValidLength = count; 
 
                        // If we completed synchronously then just return. Our caller will take care of processing the results.
                        // First EndRead must not return even if completed synchronously. 
                        if (!asyncResult.CompletedSynchronously || firstEndRead)
                        {
                            do
                            { 
                                // Write the data we've read to the request stream
                                Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeBeginWrite"); 
                                asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginWrite, pereq.RequestContentBuffer, 0, pereq.RequestContentBufferValidLength, this.AsyncEndWrite, pereq); 
                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
 
                                // If the write above completed synchronously
                                //   immediately start the next read so that we loop instead of recursion.
                                // If it completed asynchronously we just return as we will deal with the results in the EndWrite
                                if (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally) 
                                {
                                    Util.DebugInjectFault("SaveAsyncResult::AsyncRequestContentEndRead_BeforeBeginRead"); 
                                    asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq); 
                                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously;
                                } 

                                // If the read completed synchronously as well we loop to write the data to the request stream without recursion.
                                // Only loop if there's actually some data to be processed. If there's no more data then return.
                                // The request will continue inside the inner call to AsyncRequestContentEndRead (which will get 0 data 
                                //   and will end up in the else branch of the big if).
                            } 
                            while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && 
                                pereq.RequestContentBufferValidLength > 0);
                        } 
                    }
                    else
                    {
                        // Done reading data (and writing them) 
                        pereq.RequestContentBufferValidLength = 0;
                        pereq.RequestStream = null; 
                        stream.Close(); 

                        HttpWebRequest httpWebRequest = Util.NullCheck(pereq.Request, InternalError.InvalidEndWriteRequest); 
                        asyncResult = BaseAsyncResult.InvokeAsync(httpWebRequest.BeginGetResponse, this.AsyncEndGetResponse, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse
                    }
                } 
                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)
            { 
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest; 
                try 
                {
                    CompleteCheck(pereq, InternalError.InvalidEndWriteCompleted); 
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndWrite);
 
                    PerRequest.ContentStream contentStream = pereq.RequestContentStream;
                    Util.NullCheck(contentStream, InternalError.InvalidEndWriteStream); 
                    Util.NullCheck(contentStream.Stream, InternalError.InvalidEndWriteStream); 
                    Stream stream = Util.NullCheck(pereq.RequestStream, InternalError.InvalidEndWriteStream);
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndWrite_BeforeEndWrite"); 
                    stream.EndWrite(asyncResult);

                    // If the write completed synchronously just return. The caller (AsyncRequestContentEndRead)
                    //   will loop and initiate the next read. 
                    // If the write completed asynchronously we need to start the next read here. Note that we start the read
                    //   regardless if the stream has other data to offer or not. This is to avoid dealing with the end 
                    //   of the read/write loop in several places. We simply issue a read which (if the stream is at the end) 
                    //   will return 0 bytes and we will deal with that in the AsyncRequestContentEndRead method.
                    if (!asyncResult.CompletedSynchronously) 
                    {
                        Util.DebugInjectFault("SaveAsyncResult::AsyncEndWrite_BeforeBeginRead");
                        asyncResult = BaseAsyncResult.InvokeAsync(contentStream.Stream.BeginRead, pereq.RequestContentBuffer, 0, pereq.RequestContentBuffer.Length, this.AsyncRequestContentEndRead, pereq);
                        pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; 
                    }
                } 
                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)
            { 
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted"); 
                PerRequest pereq = asyncResult == null ? null : asyncResult.AsyncState as PerRequest;
                try 
                {
                    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
                    {
                        Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse::BeforeEndGetResponse");
                        response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                    }
                    catch (WebException e) 
                    { 
                        response = (HttpWebResponse)e.Response;
                        if (null == response) 
                        {
                            throw;
                        }
                    } 

                    pereq.HttpWebResponse = Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse); 
 
                    if (!IsFlagSet(this.options, SaveChangesOptions.Batch))
                    { 
                        this.HandleOperationResponse(response);
                    }

                    this.copiedContentLength = 0; 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse_BeforeGetStream");
                    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];
                        } 

                        do
                        {
                            Util.DebugInjectFault("SaveAsyncResult::AsyncEndGetResponse_BeforeBeginRead"); 
                            asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginRead, this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq);
                            pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead 
                        } 
                        while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && stream.CanRead);
                    } 
                    else
                    {
                        pereq.SetComplete();
 
                        // BeginGetResponse could fail and callback still invoked
                        if (!this.IsCompletedInternally) 
                        { 
                            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)
            {
                Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
                PerRequest pereq = asyncResult.AsyncState as PerRequest; 
                int count = 0;
                try 
                { 
                    CompleteCheck(pereq, InternalError.InvalidEndReadCompleted);
                    pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead 

                    EqualRefCheck(this.request, pereq, InternalError.InvalidEndRead);
                    Stream stream = Util.NullCheck(pereq.ResponseStream, InternalError.InvalidEndReadStream);
 
                    Util.DebugInjectFault("SaveAsyncResult::AsyncEndRead_BeforeEndRead");
                    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 
                            do 
                            {
                                asyncResult = BaseAsyncResult.InvokeAsync(stream.BeginRead, this.buildBatchBuffer, 0, this.buildBatchBuffer.Length, this.AsyncEndRead, pereq); 
                                pereq.RequestCompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
                            }
                            while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && stream.CanRead);
                        } 
                    }
                    else 
                    { 
                        pereq.SetComplete();
 
                        // BeginRead could fail and callback still invoked
                        if (!this.IsCompletedInternally)
                        {
                            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);
                }

                EqualRefCheck(this.request, pereq, InternalError.InvalidSaveNextChange); 

                if (IsFlagSet(this.options, SaveChangesOptions.Batch)) 
                { 
                    this.httpWebResponseStream.Position = 0;
                    this.request = null; 
                    this.SetCompleted();
                }
                else
                { 
                    if (0 == this.copiedContentLength)
                    { 
                        this.HandleOperationResponseNoData(); 
                    }
 
                    this.HandleOperationEnd();

                    if (!this.processingMediaLinkEntry)
                    { 
                        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.IsCompletedInternally)
                        { 
                            this.BeginNextChange(IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate));
                        } 
                    } 
                }
            } 
            #endregion

            /// <summary>wrap the full request</summary>
            private sealed class PerRequest 
            {
                /// <summary> 
                /// did the sequence (BeginGetRequest, EndGetRequest, ... complete. 0 = In Progress, 1 = Completed, 2 = Aborted 
                /// </summary>
                private int requestStatus; 

                /// <summary>
                /// Buffer used when pumping data from the write stream to the request content stream
                /// </summary> 
                private byte[] requestContentBuffer;
 
                /// <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 ContentStream RequestContentStream
                {
                    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>
                /// Short cut for testing if request has finished (either completed or aborted)
                /// </summary>
                internal bool RequestCompleted 
                {
                    get { return this.requestStatus != 0; } 
                } 

                /// <summary> 
                /// Short cut for testing request status is 2 (Aborted)
                /// </summary>
                internal bool RequestAborted
                { 
                    get { return this.requestStatus == 2; }
                } 
 
                /// <summary>
                /// Buffer used when pumping data from the write stream to the request content stream 
                /// </summary>
                internal byte[] RequestContentBuffer
                {
                    get 
                    {
                        if (this.requestContentBuffer == null) 
                        { 
                            this.requestContentBuffer = new byte[64 * 1024];
                        } 

                        return this.requestContentBuffer;
                    }
                } 

                /// <summary> 
                /// The length of the valid content in the RequestContentBuffer 
                /// Once the data is read from the request content stream into the RequestContent buffer
                /// this length is set to the amount of data read. 
                /// When the data is written into the request stream it is set back to 0.
                /// </summary>
                internal int RequestContentBufferValidLength
                { 
                    get;
                    set; 
                } 

                /// <summary> 
                /// Change the request status to completed
                /// </summary>
                internal void SetComplete()
                { 
                    System.Threading.Interlocked.CompareExchange(ref this.requestStatus, 1, 0);
                } 
 
                /// <summary>
                /// Change the request status to aborted 
                /// </summary>
                internal void SetAborted()
                {
                    System.Threading.Interlocked.Exchange(ref this.requestStatus, 2); 
                }
 
                /// <summary> 
                /// dispose of the request object
                /// </summary> 
                internal void Dispose()
                {
                    Stream stream = null;
 
                    if (null != (stream = this.ResponseStream))
                    { 
                        this.ResponseStream = null; 
                        stream.Dispose();
                    } 

                    if (null != this.RequestContentStream)
                    {
                        if (this.RequestContentStream.Stream != null && this.RequestContentStream.IsKnownMemoryStream) 
                        {
                            this.RequestContentStream.Stream.Dispose(); 
                        } 

                        // We must not dispose the stream which came from outside 
                        //   the disposing/closing of that stream depends on parameter passed to us and is dealt with
                        //   at the end of SaveChanges process.
                        this.RequestContentStream = null;
                    } 

                    if (null != (stream = this.RequestStream)) 
                    { 
                        this.RequestStream = null;
                        try 
                        {
                            Util.DebugInjectFault("PerRequest::Dispose_BeforeRequestStreamDisposed");
                            stream.Dispose();
                        } 
                        catch (WebException)
                        { 
                            // if the request is aborted, then the connect stream 
                            // cannot be disposed - since not all bytes are written to it yet
                            // In this case, we eat the exception 
                            // Otherwise, keep throwing
                            if (!this.RequestAborted)
                            {
                                throw; 
                            }
 
                            // Call Injector to report the exception so test code can verify it is thrown 
                            Util.DebugInjectFault("PerRequest::Dispose_WebExceptionThrown");
                        } 
                    }

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

                    this.Request = null; 
                    this.SetComplete();
                }

                /// <summary> 
                /// Helper class to wrap the stream with the content of the request.
                /// We need to remember if the stream came from us (IsKnownMemoryStream is true) 
                /// or if it came from outside. For backward compatibility we set the Content-Length for our streams 
                /// since they are always MemoryStream and thus know their length.
                /// For outside streams (content of the MR requests) we don't set Content-Length since the stream 
                /// might not be able to answer to the Length call.
                /// </summary>
                internal class ContentStream
                { 
                    /// <summary>
                    /// The stream with the content of the request 
                    /// </summary> 
                    private readonly Stream stream;
 
                    /// <summary>
                    /// Set to true if the stream is a MemoryStream and we produced it (so it does have the buffer accesible)
                    /// </summary>
                    private readonly bool isKnownMemoryStream; 

                    /// <summary> 
                    /// Constructor 
                    /// </summary>
                    /// <param name="stream">The stream with the request content</param> 
                    /// <param name="isKnownMemoryStream">The stream was create by us and it's a MemoryStream</param>
                    public ContentStream(Stream stream, bool isKnownMemoryStream)
                    {
                        this.stream = stream; 
                        this.isKnownMemoryStream = isKnownMemoryStream;
                    } 
 
                    /// <summary>
                    /// The stream with the content of the request 
                    /// </summary>
                    public Stream Stream
                    {
                        get { return this.stream; } 
                    }
 
                    /// <summary> 
                    /// Set to true if the stream is a MemoryStream and we produced it (so it does have the buffer accesible)
                    /// </summary> 
                    public bool IsKnownMemoryStream
                    {
                        get { return this.isKnownMemoryStream; }
                    } 
                }
            } 
        } 
    }
} 

// 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/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/Xml/System/Xml/XPath/Internal/DocumentOrderQuery@cs/1/DocumentOrderQuery@cs
">
                                                <span style="word-wrap: break-word;">DocumentOrderQuery.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/LogicalTreeHelper@cs/1305600/LogicalTreeHelper@cs
">
                                                <span style="word-wrap: break-word;">LogicalTreeHelper.cs
</span>
                                            </a></li>

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

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Core/CSharp/MS/Internal/Media/XamlSerializationHelper@cs/1305600/XamlSerializationHelper@cs
">
                                                <span style="word-wrap: break-word;">XamlSerializationHelper.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/CompMod/System/CodeDOM/CodePrimitiveExpression@cs/1305376/CodePrimitiveExpression@cs
">
                                                <span style="word-wrap: break-word;">CodePrimitiveExpression.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/Media3D/Converters/Generated/Point3DValueSerializer@cs/1305600/Point3DValueSerializer@cs
">
                                                <span style="word-wrap: break-word;">Point3DValueSerializer.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/HWStack@cs/1/HWStack@cs
">
                                                <span style="word-wrap: break-word;">HWStack.cs
</span>
                                            </a></li>

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

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

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Framework/System/Windows/TemplateKey@cs/1/TemplateKey@cs
">
                                                <span style="word-wrap: break-word;">TemplateKey.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/XmlUtils/System/Xml/Xsl/IlGen/GenerateHelper@cs/1305376/GenerateHelper@cs
">
                                                <span style="word-wrap: break-word;">GenerateHelper.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/IO/Packaging/PackagePart@cs/1/PackagePart@cs
">
                                                <span style="word-wrap: break-word;">PackagePart.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/schema/XmlSchemaChoice@cs/1/XmlSchemaChoice@cs
">
                                                <span style="word-wrap: break-word;">XmlSchemaChoice.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/BuildTasks/MS/Internal/MarkupCompiler/ParserExtension@cs/1305600/ParserExtension@cs
">
                                                <span style="word-wrap: break-word;">ParserExtension.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/Microsoft/Scripting/Actions/ExpandoObject@cs/1305376/ExpandoObject@cs
">
                                                <span style="word-wrap: break-word;">ExpandoObject.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/CompMod/System/ComponentModel/DoubleConverter@cs/1305376/DoubleConverter@cs
">
                                                <span style="word-wrap: break-word;">DoubleConverter.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/NetFx35/System@WorkflowServices/System/ServiceModel/Description/WorkflowRuntimeBehavior@cs/1305376/WorkflowRuntimeBehavior@cs
">
                                                <span style="word-wrap: break-word;">WorkflowRuntimeBehavior.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Core/System/Windows/Media/Generated/TextEffect@cs/1/TextEffect@cs
">
                                                <span style="word-wrap: break-word;">TextEffect.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/WF/Common/AuthoringOM/Design/SecondaryViewProvider@cs/1305376/SecondaryViewProvider@cs
">
                                                <span style="word-wrap: break-word;">SecondaryViewProvider.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/Globalization/EastAsianLunisolarCalendar@cs/1/EastAsianLunisolarCalendar@cs
">
                                                <span style="word-wrap: break-word;">EastAsianLunisolarCalendar.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/ndp/fx/src/DataEntity/System/Data/Map/ViewGeneration/Structures/LeafCellTreeNode@cs/2/LeafCellTreeNode@cs
">
                                                <span style="word-wrap: break-word;">LeafCellTreeNode.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/Tools/System@Activities@Presentation/System/Activities/Presentation/WorkflowElementDialog@cs/1407647/WorkflowElementDialog@cs
">
                                                <span style="word-wrap: break-word;">WorkflowElementDialog.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/Freezable@cs/1/Freezable@cs
">
                                                <span style="word-wrap: break-word;">Freezable.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/Shared/MS/Utility/bindurihelper@cs/3/bindurihelper@cs
">
                                                <span style="word-wrap: break-word;">bindurihelper.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/Orcas/QFE/ndp/fx/src/DataEntity/System/Data/Metadata/Edm/AssociationEndMember@cs/1/AssociationEndMember@cs
">
                                                <span style="word-wrap: break-word;">AssociationEndMember.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/Dom/XmlDeclaration@cs/1305376/XmlDeclaration@cs
">
                                                <span style="word-wrap: break-word;">XmlDeclaration.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/MIT/System/Web/UI/MobileControls/Design/MobileContainerDesigner@cs/1305376/MobileContainerDesigner@cs
">
                                                <span style="word-wrap: break-word;">MobileContainerDesigner.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/View/VariableDesigner@xaml@cs/1305376/VariableDesigner@xaml@cs
">
                                                <span style="word-wrap: break-word;">VariableDesigner.xaml.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/OleDb/OleDbInfoMessageEvent@cs/1305376/OleDbInfoMessageEvent@cs
">
                                                <span style="word-wrap: break-word;">OleDbInfoMessageEvent.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/Orcas/RTM/ndp/fx/src/xsp/System/Web/Extensions/ClientServices/ClientFormsIdentity@cs/1/ClientFormsIdentity@cs
">
                                                <span style="word-wrap: break-word;">ClientFormsIdentity.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/clr/src/BCL/System/Runtime/Remoting/ObjRef@cs/1/ObjRef@cs
">
                                                <span style="word-wrap: break-word;">ObjRef.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/Data/System/Data/Common/HandlerBase@cs/1/HandlerBase@cs
">
                                                <span style="word-wrap: break-word;">HandlerBase.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/CompMod/Microsoft/Win32/SafeHandles/SafeThreadHandle@cs/1305376/SafeThreadHandle@cs
">
                                                <span style="word-wrap: break-word;">SafeThreadHandle.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/WeakReference@cs/4/WeakReference@cs
">
                                                <span style="word-wrap: break-word;">WeakReference.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Core/System/Windows/Input/Stylus/RawStylusInput@cs/1/RawStylusInput@cs
">
                                                <span style="word-wrap: break-word;">RawStylusInput.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/Configuration/System/Configuration/ConfigXmlReader@cs/1/ConfigXmlReader@cs
">
                                                <span style="word-wrap: break-word;">ConfigXmlReader.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FX-1434/FX-1434/1@0/untmp/whidbey/REDBITS/ndp/fx/src/xsp/System/Web/UI/WebControls/DetailsViewInsertEventArgs@cs/1/DetailsViewInsertEventArgs@cs
">
                                                <span style="word-wrap: break-word;">DetailsViewInsertEventArgs.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/Security/Tokens/IssuedSecurityTokenProvider@cs/1/IssuedSecurityTokenProvider@cs
">
                                                <span style="word-wrap: break-word;">IssuedSecurityTokenProvider.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/UIAutomation/UIAutomationClient/System/Windows/Automation/AutomationElement@cs/1/AutomationElement@cs
">
                                                <span style="word-wrap: break-word;">AutomationElement.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/fx/src/Designer/WebForms/System/Web/UI/Design/WebParts/WebPartZoneAutoFormat@cs/1/WebPartZoneAutoFormat@cs
">
                                                <span style="word-wrap: break-word;">WebPartZoneAutoFormat.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/Configuration/AuthenticationConfig@cs/1/AuthenticationConfig@cs
">
                                                <span style="word-wrap: break-word;">AuthenticationConfig.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/schema/XmlSchemaSubstitutionGroup@cs/1305376/XmlSchemaSubstitutionGroup@cs
">
                                                <span style="word-wrap: break-word;">XmlSchemaSubstitutionGroup.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/MIT/System/Web/UI/MobileControls/Adapters/ChtmlFormAdapter@cs/1305376/ChtmlFormAdapter@cs
">
                                                <span style="word-wrap: break-word;">ChtmlFormAdapter.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/HostVisual@cs/1407647/HostVisual@cs
">
                                                <span style="word-wrap: break-word;">HostVisual.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Framework/System/Windows/Documents/TextSchema@cs/3/TextSchema@cs
">
                                                <span style="word-wrap: break-word;">TextSchema.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/ModuleConfigurationInfo@cs/1305376/ModuleConfigurationInfo@cs
">
                                                <span style="word-wrap: break-word;">ModuleConfigurationInfo.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/Configuration/ExpressionBuilderCollection@cs/1305376/ExpressionBuilderCollection@cs
">
                                                <span style="word-wrap: break-word;">ExpressionBuilderCollection.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/Markup/Baml2006/Baml2006ReaderContext@cs/1305600/Baml2006ReaderContext@cs
">
                                                <span style="word-wrap: break-word;">Baml2006ReaderContext.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/Xaml/AttributeXamlType@cs/1305376/AttributeXamlType@cs
">
                                                <span style="word-wrap: break-word;">AttributeXamlType.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DataEntity/System/Data/Query/PlanCompiler/NominalTypeEliminator@cs/1305376/NominalTypeEliminator@cs
">
                                                <span style="word-wrap: break-word;">NominalTypeEliminator.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/Input/Cursor@cs/1/Cursor@cs
">
                                                <span style="word-wrap: break-word;">Cursor.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/Dom/XmlNamedNodeMap@cs/1/XmlNamedNodeMap@cs
">
                                                <span style="word-wrap: break-word;">XmlNamedNodeMap.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/WIN_WINDOWS/lh_tools_devdiv_wpf/Windows/wcp/Framework/MS/Internal/Data/DynamicValueConverter@cs/3/DynamicValueConverter@cs
">
                                                <span style="word-wrap: break-word;">DynamicValueConverter.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/DEVDIV/depot/DevDiv/releases/whidbey/QFE/ndp/fx/src/xsp/System/Web/UnsafeNativeMethods@cs/10/UnsafeNativeMethods@cs
">
                                                <span style="word-wrap: break-word;">UnsafeNativeMethods.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/Threading/Interlocked@cs/2/Interlocked@cs
">
                                                <span style="word-wrap: break-word;">Interlocked.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/Net/System/Net/Mail/SmtpNtlmAuthenticationModule@cs/2/SmtpNtlmAuthenticationModule@cs
">
                                                <span style="word-wrap: break-word;">SmtpNtlmAuthenticationModule.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DLinq/Dlinq/SqlClient/Common/SqlServer2KCompatibilityAnnotation@cs/1305376/SqlServer2KCompatibilityAnnotation@cs
">
                                                <span style="word-wrap: break-word;">SqlServer2KCompatibilityAnnotation.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/Variant@cs/1/Variant@cs
">
                                                <span style="word-wrap: break-word;">Variant.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/CompMod/System/ComponentModel/Design/ComponentEvent@cs/1/ComponentEvent@cs
">
                                                <span style="word-wrap: break-word;">ComponentEvent.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/Configuration/System/Configuration/ExceptionUtil@cs/1/ExceptionUtil@cs
">
                                                <span style="word-wrap: break-word;">ExceptionUtil.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/WF/Common/AuthoringOM/Serializer/CollectionMarkupSerializer@cs/1305376/CollectionMarkupSerializer@cs
">
                                                <span style="word-wrap: break-word;">CollectionMarkupSerializer.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/FXUpdate3074/FXUpdate3074/1@1/DEVDIV/depot/DevDiv/releases/whidbey/QFE/ndp/fx/src/xsp/System/Web/Util/SecUtil@cs/1/SecUtil@cs
">
                                                <span style="word-wrap: break-word;">SecUtil.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/WebSysDisplayNameAttribute@cs/1/WebSysDisplayNameAttribute@cs
">
                                                <span style="word-wrap: break-word;">WebSysDisplayNameAttribute.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/DataEntity/System/Data/Metadata/Edm/EdmMember@cs/1305376/EdmMember@cs
">
                                                <span style="word-wrap: break-word;">EdmMember.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/Data/System/Data/Common/DbProviderFactory@cs/1/DbProviderFactory@cs
">
                                                <span style="word-wrap: break-word;">DbProviderFactory.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/IxmlLineInfo@cs/1/IxmlLineInfo@cs
">
                                                <span style="word-wrap: break-word;">IxmlLineInfo.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/CompMod/System/CodeDOM/CodeArrayIndexerExpression@cs/1305376/CodeArrayIndexerExpression@cs
">
                                                <span style="word-wrap: break-word;">CodeArrayIndexerExpression.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/HttpApplication@cs/10/HttpApplication@cs
">
                                                <span style="word-wrap: break-word;">HttpApplication.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/UIAutomation/UIAutomationClient/System/Windows/Automation/GridPattern@cs/1/GridPattern@cs
">
                                                <span style="word-wrap: break-word;">GridPattern.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/Orcas/SP/wpf/src/Framework/System/Windows/Automation/Peers/TabItemAutomationPeer@cs/1/TabItemAutomationPeer@cs
">
                                                <span style="word-wrap: break-word;">TabItemAutomationPeer.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/SystemWebSectionGroup@cs/4/SystemWebSectionGroup@cs
">
                                                <span style="word-wrap: break-word;">SystemWebSectionGroup.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/CompMod/System/Diagnostics/FilterElement@cs/1305376/FilterElement@cs
">
                                                <span style="word-wrap: break-word;">FilterElement.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/Documents/FixedSOMSemanticBox@cs/1305600/FixedSOMSemanticBox@cs
">
                                                <span style="word-wrap: break-word;">FixedSOMSemanticBox.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Core/CSharp/System/Windows/Media/HitTestResult@cs/1305600/HitTestResult@cs
">
                                                <span style="word-wrap: break-word;">HitTestResult.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/Extensions/UI/ClientScriptManagerWrapper@cs/1305376/ClientScriptManagerWrapper@cs
">
                                                <span style="word-wrap: break-word;">ClientScriptManagerWrapper.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/XmlUtils/System/Xml/Xsl/QIL/QilXmlWriter@cs/2/QilXmlWriter@cs
">
                                                <span style="word-wrap: break-word;">QilXmlWriter.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/IntranetCredentialPolicy@cs/1/IntranetCredentialPolicy@cs
">
                                                <span style="word-wrap: break-word;">IntranetCredentialPolicy.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/StreamGeometry@cs/1/StreamGeometry@cs
">
                                                <span style="word-wrap: break-word;">StreamGeometry.cs
</span>
                                            </a></li>

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/cdf/src/WF/Common/AuthoringOM/Compiler/TypeSystem/CodeDomLoader@cs/1305376/CodeDomLoader@cs
">
                                                <span style="word-wrap: break-word;">CodeDomLoader.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/DLinq/Dlinq/SqlClient/Query/SqlAliaser@cs/1305376/SqlAliaser@cs
">
                                                <span style="word-wrap: break-word;">SqlAliaser.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/Configuration/CapabilitiesState@cs/1/CapabilitiesState@cs
">
                                                <span style="word-wrap: break-word;">CapabilitiesState.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/Input/TouchEventArgs@cs/1305600/TouchEventArgs@cs
">
                                                <span style="word-wrap: break-word;">TouchEventArgs.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/Misc/HandleCollector@cs/1/HandleCollector@cs
">
                                                <span style="word-wrap: break-word;">HandleCollector.cs
</span>
                                            </a></li>

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

                                    
                                        <li style="padding:5px;"><a href="http://www.dotnetframework.org/default.aspx/Dotnetfx_Vista_SP2/Dotnetfx_Vista_SP2/8@0@50727@4016/DEVDIV/depot/DevDiv/releases/whidbey/NetFxQFE/ndp/fx/src/xsp/System/Web/UI/HtmlControls/HtmlSelect@cs/1/HtmlSelect@cs
">
                                                <span style="word-wrap: break-word;">HtmlSelect.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/FormatException@cs/1305376/FormatException@cs
">
                                                <span style="word-wrap: break-word;">FormatException.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/Net/System/Net/NetworkInformation/SystemUnicastIPAddressInformation@cs/1/SystemUnicastIPAddressInformation@cs
">
                                                <span style="word-wrap: break-word;">SystemUnicastIPAddressInformation.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/QueryOperators/Inlined/NullableLongSumAggregationOperator@cs/1305376/NullableLongSumAggregationOperator@cs
">
                                                <span style="word-wrap: break-word;">NullableLongSumAggregationOperator.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/Xml/System/Xml/schema/SchemaDeclBase@cs/1/SchemaDeclBase@cs
">
                                                <span style="word-wrap: break-word;">SchemaDeclBase.cs
</span>
                                            </a></li>

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