Thursday, April 22, 2021

Dependency injection for background task

Recently I faced a requirement where from a method I needed to call an independent background task.  Below is a snippet

public Task Handler()
{
    ... do something
    ... BackgroundTask()
    ... do something
}

The challenge that was encountered is that the background task was required to make use of objects  which were instantiated within the constructor of the class via dependency injection.

public class MyService
{
    private readonly IMediator mediator;
    public MyService(IMediator mediator)
    {
        this.mediator = mediator;
    }
}

The background task was required to make use of the mediator object.  However upon running this code, I started experiencing Cannot access a disposed object.

To overcome this problem what was required is to created a scoped object within the background job.  Hence we made use of the IServiceScopeFactory which would help in instantiating an object for the required service within the scope of the background task.

public class MyService
{
    private readonly IMediator mediator;
    private readonly IServiceScopeFactory scopeFactory;
    public MyService(IMediator mediator, IServiceScopeFactory scopeFactory)
    {
        this.mediator = mediator;
        this.scopeFactory = scopeFactory;
    }
    public void BackgroundTask()
    {
        using var scope = scopeFactory.CreateScope();
        var scopedMediator = scope.ServiceProvider.GetRequiredService<IMediator>();
        ... etc
    }
}

Friday, April 9, 2021

Query retrieval optimization tips for ElasticSearch

When retrieving data from ElasticSearch, one approach to do this is via the following code.

var request = new SearchRequest<Document>(indexName);
var response = await elasticClient.SearchAsync<Document>(request);

Should the document structure be something similar to the following, upon running the above search request the response would include all data persisted and map it to all the provided properties.

public class Document 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Tag> Tags { get; set; }
}

Optimizing retrieval by excluding unwanted properties

There might be instances where we would need only specific data within this structure.  On can just remove the undesired properties from the Document class.  Though this would present the user with only the set of wanted properties, performance wise it wouldn't have any benefits.  This is because ElasticSearch would still return all the persisted data.  The exclusion of the data would be just happening during the process when mapping the result to our structure.

To improve the performance by avoiding bulk and useless network traffic from the ElasticSearch server, we can optimize the search request to exclude unwanted properties. This can be achieved via the following code.

var request = new SearchRequest<Document>(documentsIndexName)
{
      Source = new SourceFilter { Excludes = "tags" }
};

Using the above search request, we would be instructing ElasticSearch to exclude the tags properties from the response.  Hence, the result sent by ElasticSearch would consist of the properties Id and Name.


Optimizing retrieval by including wanted properties

There might be instances that instead of excluding data, it would easier to define the set of wanted properties.  This can be achieved via the following code.

var request = new SearchRequest<Document>(documentsIndexName)
{
      Source = new SourceFilter { Includes = "Name" }
};

Using the above search request, we would be instructing ElasticSearch to include only the Name property.  All other properties would be set as null.

Thursday, April 8, 2021

Improve lists debugging in Visual Studio

How many times we needed to debug code related to lists?  Visual Studio watches and inspect end up showing us this kind of information (ie data types).  We then end up having to expand each element to analyze its contents.


It would help that instead of showing the data type the user gets presented with some meaningful information.  To override this information a developer can make use of DebuggerDisplay attribute and include any custom information that he would like to see.


During debugging the developer will be shown this information.  Should the user view all the properties within the element, he can then expand as per normal procedure.


We can further improve the above by removing the quotation marks.  This can be achieved by including the following.