JamesNK / Newtonsoft.Json.Schema

Json.NET Schema is a powerful, complete and easy to use JSON Schema framework for .NET
http://www.newtonsoft.com/jsonschema
Other
247 stars 107 forks source link

JSchemaGenerationProvider for MemberProperty not executed if annotation exists on metadatatype buddy class #327

Open JeffBarnard opened 11 months ago

JeffBarnard commented 11 months ago

I want to use a custom JSchemaGenerationProvider to add some properties that aren't supported out of the box, such as "readOnly".

I am using ef-core database first tools to generate portable POCO classes. I am then extending these classes by adding 'buddy classes' to annotate them for the validation rules.

    public partial class Model 
    {
        public string Name { get; set; }
    }

    [MetadataType(typeof(IModelMeta))]   
    public partial class Model : IModelMeta
    {

    }

    public interface IModelMeta
    {
        [JSchemaGenerationProvider(typeof(CustomSchemaProvider))]        
        [ReadOnly(true)] // "readOnly": true   
        string Name { get; set; }
    }

In the above example, my CustomSchemaProvider is not executed.

Even if I do not use an interface and use a local class instead, it still does not work:

[MetadataType(typeof(ModelMeta))]   
public partial class Model
{
    public class ModelMeta
    {
        [JSchemaGenerationProvider(typeof(CustomSchemaProvider))]
        [ReadOnly(true)] // "readOnly": true   
        public string Name { get; set; }

It only works if I move the annotation to the origin class definition, but I cannot do this because my base partial POCO classes are generated by tooling (efpt).

JeffBarnard commented 11 months ago

I have other code that detects metadata attributes and it basically looks like this:

var metadataType = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true)
 .OfType<MetadataTypeAttribute>().FirstOrDefault();

if (metadataType != null) 
{
    PropertyInfo[] properties = metadataType.MetadataClassType.GetProperties(BindingFlags.Public | ...);

Perhaps there is a workaround, a method that I could override to fetch the metadata properties, then I could apply a similar technique there.

JeffBarnard commented 11 months ago

When using the .net ValidationContext to validate our objects, the metadata classes need to be registered in order for that api to detect them. I don't know why they require us to do this, but perhaps this is a useful reference:

foreach (MetadataTypeAttribute attrib in type.GetCustomAttributes(typeof(MetadataTypeAttribute), true))
{
    System.ComponentModel.TypeDescriptor.AddProviderTransparent(
        new AssociatedMetadataTypeTypeDescriptionProvider(type, attrib.MetadataClassType), type);
}