Active Query Builder support area

Configuring custom state storage provider to use Active Query Builder in a web farm

Last modified:


By default, Active Query Builder depends on the Session mechanism to save the client's state. You can avoid this dependency in the Corporate version of AQB ASP.NET Edition

Using it, you can store the client state wherever you want: in a database like SQLite, in-memory storage like Redis, and even on the client-side if you want to have a stateless server.

The Corporate.sln demo solution includes code samples for all of the abovementioned cases. It's included in the installation package and available on GitHub for both ASP.NET Core and .NET Framework.

You can redefine the storage provider with your own implementation of IQueryBuilderProvider interface which is defined as follows:

public interface IQueryBuilderProvider
{
    QueryBuilder Get(string id);
    void Put(QueryBuilder qb);
    void Delete(string id);
}

Then you can replace the default SessionQueryBuilderProvider with your own during the application startup.

The following pieces of code illustrate the usage of Redis to store the state in a Load-balanced multi-server (web farm) environment. 

Classic ASP.NET 

public class MvcRazor : HttpApplication
{
    protected void Application_Start()
    {
            /*...*/
            QueryBuilderStore.Provider = new QueryBuilderRedisStoreProvider();
    }
}

ASP.NET Core

Modify the "Startup.cs" file by adding the following directives:

public class Startup
{
    // ...
    
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddScoped<IQueryBuilderProvider, QueryBuilderRedisStoreProvider>();

        // ...
    }

The state of the query in the QueryBuilder object can be serialized and deserialized using just one LayoutSQL property. Redefine the Get, Put, and Delete methods in your storage provider.

Also, one additional step should be taken: before deserializing the query state, you must fill the MetadataContainer from the XML file. Using the live database connection is highly unrecommended in this mode.

The following implementation lets store the component's state in Redis:

using StackExchange.Redis;

public class QueryBuilderRedisStoreProvider : IQueryBuilderProvider
{
    public bool SaveState { get; }

    private readonly IDatabase _db;

    public QueryBuilderRedisStoreProvider()
    {
        SaveState = true; 
        // This flag prescribes to save state to the storage after performing some manipulations with the object.
        // It must be set to true when the object state is saved in the storage unlike a situation when you are working with the reference to an instance in the storage.

        var redis = ConnectionMultiplexer.Connect();
        _db = redis.GetDatabase();
    }

    public QueryBuilder Get(string id)
    {
        var qb = new QueryBuilder(id)
        {
            SyntaxProvider = new MSSQLSyntaxProvider();
        }; 

        // loading metadata from the pre-generated XML string resource.
        qb.MetadataContainer.XML = Resources.MetadataXML; 

        var layout = _db.StringGet(id);

        // loading the query state from the storage
        if (layout.HasValue)
            qb.LayoutSQL = layout;

        return qb;
   }

   public void Put(QueryBuilder qb)
   {
        // saving the query state to the storage
        _db.StringSetAsync(qb.Tag, qb.LayoutSQL);
   }

   public void Delete(string id)
   {
        _db.StringSetAsync(id, "");
   }
}

 


Is this article helpful for you?