Search code examples
asp.net-coreasp.net-core-mvcmulti-tenant

How to add tenant / organization id to every URL and read it inside controller


I am writing an ASP.NET Core web application. In my application, the user can be a member of one or more organizations (this information is stored in the DB). I would like to give the users the possibility to select the context of organization in which the whole app should be running. This context should be passed to every controller so that I can do proper checks and return only the data from the selected org.

In other words, I would like to achieve the state when the user can access the app via: app.mydomain.com/org1/controller/action/id and using a dropdown they should be able to switch to org2 and access app.mydomain/org2/controller/action/id

In both cases I need to be able to read the organization inside the controller. This should apply to every controller.

How should this be done? Is it possible to construct a route that would handle it and just add new parameter to every controller, e.g. orgId? Or maybe there should be a service that reads this information from the URL and can be injected into controllers? How would the route look then? I have read some tutorials about handling multiple languages in a similar way (with the culture in URL) but I am not able to translate that into my case.


Solution

  • For how to pass the select org id to the controller:

    View:

    <form action="/Orgnization/Test">
        <select id="select" name="select" asp-items="@ViewBag.Sel"></select>
    </form>
    @section Scripts
    {
    <script>
        $(document).ready(function () {
    
            $("#select").change(function () {
                $('form').submit();
            });
        })
    </script>
    }
    

    Configure selectlist:

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            //for easy testing,I just set it manually...
            ViewBag.Sel = new List<SelectListItem>() {
                new SelectListItem() { Value = "-1", Text = "--- Select ---" },
                new SelectListItem() { Value = "org1", Text = "org1" },
                new SelectListItem() { Value = "org2", Text = "org2" },
                new SelectListItem() { Value = "org3", Text = "org3" },
            };
            return View();
        }
    }
    

    Controller:

    public class OrgnizationController : Controller
    {
        public IActionResult Test(string select)
        {
            //the select is the value you choose
            //do your stuff....
            return View();
        }
    }
    

    If you want to add prefix to the route and get it in the controller:

    Startup.cs:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{orgid?}/{controller=Home}/{action=Privacy}/{id?}");
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Privacy}/{id?}");
    });
    

    Controller:

    public class OrgnizationController : Controller
    {
        public IActionResult Test(string select)
        {
            var org = "";
            if (select==null)
            {
                var path = Request.Path.ToString();
                org = path.Split('/')[1];
            }
            //do your stuff....
            return View();
        }
    }
    

    Result:

    enter image description here