How To: Getting events from SQL Server

Overview

Sometimes we need to execute some long-running SQL Server processes (Stored procedures or functions) and it’d be nice to get progress messages, and why not, a percent value in order to show a progress bar in our application.

In the past I’ve used different techniques to archive this, from SQL Assemblies for calling a SignalR server, to execute xp_cmdshell, and so many other esoteric ways.

None of that solved the problem in an elegant way, but well, it worked… more or less…

Changing the point of view

Today I noticed the SqlConnection class has an InfoMessage event, and it can be used for “Clients that want to process warnings or informational messages sent by the server” which is EXACTLY what I was looking for.

It looks promising but, how can I trigger an error from my SQL?

The answer is really E-A-S-Y :)

If you are a TSQL programmer you surely know RAISERROR, which generates an error message in a similar way the throw C# keyword does.

The trick here is its severity argument: It indicates the type of problem encountered by SQL Server, and values under 10 indicate that these errors are not severe. Just warnings or information that SQL server sends to anyone is listening.

And who’s listening? You can imagine…

Putting it all together (show me the code)

Let’s assume we’ve this long-running stored procedure in our database:

CREATE PROCEDURE [dbo].[TestLongRunningSP]
AS
BEGIN
RAISERROR('1) Starting', 0, 0) WITH NOWAIT;
WAITFOR DELAY '00:00:03'; --Wait for 3 seconds

RAISERROR('2) Fetching data', 0, 0) WITH NOWAIT;
WAITFOR DELAY '00:00:05'; --Wait for 5 seconds

RAISERROR('3) Some other actions', 0, 0) WITH NOWAIT;
WAITFOR DELAY '00:00:03'; --Wait for 3 seconds

RAISERROR('4) Calculating', 0, 0) WITH NOWAIT;
WAITFOR DELAY '00:00:02'; --Wait for 2 seconds

RAISERROR('5) Finishing', 0, 0) WITH NOWAIT;
END

Now let’s create some C# code:

First: A class to send the received messages from our repository to its consumer, which in this case the UI will be just a Windows Form (good old boys never die).

public class SqlMessageEventArgs {
public string Message { get; set; }
public int Progress { get; set; }
}

Notice the Progress property. We will use it in the last part, be patient ;)

Second: A repository class that open a connection, execute the stored procedure and send messages using a ProcessMessage event. We must explicitly enable the connection to receive these errors and raise handling the InfoMessage event:

public class SqlServerRepo
{
public event EventHandler ProcessMessage;
public string ConnectionString { get; internal set; }
public SynchronizationContext SyncContext { get; internal set; }
public async Task GetDataAsync() {
using (var con = new SqlConnection(ConnectionString))
{
con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += (s, e) =>
SyncContext.Post(_ => ProcessMessage?.Invoke(
s, new SqlMessageEventArgs
{
Message = e.Message,
}), null);
con.Open();
var sql = "EXEC dbo.TestLongRunningSP";
var commandDefinition = new CommandDefinition(sql);
await con.ExecuteAsync(commandDefinition);
con.Close();
}
}

Note: When using async pattern the received messages come from a different thread and cannot be used to update the UI directly. For this reason I always recommend send to the Repo the current synchronization context and use this Context to post to the main thread.

threaderror

BOOM: Typical cross thread exception when updating UI from a different thread.

Third: Finally let’s create a simple Windows Form with just a button, a progress bar and a list box).

const string cs = "Data Source=YOUR_SERVER;Initial Catalog=YOUR_DATABASE;Integrated Security=True;"
private async void button1_Click(object sender, EventArgs e) {
var repo = new SqlServerRepo() {
ConnectionString = cs,
SyncContext = SynchronizationContext.Current
};
repo.ProcessMessage += (ms, me) => {
listBoxLog.Items.Add($"{DateTime.Now} - {me.Message}");
};
await repo.GetDataAsync();
listBoxLog.Items.Add($"Finished Process!");
}

This code creates the repo, pass the connection string and the current synchronization context, handles the ProcessMessage event and invoke the GetDataAsync method.

Simply and elegant. No dependent assemblies or external resources.

One more thing

What about the progress bar? Also easy. Just use the state argument of the RAISERROR method on the SP like this:

RAISERROR('1) Starting', 0, 10) WITH NOWAIT;
WAITFOR DELAY '00:00:03'; --Wait for 3 seconds

RAISERROR('2) Fetching data', 0, 30) WITH NOWAIT;
WAITFOR DELAY '00:00:05'; --Wait for 5 seconds

RAISERROR('3) Some other actions', 0, 60) WITH NOWAIT;
WAITFOR DELAY '00:00:03'; --Wait for 3 seconds

RAISERROR('4) Calculating', 0, 70) WITH NOWAIT;
WAITFOR DELAY '00:00:02'; --Wait for 2 seconds

RAISERROR('5) Finishing', 0, 100) WITH NOWAIT;

Then update the GetDataAsync method:

public async Task GetDataAsync() {
using (var con = new SqlConnection(ConnectionString))
{
con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += (s, e) =>
SyncContext.Post(_ => ProcessMessage?.Invoke(
s, new SqlMessageEventArgs
{
Message = e.Message,
Progress = e.Errors[0]?.State ?? 0
}), null);
con.Open();
var sql = "EXEC dbo.TestLongRunningSP";
var commandDefinition = new CommandDefinition(sql);
await con.QueryAsync(commandDefinition);
con.Close();
}
}

And finally the code in the form:

repo.ProcessMessage += (ms, me) => {
listBoxLog.Items.Add($"{DateTime.Now} - {me.Message}");
progressBar.Value = me.Progress;
};

And that’s all!

Hope you enjoy it, and please, send me your thoughts about this solution ;)

How To: Get data from OLAP cubes

cuberubikToday I had to read some data from different OLAP cubes and show this information in our application. This could be accomplished using ADOMD.NET client library, which is the multidimensional equivalent to the ADO.NET libraries.

This library provides a set of classes (Connections, Commands and Readers) that allows developers to connect, query and get data from these multidimensional sources in the same way the classical ADO.NET library does.

Maybe the easiest way to read data is using the class AdomdDataReader. This object retrieves a read-only, forward-only, flattened stream of data from an analytical data source, and also implements the IDataReader interface (like the good-old DataReader).

In non dynamic scenarios, we developers, tend to use ORMs like NHibertate, EF or Dapper (my favorite), to translate data from our models to classes. But these ORMs doesn’t support multidimensional sources, because after all, they are only supersets or extensions of the ADO.NET model and are based on this existing object model.

So, our goal here will be replicate in a multidimensional environment the way Dapper allows you to connect to a server, read some data and (the most important part) return these data as a typed List<T> of objects.

Let’s see how it works before dig into the details:

First of all we have a SQL script that returns some sample data of 3 different measures year by year (gains in period, gains year-to-date and the amount of money).

mddata

And we’d like to translate these data into a generic List of my own DTO:

Notice that in C# properties can not contain spaces so we previously have to ‘map’ the DataReader column names into valid property names. The trick here is create an attribute for decorating each property with the equivalent column name in the reader.

The magic here is inside the generic Query<T> Method. This method is just an extension method of the AdomdConnection object (Dapper style) and it’s mission will be:

  1. Replace the parameters in the command string “…Where ({ @PortfolioId })”
  2. Execute the command against a valid connection
  3. Transform the returned IDataReader into a List<MyResultDTO>

We’ll focus on the third one. Let’s create another extension method of the IDataReader interface. OMG! Code on interfaces? Yes… I’ll burn in hell, I know it… :D

This is the extension method with some auxiliary functions:

EDIT (2018-12-11) : Added custom attribute to the post, used to decorate our DTO.

As you can see the method iterates over the reader’s data and uses reflection to create an object per each row, map each column’s value to the correct property and then add the new object to the returned collection (*). Easy!

adomd_result

(*) image courtesy of oz-code, the best debugger addin for visual studio #imho ;)

Hope this helps! ;)

How To: Connect via SFTP using SSH.NET

Overview

In these times of APIs-everywhere, it may sound like an anachronism the use SFTP to connect to a remote server and get a list of files for exchanging information, but in the financial world (sadly) it’s more common than you think.

In my current project I’ve to connect to a remote server via Secure File Transfer Protocol (aka SFTP) using a user name, a RSA private key and a phassphrase. Once connected, the goal is to read some files from a remote folder and download them to a local folder.

To accomplish this I recommend you to use SSH.NET, one of the most popular SSH libraries for .NET, available on nuget.

sshnet

More info about SSH.NET here: https://github.com/sshnet/SSH.NET/

Using SSH.NET to connect to the server

The most difficult part here is configure the connection, as usual. We need to provide the server url and port, in combination with the username and a file that contains the private key of the RSA certificate, and -of course- the passphrase.

Here’s the final code, and it works :)

Bonus * the trick *

I’ve spent a lot of time before it works, receiving a SSH exception “Invalid private key file”, but the same key file works fine when using the app Filezilla to connect, so… #WhatTheHell :S

PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: rsa-key-KBL-20171006
Public-Lines: 6
AAB3NzaC1yc2EAAAJQAAAQEAnHp1CA4xF04ZdOQ/rsxJoW9fPJ2RD
FgMNVIqsUsjeRbIoZ2y8SMD9b7MMB0lpKXgJ2dYDgOnh2q
j4VTpEoI2JWh4NdQgSH0O+2oLmQnwgDPT7Kva095ggEQiqScX4+31aY02/nz
mK86sxq/sUsW/UqgS+pPViRQLVzDXFf8XIYSSZngmV+Rk108BQ==
Private-Lines: 14
khHfZWB0vBIFtKc4s98xGDFhwZNJQByUTtE7um0tcU4cwy1QTPf3GIuN
vyhHxIGx3LBtFJqzbZVJtOJVSYjkBTGbNc62D0uJCxYVf8PUUStI6GbOkkyDW/Vt
beWZ3s/DugsImjcbPxdEz/2X86uzd5U5v4/wGKQr8GWJtNksMcJ
k7JgRYGA/t0cSE2980MxhZOBg2Gn7+0A6mWgSf2Rr7hpcqsou1
hmc1HYtN7Oj4WT7hvRt8ZAC3/ekTdJ4K3K7vKglSHoQ
tnimHaanJHz4RGBb78Alllk+OYk3TN0Etcwod3401cLpjYYeq6veZLA/KfCHuiJ+
+Zqoy//NY9egfXd1hB0kmiemwO8wGfLS7ppS/WvPOknW9I8SNMllR1vmO3Hk6S3x
KfAG03ZWNoKDLvAIUllNyMpf9p8oKLF2ny4bJKsfNtr4Y0ejQJUFkC
uNz1S4VJ8j1fRcIjx4yT121B9BDfp486RUmnEgsOFEtmVyHPfNxYzDXq2MjTf4l/
MI5cKWHrDbDC/Cu3YvkF3gekLAb/j9Cie/feHmSnbuZ2VEr6zUt10yaH4hPejCOw
FYDZb0I8xxxWJZ6BbpLWDqeD0Oiss8UnDhha/iKvodA9LIG0T
VRlScvGvuzClGYkc7UIWIoARvdxp46YlGMu4mWGeVkNcrxXnmUkdKyNqGjAGJoK/
Private-MAC: d288fffe72914eb62ed60a7e50fd8ce775

The key file (*.ppk) looks something similar to this

This is because the private key must be compatible with SshNet, so we have to convert the private key using PuTTY key Generator (the same app we used to create the certificate). Once opened in PuTTY, just export your file key to OpenSSH and use this new ppk file instead of the previous one.

exportosk

If you open the new file you will see that the key file now begins with

—–BEGIN RSA PRIVATE KEY—–

And ends with

—–END RSA PRIVATE KEY—–

Finally, this is a valid SSH private key and it works like a charm ;)

Hope you enjoy it!

HowTo: Redeploy CLR assemblies to SQL Server (Newtonsoft.Json version issue)

 

sr

The Story

Hi again,

Some time ago I published a post about how to send notifications from SQL Server using SignalR. We are using SignalR self-hosted in a Windows Service in a separated server, and it had been running fine until now.

This week I had to set up a new SQL server which will replace the old one, which will replace the current ‘preprod’ one, and (entering recursive mode…).

After configuring the new SQL Server settings, I tried to update the previously imported assemblies to the database to the latest versions I’m currently using in the .NET project (Newtonsoft.Json & Microsoft.AspNet.SignalR.Client).

References map:

  • MyAssembly
    • Microsoft.AspNet.SignalR.Client
      • Newtonsoft.Json

As you can see, the app references the SignalR client, which references Newtonsoft dll.

So, in order to redeploy the assemblies it’s necessary to:

  • Remove all the CLR Stored Procedures that are using these assemblies, otherwise you cannot delete the assemblies.
  • Remove the main assembly and then all its dependencies in the correct order (Note: It’s not necessary to remove Framework assemblies if it’s not changed).
  • At this point you’ll be able to create the assembly again via CREATE ASSEMBLY
CREATE ASSEMBLY Falcon_SqlProxy FROM
'C:\Falcon\SqlServerAssemblies\Falcon.NotificationsClient.SqlProxy.dll'
WITH PERMISSION_SET = UNSAFE

All dependent assemblies will be created again in the database (in this case Newtonsoft.Json & Microsoft.AspNet.SignalR.Client). Easy…

BOOM!

However, when tried to import the assembly to SQL Server I’ve got this error:

“Assembly ‘Microsoft.AspNet.SignalR.Client’ references assembly ‘newtonsoft.json, version=6.0.0.0, culture=neutral, publickeytoken=XXXXXXXXX.’, which is not present in the current database. SQL Server attempted to locate and automatically load the referenced assembly from the same location where referring assembly came from, but that operation has failed (reason: version, culture or public key mismatch). Please load the referenced assembly into the current database and retry your request.”

I decided to import the assemblies one by one, from down to top.

Firstly I imported Newtonsoft.Json with no problems, but when I tried to import the SignalR client I received this error:

ie1

It seems a versions issue, because I’ve imported Newtonsoft.Json version 9, not 6! Let’s see what’s in the assemblies view:

select * from sys.assemblies

ie2

It’s correct. I’ve imported version 9 of the library… so why the hell SQL is looking for version 6? Well, if you inspect Microsoft.AspNet.SignalR.Client you’ll see that this library has a reference to Newtonsoft.Json version 6.0.0.0 :S

ie3

This version number is used to determine the minimum version number (the library won’t work with previous versions), but it seems SQL Server is trying to match this version number with the assembly version number in its catalog, and if the number is different is unable to import the assembly.

If I’m wrong, please correct me! Thx :)

Solution?

After spending some hours trying different solutions , the only way to solve that -at this time- is register a previous version of Newtonsoft.Json instead of the latest one.

Any version? Nope.

The only version it worked for me is 6.0.8, previous ‘6’ versions didn’t work because of this error:

“‘Method not found: ‘Newtonsoft.Json.Linq.JValue Newtonsoft.Json.Linq.JValue.CreateNull()’.'”

Finally, once I’ve copied the 6.0.8 version of the Newtonsoft.Json to the server path the import process has worked like a charm.

ie4

Now I’m looking for a better solution, because I don’t like using old versions of assemblies. I will update this post with a better solution as soon as possible :D

In the meanwhile, hope this helps.

HowTo: Send Notifications from SQL Server using SignalR

sr

Overview

In our current project we’ve to push some notifications directly from the database server (SQL Server 2014) to different apps. For example, we’ve scheduled some SSIS (SQL Server Integration Services) projects that pre-calculates large amounts of data. And well, should be nice notify all the apps when new data is available without unnecessary round trips to database. And you know? we’re already using SignalR in our apps… so, why not try to build a lightweight client for sending SignalR notifications?

Dear architects, please, don’t judge me :P

The idea

  1. I finally decided to create a small project in C# that connects to our SignalR (which is self-hosted in a Windows Service). That project contains a single method for sending notifications with a message (just a string for simplify).
  2. Once the project is ready and tested, the next step is create an ASSEMBLY, that is, a module that contains class metadata and managed code as an object in an instance of SQL Server. By referencing this module, common language runtime (CLR) functions, stored procedures, triggers, user-defined aggregates, and user-defined types can be created in the database.
  3. And finally, create a Stored Procedure that use our previous assembly CLR function (for isolation purposes and decoupling), and then use it in our SSIS projects with a simply ‘Execute SQL Task‘ when the process finalizes.

Creating the C# project

Create a blank class Library project and add the SignalR client (Nuget will add depending assemblies -like Newtonsoft.Json- automatically)

addSignalRClient

Once we added SignalR Client references to the project we need to create the C# method, so let’s add a class item to the project with this code:

public class SqlServerNotificationsClientService
{
    internal static HubConnection hubConnection = null;
    internal static IHubProxy hubProxy = null;
    [SqlFunction()]
    public static void SendMessageToHub(
        string severURL, string hubName, string hubMethod, params object[] args)
    {
        try
        {
            if (hubConnection == null || isConnectionClosed())
                hubConnection = new HubConnection(severURL.Trim()) 
                { Credentials = CredentialCache.DefaultNetworkCredentials };
            if (hubProxy == null || isConnectionClosed())
                hubProxy = hubConnection.CreateHubProxy(hubName.Trim());
            if (isConnectionClosed())
                hubConnection.Start().Wait();
            if(args.Length == 0)
                hubProxy.Invoke(hubMethod.Trim()).Wait();
            else
                hubProxy.Invoke(hubMethod.Trim(), args).Wait();
        }
        catch (Exception exc)
        {
            SqlContext.Pipe.Send(string.Format("{0}.{1} error: '{2}'{3}", 
                hubName.Trim(), hubMethod.Trim(), exc.Message, Environment.NewLine));
        }
    }

    private static bool isConnectionClosed()
    {
        return !(hubConnection.State == ConnectionState.Connected
            || hubConnection.State == ConnectionState.Reconnecting
            || hubConnection.State == ConnectionState.Connecting);
    }
}

Note: Before continue, take a look to the last parameter ‘args’. This parameter allows you to pass a different number of arguments to this method, which is nice because when we invoke the hub’s method we can use the same argument type. Unfortunately this argument type is not compatible with SQL CRL and will crash when creating the Stored Procedure in the database :( So we need to change this argument to a simple string.

This code is just an example, maybe would be a better idea split it into different methods (remember the ‘S’ of SOLID?) :)

Let’s assume the code is ok and is able to connect and send the notification. Now…

Create the SQL Assembly

In order to deploy your assemblies to a SQL Server you need the same version of the .NET Framework installed on the server. Yep, it’s too obvious but…

Create a folder in the server called ‘C:\SQLServerAssemblies’ (or wherever you want) and copy all the assemblies generated by the previous project.

signalRClientBaseAssemblies

But we’ve not finished yet… Now we’ve to add some related assemblies (assemblies dependencies). Otherwise, assembly creation will fail.

signalRClientFullListAssemblies

You can find these assemblies in the same server, in the correct version of .NET Framework. In my case:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319 -> Microsoft Framework 4.5

Once we’ve all the necessary assemblies copied, let’s create the assembly. First we need to activate some things in the server:

ALTER DATABASE Falcon SET trustworthy ON

exec sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO

exec sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO

exec sp_configure 'show advanced options', 0;
GO
RECONFIGURE;
GO

CREATE ASSEMBLY Falcon_SqlProxy from 
  'C:\SQLServerAssemblies\Falcon.NotificationsClient.SqlProxy.dll' 
WITH PERMISSION_SET = UNSAFE 


signalRSqlAssemblies

Yes! Assemblies created successfully in SQL Server ;)

Creating the SP

Finally we only need to create the Stored Procedure. I recommend you use a custom schema. I’ve created one called ‘clr’

CREATE PROCEDURE clr.SendMessageToHub
@url nchar(125) ,
@hubName nchar(75),
@hubMethod NCHAR(75),
@message NVARCHAR(MAX)
AS
EXTERNAL NAME [Falcon_SqlProxy].[Falcon.NotificationsClient.SqlProxy.SqlServerNotificationsClientService].SendMessageToHub

Remember the note? Have you changed the last argument of the method  SendMessageToHub to a string?

If you did it and copied all the assemblies to the folder it should have worked like a charm ;)

Now it’s time to test our SP… Success!

signalR_SPOk

Bonus:

If you wanna use this SP from a SSIS project to send notifications to your apps, just add a Execute SQL Task to your project and configure the SQL statement:

signalRExecuteSQLTask

Hope this helps! :)

Curiosity: What happens if you remove all the Trim() in the c# code? Why connection to SignalR fails? ;)

See you,

How to: Remove diacritics (accents) in C# strings

cs

Quick note: How to remove diacritics (accents) from a C# string?
Use this extension method ;)

public static string RemoveDiacritics(this string input)
{
    var stFormD = input.Normalize(NormalizationForm.FormD);
    var len = stFormD.Length;
    var sb = new StringBuilder();
    for (int i = 0; i < len; i++)
    {
        var uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[i]);
        if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
        {
            sb.Append(stFormD[i]);
        }
    }
    return (sb.ToString().Normalize(NormalizationForm.FormC));
}

How to: Server Side Filter database (Entity Framework + DevExpress Filter control)

Imagine you have a table with millions of rows. It’s not a good idea showing all these data in a grid or similar, and it doesn’t matter you’re developing a web or desktop application… It’s not a good idea at all.

In these cases we should use conditional filters applied in the data source (usually a database) to get part of the information and return only the rows that match with the specified criteria. Using this technique the amount of network traffic could be reduced to a hundreds of rows or less, depending on the criteria.

There are different ways of accomplish that, but today I’d like to focus on apply this technique using a control from the DevExpress suite: The Filter Editor control.

DXFilterControl

 

As you can see the control looks nice, and it’s quite simple to use: You just need to link this control to another (usually a Grid or Tree), and automatically will retrieve the columns and values information from the source control. Then you’ll be able to filter the linked control and get a filter string which you can reuse later in other controls of the suite.

However the previous filter has the disadvantage that is a client filter, and is applied after we retrieve all the rows from the data source, not before. Our goal have to be apply the filter before getting the information.

Today I’ve been playing a little bit with this control, using a SQL Server database that contains a products table with 3.7 million rows and Entity Framework 6.0 as an ORM.

Note: For this test I’d like to use a SQL Tabled-Valued Function to access the data instead of using the default DbSet, because it’s supposed that I’ve to do some hard calculations inside the function. But you can also use the EF DbSet directly, as usual.

EFModel

Now our goal here is:

  1. Create at runtime a filter over the Products table using the filter control.
  2. Parse that filter string and adapt it to the EF syntax.
  3. Append the filter to the mapped function (thx to IQueryable!) before execution.
  4. Finally, execute the filtered query against the data source

First we need to add an EF designer (we won’t use Code First because we’re going to map a Tabled valued function with is not supported). And add the table Products and the GetAllProducts function.

In our form, we just need to add a couple of Devexpress controls: A GridControl and a FilterControl, linked using the FilterControl SourceControl property (this allows the filter control to retrieve the names and data types of the grid columns).

DynamicFiltersEF

Then we’ll add three buttons. The first one will retrieve the first 25.000 rows from the database (previously I’ve tried to get all rows from table, but the app crashed with an OutOfMemory exception ;))

The second button (this is the interesting one) will execute the current filter from the FilterControl.

Let’s code:

The first button is really simple. It’s just a query over the GetAllProducts function adding a where clause which will be resolved later (because EF is based on IQueryable<T>) when calling ToListAsync method.

private async void simpleButton1_Click(object sender, EventArgs e)
{
    using (var context = new TestBigDbEntities())
    {
        var filteredproducts = context.GetAllProducts().Where(p => p.ProductId <= 25000);
        await ExecuteQueryAsync(filteredproducts);
    }
}

private async Task ExecuteQueryAsync(IQueryable filteredProducts)
{
    clock.Restart();
    productBindingSource.DataSource = await filteredProducts.ToListAsync();
    clock.Stop();
    Text = clock.ElapsedMilliseconds.ToString("n2");
}

For the second button we need something more. Something that allows us to translate the filter into a valid where clause, and append it to the function.  The good news are that this functionality is provided natively by Devexpress:

private async void simpleButton2_Click(object sender, EventArgs e)
{
    var converter = new DevExpress.Data.Linq.CriteriaToEFExpressionConverter();
    using (var context = new TestBigDbEntities())
    {
        var filteredproducts =
                DevExpress.Data.Linq.Helpers.CriteriaToQueryableExtender.AppendWhere(
                context.GetAllProducts(),
                converter,
                filterControl1.FilterCriteria);
        await ExecuteQueryAsync(filteredproducts);
    }
}

All we’ve to do is that:

Clean and simple. The first one creates a converter for translating the filter into EF syntax, while the second one appends the filter to the EF function using the previous converter.
And finally, here’s the SQL in the profiler. Exactly what I’ve expected.

SQLProfiler

So well… if you’re using Devexpress in your current project there’re no excuses for not including dynamic filters that user can save and reuse at runtime, uh? :P

Happy coding!

Bonus

The third button code shows how to get the TSQL syntax from the Filter control, that you can use it to query the database directly ;)

private void simpleButton3_Click(object sender, EventArgs e)
{
    var tsql = DevExpress.Data.Filtering.CriteriaToWhereClauseHelper.
        GetMsSqlWhere(filterControl1.FilterCriteria);
    MessageBox.Show(tsql);
}

BonusTSQLFilter