How to Ignore Properties in OData at Runtime

The goal is to ignore the “PropertyName” while building the ODataConventionModelBuilder at runtime using late-binding.

We can have an arbitrary number of classes or domain names and an arbitrary number of properties that we want to ignore dynamically. 

This can be achieved without writing a multitude of fragile if-else cases by using the following code:

public class OdataIgnoreProperty
{
    public string DomainName { get; set; }
    public string PropertyName { get; set; }
}

In the GetDataSet() method, you have the flexibility to customize the logic according to your specific requirements. If you need to retrieve data from a database, you can replace the existing logic with a SQL query. This allows you to tailor the data retrieval process to suit your needs.

public List<OdataIgnoreProperty> GetDataSet()
{
    // Dynamically replace the OdataIgnoreProperty as per your need
    return new List<OdataIgnoreProperty>
    {
        new OdataIgnoreProperty { DomainName = "Product", PropertyName = "Name" },
        new OdataIgnoreProperty { DomainName = "Product", PropertyName = "Value" },
        new OdataIgnoreProperty { DomainName = "Transporter", PropertyName = "Name" },
        new OdataIgnoreProperty { DomainName = "Transporter", PropertyName = "Tpye" },
        new OdataIgnoreProperty { DomainName = "Transporter", PropertyName = "Address" },
    };
}    

When constructing the ODataConventionModelBuilder, we will define the conventions that the OData service will follow. 

By integrating this code, you can ensure that the model builder is correctly configured i.e, Entities with Ignored Properties.

Remember, the logic you use can greatly influence the performance and functionality of your OData service, so choose it carefully.

var builder = new ODataConventionModelBuilder();

// get the properties to ignore
var getPropertiesToIgnore = GetDataSet();

var ignoreProperties = getPropertiesToIgnore.GroupBy(x => x.DomainName).Select(x => x.Key, PropertyName = x.Select(y => y.PropertyName));

foreach(var ignoreProperty in ignoreProperties)
{
    var entityType = GetType(ignoreProperty.DomainName);
    var method = builder.GetType().GetMethod("EntityType");
    
    // Invoking Entity<TEntity>() method dynamically
    var entityBuilder = method.MakeGenericMethod(entityType).Invoke(builder, null);
    
    if(entityBuilder != null)
    {
        var entityProperties = entityType.GetProperties();
        
        //Get the type of the Entity
        var entityBuilderType = entityBuilder.GetType();
        var ignoreMethod = entityBuilderType.GetMethod("Ignore");
        
        // From properties I want a particular Property to Ignore
        var singleProperty = entityProperties.FirstOrDefault(p => p.Name == property);
        if(singleProperty != null)
        {
            Type singlePropertyType = GetType(singleProperty.PropertyType.FullName);
            
            // Create a parameter expression for the entity type 
            var parameter = Expression.Parameter(entityType, "x");
            
            // Create a Property access expression for the current property 
            var propertyAccess = Expression.Property(parameter, property);
            
            // Create a lambda expression representing the property access
            var lambda = Expression.Lambda(propertyAccess, parameter);

            // Make the generic Ignore method with the correct type 
            var genericIgnoreMethod = ignoreMethod.MakeGenericMethod(singleProperty.PropertyType);
            
            // Invoke the Ignore method using the lambda expression as a argument
            genericIgnoreMethod.Invoke(entityBuilder, new object[] { lambda });
        }
    }
}
Build(builder);


private Type GetType(string typeName){
    var type = Type.GetType(typeName);
    if(type != null)return type;
    foreach(var a in AppDomain.CurrentDomain.GetAssemblies()){
        type = a.GetType(typeName);
            if(type != null)
                return type;
    }
    return null;
}