private void EnforceMutability(Operation operation, JsonPatchProperty patchProperty) { IScimTypeAttributeDefinition attrDefinition; var typeDefinition = _ServerConfiguration.GetScimTypeDefinition(patchProperty.Parent.GetType()); var propertyInfo = patchProperty.Property.DeclaringType.GetProperty(patchProperty.Property.UnderlyingName); // if attribute is readOnly OR (immutable and isReferenceType and current value is not null) if (typeDefinition != null && typeDefinition.AttributeDefinitions.TryGetValue(propertyInfo, out attrDefinition) && (attrDefinition.Mutability == Mutability.ReadOnly || (attrDefinition.Mutability == Mutability.Immutable && !attrDefinition.AttributeDescriptor.PropertyType.IsValueType && patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent) != null))) { throw new ScimPatchException( ScimErrorType.Mutability, operation); } }
protected override IList <JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { var serializableMembers = GetSerializableMembers(type).Cast <PropertyInfo>(); if (serializableMembers == null) { throw new JsonSerializationException("Null collection of seralizable members returned."); } var typeDefinition = _ServerConfiguration.GetScimTypeDefinition(type); var propertyCollection = new JsonPropertyCollection(type); foreach (var member in serializableMembers) { var property = CreateProperty(member, memberSerialization); if (property != null) { var state = _InstanceState; var propertyNameTable = state.NameTable; bool lockTaken = false; try { Monitor.Enter(propertyNameTable, ref lockTaken); property.PropertyName = state.NameTable.Add(property.PropertyName); IScimTypeAttributeDefinition attributeDefinition; if (typeDefinition != null && typeDefinition.AttributeDefinitions.TryGetValue(member, out attributeDefinition)) { // Internal json.net deserialization logic will hit the ShouldDeserialize delegate before checking property.Writable // Still, we'll set Writable to accurately reflect this property.Writable = attributeDefinition.Mutability != Mutability.ReadOnly; // deserializable? // setting property.Readable will shortcut the ShouldSerialize delegate // INTERNAL JSON.NET LOGIC // if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value)) property.Readable = attributeDefinition.Mutability != Mutability.WriteOnly; // serializable? // Only attach a conditional deserialization delegate if the attribute is not ReadWrite. if (attributeDefinition.Mutability != Mutability.ReadWrite) { property.ShouldDeserialize = o => { if (attributeDefinition.Mutability == Mutability.ReadOnly) { return(false); } return(true); }; } // Only attach a conditional serialization delegate if the attribute is not Always returned. if (attributeDefinition.Returned != Returned.Always) { var existingShouldSerializeFunc = property.ShouldSerialize; property.ShouldSerialize = o => { if (attributeDefinition.Mutability == Mutability.WriteOnly || attributeDefinition.Returned == Returned.Never) { return(false); } var httpMethod = AmbientRequestService.HttpMethod; if (attributeDefinition.Returned == Returned.Default || (attributeDefinition.Returned == Returned.Request && (httpMethod == HttpMethod.Post || httpMethod == _Patch || httpMethod == HttpMethod.Put))) { var queryOptions = AmbientRequestService.QueryOptions; if (queryOptions.Attributes.Any() && !queryOptions.Attributes.Contains(property.PropertyName)) { return(false); } if (queryOptions.ExcludedAttributes.Any() && queryOptions.ExcludedAttributes.Contains(property.PropertyName)) { return(false); } } if (existingShouldSerializeFunc != null) { return(existingShouldSerializeFunc(o)); } return(true); }; } } } finally { if (lockTaken) { Monitor.Exit(propertyNameTable); } } propertyCollection.AddProperty(property); } } return(propertyCollection.OrderBy(p => p.Order ?? -1).ToList()); }