Thursday, August 13, 2020

Performance: Linking a List of Child Objects To a List of Parent Objects

Many a time I've had to build a relationship where a parent object has a list of child objects linked to it, where the parent itself also belongs to a list. There are many ways of doing this, however, the most performant way I've found is to use an extension on the Enumerable class; ToLookup. Lets say we have a list of parent objects and a list of child objects, and that we need to link to each parent all its children. Parent Object:
public class Parent
{
    public long Identifier { get; set; }

    public List Children { get; set; } = new List();

    public Parent(long identifier)
    {
        this.Identifier = identifier;
    }
}
Child Object:
public class Child
{
    public long Identifier { get; set; }

    public long ParentIdentifier { get; set; }

    public Child(long identifier, long parentIdentifier)
    {
        this.Identifier = identifier;
        this.ParentIdentifier = parentIdentifier;
    }
}
We will assume we have some code that gets us a large list of parents and a large list of children to link to the parents. Each parent has an average of 25 children, some could have no children, some could have more than 25.
List parents = GetParents().ToList(); // 15,000 parents
List children = GetChildren().ToList(); // 300,000 children.
Typically, I would loop through the parents and do a search of the children for any that have a corresponding parent id.
foreach (var parent in parents)
{
    parent.Children = children.Where(d => d.ParentIdentifier == parent.Identifier).ToList();
}
While this method of linking the children to the parents is straightforward, and works fine for small data sets, it really hits the wall on a large dataset; such as our example. The above method takes an average of 88 seconds to complete the linking. We can do better. Lets use the Enumerable.ToLookup instead. We will use ToLookup to build a dictionary of the children grouped by the parent. Then its a simple retrieval of the children for a given parent.
var childrenLookup = children.ToLookup(d => d.ParentIdentifier);

foreach (var parent in parents)
{
    parent.Children = childrenLookup[parent.Identifier].ToList();
}
Using the ToLookup knocks our average linking time down to 0.08 seconds! That's a 99% performance increase!

SQL Server Profiler - Just My Queries

To record only the actions you are performing, and not everything else from all the other users and services, simply add a filter for the ClientProcessID.

Trace File Properties:
 - Column Filters
     - ClientProcessID
         - Set the value to the your clients process.

Monday, March 2, 2020

Read WCF Service Web.config Sections and Values

Get the Web.Config contents as a Configuration object.
private static Configuration GetWebConfig()
{
    var vdm = new VirtualDirectoryMapping(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, true);
    var wcfm = new WebConfigurationFileMap();
    wcfm.VirtualDirectories.Add("/", vdm);

    var webConfig = WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");

    return webConfig;
}
Get a value from the appSettings section.
public static string GetConfigurationValue(string keyName)
{
    string value = null;

    var webConfig = GetWebConfig();

    if (webConfig.AppSettings.Settings.Count > 0)
    {
        var setting = webConfig.AppSettings.Settings[keyName];
        if (setting != null)
        {
            value = setting.Value;
        }
    }

    return value;
}
Get a specific binding.
public static Binding ResolveBinding(string name)
{
    var section = GetBindingsSection();
    var nameLower = name.ToLower();

    foreach (var bindingCollection in section.BindingCollections.Where(collection => collection.ConfiguredBindings.Any()))
    {
        var bindingElement = bindingCollection.ConfiguredBindings.FirstOrDefault(element => element.Name.ToLower() == nameLower);
        if (bindingElement == null)
        {
            continue;
        }

        var binding = (Binding)Activator.CreateInstance(bindingCollection.BindingType);
        binding.Name = bindingElement.Name;
        bindingElement.ApplyConfiguration(binding);

        return binding;
    }

    var message = $"Binding with name '{name}' could not be found in the service web.config.";
    throw new FaultException(new FaultReason(message));
}
Get a specific endpoint.
public static ChannelEndpointElement ResolveClientEndpoint(string name)
{
    var section = GetClientSection();
    var nameLower = name.ToLower();

    var endpoint = section.Endpoints.OfType()
        .FirstOrDefault(e => e.Name.ToLower() == nameLower);

    if (endpoint != null)
    {
        return endpoint;
    }

    var message = $"Client endpoint with name '{name}' could not be found in the service web.config.";
    throw new FaultException(new FaultReason(message));
}
Get the Binding section.
public static BindingsSection GetBindingsSection()
{
    var webConfig = GetWebConfig();
    var bindingSection = ServiceModelSectionGroup.GetSectionGroup(webConfig)?.Bindings;

    if (bindingSection != null)
    {
        return bindingSection;
    }

    const string message = "The service web.config is missing the bindings section.";
    throw new FaultException(new FaultReason(message));
}
Get the Client section.
public static ClientSection GetClientSection()
{
    var webConfig = GetWebConfig();
    var clientSection = ServiceModelSectionGroup.GetSectionGroup(webConfig)?.Client;

    if (clientSection != null)
    {
        return clientSection;
    }

    const string message = "The service web.config is missing the client section.";
    throw new FaultException(new FaultReason(message));
}

Performance: Linking a List of Child Objects To a List of Parent Objects

Many a time I've had to build a relationship where a parent object has a list of child objects linked to it, where the parent itself als...