Fork me on GitHub

Fluent rules Edit on GitHub


The mapping configuration for a specific type can be defined as a method in any class.


    public class FluentRules
    {
        public void Map(ITypeMappingConfigurator<Customer> map)
        {
            map.Exclude(x => x.Password);
            map.Include(x => x.Name);
            map.Include(x => x.Identifier, o => o.AsPrimaryKey());
        }
    }

Any object containing fluent rules must be returned from the FluentRuleObjects property of your configuration class to be considered:

Pomona will scan fluent rule objects and look for methods taking one argument of type ITypeMappingConfigurator<T>. A rule methods will be applied to T and all subtypes of T.


    public class Configuration : PomonaConfigurationBase
    {
        public override IEnumerable<object> FluentRuleObjects
        {
            get { yield return new FluentRules();}
        }
    }

Type options

Type options are defined through the ITypeMappingConfigurator<T> interface.

Rules specified using ITypeMappingConfigurator<T> can either be chained, or split up in multiple declarations.

Ignoring properties

A property can be ignored and hidden from the exposed resource by using the Exclude method.


        public void ExcludeRule(ITypeMappingConfigurator<Customer> customer)
        {
            customer.Exclude(x => x.Password);
        }

Selecting handler

A handler class can be chosen for a resource type by using the HandledBy<T> method.


        public void HandlerRule(ITypeMappingConfigurator<Customer> customer)
        {
            customer.HandledBy<CustomerHandler>();
        }

You can find out more about this in Resource handlers

Treating type as a value object

We can treat a complex type as a value object, as opposed to a resource. A value object can be a part of resource or another value object, and has no URI.


        public void ValueObjectRule(ITypeMappingConfigurator<Customer> customer)
        {
            customer.AsValueObject();
        }

You can learn more about value types in Contributors guide

Custom construction of object

When Pomona needs to instantiate a resource or value object type during deserialization, it uses the empty constructor by default if available.

If we want to instantiate the object using a non-empty constructor or a method taking parameters, we can use the ConstructedUsing method.


        public void ConstructedUsingRule(ITypeMappingConfigurator<Customer> customer)
        {
            customer.ConstructedUsing(c => new Customer(c.Requires().Name, c.Optional().Password));
        }

The ConstructedUsing method accepts an Expression<Func<IConstructorControl<TDeclaringType>, TDeclaringType>> argument.

The IConstructorControl<T> parameter can then be used to bind properties with any corresponding parameters.

Constructor context

If we need to access some service while instantiating a type we can use the Context<T>() method of IConstructorControl<T>.


        public void ContextfulConstructionRule(ITypeMappingConfigurator<Customer> customer)
        {
            customer.ConstructedUsing(
                c => c.Context<ICustomerFactory>()
                      .CreateCustomer(c.Requires().Name, c.Optional().Password));
        }

Specifying plural name of type

Pomona will try to derive the plural name of a type by using a few simple rules, which works for a majority of English words.

This value is used to generate the URI for a root resource collection type.


        public void PluralNameRule(ITypeMappingConfigurator<Mouse> mouse)
        {
            mouse.WithPluralName("Mice");
        }

Property options

We can change how a property will be exposed by using the Include method of ITypeMappingConfigurator with an options lambda argument specified.

Changing exposed name of property

To use a different name for a property when exposed you can use Named method.


        public void IncludePropertyNamed(ITypeMappingConfigurator<Customer> customer)
        {
            customer.Include(x => x.Identifier, x => x.Named("Id"));
        }

Using custom accessors

By using the following methods we can change how a property is accessed.

  • OnGet: Used when serializing from resource
  • OnSet: Used when deserializing to resource
  • OnQuery: For building LINQ queries, usually for properties not recognized by underlying LINQ provider

        public void IncludePropertyWithCustomAccessors(ITypeMappingConfigurator<Customer> customer)
        {
            customer
                .Include(x => x.Name, x => x
                    .OnGet(y => y.Name.ToUpper())
                    .OnSet((c, v) => c.Name = v.ToLower())
                    .OnQuery(y => y.Name.ToUpper()));
        }

Expand

We can use Expand to configure whether, and how, resource(s) referenced by properties are included when serializing. It takes one parameter of type ExpandMode, which can have the following values:

  • ExpandMode.Full: For properties pointing to a single resource, it means expand that resource. For properties having a list of resources this means expand the list itself and every item.
  • ExpandMode.Shallow: Expands as list of references to resources. Only applicable to properties having a collection of resources.

        public void ExpandProperty(ITypeMappingConfigurator<Customer> customer)
        {
            customer
                .Include(x => x.Address, x => x.Expand(ExpandMode.Full));
        }