Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use the controllers and views in a multi-tenant application #33

Open
VahidNaderi opened this issue Oct 20, 2022 · 3 comments
Open

Comments

@VahidNaderi
Copy link

VahidNaderi commented Oct 20, 2022

The sample multi-tenancy project (MultiTenantApplication.csproj) works fine with razor pages but how should we enable controllers and views?
Trying to add them by adding

builder.Services.AddControllersWithViews();
...
app.MapDefaultControllerRoute();

results in the error:

ArgumentException: Value cannot be null or empty. (Parameter 'areaName')

if instead of MapDefaultControllerRoute() I use endpoints like this:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("MyDefaultRoute", "{controller=Home}/{action=Index}");
});

It works fine, but when I want to use DI to inject shell settings as in the razor pages sample in the index view

@inject ShellSettings settings

And use constructor injection

    public class MessageController : Controller
    {
        private readonly ShellSettings _settings;
        public MessageController(ShellSettings settings)
        {
            _settings = settings;
        }
   }

I get the error:

InvalidOperationException: Unable to resolve service for type 'OrchardCore.Environment.Shell.ShellSettings' while attempting to activate 'MultiTenantApplication.Controllers.MessageController'.

@jeremycook
Copy link
Contributor

There is an example of an MVC controller in Module1 project named HomeController. I would recommend creating controllers in module projects instead of directly in your application project. Note that it is the HomeController of that module and not the HomeController of the application in the traditional ASP.NET MVC way that you may be used to.

Controllers and views are enabled by default for OrchardCore via .AddMvc() configuration. No additional configuration is needed, and additional configuration like you indicate can actually bypass the OrchardCore pipeline and result in things like Orchard's service provider not being available (which is why you get unable to resolve service for type exception). Keep in mind that Applications are treated like Modules (in a way) and each Module gets mapped as an area. This means that you would navigate to /SomeApplicationOrModule/SomeController/SomeAction or /SomeTenant/SomeApplicationOrModule/SomeController/SomeAction, and not simply to /SomeController/SomeAction or /SomeTenant/SomeController/SomeAction. HTH.

@VahidNaderi
Copy link
Author

@jeremycook thanks for your clarification.
I saw that in modules, but I was thinking to have the main functionality in the main application and use modules as add-ons to the main. Isn't it a valid scenario in orchardcore applications?
And about the paths, as it's in the sample we can have paths like /SomePage in addition to /SomeTenant/SomePage with Razor Pages, why can't we have /SomeTenant/SomeController/SomeAction?

@jeremycook
Copy link
Contributor

I'd like to caveat the following responses with the fact that I'm not a core developer of OrchardCore. I understand OrchardCore through the lens of experience and not from the perspective of one of its authors. (TL;DR; I might state something that turns out to be incorrect.)

I saw that in modules, but I was thinking to have the main functionality in the main application and use modules as add-ons to the main. Isn't it a valid scenario in orchardcore applications?

This is possible, but when investigating your question, my experiments resulted in a kind of awkwardness that leads me to conclude that using modules is the way to go. Embedding controllers in a module even if that module is only consumed by one application feels more natural to the OrchardCore way of doing things. Plus if you ever do need to reuse said module in another application you get the added benefit of it already being broken out into a module. Another compelling reason is that if you are using OrchardCore for multi-tenancy you can now enable that module for some tenants and disable for others. I more-or-less think of modules as areas in a traditional MVC app.

And about the paths, as it's in the sample we can have paths like /SomePage in addition to /SomeTenant/SomePage with Razor Pages, why can't we have /SomeTenant/SomeController/SomeAction?

Take a look around https://github.com/OrchardCMS/OrchardCore/blob/main/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs#L64 to get an idea. I apologize for not mentioning this in my first response.

And finally here's a curve ball that may be worth considering. If you need runtime multi-tenancy or runtime modularity OrchardCore can give you either or both of those. If you do not need either then a vanilla MVC application with-or-without Razor Class Library projects is a simpler way to go about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants