public virtual async Task <IHttpActionResult> Patch([FromODataUri] TKey key, Delta <TEntity> patch, ODataQueryOptions <TEntity> options) { Validate(patch.GetInstance()); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties)) { var updateableProperties = AllowedSelectProperties.Split(',').Select(x => x.Trim()); /***************************************************************** * Example that prevents patch when invalid fields are presented * * Comment this block to passively allow the operation and skip * * over the invalid fields * * ***************************************************************/ if (patch.GetChangedPropertyNames().Any(x => updateableProperties.Contains(x, StringComparer.OrdinalIgnoreCase))) { return(BadRequest("Can only Patch the following fields: " + this.AllowedSelectProperties)); } /***************************************************************** * Passive example, re-create the delta and skip invalid fields * * ***************************************************************/ var delta = new Delta <TEntity>(); foreach (var field in updateableProperties) { if (delta.TryGetPropertyValue(field, out object value)) { delta.TrySetPropertyValue(field, value); } } patch = delta; } var itemQuery = GetEntitySet().Where(FindByKey(key)); var item = itemQuery.FirstOrDefault(); if (item == null) { return(NotFound()); } patch.Patch(item); try { await db.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!ItemExists(key)) { return(NotFound()); } else { throw; } } return(Updated(item)); }
public virtual async Task <IHttpActionResult> Post(TEntity item) { // If you are validating model state, then the POST will still need to include the properties that we don't want to allow // By convention lets consider that the value of the default fields must be equal to the default value for that type. // You may need to remove this standard validation if this.AllowedSelectProperties has a value if (!ModelState.IsValid) { return(BadRequest(ModelState)); } if (!String.IsNullOrWhiteSpace(this.AllowedSelectProperties)) { var updateableProperties = AllowedSelectProperties.Split(',').Select(x => x.Trim()); /***************************************************************** * Example that prevents patch when invalid fields are presented * * Comment this block to passively allow the operation and skip * * over the invalid fields * * ***************************************************************/ // I hate to use reflection here, instead of reflection I would use scripts or otherwise inject this logic var props = typeof(TEntity).GetProperties(); foreach (var prop in props) { if (!updateableProperties.Contains(prop.Name, StringComparer.OrdinalIgnoreCase)) { var value = prop.GetValue(item); bool isNull = false; if (prop.PropertyType.IsValueType) { isNull = value == Activator.CreateInstance(prop.PropertyType); } else { isNull = value == null; } if (isNull) { return(BadRequest("Can only PUT an object with the following fields: " + this.AllowedSelectProperties)); } } } /*********************************************************************** * Passive example, create a new object with only the valid fields set * * *********************************************************************/ var sanitized = Activator.CreateInstance <TEntity>(); foreach (var field in updateableProperties) { var prop = props.First(x => x.Name.Equals(field, StringComparison.OrdinalIgnoreCase)); prop.SetValue(sanitized, prop.GetValue(item)); } item = sanitized; } GetEntitySet().Add(item); await db.SaveChangesAsync(); return(Created(item)); }