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"); IListetagProperties = 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"); IListetagProperties = 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlSchemaInferenceException.cs
- xdrvalidator.cs
- Symbol.cs
- AnimatedTypeHelpers.cs
- DebugView.cs
- ConfigXmlComment.cs
- KeyValuePair.cs
- DateTimeConstantAttribute.cs
- DecimalFormatter.cs
- MarshalByValueComponent.cs
- FileSystemWatcher.cs
- RadialGradientBrush.cs
- DesignerImageAdapter.cs
- Types.cs
- objectresult_tresulttype.cs
- SettingsAttributeDictionary.cs
- PageThemeParser.cs
- TypeInitializationException.cs
- PersonalizationEntry.cs
- SqlError.cs
- SchemaImporterExtensionElementCollection.cs
- CultureMapper.cs
- Encoder.cs
- AnimatedTypeHelpers.cs
- EntityContainer.cs
- RelOps.cs
- TraceHandler.cs
- InputReport.cs
- LinkedResource.cs
- SchemaElementDecl.cs
- MetadataCollection.cs
- ResizeGrip.cs
- HierarchicalDataSourceControl.cs
- GeometryModel3D.cs
- ConfigurationElementProperty.cs
- ClockController.cs
- RowTypeElement.cs
- ArrangedElement.cs
- LoginName.cs
- BufferAllocator.cs
- SecurityProtocolCorrelationState.cs
- PropertyValueUIItem.cs
- HttpPostedFile.cs
- BrushConverter.cs
- XPathAncestorQuery.cs
- HebrewCalendar.cs
- ConvertEvent.cs
- NonBatchDirectoryCompiler.cs
- ProfessionalColorTable.cs
- GridLengthConverter.cs
- HwndAppCommandInputProvider.cs
- DesignerPerfEventProvider.cs
- ToolStripGripRenderEventArgs.cs
- SerializationObjectManager.cs
- IProducerConsumerCollection.cs
- ConfigurationLocationCollection.cs
- EmptyEnumerator.cs
- Simplifier.cs
- ClientUrlResolverWrapper.cs
- ToolStripMenuItem.cs
- XmlSchemaObjectCollection.cs
- PipeStream.cs
- MimePart.cs
- MouseDevice.cs
- TextElementEditingBehaviorAttribute.cs
- SqlNodeAnnotation.cs
- ClientTargetCollection.cs
- wgx_exports.cs
- QualifiedCellIdBoolean.cs
- Error.cs
- HttpHeaderCollection.cs
- PolicyVersion.cs
- RoutingTable.cs
- _ChunkParse.cs
- TogglePatternIdentifiers.cs
- AutomationEvent.cs
- GenericArgumentsUpdater.cs
- ByteAnimationBase.cs
- PersonalizationStateInfoCollection.cs
- PrintEvent.cs
- PropertyDescriptorComparer.cs
- ToolStripMenuItem.cs
- UTF32Encoding.cs
- TransformPattern.cs
- DbConnectionPoolGroup.cs
- UnmanagedMemoryStreamWrapper.cs
- WindowsHyperlink.cs
- TextElementEnumerator.cs
- InputLangChangeEvent.cs
- XmlSiteMapProvider.cs
- xdrvalidator.cs
- SystemWebExtensionsSectionGroup.cs
- CombinedGeometry.cs
- ComMethodElementCollection.cs
- CachedTypeface.cs
- ConnectionManagementElementCollection.cs
- ExpressionPrefixAttribute.cs
- SignatureDescription.cs
- WebPartConnectionCollection.cs
- NameValueConfigurationElement.cs