Ehsan Ghanbari

Experience, DotNet, Solutions

Multiple workers in asp.net core

In asp.net core project templates, you can find something name Worker. It’s a service-based project which has the capability of being converted to windows service. After creating the project, you can see the following piece of code as worker service:

 

  public class Worker : BackgroundService

    {

        private readonly ILogger<Worker> _logger;

 

        public Worker(ILogger<Worker> logger)

        {

            _logger = logger;

        }

 

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)

        {

            while (!stoppingToken.IsCancellationRequested)

            {

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

                await Task.Delay(1000, stoppingToken);

            }

        }

    }

 

It's being hosted in Program  class:

 

 public class Program

    {

        public static void Main(string[] args)

        {

            CreateHostBuilder(args).Build().Run();

        }

 

        public static IHostBuilder CreateHostBuilder(string[] args) =>

            Host.CreateDefaultBuilder(args)

                .ConfigureServices((hostContext, services) =>

                {

                    services.AddHostedService<Worker>();

                });

    }

 

You can have multiple workers in ExecuteAsync by changing a bit:

 

 public class Worker : BackgroundService

    {

        private readonly ILogger<Worker> _logger;

 

        public Worker(ILogger<Worker> logger)

        {

            _logger = logger;

        }

       

        protected override Task ExecuteAsync(CancellationToken stoppingToken)

        {

            return Task.Factory.StartNew(async () =>

            {

                while (!stoppingToken.IsCancellationRequested)

                {

                    var workers = new List<Task>

                    {

                        RunWorker1(stoppingToken),

                        RunWorker2(stoppingToken)

                    };

                    await Task.WhenAll(workers.ToArray());

                }

            }, stoppingToken);

        }

 

        private async Task RunWorker1(CancellationToken stoppingToken)

        {

            while (!stoppingToken.IsCancellationRequested)

            {

                _logger.LogInformation("Worker1 running at: {time}", DateTimeOffset.Now);

                await Task.Delay(1000, stoppingToken);

            }

        }

 

        private async Task RunWorker2(CancellationToken stoppingToken)

        {

            while (!stoppingToken.IsCancellationRequested)

            {

                _logger.LogInformation("Worker2 running at: {time}", DateTimeOffset.Now);

                await Task.Delay(1000, stoppingToken);

            }

        }

    }

 



Localization in asp.net core API for every request

Recently I was tackling a problem with localization in asp.net core. I wanted to get the culture in every request from API and respond based on the requested culture. So I created the following middleware as it's not possible to have access HttpContext in asp.net core by default.

 

public class CultureValidationMiddleware

    {

        private readonly RequestDelegate _next;

 

        public CultureValidationMiddleware(RequestDelegate next)

        {

            _next = next;

        }

 

        public async Task Invoke(HttpContext httpContext)

        {

            IHeaderDictionary headers = httpContext.Request.Headers;

            var culture = CultureManager.GetImplementedCulture(headers["culture"]);

          

            var supportedCultures = CultureManager.GetSupportedCultures();

            var localizationOptions = new RequestLocalizationOptions

            {

                DefaultRequestCulture = new RequestCulture(culture),

                SupportedCultures = supportedCultures,

                SupportedUICultures = supportedCultures

            };

        

            await _next.Invoke(httpContext);

        }

    }

 

In order to use the above middleware I had to create an extension method like below:

 

  

public static class ApplicationBuilderExtensions

    {

        public static IApplicationBuilder SetCultureValue(this IApplicationBuilder app)

        {

            return app.UseMiddleware<CultureValidationMiddleware>();

        }

    }

 

The point was this that I couldn’t use  app.UseRequestLocalization(); in the startup as I wanted to get the culture in every request! After tackling a lot I found another way to solve the issue.

 


  public class UserProfileRequestCultureProvider : RequestCultureProvider

    {

        public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)

        {

            if (httpContext == null)

            {

                throw new ArgumentNullException(nameof(httpContext));

            }

 

            IHeaderDictionary headers = httpContext.Request.Headers;

            var culture = CultureManager.GetImplementedCulture(headers["culture"]);

 

            return Task.FromResult(new ProviderCultureResult(culture));

        }

    }

 

By configuring the above provider in services of Startup class I solved the issue!

 

services.Configure<RequestLocalizationOptions>(options =>

            {

                options.DefaultRequestCulture = new RequestCulture(culture: "fa-ir");

                options.SupportedCultures = supportedCultures;

                options.SupportedUICultures = supportedCultures;

                options.RequestCultureProviders.Clear();

                options.RequestCultureProviders.Add(new UserProfileRequestCultureProvider());

            });

 

If you know a better way, please help me!



Asp.net core razor pages with a simple command, query handler

I'm already working on a project and a challenging decision has been made to use asp.net core razor pages. Based on Microsoft definition:" ASP.NET Core Razor Pages is a page-focused framework for building dynamic, data-driven web sites with clean separation of concerns." I've found razor pages so cool so far as it's totally compatible with the architecture of the current project of mine. I'm using a simple command query (it's not CQRS) in this project. Once I shared another architectural pattern about Command and query over here. Take a deep look at the following simple base classes and interfaces:

 

 public interface ICommand<out TResult> { }

   public interface ICommandHandler<in TCommand, out TResult> where TCommand : 
   ICommand<TResult>
    {
        TResult Execute();
    }

    public class CommandResult
    {
        public bool Faild { get; set; }

        public string Message { get; set; }
     }

    public interface IQuery<out TResponse> { }

    public interface IQueryHandler<in TQuery, out TResponse> where TQuery :  
    Query<TResponse>
     {
        TResponse Get();
     }

 

I'm sharing these classes in one code snippet, but Commands and Queries will be lived in different assemblies although the above classes are bases and could be in an infrastructural assembly as well. Let's create a query sample. For example for querying a user detail, firstly I should create the related QueryView:

 


    public class UserDetailQueryView 
    {
        public int Id { get; set; }
        public string Username { get; set; }
    }

 

And then it's Query class turn. Note that the query class is just like Request in Request/Response pattern.

 

    public class UserDetailQuery : IQuery<UserDetailQueryView>
    {
        public long UserId { get; private set; }

        public UserDetailQuery(long userId)
        {
            UserId = userId;
        }
     }

 

And then create the handler of the above Query:

 

  
   internal class UserDetailQueryHandler : IQueryHandler<UserDetailQuery, 
   UserDetailQueryView>
    {
        private readonly UserDetailQuery _userDetailQuery;
     
        public UserDetailQueryHandler(UserDetailQuery userDetailQuery)
        {
            _userDetailQuery = userDetailQuery;
        }

        public UserDetailQueryView Get()
        {
            var user = MyDdContext.Users.GetById(_userDetailQuery.UserId);
            return new UserDetailQueryView { Username = user.Username, Id = user.Id };       
        }
    }

 

As you know, it's not a good idea to directly call EF DbContext to fetch data, it's just a sample code I'm sharing over here. And finally let's aggregate the queries in one Factory class  like this:

 

    public static class UserQueryFactory
    {
        public static IQueryHandler<UserDetailQuery, UserDetailQueryView> 
        Build(UserDetailQuery query)
        {
            return new UserDetailQueryHandler(query);
        }
     }

 

Now add a Razor page just like it's depicted below:

 

 

Now you can call the UserQueryFactory class in the razor page that we have created:

 


    public class DetailModel : PageModel
    {
        public int UserId { get; set; }

        public UserDetailQueryView UserDetailQueryView { get; set; }

        public IActionResult OnGet()
        {
            var query = new UserDetailQuery(UserId);
            var queryHandler = UserQueryFactory.Build(query);
            UserDetailQueryView = queryHandler.Get();

            if (UserDetailQueryView == null)
            {
                return NotFound();
            }

            return Page();
        }
     }

 

Now if you are interested to know how I'm using Commands, stay with me to create another command sample. A command is something the changes the state of an object. Such an example, ChangePassword is a command. Let's create it.

 


    public class ChangePasswordCommand : ICommand<CommandResult>
    {
        public string Username { get; set; }

        public string OldPassword { get; set; }

        public string NewPassword { get; set; }

        public string ConfirmPassword { get; set; }
     }

 

And again we should create a handler for the above command:

 

   internal class UserCommandHandler : ICommandHandler<ChangePasswordCommand, 
   CommandResult>
    {
        public CommandResult Execute()
        {
            var commandResult = new CommandResult();

            try
            {
                //fetch data from database and change the password
                
            }
            catch (Exception exception)
            {
                commandResult.Faild = true;
            }

            return commandResult;
        }
     }

 

And finally, just like query, let's create a factory for having all of the handlers in one place:

 

    public static class UserCommandFactory
    {
        public static ICommandHandler<ChangePasswordCommand, CommandResult> 
        Build(ChangePasswordCommand command)
        {
            return new UserCommandHandler();
        }
     }

 

Create another razor page for ChangePassword and in the class create with the same name, add the following command for changing the password:

 

    public class ChangePasswordModel : PageModel
    {
        [BindProperty]
        public string Username { get; set; }

        [BindProperty]
        public string OldPassword { get; set; }

        [BindProperty]
        public string NewPassword { get; set; }

        [BindProperty]
        public string ConfirmPassword { get; set; }

        public IActionResult OnPost()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            var changePasswordCommand = new ChangePasswordCommand
            {
                ConfirmPassword = ConfirmPassword,
                NewPassword = NewPassword,
                OldPassword = OldPassword,
                Username = Username
            };

            var commandHandler = 
            UserCommandFactory.Build(changePasswordCommand);
            var commandResult = commandHandler.Execute();

            if(commandResult.Faild)
            {
                //redirect to error page or return the message
            }

            return RedirectToPage("./Index");
        }
     }

 

Voila!



Specifying the bounded port in asp.net core

I just faced a problem in asp.net core which was specifying the bounded port. There is an extension in WebHostBuilder named  UseUrls() to specify that:

 

 public class Program

    {

        public static void Main(string[] args)

        {

            CreateWebHostBuilder(args)

                .UseKestrel()

                .UseContentRoot(Directory.GetCurrentDirectory())

                .UseIISIntegration()

                .UseStartup<Startup>()

                .UseUrls("http://localhost:5002/")

                .Build()

                .Run();

        }

 

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>

            WebHost.CreateDefaultBuilder(args)

                .UseStartup<Startup>();

    }

 

Rather than the solution above, you can specify it in launchSettings.json under properties of asp.net core. Look at the default values of the file:

 

{

  "$schema": "http://json.schemastore.org/launchsettings.json",

  "iisSettings": {

    "windowsAuthentication": false,

    "anonymousAuthentication": true,

    "iisExpress": {

      "applicationUrl": "http://localhost:60901",

      "sslPort": 44343

    }

  },

  "profiles": {

    "IIS Express": {

      "commandName": "IISExpress",

      "launchBrowser": true,

      "launchUrl": "api/values",

      "environmentVariables": {

        "ASPNETCORE_ENVIRONMENT": "Development"

      }

    },

    "Khorjin.Core.API": {

      "commandName": "Project",

      "launchBrowser": true,

      "launchUrl": "api/values",

      "applicationUrl": "https://localhost:5001;http://localhost:5000",

      "environmentVariables": {

        "ASPNETCORE_ENVIRONMENT": "Development"

      }

    }

  }

}

 

In applicationUrl  you can even initial more than one Url separated by a semicolon:

 

"applicationUrl": "http://localhost:60901;http://localhost:5002",

 



Using Middleware to handle exceptions in asp.net core

There are a few ways to handle exceptions in asp.net core 2.1. using Middleware is so straightforward, and it handles the application exceptions as well as exceptions from filters and you can have full control over. Look at the following class:

 

 public class MiddlewareExceptionHandler

    {

        private readonly RequestDelegate _requestDelegate;

 

        public MiddlewareExceptionHandler(RequestDelegate requestDelegate)

        {

            _requestDelegate = requestDelegate;

        }

 

        public async Task Invoke(HttpContext context)

        {

            try

            {

                await _requestDelegate(context);

            }

            catch (Exception ex)

            {

                await HandleExceptionAsync(context, ex);

            }

        }

 

        private static Task HandleExceptionAsync(HttpContext context, Exception exception)

        {

            var code = HttpStatusCode.InternalServerError;

            var result = JsonConvert.SerializeObject(new { error = exception.Message });

            context.Response.ContentType = "application/json";

            context.Response.StatusCode = (int)code;

            return context.Response.WriteAsync(result);

        }

    }

 

And register the class in Configure method of Startup class:

 

 

  public void Configure(IApplicationBuilder app, IHostingEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }

            else

            {

                app.UseExceptionHandler("/Home/Error");

                app.UseHsts();

            }

 

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseCookiePolicy();

 

            app.UseMiddleware(typeof(MiddlewareExceptionHandler));

 

            app.UseMvc(routes =>

            {

                routes.MapRoute(

                    name: "default",

                    template: "{controller=Home}/{action=Index}/{id?}");

            });

        }

 

Note that I'm returning the exception as JSON. In order to Invoke the exception in HTTP, you can change the MiddlewareExceptionHandler class like below:

 

  

 public class MiddlewareExceptionHandler

    {

        private readonly RequestDelegate _requestDelegate;

 

        public MiddlewareExceptionHandler(RequestDelegate requestDelegate)

        {

            _requestDelegate = requestDelegate;

        }

 

        public async Task Invoke(HttpContext context)

        {

            try

            {

                await _requestDelegate(context);

            }

            catch (Exception ex)

            {

                if (context.Response.HasStarted)

                {

                    throw;

                }

 

                await context.Response.WriteAsync(ex.Message);

 

                return;

            }

        }

    }

 



About Me

Ehsan Ghanbari

Hi! my name is Ehsan. I'm a developer, passionate technologist, and fan of clean code. I'm interested in enterprise and large-scale applications architecture and design patterns and I'm spending a lot of my time on architecture subject. Since 2008, I've been as a developer for companies and organizations and I've been focusing on Microsoft ecosystem all the time. During the&nb Read More

Post Tags
Pending Blog Posts
Strategic design
Factory Pattern
time out pattern in ajax
Selectors in Jquery
Peridic pattern
How to query over Icollection<> of a type with linq
How to use PagedList In asp.net MVC
Domain driven design VS model driven architecture
What's the DDD-lite?
Using Generic type for type casting in F#