public virtual void SetValue(object targetResource, string propertyName, object propertyValue) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource"); targetResource = token.Resource; token.PendingPropertyUpdates[propertyName] = propertyValue; this.pendingChanges.Add(delegate { object generatedValue; Type t = targetResource.GetType(); PropertyInfo pi = t.GetProperty(propertyName); ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name }); if (this.TryGetStoreGeneratedValue(GetResourceTypeFullName(t), propertyName, out generatedValue)) { propertyValue = generatedValue; } if (this.IsCollectionProperty(pi)) { ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null", new object[0]); IEnumerable enumerable = propertyValue as IEnumerable; ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable", new object[0]); this.SetCollectionPropertyValue(targetResource, pi, enumerable); } else { propertyValue = UpdatableToken.ResolveIfToken(propertyValue); pi.SetValue(targetResource, propertyValue, null); } }); }
/// <summary> /// Resets the value of the given resource to its default value /// </summary> /// <param name="resource">resource whose value needs to be reset</param> /// <returns>same resource with its value reset</returns> public virtual object ResetResource(object resource) { ExceptionUtilities.CheckArgumentNotNull(resource, "resource"); var token = UpdatableToken.AssertIsToken(resource, "resource"); resource = token.Resource; // create a new token to return token = new UpdatableToken(resource); object newInstance = Activator.CreateInstance(resource.GetType()); ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", resource.GetType().Name); string[] propertiesToReset = this.ReflectionMetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType())); // We must only reset values of scalar, scalar Collection, complex, and complexCollection properties, the key and navigations must stay the same foreach (string propertyToReset in propertiesToReset) { PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset); ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", propertyToReset); object newValue = pi.GetValue(newInstance, null); this.pendingChanges.Add(() => pi.SetValue(resource, newValue, null)); token.PendingPropertyUpdates[propertyToReset] = newValue; } return(token); }
/// <summary> /// Gets the value of the given property on the target object /// </summary> /// <param name="targetResource">target object which defines the property</param> /// <param name="propertyName">name of the property whose value needs to be updated</param> /// <returns>the value of the property for the given target resource</returns> public virtual object GetValue(object targetResource, string propertyName) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); // resolve the token, and return a pending value if there is one // NOTE: this code is specifically to handle cases of mapped complex-type values, because the product does not cache the // value returned by CreateResource so we need to take into account any pending updates, or we risk returning stale data var token = UpdatableToken.AssertIsToken(targetResource, "targetResource"); if (token.PendingPropertyUpdates.ContainsKey(propertyName)) { return(token.PendingPropertyUpdates[propertyName]); } targetResource = token.Resource; PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", propertyName, targetResource.GetType().Name); var value = pi.GetValue(targetResource, null); // NOTE: we need to token-ize any complex values before returning them // we should have a better way of telling a type is complex, but this works for now if (value != null && pi.PropertyType.Assembly == this.GetType().Assembly) { ExceptionUtilities.Assert(!this.ReflectionMetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", pi.PropertyType.FullName, propertyName); value = new UpdatableToken(value); } return(value); }
private UpdatableToken InstantiateResourceType(string fullTypeName) { Type t = this.MetadataHelper.FindClrTypeByFullName(fullTypeName); object instance = Activator.CreateInstance(t); UpdatableToken token = new UpdatableToken(instance); foreach (PropertyInfo p in t.GetProperties()) { object generatedValue; PropertyInfo property = p; if (this.IsCollectionProperty(property)) { Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name); if (collectionType != null) { object newCollection = Activator.CreateInstance(collectionType); token.PendingPropertyUpdates[property.Name] = newCollection; this.pendingChanges.Add(delegate { property.SetValue(instance, newCollection, null); }); } } if (this.TryGetStoreGeneratedValue(fullTypeName, property.Name, out generatedValue)) { token.PendingPropertyUpdates[property.Name] = generatedValue; this.pendingChanges.Add(delegate { property.SetValue(instance, generatedValue, null); }); } } return(token); }
/// <summary> /// Adds the given value to the collection /// </summary> /// <param name="targetResource">target object which defines the property</param> /// <param name="propertyName">name of the property whose value needs to be updated</param> /// <param name="resourceToBeAdded">value of the property which needs to be added</param> public virtual void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); ExceptionUtilities.CheckArgumentNotNull(resourceToBeAdded, "resourceToBeAdded"); // resolve the target token var targetToken = UpdatableToken.AssertIsToken(targetResource, "targetResource"); targetResource = targetToken.Resource; // resolve the added token resourceToBeAdded = UpdatableToken.AssertIsTokenAndResolve(resourceToBeAdded, "resourceToBeAdded"); // All resource set reference properties must be of type IList<T> where T is the type of an entitySet // Note that we don't support bi-directional relationships so we only handle the one resource set reference property in isolation. IList list = this.GetValue(targetToken, propertyName) as IList; ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", propertyName, targetResource.GetType().Name); this.pendingChanges.Add(() => { list.Add(resourceToBeAdded); }); }
public static UpdatableToken AssertIsToken(object resource, string name) { ExceptionUtilities.CheckArgumentNotNull(resource, "resource"); UpdatableToken token = resource as UpdatableToken; ExceptionUtilities.CheckObjectNotNull(token, "{0} was not a token. Type was: '{1}'", new object[] { name, resource.GetType() }); return(token); }
public static object ResolveIfToken(object resource) { UpdatableToken token = resource as UpdatableToken; if (token != null) { resource = token.Resource; } return(resource); }
public virtual void SetReference(object targetResource, string propertyName, object propertyValue) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); if (propertyValue != null) { UpdatableToken.AssertIsToken(propertyValue, "propertyValue"); } this.SetValue(targetResource, propertyName, propertyValue); }
public virtual void SetConcurrencyValues(object resourceCookie, bool?checkForEquality, IEnumerable <KeyValuePair <string, object> > concurrencyValues) { ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie"); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 0x1a1, "Missing concurrency token for update operation", new object[0]); ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false", new object[0]); ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues"); if (concurrencyValues.Any <KeyValuePair <string, object> >()) { resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie"); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(CompareETagValues(this.GetConcurrencyValues(resourceCookie), concurrencyValues), 0x19c, "Concurrency tokens do not match", new object[0]); } }
public virtual object CreateResource(string containerName, string fullTypeName) { ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName"); UpdatableToken token = this.InstantiateResourceType(fullTypeName); if (containerName != null) { this.pendingChanges.Add(delegate { this.GetResourceSetEntities(containerName).Add(token.Resource); }); } return(token); }
protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue) { object collection; ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo"); ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue"); Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name); ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property", new object[0]); propertyValue = propertyValue.Cast <object>().Select <object, object>(delegate(object o) { return(UpdatableToken.ResolveIfToken(o)); }); ConstructorInfo enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) }); if (enumerableConstructor != null) { collection = enumerableConstructor.Invoke(new object[] { propertyValue }); } else if (collectionType.IsGenericType && (collectionType.GetGenericArguments().Count <Type>() == 1)) { Type typeArgument = collectionType.GetGenericArguments().Single <Type>(); ConstructorInfo typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable <>).MakeGenericType(new Type[] { typeArgument }) }); if (typedEnumerableConstructor != null) { object typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new Type[] { typeArgument }).Invoke(null, new object[] { propertyValue }); collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable }); } else { MethodInfo typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument }); ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]); collection = Activator.CreateInstance(collectionType); foreach (object element in propertyValue) { typedAddMethod.Invoke(collection, new object[] { element }); } } } else { MethodInfo addMethod = collectionType.GetMethod("Add"); ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]); collection = Activator.CreateInstance(collectionType); foreach (object element in propertyValue) { addMethod.Invoke(collection, new object[] { element }); } } propertyInfo.SetValue(targetResource, collection, null); }
public virtual void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); ExceptionUtilities.CheckArgumentNotNull(resourceToBeRemoved, "resourceToBeRemoved"); UpdatableToken.AssertIsToken(targetResource, "targetResource"); resourceToBeRemoved = UpdatableToken.AssertIsTokenAndResolve(resourceToBeRemoved, "resourceToBeRemoved"); IList list = this.GetValue(targetResource, propertyName) as IList; ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name }); this.pendingChanges.Add(delegate { list.Remove(resourceToBeRemoved); }); }
public virtual void DeleteResource(object targetResource) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource"); string resourceSetName = this.GetResourceSetOfTargetResource(targetResource); ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete", new object[0]); this.deletedObjects.Add(targetResource); IList resourceSetList = this.GetResourceSetEntities(resourceSetName); this.DeleteAllReferences(targetResource); this.pendingChanges.Add(delegate { resourceSetList.Remove(targetResource); }); }
/// <summary> /// Sets the value of the given reference property on the target object /// </summary> /// <param name="targetResource">target object which defines the property</param> /// <param name="propertyName">name of the property whose value needs to be updated</param> /// <param name="propertyValue">value of the property</param> public virtual void SetReference(object targetResource, string propertyName, object propertyValue) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); if (propertyValue != null) { UpdatableToken.AssertIsToken(propertyValue, "propertyValue"); } // Note that we don't support bi-directional relationships so we only handle the one resource reference property in isolation. // Our reference properties are just like normal properties we just set the property value to the new value // we don't perform any special actions for references. // So just call the SetValue which will do exactly that. this.SetValue(targetResource, propertyName, propertyValue); }
/// <summary> /// Sets the value of the given property on the target object /// </summary> /// <param name="targetResource">target object which defines the property</param> /// <param name="propertyName">name of the property whose value needs to be updated</param> /// <param name="propertyValue">value of the property</param> public virtual void SetValue(object targetResource, string propertyName, object propertyValue) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); var token = UpdatableToken.AssertIsToken(targetResource, "targetResource"); targetResource = token.Resource; // note that propertyValue might be a token itself, but GetValue will simply return whatever is stored in the token token.PendingPropertyUpdates[propertyName] = propertyValue; // Add a pending change to modify the value of the property this.pendingChanges.Add(() => { Type t = targetResource.GetType(); PropertyInfo pi = t.GetProperty(propertyName); ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", propertyName, targetResource.GetType().Name); string entitySetName = this.ReflectionMetadataHelper.FindSetNameForType(t); object generatedValue; if (this.TryGetStoreGeneratedValue(entitySetName, GetResourceTypeFullName(t), propertyName, out generatedValue)) { propertyValue = generatedValue; } if (this.IsCollectionProperty(pi)) { ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null"); var enumerable = propertyValue as IEnumerable; ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable"); this.SetCollectionPropertyValue(targetResource, pi, enumerable); } else { propertyValue = UpdatableToken.ResolveIfToken(propertyValue); pi.SetValue(targetResource, propertyValue, null); } }); }
/// <summary> /// Sets the concurrencyValues /// </summary> /// <param name="resourceCookie">The resource to be evaluated</param> /// <param name="checkForEquality">Determines whether to apply the equality check or not</param> /// <param name="concurrencyValues">The concurrency values to compare against</param> public virtual void SetConcurrencyValues(object resourceCookie, bool?checkForEquality, IEnumerable <KeyValuePair <string, object> > concurrencyValues) { ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie"); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 417, "Missing concurrency token for update operation"); ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false"); ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues"); // If-Match: * if (!concurrencyValues.Any()) { return; } resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie"); Dictionary <string, object> etags = this.GetConcurrencyValues(resourceCookie); bool matches = CompareETagValues(etags, concurrencyValues); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(matches, 412, "Concurrency tokens do not match"); }
public virtual object ResetResource(object resource) { ExceptionUtilities.CheckArgumentNotNull(resource, "resource"); UpdatableToken token = UpdatableToken.AssertIsToken(resource, "resource"); resource = token.Resource; token = new UpdatableToken(resource); object newInstance = Activator.CreateInstance(resource.GetType()); ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", new object[] { resource.GetType().Name }); foreach (string propertyToReset in this.MetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType()))) { PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset); ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", new object[] { propertyToReset }); object newValue = pi.GetValue(newInstance, null); this.pendingChanges.Add(delegate { pi.SetValue(resource, newValue, null); }); token.PendingPropertyUpdates[propertyToReset] = newValue; } return(token); }
public virtual object GetValue(object targetResource, string propertyName) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource"); if (token.PendingPropertyUpdates.ContainsKey(propertyName)) { return(token.PendingPropertyUpdates[propertyName]); } targetResource = token.Resource; PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name }); object value = pi.GetValue(targetResource, null); if ((value != null) && (pi.PropertyType.Assembly == base.GetType().Assembly)) { ExceptionUtilities.Assert(!this.MetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", new object[] { pi.PropertyType.FullName, propertyName }); value = new UpdatableToken(value); } return(value); }
/// <summary> /// Delete the given resource /// </summary> /// <param name="targetResource">resource that needs to be deleted</param> public virtual void DeleteResource(object targetResource) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource"); string resourceSetName = this.GetResourceSetOfTargetResource(targetResource); ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete"); this.deletedObjects.Add(targetResource); IList resourceSetList = this.GetResourceSetEntities(resourceSetName); // Remove any any references this target resource has this.DeleteAllReferences(targetResource); // Add a pending change to remove the resource from the resource set this.pendingChanges.Add(() => { resourceSetList.Remove(targetResource); }); }
private UpdatableToken InstantiateResourceType(string fullTypeName) { Type t = this.ReflectionMetadataHelper.FindClrTypeByFullName(fullTypeName); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!t.IsAbstract, 400, "Cannot create resource because type \"{0}\" is abstract", t.FullName); var instance = Activator.CreateInstance(t); var token = new UpdatableToken(instance); foreach (var p in t.GetProperties().Where(p => p.CanWrite)) { // make local variable so that lambdas below work var property = p; if (this.IsCollectionProperty(property)) { Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name); if (collectionType != null) { var newCollection = Activator.CreateInstance(collectionType); token.PendingPropertyUpdates[property.Name] = newCollection; this.pendingChanges.Add(() => property.SetValue(instance, newCollection, null)); } } string entitySetName = this.ReflectionMetadataHelper.FindSetNameForType(t); object generatedValue; if (this.TryGetStoreGeneratedValue(entitySetName, fullTypeName, property.Name, out generatedValue)) { token.PendingPropertyUpdates[property.Name] = generatedValue; this.pendingChanges.Add(() => property.SetValue(instance, generatedValue, null)); } } return(token); }
public virtual object ResolveResource(object resource) { ExceptionUtilities.CheckArgumentNotNull(resource, "resource"); return(UpdatableToken.AssertIsTokenAndResolve(resource, "resource")); }
/// <summary> /// Sets the value of a collection property /// </summary> /// <param name="targetResource">The resource to set the value on</param> /// <param name="propertyInfo">The property to set</param> /// <param name="propertyValue">The collection value</param> protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo"); ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue"); Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name); ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property"); object collection; // need to go through the enumerable and resolve any tokens propertyValue = propertyValue.Cast <object>().Select(o => UpdatableToken.ResolveIfToken(o)); // Algorithm for setting a collection value: // - Get a collection of the correct instance type // - Look for a constructor that takes a non-generic IEnumerable, if one is found invoke it // - If the type is generic // - look for a constuctor taking IEnumerable<T>, if one is found invoke it // - look for an Add method taking T, if one is found use default constructor and add each item // - look for an untyped Add method, if one is found use default constructor and add each item // - Set the property normally, using the new collection instance var enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) }); if (enumerableConstructor != null) { // invoke the IEnumerable constructor with the property value collection = enumerableConstructor.Invoke(new object[] { propertyValue }); } else if (collectionType.IsGenericType && collectionType.GetGenericArguments().Count() == 1) { // determine the element type var typeArgument = collectionType.GetGenericArguments().Single(); // look for a constructor taking IEnumerable<T> var typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable <>).MakeGenericType(typeArgument) }); if (typedEnumerableConstructor != null) { // convert the IEnumerable into IEnumerable<T> using Enumerable.Cast var typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(typeArgument).Invoke(null, new object[] { propertyValue }); // invoke the constructor collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable }); } else { // look for an Add method accepting T var typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument }); // for generic types, we must find either a constructor or an Add method ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName); // create a new instance, and add each item collection = Activator.CreateInstance(collectionType); foreach (var element in propertyValue) { typedAddMethod.Invoke(collection, new object[] { element }); } } } else { // look for an Add method var addMethod = collectionType.GetMethod("Add"); // fail if no method is found ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName); // create a new instance and add each item collection = Activator.CreateInstance(collectionType); foreach (var element in propertyValue) { addMethod.Invoke(collection, new object[] { element }); } } // set the new collection instance as the value propertyInfo.SetValue(targetResource, collection, null); }