Fork me on GitHub

Generated client Edit on GitHub


Pomona can generate a .NET compatible client for our service if desired.

A client NuGet package can be generated and downloaded by accessing the /client.nupkg url on the service.

Alternatively the DLL can be downloaded directly from /{ClientAssembly}.dll, where {ClientAssembly} must be replaced with the configured name of the client dll (see below for this).

Controlling client generation

Metadata

By overriding the ClientMetadata property of a ITypeMappingFilter, we can change the assembly name, interface name, type name and namespace of the client.


        public override ClientMetadata ClientMetadata =>
            base.ClientMetadata.With(
                assemblyName : "Critters.Client",
                name : "CritterClient",
                interfaceName : "ICritterClient",
                @namespace : "Critters.Client");

Merged assembly

By returning true from the GenerateIndependentClient() method of ITypeMappingFilter we can generate an assembly with Pomona.Common.dll merged.

Note that the resulting assembly will still have a dependency on Newtonsoft.Json.

LINQ support

As the IQueryable interface by nature is a leaky abstraction, supporting all queries is not practical.

Common use cases should however be supported, although sometimes with a bit of Expression acrobatics.

Simple queries

Simple non-aggregate queries must be structured in a way described in the example below:


client.Weapons
      .Query()
      .Where(x => x.Price > 100.0m /* any number of where expressions */)
      .Select(x => x.Model /* any number of select expressions */)
      .Where(x => x.Name.StartsWith("NERF") /* where and select expressions can be mixed */)
      .OrderBy(x => x.Name /* ordering must come after where and select */)
      .Skip(50 /* skip after order by */)
      .Take(50 /* take after skip */)
      .ToList();

Group by queries

Aggregate queries must be structured in a way described in the example below:


client.Weapons
        .Query()
        .Where(x => x.Price > 100.0m /* any number of where expressions */)
        .GroupBy(x => x.Model.Name /* group by after where */)
        .Select(x => new { modelName = x.Key, totalPrice = x.Sum(y => y.Price) })
        .OrderBy(x => x.totalPrice)
        .ToList();

Supported expressions

A few of the supported methods are listed here

  • Operators: + - / * && ||
  • String
    • .Length
    • .StartsWith(string value)
    • .Contains(string value)
    • .ToLower()
    • .ToUpper()
  • IEnumerable<T>
    • .Where(Func<,> predicate)
    • .Select(Func<,> selector)
    • .Sum()
    • .Count()

A more complete list can be found in QueryFunctionMapping.cs of the Pomona source code.

Extended resources and attributes

In some cases it is useful for resources to contain a Dictionary<string,object> to store dynamic data, which keys might only be known by the client side.

Unfortunately a .NET dictionary is not very convenient to work with in queries, and also leads to a lot of clumsy mapping code.

To simplify this Pomona makes it possible to automatically map statically typed properties to a resource dictionary by declaring the dictionary property as an attribute container.


            map.Include(x => x.Map, o => o.AsAttributes());

Now we can inherit the client generated interface, and any added properties with primitive values will automatically project to Map.


        public interface IExtendedResource : IDictionaryContainer
        {
            string CustomString { get; set; }
            string OtherCustom { get; set; }
        }

After this we can query the resource using the IExtendedResource interface, which will automatically redirect CustomString to Map["CustomString"], and OtherCustom to Map["OtherCustom"].

For more details about this feature looking at the ExtendedResourceClientTests.cs file is recommended.