Tuesday, July 15, 2014

Group by in C# and linq.js

Being a C# developer I really like and use Linq a lot. It can simplify code a great deal. So it is only natural to want the same goodness in javascript. Luckily there is a framework - linq.js - that provides this functionality. However, the syntax is not quite the same, so it takes a little getting used to.

In this post I want to show an example of how to do a group by.

I have a bunch of people in a collection, each person defined by name, age and job. Now I want to group these people by job. The result should be a grouped collection, where each group contains the person objects belonging to a specific job.

In C# it looks something like this:

var people = new[] {
    new { Name = "Carl", Age = 33, Job = "Tech" },
    new { Name = "Homer", Age = 42, Job = "Tech" },
    new { Name = "Phipps", Age = 35, Job = "Nurse" },
    new { Name = "Doris", Age = 27, Job = "Nurse" },
    new { Name = "Willy", Age = 31, Job = "Janitor" }
};

var grouped = people.GroupBy(
    person => person.Job,
    (job, persons) => new { Job = job, Persons = persons });

foreach (var group in grouped)
{
    System.Diagnostics.Debug.WriteLine("job: " + group.Job);
    foreach (var person in group.Persons)
    {
        System.Diagnostics.Debug.WriteLine("   name: {0}, age: {1}, job: {2}",
            person.Name,
            person.Age,
            person.Job);
    }
}

The group by statement is fairly simple, and the output is exactly as expected:

job: Tech
   name: Carl, age: 33, job: Tech
   name: Homer, age: 42, job: Tech
job: Nurse
   name: Phipps, age: 35, job: Nurse
   name: Doris, age: 27, job: Nurse
job: Janitor
   name: Willy, age: 31, job: Janitor

The same thing in linq.js is a little bit more involved, and for me it did take some playing around before I ended up with the code below. But basically it is quite similar to the C# version.

var people = [
    { name: "Carl", age : 33, job: "Tech" },
    { name: "Homer", age : 42, job: "Tech" },
    { name: "Phipps", age : 35, job: "Nurse" },
    { name: "Doris", age: 27, job: "Nurse" },
    { name: "Willy", age: 31, job: "Janitor" }
];

var grouped = Enumerable
    .From(people)
    .GroupBy(
        function (person) { return person.job; }, // Key selector
        function (person) { return person; },     // Element selector
        function (job, grouping) {                // Result selector
            return {
                job: job,
                persons: grouping.source
            };
        })
    .ToArray();

alert(JSON.stringify(grouped));

And the result:

[{
    "job": "Tech",
    "persons": [{
        "name": "Carl",
        "age": 33,
        "job": "Tech"
    },
    {
        "name": "Homer",
        "age": 42,
        "job": "Tech"
    }]
},
{
    "job": "Nurse",
    "persons": [{
        "name": "Phipps",
        "age": 35,
        "job": "Nurse"
    },
    {
        "name": "Doris",
        "age": 27,
        "job": "Nurse"
    }]
},
{
    "job": "Janitor",
    "persons": [{
        "name": "Willy",
        "age": 31,
        "job": "Janitor"
    }]
}]

Disabling WebDAV in a Sitecore web application

As the trends for web applications moves towards more heavy clients, it puts new demands on how to structure the web application, e.g. it is now quite common to let the client handle the complexities of user interface functionality, and then just call the server for querying raw data. This could be done using ajax calls to query RESTful WebApi services for data. Javascript on the client will then handle processing and presentation of the data.

Now, RESTful web APIs with any self-respect will want to use common HTTP verbs, such as GET, POST, PUT, DELETE etc. But for Sitecore web applications hosted in IIS this turns out to be a problem. And the problem is called WebDAV. WebDAV takes over HTTP verbs like PUT and DELETE, so they cannot be used in, for example, a WebApi controller. In many situations WebDAV is not really needed by a Sitecore web application, but apparently it is enabled by default. And while it may not actually be enabled on the IIS, default Sitecore web.config somehow enables it anyway, at least enough to cause problems.

Disabling WebDAV in a Sitecore web application can be a bit tricky. So here is a way to do it.

  1. Open web.config
  2. Locate the log4net appender section "WebDAVLogFileAppender" and remove it or comment it out.
  3. Locate the log4net logger section "Sitecore.Diagnostics.WebDAV" and remove it or comment it out.
  4. Under <system.webserver> locate the handlers section and replace these lines:
    <add name="WebDAVRoot" path="*" verb="OPTIONS,PROPFIND" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
    <add name="WebDAVRoot64" path="*" verb="OPTIONS,PROPFIND" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
    <add verb="*" path="sitecore_webDAV.ashx" type="Sitecore.Resources.Media.WebDAVMediaRequestHandler, Sitecore.Kernel" name="Sitecore.WebDAVMediaRequestHandler" />
    
    with:
    <remove name="WebDAV" />
    
  5. Under <system.web> locate the handlers section and replace this line:
    <add verb="*" path="sitecore_webDAV.ashx" type="Sitecore.Resources.Media.WebDAVMediaRequestHandler, Sitecore.Kernel" />
    
    with:
    <remove name="WebDAV" />
  6. Remove the Sitecore.WebDAV.config file from App_Config\Include
As far as I have been able to find out, the only thing that will be missing in Sitecore after disabling WebDAV is the so called WebDAV dialog, which is something that can be opened in the media library to make it possible to drag'n'drop media files from the file system into Sitecore.

Notes:
Procedure devised using Sitecore 7.2

AutoMapper Children Value Resolver

When exposing data to the outside world (e.g. through a service) one could easily find oneself thinking about such matters as performance and load on the wire.

We may have a scenario where we need to expose a customer service, which could be used in different scenarios, where sometimes callers just want customer master data, and at other times callers want customers with their order history. Depending on the system landscape order data may come from another system than where the customer data is stored; and these systems may perform differently, so that retrieval of customer data could be a relatively inexpensive operation, whereas retrieval of order data could be more expensive.

A common practice when creating services is to transform the entities from the domain into DTO objects, and a widely used component for this is AutoMapper. But how to get AutoMapper to deal with the scenario above?

As stated, sometimes we want to expose only customer data, and sometimes order data should be included. The domain may have been implemented as an aggregate, where a customer has a collection of orders, like this:

public class Order
{
    public Guid Id { get; set; }
    public DateTime Created { get; set; }
    public string Text { get; set; }
}

public class Customer
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public IEnumerable<order> Orders { get; set; }
}

And DTOs like this (for some reason we don't want to expose the internal IDs):

public class OrderDto
{
    public DateTime Created { get; set; }
    public string Text { get; set; }
}

public class CustomerDto
{
    public string Name { get; set; }
    public string Address { get; set; }
    public IEnumerable<Order> Orders { get; set; }
}

The data retrieval code may have been implemented with lazy load, so that order data is only queried if used. However, since AutoMapper will map the Orders collection by default, orders will be queried. So we need to modify the way customers are mapped. To that end I've devised an IValueResolver called ChildrenResolver. It is a general resolver that can be used for any child collection, and it looks like this:

public class ChildrenResolver<TSource, TMember> : IValueResolver
{
    private readonly Func<TSource, IEnumerable<TMember>> _childrenExpression;

    public ChildrenResolver(Expression<Func<TSource, IEnumerable<TMember>>> childrenExpression)
    {
        _childrenExpression = childrenExpression.Compile();
    }

    public ResolutionResult Resolve(ResolutionResult source)
    {
        bool includeChildren = false;
        if (source.Context.Options.Items.ContainsKey("IncludeChildren"))
        {
            includeChildren = (bool)source.Context.Options.Items["IncludeChildren"];
        }
        return source.New(includeChildren ? _childrenExpression.Invoke((TSource)source.Value) : null);
    }
}

The constructor takes an expression selecting the children collection member from the source entity, i.e. in our scenario it tells the resolver that we want to map the Orders property of the Customer entity. The Resolve method first looks up an options item called IncludeChildren, which is a boolean that we will set from the outside. It tells the resolver whether or not we want it to resolve the specified children collection property, and if so it returns a ResolutionResult with the children collection.

The ChildrenResolver is then used when defining a mapping, like this:

Mapper.CreateMap<Customer, CustomerDto>()
    .ForMember(dto => dto.Orders, opt => opt
        .ResolveUsing<ChildrenResolver<Customer, Order>>()
        .ConstructedBy(() => new ChildrenResolver<Customer, Order>(entity => entity.Orders)));

The mapping defines that we want to map from Customer entity to CustomerDto, and for the Orders member of the DTO we want to use the ChildrenResolver, which is instructed to grab the Orders collection of the Customer entity (this gives the flexibility of not having a one-to-one naming relationship between source and target properties.) Notice the usage of ResolveUsing is a bit more complex than typically seen. Since the ChildrenResolver takes a constructor parameter, we need to tell AutoMapper that we will handle the resolver instantiation ourselves, which we do by using ConstructedBy method.

Finally, we are ready to use the whole thing in our customer service, which may be a WebApi controller with the following method:

[Route("api/customers/{id}")]
public CustomerDto GetCustomer(Guid id, bool includeChildren = false)
{
    var customer = _customerRepository[id];
    if (customer == null)
    {
        // todo: handle if customer not found
    }

    var customerDto = Mapper.Map<CustomerDto>(customer, opts =>
    {
        opts.Items["IncludeChildren"] = includeChildren;
    });
    
    return customerDto;
}

Notice that when we do the mapping, we set the IncludeChildren options item to specify whether or not we want children collections mapped, and in this case that information comes from a service parameter.

That's it. I hope someone finds this useful :-)

Notes:
The code is based on usage of AutoMapper version 3.2.1.