Continuous Speech Recognition in .NET Core WPF applications

06/08/2020 2 comments

In the last article we talked about how to integrate Speech Recognition in .NET Core WPF applications with the Cognitive Services Speech SDK. In that occasion, we shown how to use the RecognizeOnceAsync method to recognize a single utterance. But the Speech SDK supports also continuous recognition, so today we’ll see how to leverage this feature.

Basically, instead of RecognizeOnceAsync, we need to use StartContinuousRecognitionAsync method and subscribe to the appropriate events.

Starting from the previous sample, as usual we have to define some constants and a reference to a SpeechRecognizer object:

private const string SpeechSubscriptionKey = "";
private const string SpeechRegion = "";
private const string Culture = "";

private readonly SpeechRecognizer speechRecognizer;
private bool isRecognizing;

Then, in the constructor of the Window we can initialize the recognizer:

public MainWindow()
{
    InitializeComponent();

    var config = SpeechConfig.FromSubscription
        (SpeechSubscriptionKey, SpeechRegion);

    speechRecognizer = new SpeechRecognizer(config, Culture);
    speechRecognizer.Recognized += SpeechRecognizer_Recognized;
}

At line 9 we register to the RecognizedEvent evebt, that is raised every time a final recognition result is received:

private async void SpeechRecognizer_Recognized(object sender, 
    SpeechRecognitionEventArgs e)
{
    if (e.Result.Reason == ResultReason.RecognizedSpeech)
    {
        await Dispatcher.InvokeAsync(() =>
            RecognitionTextBox.Text += $"{e.Result.Text} ");
    }
}

If the recognition succeeds (line 4), we use the Dispatcher (line 6, because recognition is performed in a background task) to add the recognized text to the TextBox.

Now we only need to start and stop recognition when the user press the corresponding button:

private async void RecognitionButton_Click(object sender, RoutedEventArgs e)
{
    if (!isRecognizing)
    {
        var isMicAvailable = await CheckEnableMicrophoneAsync();
        if (!isMicAvailable)
        {
            return;
        }

        await speechRecognizer.StartContinuousRecognitionAsync();

        RecognitionTextBox.Text = string.Empty;
        isRecognizing = true;
        RecognitionButton.Content = "Stop Recognition";
    }
    else
    {
        await speechRecognizer.StopContinuousRecognitionAsync();

        isRecognizing = false;
        RecognitionButton.Content = "Start Recognition";
    }
}

The CheckEnableMicrophoneAsync method is the same you can find in the previous article. After we call the StartContinuousRecognitionAsync method at lines 11, the SDK begins to raise the RecognizedEvent event for each recognized utterance. To stop this behavior, we need to invoke the StopContinuousRecognitionAsync (lines 19).

So, here it is our application running:

The WPF Continuous Recognition App

The WPF Continuous Recognition App

You can download the sample app using the link below:

Continuous Speech Recognition in .NET Core WPF applications

Categories: .NET, .NET Core, C#, WPF

Integrating Cognitive Service Speech Recognition in .NET Core WPF applications

31/07/2020 3 comments

Some times ago we talked about how to integrate the Cognitive Service Speech Service in UWP apps. Now, let’s see how to use the same service in a .NET Core WPF application.

In the original article, we shown how to use the UWP MediaCapture APIs to check the availability of the microphone. Thanks to the Microsoft.Windows.SDK.Contracts NuGet package, we can use the same APIs also from .NET Framework 4.6+ and .NET Core 3.0+ platforms:

The Microsoft.Windows.SDK.Contracts NuGet package

The Microsoft.Windows.SDK.Contracts NuGet package

At the time of writing, this package includes all the supported Windows Runtime APIs up to Windows 10 version 2004. So, in order to check whether the microphone is enabled and available, we can use the same exact code of the old article:

private async Task<bool> CheckEnableMicrophoneAsync()
{
    var isMicAvailable = false;

    try
    {
        var mediaCapture = new MediaCapture();
        var settings = new MediaCaptureInitializationSettings
        {
            StreamingCaptureMode = StreamingCaptureMode.Audio
        };

        await mediaCapture.InitializeAsync(settings);
        isMicAvailable = true;
    }
    catch
    {
        await Launcher.LaunchUriAsync
            (new Uri("ms-settings:privacy-microphone"));
    }

    return isMicAvailable;
}

And now we can add the Microsoft.CognitiveServices.Speech NuGet package to the project and use a slight modified version of the code of the original article (because in the meantime the SDK has changed a bit):

private async void RecognitionButton_Click(object sender, RoutedEventArgs e)
{
    const string SpeechSubscriptionKey = "";
    const string SpeechRegion = "";
    const string Culture = "";

    var isMicAvailable = await CheckEnableMicrophoneAsync();
    if (!isMicAvailable)
    {
        return;
    }

    RecognitionButton.Content = "Recognizing...";
    RecognitionButton.IsEnabled = false;
    RecognitionTextBox.Text = string.Empty;

    var config = SpeechConfig.FromSubscription
        (SpeechSubscriptionKey, SpeechRegion);

    // Starts recognition. It returns when the first utterance has been 
    // recognized.
    using var cognitiveRecognizer = new SpeechRecognizer(config, Culture);

    var result = await cognitiveRecognizer.RecognizeOnceAsync();

    // Checks result.
    if (result.Reason == ResultReason.RecognizedSpeech)
    {
        RecognitionTextBox.Text = result.Text;
    }
    else
    {
        MessageBox.Show(result.Reason.ToString(), "Recognition Result",
            MessageBoxButton.OK, MessageBoxImage.Warning);
    }

    RecognitionButton.Content = "Start recognition";
    RecognitionButton.IsEnabled = true;
}

The lines 3-5 must be completed with the Speech subscription key that we can find on Azure portal, the name of the region in which the service has been created and the language of the speech.

After checking for the microphone availability at lines 7-11, we can start the real recognition process. We instantiate a SpeechConfig at lines 17-18 and use it to create the Cognitive Speech recognizer at line 22. The RecognizeOnceAsync method (line 25) starts speech recognition and stops after the first utterance is recognized.

If the Reason property is equal to RecognizedSpeech (line 27), it means that the recognition succeeded, so we can read the Text property (line 29) to access the recognized text:

The WPF Recognition App

The WPF Recognition App

You can download the sample app using the link below:

Integrating Cognitive Service Speech Recognition in .NET Core WPF applications

As said before, RecognizeOnceAsync returns when the first utterance that has been recognized, so it is suitable only for single shot recognition like command or query. For long-running recognition, we can use the StartContinuousRecognitionAsync method instead. If you are interested in this feature, you can read the article Continuous Speech Recognition in .NET Core WPF applications.

Categories: .NET, .NET Core, C#, WPF

JSON handling made easy with System.Net.Http.Json

21/05/2020 1 comment

Nowadays, we all have to deal with JSON, the de facto standard for data interchange in HTTP communications. In the rest of the article, we’ll use JSONPlaceholder, a fake Online REST API Server. Suppose we have the following class and initialization for HttpClient and JsonSerializer:

public class Post
{
    public int Id { get; set; }

    public int UserId { get; set; }

    public string Title { get; set; }

    public string Body { get; set; }
}

private static readonly HttpClient httpClient = new HttpClient
  {
      BaseAddress = new Uri("https://jsonplaceholder.typicode.com")
  };

private static readonly JsonSerializerOptions jsonSerializerOptions
    = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };

If we want to get all the posts, we usually write something like this:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    using var response = await httpClient.GetAsync("posts");
    response.EnsureSuccessStatusCode();

    using var contentStream = await response.Content.ReadAsStreamAsync();
    
    var posts = await JsonSerializer.DeserializeAsync<IEnumerable<Post>>
        (contentStream, jsonSerializerOptions);

    return posts;
}

Of course, there are different ways (more or less efficient) to get the results, but, in general, we always make the request, read its content and deserialize it. Note that, for the sake of simplicity, we don’t have any error handling.

In the same way, in order to make a POST we need the following:

private static async Task SendPostAsync(Post post)
{
    var jsonContent = JsonSerializer.Serialize(post, jsonSerializerOptions);
    using var httpContent = new StringContent
        (jsonContent, Encoding.UTF8, "application/json");

    using var response = await httpClient.PostAsync("posts", httpContent);
    
    response.EnsureSuccessStatusCode();
}

We serialize the input object, create the HttpContent using the correct encoding and media type and then make the POST request to the server.

Even if this is not too complex, it is the classic example of boilerplate code. But now we have an official alternative: during the Build 2020 event, the new System.Net.Http.Json package has been released as stable version. It provides some extension methods for HttpClient that make working with JSON very straightforward. For example, after adding this package to our project, we can update the previous code in this way:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    var posts = await httpClient.GetFromJsonAsync<IEnumerable<Post>>("posts");

    return posts;
}

private static async Task SendPostAsync(Post post)
{
    using var response = await httpClient.PostAsJsonAsync("posts", post);

    response.EnsureSuccessStatusCode();
}

As we can see, every operation is reduced to a single line of code. Under the hood, it uses JsonSerializer for serialization/deserialization, so for example (besides the classic HttpClient exceptions) we obtain a JsonException if the JSON is invalid. Moreover, if the content type is incorrect for JSON requests, we get a NotSupportedException. And we don’t need to pass anymore a JsonSerializerOptions object to these methods, because they automatically use one with Camel case naming policy and case-insensitive comparison during deserialization (as we normally expect when working with JSON).

If we want more control while sending and receiving, we can leverage some other extension methods and helpers:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    using var request = new HttpRequestMessage(HttpMethod.Get, "posts");

    // Additional code for HttpRequest...

    using var response = await httpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();

    var posts = await response.Content.ReadFromJsonAsync<IEnumerable<Post>>();

    return posts;
}

private static async Task SendPostAsync(Post post)
{
    using var request = new HttpRequestMessage(HttpMethod.Post, "posts")
    {
        Content = JsonContent.Create(post)
    };

    // Additional code for HttpRequest...

    using var response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode();
}

At line 10 we have used the ReadFromJsonAsync extension method on the HttpContent class, while at line 19 we have created the content for the HttpRequestMessage with the JsonContent helper.

This new approach should become the “standard”, because, among the other things, it internally uses Span<T> for serialization/deserialization, so it can be more efficient than the “classic” code we have used till today.

Categories: .NET Core, C#

Using HostBuilder, ServiceProvider and Dependency Injection with Windows Forms on .NET Core 3

09/03/2020 2 comments

In the last posts we talked about how to use .NET Core 3.0 Dependency Injection and Service Provider with WPF. But also Windows Forms is supported by .NET Core 3.x, so it’s time to show how to use the same concepts of HostBuilder, Service Provider and Dependency Injection with this application model.

First of all, after creating a .NET Core Windows Forms application, we need to add the NuGet package Microsoft.Extensions.Hosting to the project. It will allow us to use HostBuilder and, moreover, it automatically imports a bunch of other required packages. Now let’s open the Program.cs file and add the following code:

private static void Main()
{
    // ...
    var host = Host.CreateDefaultBuilder()
             .ConfigureAppConfiguration((context, builder) =>
             {
                 // Add other configuration files...
                 builder.AddJsonFile("appsettings.local.json", optional: true);
             })
             .ConfigureServices((context, services) =>
             {
                 ConfigureServices(context.Configuration, services);
             })
             .ConfigureLogging(logging =>
             {
                 // Add other loggers...
             })
             .Build();

    var services = host.Services;
    var mainForm = services.GetRequiredService<MainForm>();
    Application.Run(mainForm);
}

private static void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    // ...
    services.AddSingleton<MainForm>();
}

HostBuilder configuration at lines 4-18 follows the same structure we have already presented in the previous article, so refer to it for more information. After that, at lines 21 we retrive the MainForm we added in the Service Collection (line 29) and finally we start the application using the Application.Run method (line 22).

We can now run the application: everything will work as expected. And now we can leverage all the features that .NET Core 3 provides. Let’s add also a file named appsettings.json to the root folder of the project. Set its Build Action property to Content and Copy to Output Directory to Copy if newer:

{
  "AppSettings": {
    "StringSetting": "Value",
    "IntegerSetting": 42,
    "BooleanSetting": true
  }
}

This file is automatically loaded and made available to the application by the CreateDefaultBuilder method we saw before. Then, we create an AppSettings.cs file to hold configuration settings. This file will map the settings that we write in appsettings.json:

public class AppSettings
{
    public string StringSetting { get; set; }
 
    public int IntegerSetting { get; set; }
 
    public bool BooleanSetting { get; set; }
}

Moreover, create also a sample service with its interface:

public interface ISampleService
{
    string GetCurrentDate();
}
 
public class SampleService : ISampleService
{
    public string GetCurrentDate() => DateTime.Now.ToLongDateString();
}

Now we must register these services in the IoC Container, as usual:

private void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    services.Configure<AppSettings>
            (configuration.GetSection(nameof(AppSettings)));

    services.AddScoped<ISampleService, SampleService>();

    //...
}

Remember that the MainForm itself is in the IoC Container. So, when we get it from the Service Provider, it will automatically be injected with all the required services. We just need to modify its constructor:

private readonly IServiceProvider serviceProvider;
private readonly ISampleService sampleService;
private readonly AppSettings settings;

public MainForm(IServiceProvider serviceProvider,
                ISampleService sampleService,
                IOptions<AppSettings> settings)
{
    InitializeComponent();

    this.serviceProvider = serviceProvider;
    this.sampleService = sampleService;
    this.settings = settings.Value;
}

Running this code, we’ll obtain a result like the following:

The .NET Core 3.0 Windows Forms application with dependecies injected

The .NET Core 3.0 Windows Forms application with dependecies injected

Finally, let’s try to add a second Form to the application and open it using a button from the Main Form. But, before doing that, remember that, at the time of writing, the Windows Forms Designer for .NET Core is available only in Visual Studio 16.5 Preview. If you haven’t it yet, you can refer to the complete sample you’ll find at the end of the article.

So, register the new form in the Service Collection (inside Program.cs file):

private static void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    // ...
    services.AddTransient<SecondForm>();
}

At line 5 we register the Form as transient dependency, meaning that, everytime we try to get a reference to it, we’ll get a new instance. Of course, we can use AddScoped or AddSingleton as well. Keep in mind that, in the context of a desktop application, Scoped and Singleton get always the same instance, because in this case we have a scope as long as our application runs.

Then, in MainForm.cs add the code to open the new Form when clicking the button:

private void OpenSecondFormButton_Click(object sender, EventArgs e)
{
    var form = serviceProvider.GetRequiredService<SecondForm>();
    form.ShowDialog(this);
}

We use the ServiceProvider we passed to the MainForm constructor to get a reference to SecondForm and we call its ShowDialog method (lines 3-4). But SecondForm is itself in the IoC Container, so in turn it can receive the dependencies it needs in the constructor:

public partial class SecondForm : Form
{
    private readonly ISampleService sampleService;
    private readonly AppSettings settings;

    public SecondForm(ISampleService sampleService,
                      IOptions<AppSettings> settings)
    {
        InitializeComponent();

        this.sampleService = sampleService;
        this.settings = settings.Value;
    }
}
Opening a second Form with the Service Provider

Opening a second Form with the Service Provider

You can download the sample app using the link below:

Using HostBuilder, ServiceProvider and Dependency Injection with Windows Forms on .NET Core 3

Categories: .NET Core, C#, Windows Forms

An MVVM-aware NavigationService for WPF running on .NET Core

13/01/2020 8 comments

In the last article we talked about how to use the MVVM pattern in WPF applications running on .NET Core. Today, we’ll add support for navigation through Window from View Models. For this purpose, we start from the code of the last article. Our goal is to extend it adding a method to open new Window from View Models and, at the same time, pass parameters to View Models.

So, let’s start with the NavigationService:

public interface IActivable
{
    Task ActivateAsync(object parameter);
}

public class NavigationService
{
    private Dictionary<string, Type> windows { get; }
        = new Dictionary<string, Type>();

    private readonly IServiceProvider serviceProvider;

    public void Configure(string key, Type windowType) 
        => windows.Add(key, windowType);

    public NavigationService(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public async Task ShowAsync(string windowKey,
        object parameter = null)
    {
        var window = await GetAndActivateWindowAsync(windowKey, parameter);
        window.Show();
    }

    public async Task<bool?> ShowDialogAsync(string windowKey,
        object parameter = null)
    {
        var window = await GetAndActivateWindowAsync(windowKey, parameter);
        return window.ShowDialog();
    }

    private async Task<Window> GetAndActivateWindowAsync(string windowKey,
        object parameter = null)
    {
        var window = serviceProvider.GetRequiredService(windows[windowKey])
            as Window;

        if (window.DataContext is IActivable activable)
        {
            await activable.ActivateAsync(parameter);
        }

        return window;
    }
}

First of all, at lines 1-4 we define an IActivable interface to mark View Models that support “activation”, i.e. the ability to receive parameters when the corresponding Window is loaded. Then, the NavigationService class encapsulates all the logic we need:

  • it defines a Configure method (lines 13-14) to map a string identifier to a window type. We follow this approach because we want to use the NavigationService from View Models that don’t have to know the Views;
  • it provides methods to open a window (modeless or modal, lines 24-25 and 31-32 respectively), getting it from the ServiceProvider using the windowKey parameter (lines 37-38);
  • if the Window.DataContext is a View Model that implements the IActivable interface, it calls its ActivateAsync method (lines 41-44), passing to it the specified parameter, if any.

Now we need to properly register the NavigationService and all the Windows and corresponding View Models of our application in the ConfigureServices method of App.xaml.cs file we defined in the previous post:

public static class Windows
{
    public const string MainWindow = nameof(MainWindow);
    public const string DetailWindow = nameof(DetailWindow);
}

private void ConfigureServices(IConfiguration configuration, 
    IServiceCollection services)
{
    // ...

    services.AddScoped<NavigationService>(serviceProvider =>
    {
        var navigationService = new NavigationService(serviceProvider);
        navigationService.Configure(Windows.MainWindow, typeof(MainWindow));
        navigationService.Configure(Windows.DetailWindow, typeof(DetailWindow));

        return navigationService;
    });

    services.AddSingleton<MainViewModel>();
    services.AddSingleton<DetailViewModel>();

    services.AddTransient<MainWindow>();
    services.AddTransient<DetailWindow>();
}

At lines 1-5 we create a Windows class that holds strings corresponding to the Windows of the application, in this sample a MainWindow and a DetailWindow (we’ll talk about them later in this article). Then, we create the NavigationService, configure all the Windows and add it to the services collection (lines 12-19). Finally, at lines 21-25 we add Views Models and Windows themselves.

In the OnStartup method, we can use the new service to show the MainWindow:

protected override async void OnStartup(StartupEventArgs e)
{
    await host.StartAsync();

    var navigationService = 
        ServiceProvider.GetRequiredService<NavigationService>();

    await navigationService.ShowAsync(Navigation.Windows.MainWindow);

    base.OnStartup(e);
}

Now let’s see how to use it. Our MainWindow already contains a TextBox and a Button from the last sample. These objects are already bound to the MainViewModel, so we need to modify it to obtain something like this:

public class MainViewModel : ViewModelBase
{
    private string input;
    public string Input
    {
        get => input;
        set => Set(ref input, value);
    }

    private readonly NavigationService navigationService;
    private readonly ISampleService sampleService;
    private readonly AppSettings settings;

    public RelayCommand ExecuteCommand { get; }

    public MainViewModel(NavigationService navigationService, 
        ISampleService sampleService, IOptions<AppSettings> options)
    {
        this.navigationService = navigationService;
        this.sampleService = sampleService;
        settings = options.Value;

        ExecuteCommand = new RelayCommand(
            async () => await ExecuteAsync());
    }

    private Task ExecuteAsync()
    {
        Debug.WriteLine($"Current value: {input}");
        return navigationService.ShowDialogAsync(Windows.DetailWindow, input);
    }
}

First of all, in the constructor we pass a reference to the NavigationService (line 16). As usual, the .NET Core ServiceProvider is responsible to instantiate it and pass it to the class. Then, in the ExecuteAsync method we show the DetailWindow as dialog using the service, passing the specified input as parameter (line 30).

The DetailWindow can be something like the following:

<Window
    x:Class="WpfNetCoreMvvm.Views.DetailWindow"
    ...
    DataContext
        ="{Binding Source={StaticResource Locator}, Path=DetailViewModel}"
    >

    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="Passed Parameter:" />
            <TextBlock Text="{Binding Parameter}" />
        </StackPanel>
    </Grid>
</Window>

Note in particular the DataContext property at line 4-5 and the binding at line 11. Now we need to define the DetailViewModel itself:

public class DetailViewModel : ViewModelBase, IActivable
{
    private string parameter;
    public string Parameter
    {
        get => parameter;
        set => Set(ref parameter, value);
    }

    public Task ActivateAsync(object parameter)
    {
        Parameter = parameter?.ToString();
        return Task.CompletedTask;
    }
}

When we navigate to DetailWindow from MainViewModel, we pass a parameter, so the DetailViewModel must be able to handle it. For this reason, it implements the IActivable interface (lines 10-13): in this way, the input value from MainViewModel is automatically passed to the ActivateAsync method.

Now we can finally try running the application:

Navigation in the WPF Application with MVVM running on top of .NET Core

Navigation in the WPF Application with MVVM running on top of .NET Core

You can download the sample application using the link below:

An MVVM-aware NavigationService for WPF running on .NET Core

Categories: .NET Core, C#, MVVM, WPF

Using the MVVM pattern in WPF applications running on .NET Core

07/01/2020 22 comments

Some time ago we talked about leveraging .NET Core features (like Host Builder, Service Provider and Dependency Injection) in WPF applications. Now it’s time to integrate them with the MVVM pattern. In this article we’ll use MVVM Light, but only for what concerns helpers methods and classes for View Models. In particular, instead of its SimpleIoc, we’ll show how to use the .NET Core ServiceProvider. So, let’s start from the code that we realized in the latest article and modify it to add MVVM support.

First of all, let’s add the MvvmLightLibsStd10 NuGet package to the project. Then, we need to create a ViewModel for our MainWindow. Keeping in mind that in our original sample the MainWindow receives two parameters in the constructor via Dependency Injection, we want to move them to the View Model. So, we’ll have something like this:

public class MainViewModel : ViewModelBase
{
    private readonly ISampleService sampleService;
    private readonly AppSettings settings;

    public MainViewModel(ISampleService sampleService, 
        IOptions<AppSettings> options)
    {
        this.sampleService = sampleService;
        settings = options.Value;
    }
}

Then, we need to modify the App.xaml.cs file to register this View Model. We also need to expose a reference to the ServiceProvider (we’ll use it later):

public partial class App : Application
{
    private readonly IHost host;

    public static IServiceProvider ServiceProvider { get; private set; }

    public App()
    {
        // Original host configuration...

        ServiceProvider = host.Services;
    }

    private void ConfigureServices(IConfiguration configuration, 
        IServiceCollection services)
    {
        services.Configure<AppSettings>(configuration
            .GetSection(nameof(AppSettings)));
        services.AddScoped<ISampleService, SampleService>();

        // Register all ViewModels.
        services.AddSingleton<MainViewModel>();

        // Register all the Windows of the applications.
        services.AddTransient<MainWindow>();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await host.StartAsync();

        var window = ServiceProvider.GetRequiredService<MainWindow>();
        window.Show();

        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        // Original code...
    }
}

At line 5 we declare a static reference to the IServiceProvider, that we assign at the end of the App constructor using the IHost.Services property (line 11). In the ConfigureServices method, line 22, we register the MainViewModel. In this way, we can get it from the ServiceProvider and, more important, we can pass to its constructor all the dependencies it needs, that will be automatically resolved during instantiation (in this case, AppSettings and ISampleService from lines 17-19).

Note that, typically, View Models are registered as singleton (line 22), but of course we can decide to use the AddTransient method if necessary for our scenario. Moreover, for the sake of simplicity all the registrations are kept together in the same file, but of course it is possible to organize the code as we want.

Now we need to create the ViewModelLocator, i.e. a class that provides (as the name implies) references to View Models that will be bound to Views:

public class ViewModelLocator
{
    public MainViewModel MainViewModel 
        => App.ServiceProvider.GetRequiredService<MainViewModel>();
}

In this case, we have only one View Model, as at lines 3-4 we get it using the ServiceProvider property that is exposed by the App class. As we said earlier, all registrations are contained in the ConfigureServices method of the App class, so the ViewModelLocator need only to provide getter properties for View Models.

The last thing to do is to reference the ViewModelLocator in XAML and link the View Model to the View. So, in the App.xaml file we need to write something like this:

<Application
    x:Class="WpfNetCoreMvvm.App"
    ...>

    <Application.Resources>
        <ResourceDictionary>
            <vm:ViewModelLocator
                xmlns:vm="clr-namespace:WpfNetCoreMvvm.ViewModels"
                x:Key="Locator" />

            <!-- Application styles definition -->
        </ResourceDictionary>
    </Application.Resources>
</Application>

And, finally, set the DataContext property of MainWindow.xaml:

<Window
    x:Class="WpfNetCoreMvvm.Views.MainWindow"
    ...
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}">

Now everything is set. We can put a breakpoint in the MainViewModel constructor and verify that it will be correctly invoked when the application starts, with all the dependencies it needs:

The View Model of the .NET Core 3.1 WPF application with dependencies injected

The View Model of the .NET Core 3.1 WPF application with dependencies injected

To make a further test, we can add a bit of code to the View Model:

public class MainViewModel : ViewModelBase
{
    private string input;
    public string Input
    {
        get => input;
        set => Set(ref input, value);
    }

    private readonly ISampleService sampleService;
    private readonly AppSettings settings;

    public RelayCommand ExecuteCommand { get; }

    public MainViewModel(ISampleService sampleService,
        IOptions<AppSettings> options)
    {
        this.sampleService = sampleService;
        settings = options.Value;

        ExecuteCommand = new RelayCommand(async () => await ExecuteAsync());
    }

    private Task ExecuteAsync()
    {
        Debug.WriteLine($"Current value: {input}");
        return Task.CompletedTask;
    }
}

Now we have an Input property (lines 3-8) and a RelayCommand (line 13, with the implementation at lines 24-28). So, as usual, we can use binding in our Window:

<Window
    ...>

    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="Input:" />
            <TextBox Width="300" Text="{Binding Input, Mode=TwoWay}" />
            <Button Command="{Binding ExecuteCommand}" Content="Execute" />
        </StackPanel>
    </Grid>
</Window>

Let’s try running the application:

The WPF Application with MVVM running on top of .NET Core

The WPF Application with MVVM running on top of .NET Core

You can download the sample application using the link below:

Using the MVVM pattern in WPF application running on .NET Core

In the next article we’ll add an important feature that is currently missing: the ability to navigate through Window from View Models passing parameters to them upon activation.

Categories: .NET Core, C#, MVVM, WPF

JSON Serialization and Deserialization using System.Text.Json with Refit

13/11/2019 Comments off

Refit is a very useful library that allows to define an interface for a REST API and call it hiding all the HTTP and JSON serialization/deserialization bits. A lot of samples of its usage are available on GitHub.

By default, Refit uses JSON.NET under-the-hood to handle serializing and deserializing JSON. However, we can change this behavior and use the new System.Text.Json objects by defining a custom Content Serializer, i.e. a class that implements the IContentSerializer interface:

public interface IContentSerializer
{
    Task<T> DeserializeAsync<T>(HttpContent content);
    
    Task<HttpContent> SerializeAsync<T>(T item);
}

So, we can provide an implementation like the following:

public class JsonContentSerializer : IContentSerializer
{
    private readonly JsonSerializerOptions serializerOptions;

    public JsonContentSerializer(JsonSerializerOptions serializerOptions = null)
    {
        this.serializerOptions = serializerOptions ?? new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = true,
        };
    }

    public async Task<T> DeserializeAsync<T>(HttpContent content)
    {
        using var utf8Json = await content.ReadAsStreamAsync()
            .ConfigureAwait(false);

        return await JsonSerializer.DeserializeAsync<T>(utf8Json,
            serializerOptions).ConfigureAwait(false);
    }

    public Task<HttpContent> SerializeAsync<T>(T item)
    {
        var json = JsonSerializer.Serialize(item, serializerOptions);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        return Task.FromResult((HttpContent)content);
    }
}

At lines 20-21 and 26, we’re using the JsonSerializer class from System.Text.Json to perform serialization and deserialization.

Finally, we need to tell Refit to use this implementation instead of the default one:

var settings = new RefitSettings
{
    ContentSerializer = new JsonContentSerializer()
};

var api = RestService.For<IMyServiceApi>("<service_url>", settings);

At lines 1-4, we create a RefitSettings object that specifies the Content Serializer to use. Then, we pass it to the static RestService.For method (line 6). Now all the JSON content will be handled with System.Text.Json.

Categories: .NET Core, C#

Update on using HostBuilder, Dependency Injection and Service Provider with .NET Core 3.0 WPF applications

07/11/2019 18 comments

Some months ago we talked about how to use .NET Core 3.0 Dependency Injection and Service Provider with WPF. Now that the final version of .NET Core 3.0 has reached its GA, it’s time to update that article showing the right approach to use HostBuilder, Dependency Injection and Service Provider in WPF applications.

So, after creating a .NET Core WPF application, we need to add the NuGet package Microsoft.Extensions.Hosting to the project. It will allow us to use HostBuilder and, moreover, it automatically imports a bunch of other required packages.

Now, Let’s open the App.xaml file and remove the StartupUri property of the Application class. Then, write the following code in the App.xaml.cs file:

public partial class App : Application
{
    private readonly IHost host;

    public App()
    {
        host = Host.CreateDefaultBuilder()
               .ConfigureServices((context, services) =>
               {
                   ConfigureServices(context.Configuration, services);
               })
               .Build();
    }

    private void ConfigureServices(IConfiguration configuration, 
        IServiceCollection services)
    {
        // ...
        services.AddSingleton<MainWindow>();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await host.StartAsync();

        var mainWindow = host.Services.GetRequiredService<MainWindow>();
        mainWindow.Show();

        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        using (host)
        {
            await host.StopAsync(TimeSpan.FromSeconds(5));
        }

        base.OnExit(e);
    }
}

At line 7, we create a HostBuilder using the Host.CreateDefaultBuilder method. As we can read in the documentation, it automatically configures some defaults (that are tipically useful for every application):

If we don’t want these configuration, but instead we prefer to manually configure every setting, we can simply initialize a new HostBuilder. In any case, it is possible to invoke other methods to further configure our host:

host = Host.CreateDefaultBuilder()  // Use default settings
       //new HostBuilder()          // Initialize an empty HostBuilder
        .ConfigureAppConfiguration((context, builder) =>
        {
            // Add other configuration files...
            builder.AddJsonFile("appsettings.local.json", optional: true);
        }).ConfigureServices((context, services) =>
        {
            ConfigureServices(context.Configuration, services);
        })
        .ConfigureLogging(logging => 
        {
            // Add other loggers...
        })
        .Build();

Going back to the first App.xaml.cs file, at line 8 we call HostBuilder.ConfigureService, that is responsible to add all our services in the .NET Core IoC Container. This method in turn calls our ConfigureServices implementation (lines 15-20), in which we register all the services used by the application in the exact same way of ASP. NET Core. We’ll complete this method in a moment, but for now let’s notice that we register also the MainWindow class (line 19). This is important because, in this way, the window itself becomes part of the Dependency Injection chain. It means that, after calling this method, at line 26-27 we can get it from the ServiceProvider and then show it. But, more important, it means that we can pass to the MainWindow constructor all the dependencies it needs, as we do for ASP.NET Core Controllers.

In the OnStartup override (lines 22-30), we call the StartAsync method to start the program (line 24): at this moment, it calls IHostedService.StartAsync on each implementation of IHostedService that it finds in the DI container (we don’t have any of this in our app, so in fact this method does nothing). Finally, as said before, at line 26-27 we get the MainWindow from the ServiceProvider and then show it.

As last step, in the OnExit method (lines 32-39), we call StopAsync to gracefully stop the host.

Even if the actual services aren’t yet registered, we can run the application and see that everything works as expected.

Now it’s time to complicate the things a bit. Let’s add a file named appsettings.json to the root folder of the project. Set its Build Action property to Content and Copy to Output Directory to Copy if newer:

{
  "AppSettings": {
    "StringSetting": "Value",
    "IntegerSetting": 42,
    "BooleanSetting": true
  }
}

This file is automatically loaded and made available to the application by the CreateDefaultBuilder method we talked before. Then, we create an AppSettings.cs file to hold configuration settings. This file will map the settings that we write in appsettings.json:

public class AppSettings
{
    public string StringSetting { get; set; }
 
    public int IntegerSetting { get; set; }
 
    public bool BooleanSetting { get; set; }
}

Moreover, create also a sample service with its interface:

public interface ISampleService
{
    string GetCurrentDate();
}
 
public class SampleService : ISampleService
{
    public string GetCurrentDate() => DateTime.Now.ToLongDateString();
}

Now we must register these services in the IoC Container, as usual:

private void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    services.Configure<AppSettings>
            (configuration.GetSection(nameof(AppSettings)));

    services.AddScoped<ISampleService, SampleService>();

    //...
}

As said before, the MainWindow itself is in the IoC Container. So, when we get it from the Service Provider, it will automatically be injected with all the required services. So, we just need to modify its constructor:

public partial class MainWindow : Window
{
    private readonly ISampleService sampleService;
    private readonly AppSettings settings;
 
    public MainWindow(ISampleService sampleService, 
                      IOptions<AppSettings> settings)
    {
        InitializeComponent();
 
        this.sampleService = sampleService;
        this.settings = settings.Value;
    }
 
    // ...
}

Running this code, we’ll obtain a result like the following:

The .NET Core 3.0 WPF application with dependecies injected

The .NET Core 3.0 WPF application with dependecies injected

You can download the sample app using the link below:

Update on using HostBuilder, Dependency Injection and Service Provider with .NET Core 3.0 WPF applications

Categories: .NET Core, C#, WPF

A simple NavigationService with Dependency Injection for WPF on .NET Core 3.0

21/05/2019 1 comment

We already talked about how to use Dependency Injection and Service Provider with WPF on .NET Core 3.0. In that occasion we said that windows themselves are registered in the IoC, so that we need to use the ServiceProvider to get and load them, for example:

var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();

This approach works correctly, but we need to use two instructions every time we want to open a new window. Moreover, we don’t have a straight way to pass parameters to the new window. To make things simpler, we can write a couple of classes to manage this task:

public interface IActivable
{
    Task ActivateAsync(object parameter);
}

public class SimpleNavigationService
{
    private readonly IServiceProvider serviceProvider;

    public SimpleNavigationService(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public async Task ShowAsync<T>(object parameter = null) where T : Window
    {
        var window = serviceProvider.GetRequiredService<T>();
        if (window is IActivable activableWindow)
        {
            await activableWindow.ActivateAsync(parameter);
        }

        window.Show();
    }

    public async Task<bool?> ShowDialogAsync<T>(object parameter = null) 
        where T : Window
    {
        var window = serviceProvider.GetRequiredService<T>();
        if (window is IActivable activableWindow)
        {
            await activableWindow.ActivateAsync(parameter);
        }

        return window.ShowDialog();
    }
}

First of all, at lines 1-4 we define an IActivable interface to mark Windows that support “activation”, i.e. the ability to receive parameters upon loading. Then, the SimpleNavigationService class encapsulates all the logic we need:

  • it provides methods to open a window, getting it from the ServiceProvider (lines 15-36), so every dependency is automatically resolved and passed to its constructor;
  • if the window implements the IActivable interface, it calls the ActivateAsync method before actually showing it.

Now we just need to properly register the SimpleNavigationService and all the windows of our application in the ConfigureServices methods we defined in the previous post:

private void ConfigureServices(IServiceCollection services)
{
    // ...

    // Add SimpleNavigationService for the application.
    services.AddScoped<SimpleNavigationService>();

    // Register all the windows of the applications.
    services.AddTransient<MainWindow>();
    services.AddTransient<DetailWindow>();
}

At the end of the OnStartup method, we can use the new service to show the MainWindow:

protected override void OnStartup(StartupEventArgs e)
{
    // ....

    var navigationService = ServiceProvider
                            .GetRequiredService<SimpleNavigationService>();
    var task = navigationService.ShowAsync<MainWindow>();
}

Now let’s see how to use it. Let’s suppose to have a window with a TextBox and a Button:

<Window
    ...>

    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="Parameter:" />
            <TextBox x:Name="ParameterTextBox" Width="300" />
            <Button
                x:Name="OpenDetailWindowButton"
                Click="OpenDetailWindowButton_Click"
                Content="Go to Detail Window" />
        </StackPanel>
    </Grid>
</Window>

We want that, pressing the Button at lines 8-11, the DetailWindow will be opened, receiving the value of the TextBox. So, the code-behind in MainWindow.xaml.cs is the following:

public partial class MainWindow : Window
{
    private readonly SimpleNavigationService navigationService;

    public MainWindow(SimpleNavigationService navigationService)
    {
        // ...
        this.navigationService = navigationService;
    }

    private async void OpenDetailWindowButton_Click(object sender, 
                                                    RoutedEventArgs e)
    {
        var result = await navigationService
                           .ShowDialogAsync<DetailWindow>(ParameterTextBox.Text);
    }
}

We pass the SimpleNavigationService in the MainWindow constructor through Dependency Injection, then in the button event handler we call the ShowDialogAsync method specifying the type of the Window to open and the parameter to initialize it. To be able to handle this, the DetailWindow code-behind should be something like that:

public partial class DetailWindow : Window, IActivable
{
    public DetailWindow()
    {
        // ...
    }

    public Task ActivateAsync(object parameter)
    {
        ParameterTextBox.Text = parameter?.ToString();
        return Task.CompletedTask;
    }
}

As DetailWindow implements the IActivable interface (line 1), SimpleNavigationService will ensure that the ActivateAsync method is called before showing the UI. In this sample, we just set the parameter in a TextBox (line 10). Of course, also the DetailWindow class could receive dependencies in its constructor, if necessary.

You can download the sample app using the link below:

A simple NavigationService with Dependency Injection for WPF on .NET Core 3.0

Categories: .NET Core, C#, WPF

Using Entity Framework Core with WPF on .NET Core 3.0

19/03/2019 2 comments

We talked about how to configure a .NET Core 3.0 WPF application in the same way as we do with ASP.NET Core. We can keep using this approach also if we need to use Entity Framework Core. It is important to note that tipically we use an external service to perform data access (for example, a REST Web APIs backend), but in some cases (especially if we’re working with a legacy system) it might be necessary to access a database directly from within our application.

And the story is again the same: you use the same code of ASP.NET Core. Let’s see how to do that. As always, take this sample as reference. First of all, we need to add the NuGet package for Entity Framework Core:

Adding Entity Framework Core to .NET Core 3.0 WPF application

Adding Entity Framework Core to .NET Core 3.0 WPF application

In this example, we’re using Entity Framework with SQL Server, but of course we can use every database supported by this OR/M.

Now, let’s add a connection string in the appsettings.json file:

{
  "ConnectionStrings": {
    "SqlConnection": ""
  }
}

Then, we must create our data context, i.e., a class that inherits form DbContext and provides access to the database:

public class DataContext : DbContext
{
    // DbSet properties declarations...

    public DataContext(DbContextOptions<DataContext> options) : base(options)
    {
    }
}

The DataContext class contains a constructor that takes a DbContextOptions as argument. It is used to pass configuration settings to the Context via Dependency Injection. For the rest, we can add to the class the usual DbSets we are accustomed to and configure the model by overriding the OnConfiguring and OnModelCreating methods.

Finally, we need to register the DbContext in the ServiceProvider collection, like we did in the previous post:

private void ConfigureServices(IServiceCollection services)
{
     services.AddDbContext<DataContext>
        (options => options.UseSqlServer(
                    Configuration.GetConnectionString("SqlConnection")));

            
     services.AddTransient(typeof(MainWindow));
}

At lines 4-5 we setup the DataContext to use SQL Server with the connection string from the appsettings.json file we defined before.

Now we’re ready to use the DataContext in every Window we need it. For example:

private readonly DataContext dataContext;

public MainWindow(DataContext dataContext)
{
    InitializeComponent();

    this.dataContext = dataContext;
}

As we can see, also in this case the approach is the same we use with ASP.NET Core. Of course, we can choose to pass the DataContext to a business service, instead of accessing it directly: as long as the service is itself in the IoC container, everything works in the same way.

Categories: .NET Core, C#, Entity Framework, WPF