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());
        }