UpdatableWrapper.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 / Server / System / Data / Services / UpdatableWrapper.cs / 1305376 / UpdatableWrapper.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//     Wraps all the calls to IUpdatable interface.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services
{
    using System.Linq; 
    using System.Diagnostics;
    using System.Collections.Generic; 
    using System.Data.Services.Providers; 

    ///  
    /// This class wraps all the calls to IUpdatable interface.
    /// 
    internal class UpdatableWrapper
    { 
        ///  instance implementation of IUpdatable.
        private IUpdatable updateProvider; 
 
        ///  data service instance.
        private IDataService service; 

        /// 
        /// creates an instance of UpdatableWrapper, which wraps all the calls to IUpdatable interface.
        ///  
        /// instance of the data service.
        internal UpdatableWrapper(IDataService serviceInstance) 
        { 
            this.service = serviceInstance;
        } 

        /// 
        /// Get the instance of IUpdatable.
        ///  
        private IUpdatable UpdateProvider
        { 
            get 
            {
                if (this.updateProvider == null) 
                {
                    // We need to call IUpdatable only for V1 providers. For ObjectContextServiceProvider, this always returns null.
                    // Hence basically, this call is only for reflection service provider.
                    if (this.service.Provider.IsV1Provider) 
                    {
                        this.updateProvider = this.service.Provider.GetService((IDataService)this.service.Instance); 
                    } 

                    if (this.updateProvider == null) 
                    {
                        this.updateProvider = this.service.Provider.GetService((IDataService)this.service.Instance);
                    }
                } 

                if (this.updateProvider == null) 
                { 
                    if (this.service.Provider.IsV1Provider)
                    { 
                        throw DataServiceException.CreateMethodNotImplemented(Strings.UpdatableWrapper_MissingIUpdatableForV1Provider);
                    }
                    else
                    { 
                        throw DataServiceException.CreateMethodNotImplemented(Strings.UpdatableWrapper_MissingUpdateProviderInterface);
                    } 
                } 

                return this.updateProvider; 
            }
        }

        ///  
        /// Creates the resource of the given type and belonging to the given container
        ///  
        /// container name to which the resource needs to be added 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and belonging to the given container 
        internal object CreateResource(string containerName, string fullTypeName)
        {
            // container name can be null for complex types
            // type name can be null when we don't know the type - e.g. DELETE /Customers(1) 
            // In case of inheritance we don't know the actual type of customer instance.
            object resource = this.UpdateProvider.CreateResource(containerName, fullTypeName); 
            if (resource == null) 
            {
                throw new InvalidOperationException(Strings.BadProvider_CreateResourceReturnedNull); 
            }

            return resource;
        } 

        ///  
        /// Gets the resource of the given type that the query points to 
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and as referenced by the query
        internal object GetResource(IQueryable query, string fullTypeName)
        { 
            Debug.Assert(query != null, "query != null");
            try 
            { 
                // TypeName can be null since for open types, we may not know the type yet.
                return this.UpdateProvider.GetResource(query, fullTypeName); 
            }
            catch (ArgumentException e)
            {
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidUriSpecified, e); 
            }
        } 
 
        /// 
        /// Resets the value of the given resource to its default value 
        /// 
        /// resource whose value needs to be reset
        /// same resource with its value reset
        internal object ResetResource(object resource) 
        {
            Debug.Assert(resource != null, "resource != null"); 
            object resetResource = this.UpdateProvider.ResetResource(resource); 
            if (resetResource == null)
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResetResourceReturnedNull);
            }

            return resetResource; 
        }
 
        ///  
        /// If the provider implements IConcurrencyProvider, then this method passes the etag values
        /// to the provider, otherwise compares the etag itself. 
        /// 
        /// etag values for the given resource.
        /// container for the given resource.
        internal void SetETagValues(object resourceCookie, ResourceSetWrapper container) 
        {
            Debug.Assert(resourceCookie != null, "resourceCookie != null"); 
            Debug.Assert(container != null, "container != null"); 
            DataServiceHostWrapper host = this.service.OperationContext.Host;
            Debug.Assert(String.IsNullOrEmpty(host.RequestIfNoneMatch), "IfNoneMatch header cannot be specified for Update/Delete operations"); 

            // Resolve the cookie first to the actual resource type
            object actualEntity = this.ResolveResource(resourceCookie);
            Debug.Assert(actualEntity != null, "actualEntity != null"); 

            ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(this.service.Provider, actualEntity); 
            Debug.Assert(resourceType != null, "resourceType != null"); 

            IList etagProperties = this.service.Provider.GetETagProperties(container.Name, resourceType); 

            if (etagProperties.Count == 0)
            {
                if (!String.IsNullOrEmpty(host.RequestIfMatch)) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.Serializer_NoETagPropertiesForType); 
                } 

                // If the type has no etag properties, then we do not need to do any etag checks 
                return;
            }

            // If the provider implements IConcurrencyProvider, then we need to call the provider 
            // and pass the etag values. Else, we need to compare the etag values ourselves.
            IDataServiceUpdateProvider concurrencyProvider = this.updateProvider as IDataServiceUpdateProvider; 
            if (concurrencyProvider != null) 
            {
                bool? checkForEquality = null; 
                IEnumerable> etagValues = null;
                if (!String.IsNullOrEmpty(host.RequestIfMatch))
                {
                    checkForEquality = true; 
                    etagValues = ParseETagValue(etagProperties, host.RequestIfMatch);
                } 
                else 
                {
                    etagValues = new KeyValuePair[0]; 
                }

                concurrencyProvider.SetConcurrencyValues(resourceCookie, checkForEquality, etagValues);
            } 
            else if (String.IsNullOrEmpty(host.RequestIfMatch))
            { 
                throw DataServiceException.CreateBadRequestError(Strings.DataService_CannotPerformOperationWithoutETag(resourceType.FullName)); 
            }
            else if (host.RequestIfMatch != XmlConstants.HttpAnyETag) 
            {
                // Compare If-Match header value with the current etag value, if the If-Match header value is not equal to '*'
                string etagValue = WebUtil.GetETagValue(resourceCookie, resourceType, etagProperties, this.service, false /*getMethod*/);
                Debug.Assert(!String.IsNullOrEmpty(etagValue), "etag value can never be null"); 

                if (etagValue != host.RequestIfMatch) 
                { 
                    throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch);
                } 
            }
        }

        ///  
        /// Sets the value of the given property on the target object
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// value of the property 
        internal void SetValue(object targetResource, string propertyName, object propertyValue)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            this.UpdateProvider.SetValue(targetResource, propertyName, propertyValue);
        } 
 
        /// 
        /// Gets the value of the given property on the target object 
        /// 
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// the value of the property for the given target resource 
        internal object GetValue(object targetResource, string propertyName)
        { 
            Debug.Assert(targetResource != null, "targetResource != null"); 
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            return this.UpdateProvider.GetValue(targetResource, propertyName); 
        }

        /// 
        /// Sets the value of the given reference property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property
        internal void SetReference(object targetResource, string propertyName, object propertyValue) 
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            this.UpdateProvider.SetReference(targetResource, propertyName, propertyValue); 
        }
 
        ///  
        /// Adds the given value to the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// value of the property which needs to be added
        internal void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) 
        {
            Debug.Assert(targetResource != null, "targetResource != null"); 
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            this.UpdateProvider.AddReferenceToCollection(targetResource, propertyName, resourceToBeAdded);
        } 

        /// 
        /// Removes the given value from the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be removed 
        internal void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        { 
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            this.UpdateProvider.RemoveReferenceFromCollection(targetResource, propertyName, resourceToBeRemoved);
        } 

        ///  
        /// Delete the given resource 
        /// 
        /// resource that needs to be deleted 
        internal void DeleteResource(object targetResource)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            this.UpdateProvider.DeleteResource(targetResource); 
        }
 
        ///  
        /// Saves all the pending changes made till now
        ///  
        internal void SaveChanges()
        {
            this.UpdateProvider.SaveChanges();
        } 

        ///  
        /// Returns the actual instance of the resource represented by the given resource object 
        /// 
        /// object representing the resource whose instance needs to be fetched 
        /// The actual instance of the resource represented by the given resource object
        internal object ResolveResource(object resource)
        {
            Debug.Assert(resource != null, "resource != null"); 
            object resolvedResource = this.UpdateProvider.ResolveResource(resource);
            if (resolvedResource == null) 
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResolveResourceReturnedNull);
            } 

            return resolvedResource;
        }
 
        /// 
        /// Revert all the pending changes. 
        ///  
        internal void ClearChanges()
        { 
            this.UpdateProvider.ClearChanges();
        }

        ///  
        /// Dispose the update provider instance
        ///  
        internal void DisposeProvider() 
        {
            if (this.updateProvider != null) 
            {
                WebUtil.Dispose(this.updateProvider);
                this.updateProvider = null;
            } 
        }
 
        ///  
        /// Parse the given etag value in the If-Match request header.
        ///  
        /// List of etag properties for the type whose etag values we are parsing.
        /// value of the If-Match header as specified in the request.
        /// returns the etag value as a list containing the property name and its corresponding value. If the If-Match header value is '*', then returns an empty collection.
        private static IEnumerable> ParseETagValue(IList etagProperties, string ifMatchHeaderValue) 
        {
            Debug.Assert(etagProperties != null && etagProperties.Count != 0, "There must be atleast one etag property specified"); 
            Debug.Assert(!String.IsNullOrEmpty(ifMatchHeaderValue), "IfMatch header cannot be null"); 

            if (ifMatchHeaderValue == XmlConstants.HttpAnyETag) 
            {
                // if the value is '*', then we return an empty IEnumerable.
                return new KeyValuePair[0];
            } 

            Debug.Assert(ifMatchHeaderValue.StartsWith(XmlConstants.HttpWeakETagPrefix, StringComparison.Ordinal), "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); 
            Debug.Assert(ifMatchHeaderValue.Length >= XmlConstants.HttpWeakETagPrefix.Length + 1, "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); 

            // Just get the etag value - we need to ignore the 'W/"' and the last '"' character from the etag 
            string strippedETag = ifMatchHeaderValue.Substring(XmlConstants.HttpWeakETagPrefix.Length, ifMatchHeaderValue.Length - XmlConstants.HttpWeakETagPrefix.Length - 1);

            KeyInstance keyInstance = null;
            bool success; 
            Exception innerException = null;
 
            // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the 
            // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
            // it with the If-Match request header. Hence all invalid cases always used to throw 
            // DataServiceException with 412, since the etags didn't match.
            // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
            // the etag values and parse it to the provider, if it has implement this interface. To avoid
            // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400 
            // to avoid it from becoming a breaking change.
            try 
            { 
                success = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(strippedETag), out keyInstance);
            } 
            catch (DataServiceException e)
            {
                success = false;
                innerException = e; 
            }
 
            if (!success) 
            {
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
            }
 
            if (keyInstance.PositionalValues.Count != etagProperties.Count)
            { 
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch); 
            }

            KeyValuePair[] etagPropertyInfo = new KeyValuePair[etagProperties.Count];
            for (int i = 0; i < etagPropertyInfo.Length; i++) 
            {
                ResourceProperty etagProperty = etagProperties[i]; 
                object propertyValue = null; 
                string value = (string)keyInstance.PositionalValues[i];
 
                if (value != XmlConstants.NullLiteralInETag)
                {
                    // The reason we need to catch the Overflow Exception here is because of the Bug #679728.
                    // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the 
                    // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
                    // it with the If-Match request header. Hence all invalid cases always used to throw 
                    // DataServiceException with 412, since the etags didn't match. 
                    // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
                    // the etag values and parse it to the provider, if it has implement this interface. To avoid 
                    // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400
                    // to avoid it from becoming a breaking change.
                    try
                    { 
                        success = System.Data.Services.Parsing.WebConvert.TryKeyStringToPrimitive(value, etagProperty.Type, out propertyValue);
                    } 
                    catch (OverflowException e) 
                    {
                        success = false; 
                        innerException = e;
                    }

                    if (!success) 
                    {
                        // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                        // we used to do throw 412 in V1, keeping it that way to avoid breaking change. 
                        throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
                    } 
                }

                etagPropertyInfo[i] = new KeyValuePair(etagProperties[i].Name, propertyValue);
            } 

            return etagPropertyInfo; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//     Wraps all the calls to IUpdatable interface.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services
{
    using System.Linq; 
    using System.Diagnostics;
    using System.Collections.Generic; 
    using System.Data.Services.Providers; 

    ///  
    /// This class wraps all the calls to IUpdatable interface.
    /// 
    internal class UpdatableWrapper
    { 
        ///  instance implementation of IUpdatable.
        private IUpdatable updateProvider; 
 
        ///  data service instance.
        private IDataService service; 

        /// 
        /// creates an instance of UpdatableWrapper, which wraps all the calls to IUpdatable interface.
        ///  
        /// instance of the data service.
        internal UpdatableWrapper(IDataService serviceInstance) 
        { 
            this.service = serviceInstance;
        } 

        /// 
        /// Get the instance of IUpdatable.
        ///  
        private IUpdatable UpdateProvider
        { 
            get 
            {
                if (this.updateProvider == null) 
                {
                    // We need to call IUpdatable only for V1 providers. For ObjectContextServiceProvider, this always returns null.
                    // Hence basically, this call is only for reflection service provider.
                    if (this.service.Provider.IsV1Provider) 
                    {
                        this.updateProvider = this.service.Provider.GetService((IDataService)this.service.Instance); 
                    } 

                    if (this.updateProvider == null) 
                    {
                        this.updateProvider = this.service.Provider.GetService((IDataService)this.service.Instance);
                    }
                } 

                if (this.updateProvider == null) 
                { 
                    if (this.service.Provider.IsV1Provider)
                    { 
                        throw DataServiceException.CreateMethodNotImplemented(Strings.UpdatableWrapper_MissingIUpdatableForV1Provider);
                    }
                    else
                    { 
                        throw DataServiceException.CreateMethodNotImplemented(Strings.UpdatableWrapper_MissingUpdateProviderInterface);
                    } 
                } 

                return this.updateProvider; 
            }
        }

        ///  
        /// Creates the resource of the given type and belonging to the given container
        ///  
        /// container name to which the resource needs to be added 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and belonging to the given container 
        internal object CreateResource(string containerName, string fullTypeName)
        {
            // container name can be null for complex types
            // type name can be null when we don't know the type - e.g. DELETE /Customers(1) 
            // In case of inheritance we don't know the actual type of customer instance.
            object resource = this.UpdateProvider.CreateResource(containerName, fullTypeName); 
            if (resource == null) 
            {
                throw new InvalidOperationException(Strings.BadProvider_CreateResourceReturnedNull); 
            }

            return resource;
        } 

        ///  
        /// Gets the resource of the given type that the query points to 
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and as referenced by the query
        internal object GetResource(IQueryable query, string fullTypeName)
        { 
            Debug.Assert(query != null, "query != null");
            try 
            { 
                // TypeName can be null since for open types, we may not know the type yet.
                return this.UpdateProvider.GetResource(query, fullTypeName); 
            }
            catch (ArgumentException e)
            {
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidUriSpecified, e); 
            }
        } 
 
        /// 
        /// Resets the value of the given resource to its default value 
        /// 
        /// resource whose value needs to be reset
        /// same resource with its value reset
        internal object ResetResource(object resource) 
        {
            Debug.Assert(resource != null, "resource != null"); 
            object resetResource = this.UpdateProvider.ResetResource(resource); 
            if (resetResource == null)
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResetResourceReturnedNull);
            }

            return resetResource; 
        }
 
        ///  
        /// If the provider implements IConcurrencyProvider, then this method passes the etag values
        /// to the provider, otherwise compares the etag itself. 
        /// 
        /// etag values for the given resource.
        /// container for the given resource.
        internal void SetETagValues(object resourceCookie, ResourceSetWrapper container) 
        {
            Debug.Assert(resourceCookie != null, "resourceCookie != null"); 
            Debug.Assert(container != null, "container != null"); 
            DataServiceHostWrapper host = this.service.OperationContext.Host;
            Debug.Assert(String.IsNullOrEmpty(host.RequestIfNoneMatch), "IfNoneMatch header cannot be specified for Update/Delete operations"); 

            // Resolve the cookie first to the actual resource type
            object actualEntity = this.ResolveResource(resourceCookie);
            Debug.Assert(actualEntity != null, "actualEntity != null"); 

            ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(this.service.Provider, actualEntity); 
            Debug.Assert(resourceType != null, "resourceType != null"); 

            IList etagProperties = this.service.Provider.GetETagProperties(container.Name, resourceType); 

            if (etagProperties.Count == 0)
            {
                if (!String.IsNullOrEmpty(host.RequestIfMatch)) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.Serializer_NoETagPropertiesForType); 
                } 

                // If the type has no etag properties, then we do not need to do any etag checks 
                return;
            }

            // If the provider implements IConcurrencyProvider, then we need to call the provider 
            // and pass the etag values. Else, we need to compare the etag values ourselves.
            IDataServiceUpdateProvider concurrencyProvider = this.updateProvider as IDataServiceUpdateProvider; 
            if (concurrencyProvider != null) 
            {
                bool? checkForEquality = null; 
                IEnumerable> etagValues = null;
                if (!String.IsNullOrEmpty(host.RequestIfMatch))
                {
                    checkForEquality = true; 
                    etagValues = ParseETagValue(etagProperties, host.RequestIfMatch);
                } 
                else 
                {
                    etagValues = new KeyValuePair[0]; 
                }

                concurrencyProvider.SetConcurrencyValues(resourceCookie, checkForEquality, etagValues);
            } 
            else if (String.IsNullOrEmpty(host.RequestIfMatch))
            { 
                throw DataServiceException.CreateBadRequestError(Strings.DataService_CannotPerformOperationWithoutETag(resourceType.FullName)); 
            }
            else if (host.RequestIfMatch != XmlConstants.HttpAnyETag) 
            {
                // Compare If-Match header value with the current etag value, if the If-Match header value is not equal to '*'
                string etagValue = WebUtil.GetETagValue(resourceCookie, resourceType, etagProperties, this.service, false /*getMethod*/);
                Debug.Assert(!String.IsNullOrEmpty(etagValue), "etag value can never be null"); 

                if (etagValue != host.RequestIfMatch) 
                { 
                    throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch);
                } 
            }
        }

        ///  
        /// Sets the value of the given property on the target object
        ///  
        /// target object which defines the property 
        /// name of the property whose value needs to be updated
        /// value of the property 
        internal void SetValue(object targetResource, string propertyName, object propertyValue)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            this.UpdateProvider.SetValue(targetResource, propertyName, propertyValue);
        } 
 
        /// 
        /// Gets the value of the given property on the target object 
        /// 
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// the value of the property for the given target resource 
        internal object GetValue(object targetResource, string propertyName)
        { 
            Debug.Assert(targetResource != null, "targetResource != null"); 
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            return this.UpdateProvider.GetValue(targetResource, propertyName); 
        }

        /// 
        /// Sets the value of the given reference property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property
        internal void SetReference(object targetResource, string propertyName, object propertyValue) 
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            this.UpdateProvider.SetReference(targetResource, propertyName, propertyValue); 
        }
 
        ///  
        /// Adds the given value to the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated
        /// value of the property which needs to be added
        internal void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) 
        {
            Debug.Assert(targetResource != null, "targetResource != null"); 
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)"); 
            this.UpdateProvider.AddReferenceToCollection(targetResource, propertyName, resourceToBeAdded);
        } 

        /// 
        /// Removes the given value from the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be removed 
        internal void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        { 
            Debug.Assert(targetResource != null, "targetResource != null");
            Debug.Assert(!String.IsNullOrEmpty(propertyName), "!String.IsNullOrEmpty(propertyName)");
            this.UpdateProvider.RemoveReferenceFromCollection(targetResource, propertyName, resourceToBeRemoved);
        } 

        ///  
        /// Delete the given resource 
        /// 
        /// resource that needs to be deleted 
        internal void DeleteResource(object targetResource)
        {
            Debug.Assert(targetResource != null, "targetResource != null");
            this.UpdateProvider.DeleteResource(targetResource); 
        }
 
        ///  
        /// Saves all the pending changes made till now
        ///  
        internal void SaveChanges()
        {
            this.UpdateProvider.SaveChanges();
        } 

        ///  
        /// Returns the actual instance of the resource represented by the given resource object 
        /// 
        /// object representing the resource whose instance needs to be fetched 
        /// The actual instance of the resource represented by the given resource object
        internal object ResolveResource(object resource)
        {
            Debug.Assert(resource != null, "resource != null"); 
            object resolvedResource = this.UpdateProvider.ResolveResource(resource);
            if (resolvedResource == null) 
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResolveResourceReturnedNull);
            } 

            return resolvedResource;
        }
 
        /// 
        /// Revert all the pending changes. 
        ///  
        internal void ClearChanges()
        { 
            this.UpdateProvider.ClearChanges();
        }

        ///  
        /// Dispose the update provider instance
        ///  
        internal void DisposeProvider() 
        {
            if (this.updateProvider != null) 
            {
                WebUtil.Dispose(this.updateProvider);
                this.updateProvider = null;
            } 
        }
 
        ///  
        /// Parse the given etag value in the If-Match request header.
        ///  
        /// List of etag properties for the type whose etag values we are parsing.
        /// value of the If-Match header as specified in the request.
        /// returns the etag value as a list containing the property name and its corresponding value. If the If-Match header value is '*', then returns an empty collection.
        private static IEnumerable> ParseETagValue(IList etagProperties, string ifMatchHeaderValue) 
        {
            Debug.Assert(etagProperties != null && etagProperties.Count != 0, "There must be atleast one etag property specified"); 
            Debug.Assert(!String.IsNullOrEmpty(ifMatchHeaderValue), "IfMatch header cannot be null"); 

            if (ifMatchHeaderValue == XmlConstants.HttpAnyETag) 
            {
                // if the value is '*', then we return an empty IEnumerable.
                return new KeyValuePair[0];
            } 

            Debug.Assert(ifMatchHeaderValue.StartsWith(XmlConstants.HttpWeakETagPrefix, StringComparison.Ordinal), "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); 
            Debug.Assert(ifMatchHeaderValue.Length >= XmlConstants.HttpWeakETagPrefix.Length + 1, "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); 

            // Just get the etag value - we need to ignore the 'W/"' and the last '"' character from the etag 
            string strippedETag = ifMatchHeaderValue.Substring(XmlConstants.HttpWeakETagPrefix.Length, ifMatchHeaderValue.Length - XmlConstants.HttpWeakETagPrefix.Length - 1);

            KeyInstance keyInstance = null;
            bool success; 
            Exception innerException = null;
 
            // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the 
            // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
            // it with the If-Match request header. Hence all invalid cases always used to throw 
            // DataServiceException with 412, since the etags didn't match.
            // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
            // the etag values and parse it to the provider, if it has implement this interface. To avoid
            // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400 
            // to avoid it from becoming a breaking change.
            try 
            { 
                success = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(strippedETag), out keyInstance);
            } 
            catch (DataServiceException e)
            {
                success = false;
                innerException = e; 
            }
 
            if (!success) 
            {
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
            }
 
            if (keyInstance.PositionalValues.Count != etagProperties.Count)
            { 
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch); 
            }

            KeyValuePair[] etagPropertyInfo = new KeyValuePair[etagProperties.Count];
            for (int i = 0; i < etagPropertyInfo.Length; i++) 
            {
                ResourceProperty etagProperty = etagProperties[i]; 
                object propertyValue = null; 
                string value = (string)keyInstance.PositionalValues[i];
 
                if (value != XmlConstants.NullLiteralInETag)
                {
                    // The reason we need to catch the Overflow Exception here is because of the Bug #679728.
                    // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the 
                    // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
                    // it with the If-Match request header. Hence all invalid cases always used to throw 
                    // DataServiceException with 412, since the etags didn't match. 
                    // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
                    // the etag values and parse it to the provider, if it has implement this interface. To avoid 
                    // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400
                    // to avoid it from becoming a breaking change.
                    try
                    { 
                        success = System.Data.Services.Parsing.WebConvert.TryKeyStringToPrimitive(value, etagProperty.Type, out propertyValue);
                    } 
                    catch (OverflowException e) 
                    {
                        success = false; 
                        innerException = e;
                    }

                    if (!success) 
                    {
                        // We could have throwed BadRequest here since the etag value is not properly formattted. But since 
                        // we used to do throw 412 in V1, keeping it that way to avoid breaking change. 
                        throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
                    } 
                }

                etagPropertyInfo[i] = new KeyValuePair(etagProperties[i].Name, propertyValue);
            } 

            return etagPropertyInfo; 
        } 
    }
} 

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

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK