Handle SubDomain in Asp.net Core 3.1 application

Viewed 1022

I'm working on an asp.net core 3.1 application (MVC), and as a requirement, every account should have its subdomain (ex : mystore.domain.com) and its data. So I'm trying to figure out how to add the subdomain part in the routing pattern, and catch it in my controller in order to get the user data, and return it in a view.

I've done some research and found solutions for asp.net core version 2, unfortunettly, it does not work on version 3 (so much have changed) this article for example.

Summary :

  1. User types : mystore.domain.com or mystore.domain.com\store
  2. I catch the subsomain "mystore", search the database for the user data, and render a view.
1 Answers

You could use a filter, specifically, an action filter, which could:

  • Run code immediately before and after an action method is called.
  • Can change the arguments passed into an action.
  • Can change the result returned from the action.
  • Are not supported in Razor Pages.

An example is

public class MySampleActionFilter : IActionFilter 
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }
}

Here you could prepare a scoped service, load the user based on the service and then reuse it in any service that requires that data.

Even without the filter, you could simply create a UserService with a scoped lifetime, load the user there and use it anywhere in your services.

In our system we are doing something similar:

A service to load the session data:

public class ClientTokenService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ClientTokenService(
        IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public Profile LoadProfile()
    {
        if (_httpContextAccessor.HttpContext.User == null)
        {
            throw new Exception("No user claims found to load Profile");
        }

        var user = _httpContextAccessor.HttpContext.User;

        var numberType = (NumberType)int.Parse(user.FindFirst("numberType").Value);
        var profileType = (PackagePlan)int.Parse(user.FindFirst("profileType").Value);
        var lineOfBusiness = (LineOfBusiness)int.Parse(user.FindFirst("lineOfBusiness").Value);

        // More stuff

        // Prepare the profile data
        return new Profile(
            user.FindFirst("number").Value,
            user.FindFirst("contractId").Value,
            numberType,
            profileType,
            user.FindFirst("cc")?.Value,
            user.FindFirst("app").Value,
            user.FindFirst("clickId")?.Value,
            user.FindFirst("wifi") != null,
            lineOfBusiness
        );
    }
}

This service can be transient, and then a scoped service which saves the data

public class ClientSessionContext
{
    public Profile Profile { get; }

    public ClientSessionContext(
        ClientTokenService sessionService)
    {
        Profile = sessionService.LoadProfile();
    }
}

Declare this service as scoped, so this class is initialized just once per request

Statup.cs

services.AddScoped<ClientSessionContext>();

Then just inject this service anywhere where you need access to the user data.

Related