Wednesday, April 24, 2024

Dive Deep: Unveiling DevExpress Splash Screen in Your WinForms App

 Introduction:

In today's fast-paced digital world, user experience plays a pivotal role in the success of any application. One aspect that significantly contributes to a positive user experience is the loading screen or splash screen. A well-designed splash screen enhances the aesthetic appeal of your application and provides users with visual feedback during the loading process, reducing perceived wait times.

In this tutorial, we'll explore implementing a splash screen in a Winforms application using DevExpress, a powerful suite of UI controls and components. By the end of this tutorial, you'll have a sleek and professional-looking splash screen integrated into your Winforms application, enhancing its overall user experience.

Step 1: Setting Up Your Winforms Project

Before implementing the DevExpress splash screen, let's set up a basic Winforms project in Visual Studio.

  1. Open Visual Studio and create a new Winforms project.
  2. Name your project and choose a location to save it.
  3. Once the project is created, you'll see the default form in the designer view.

Step 2: Installing DevExpress

You must install the DevExpress NuGet package to use the DevExpress controls and components in your Winforms project.

  1. Right-click on your project in the Solution Explorer.
  2. Select "Manage NuGet Packages" from the context menu.
  3. In the NuGet Package Manager, search for "DevExpress" and install the appropriate package for your project.

Step 3: Adding a Splash Screen Form

Now, let's create a new form for our splash screen.

  1. Right-click on your project in the Solution Explorer.
  2. Select "Add DevExpress Item" from the context menu.
  3. Select "Splash Screen" from the DevExpres Template Gallery.
  4. Name the form "SplashScreenForm" and click "Add Item"
  5. Design your splash screen form using DevExpress controls to customize its appearance according to your preferences. You can add images, animations, and progress indicators to make it visually appealing.

Step 4: Configuring Application Startup

Next, we must configure our application to display the splash screen during startup.

  1. Open the Program.cs file in your project.

  2. Locate the Application.Run method, typically found within the Main method.

  3. Before calling Application.Run, create and display an instance of your splash screen form.

     static void Main()
     {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
     
         //Application.Run(new MainFormWithSplashScreenManager());
         var form = new MainForm();
         DevExpress.XtraSplashScreen.SplashScreenManager.ShowForm(form, typeof(SkinnedSplashScreen));
         //...
         //Authentication and other activities here
         Bootstrap.Initialize();                        
     
         DevExpress.XtraSplashScreen.SplashScreenManager.CloseForm();                      
         Application.Run(form);
     }
    
     internal class Bootstrap
     {
         internal static void Initialize()
         {
             // Add initialization logic here
             //Authentication and other activities here
             LoadResources();            
             
         }
         private static void LoadResources()
         {
             // Perform resource loading tasks
             // Example: Load configuration settings, connect to a database, etc.
    
             Thread.Sleep(1000);//For testing
         }
     }

Step 5: Adding Splash Screen Logic

Now that our splash screen is displayed during application startup let's add some logic to control its behaviour.

  1. Open the SplashScreenForm.cs file.

  2. Add any initialization logic or tasks that must be performed while the splash screen is displayed. For example, you can load resources, perform database connections, or initialize application settings.

     public partial class SkinnedSplashScreen : SplashScreen
     {
         public SkinnedSplashScreen()
         {
             InitializeComponent();
             this.labelCopyright.Text = "Copyright © 1998-" + DateTime.Now.Year.ToString();
         }
    
         #region Overrides
    
         public override void ProcessCommand(Enum cmd, object arg)
         {
             base.ProcessCommand(cmd, arg);
         }
    
         #endregion
    
         public enum SplashScreenCommand
         {
         }
    
         private void SkinnedSplashScreen_Load(object sender, EventArgs e)
         {
             
         }
     }

Step 6: Testing Your Application

With the splash screen implemented, it's time to test your Winforms application.

  1. Build your project to ensure there are no compilation errors.
  2. Run the application and observe the splash screen displayed during startup.
  3. Verify that the application functions correctly after the splash screen closes.

See the following topic for information on how to execute code when your application starts: How to: Perform Actions On Application Startup.

Conclusion:

In this tutorial, we've learned how to implement a splash screen in a Winforms application using DevExpress. By following these steps, you can enhance the user experience of your application by providing visual feedback during the loading process. You can customize the splash screen further to match the branding and style of your application and experiment with different animations and effects to create a memorable first impression for your users.

References
Splash Screen
Splash Screen Manager

Source Code

Friday, April 19, 2024

Leveraging Consul for Service Discovery in Microservices with .NET Core

Introduction:

In a microservices architecture, service discovery is pivotal in enabling seamless communication between services. Imagine having a multitude of microservices running across different ports and instances and the challenge of locating and accessing them dynamically. This is where the Consul comes into play.

Introduction to Consul:
Consul, a distributed service mesh solution, offers robust service discovery, health checking, and key-value storage features. This tutorial will explore leveraging Consul for service discovery in a .NET Core environment. We’ll set up Consul, create a .NET Core API for service registration, and develop a console application to discover the API using Consul.

Step 1: Installing Consul:
Before integrating Consul into our .NET Core applications, we need to install Consul. Follow these steps to install Consul:

  1. Navigate to the Consul downloads page: Consul Downloads.
  2. Download the appropriate version of Consul for your operating system.
  3. Extract the downloaded archive to a location of your choice. 
  4. Add the Consul executable to your system’s PATH environment variable to run it from anywhere in the terminal or command prompt. 
  5. Open a terminal or command prompt and verify the Consul installation by running the command consul --version.
  6. Run the Consul server by running the command consul agent -dev

Step 2: Setting Up the Catalog API:

Now, let’s create a .NET Core API project named ServiceDiscoveryTutorials.CatalogApi. This API will act as a service that needs to be discovered by other applications. Use the following command to create the project:

dotnet new webapi -n ServiceDiscoveryTutorials.CatalogApi

Next, configure the API to register with the Consul upon startup. Add the Consul client package to the project:

dotnet add package Consul

In the Startup.cs file, configure Consul service registration in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddSingleton<IConsulClient>(p => new ConsulClient(consulConfig =>
    {
        var consulHost = builder.Configuration["Consul:Host"];
        var consulPort = Convert.ToInt32(builder.Configuration["Consul:Port"]);
        consulConfig.Address = new Uri($"http://{consulHost}:{consulPort}");
    }));
    
    services.AddSingleton<IServiceDiscovery, ConsulServiceDiscovery>();

}

Create a class named ConsulServiceDiscovery that implements the IServiceDiscovery interface to handle service registration:

public interface IServiceDiscovery
{
    Task RegisterServiceAsync(string serviceName, string serviceId, string serviceAddress, int servicePort);
    Task RegisterServiceAsync(AgentServiceRegistration serviceRegistration);
    
    Task DeRegisterServiceAsync(string serviceId);
}

public class ConsulServiceDiscovery : IServiceDiscovery
{
    private readonly IConsulClient _consulClient;

    public ConsulServiceDiscovery(IConsulClient consulClient)
    {
        _consulClient = consulClient;
    }

    public async Task RegisterServiceAsync(string serviceName, string serviceId, string serviceAddress, int servicePort)
    {
        var registration = new AgentServiceRegistration
        {
            ID = serviceId,
            Name = serviceName,
            Address = serviceAddress,
            Port = servicePort
        };
        await _consulClient.Agent.ServiceDeregister(serviceId);
        await _consulClient.Agent.ServiceRegister(registration);
    }

    public async Task DeRegisterServiceAsync(string serviceId)
    {
        await _consulClient.Agent.ServiceDeregister(serviceId);
    }

    public async Task RegisterServiceAsync(AgentServiceRegistration registration)
    {
        await _consulClient.Agent.ServiceDeregister(registration.ID);
        await _consulClient.Agent.ServiceRegister(registration);
    }
}

In the Configure method of Startup.cs, add the service registration logic:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConsulClient consulClient)
{
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    //app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    
    app.MapControllers();
    
    var discovery = app.Services.GetRequiredService<IServiceDiscovery>();
    var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
    var serviceName = "CatalogApi";
    var serviceId = Guid.NewGuid().ToString();
    var serviceAddress = "localhost";
    var servicePort = 7269;
    
    lifetime.ApplicationStarted.Register(async () =>
    {
        var registration = new AgentServiceRegistration
        {
            ID = serviceId,
            Name = serviceName,
            Address = serviceAddress,
            Port = servicePort,
            Check = new AgentServiceCheck
            {
                HTTP = $"https://{serviceAddress}:{servicePort}/Health",
                Interval = TimeSpan.FromSeconds(10),
                Timeout = TimeSpan.FromSeconds(5)
            }
        };
        await discovery.RegisterServiceAsync(registration);
    });
    
    lifetime.ApplicationStopping.Register(async () =>
    {
        await discovery.DeRegisterServiceAsync(serviceId);
    });

}

With these configurations, the Catalog API will register itself with the Consul upon startup and deregister upon shutdown.

Step 3: Creating the Client Application:

Next, create a console application named ServiceDiscoveryTutorials.ClientApp. Use the following command to create the project:

dotnet new console -n ServiceDiscoveryTutorials.ClientApp

Add the Consul client package to the project:

dotnet add package Consul

In the Program.cs file, configure the Consul client to discover services:

class Program
{
    static async Task Main(string[] args)
    {
        using (var client = new ConsulClient(consulConfig =>
        {
            consulConfig.Address = new Uri("http://localhost:8500");
        }))
        {
            var services = await client.Catalog.Service("CatalogApi");
            foreach (var service in services.Response)
            {
                Console.WriteLine($"Service ID: {service.ServiceID}, Address: {service.ServiceAddress}, Port: {service.ServicePort}");
            }
        }
        //var consulClient = new ConsulClient();
        //// Specify the service name to discover
        //string serviceName = "CatalogApi";
        //// Query Consul for healthy instances of the service
        //var services = (await consulClient.Health.Service(serviceName, tag: null, passingOnly: true)).Response;
        //// Iterate through the discovered services
        //foreach (var service in services)
        //{
        //    var serviceAddress = service.Service.Address;
        //    var servicePort = service.Service.Port;
        //    Console.WriteLine($"Found service at {serviceAddress}:{servicePort}");
        //    // You can now use the serviceAddress and servicePort to communicate with the discovered service.
        //}

    }
}

This code snippet retrieves all instances of the CatalogApi service registered with the Consul.

Step 3: Testing the API and Client Application:

Below is the project structure in the Visual Studio. 

Next, let’s run both applications using the command dotnet run. When this application starts, the Consul portal will display the registered service. 

Below is the final results of the application.

Conclusion:
In this tutorial, we’ve learned how to set up Consul for service discovery and register a .NET Core API with Consul. Additionally, we’ve developed a console application to discover services using Consul’s API. By leveraging Consul, you can enhance the scalability and reliability of your microservices architecture.

Source Code