OrchardCMS / Orchard

Orchard is a free, open source, community-focused Content Management System built on the ASP.NET MVC platform.
https://orchardproject.net
BSD 3-Clause "New" or "Revised" License
2.38k stars 1.12k forks source link

Load extensions from subfolders (Please Help) #8741

Open mehranrezaei opened 11 months ago

mehranrezaei commented 11 months ago

Hi guys

I have an important problem and although I spent a lot of time on it, I could not solve it.

Considering that the number of my modules is very large and the compilation of this number of projects becomes very large due to frequent references to Orchard modules and my modules, I am forced to merge some of these modules, but I want to each sub module be placed in separate subfolder like Orchard.Core.

I know that orchard has the ability to place the module in the desired folder through the settings in the web.config, but this feature is not useful for me because I want to have a project like Orchard.Core and different modules as its subfolders without having .csproj file and separate references for each sub module.

According to the discussion here and many studies and countless tests, I failed to do this.

Using Autofac.Module and overriding Load method, I tried to create a new IExtensionFolders and IExtensionLoader exactly similar to the ones implemented for Orchard.Core modules. But apparently my implementationse joins the system late and is not available in the phase that Orchard needs.

Although I managed to make the desired modules appear in the list of features, but when I want to activate it, I get this error:

No loader found for feature's ("Test") exension!

Please guide me how I can solve this problem and use the Autofac.Module to introduce the desired subfolders and loader.

Another problem is that I don't want to change the Orchard code. How can I put such a code that is needed in the startup phase in a module that is loaded with a delay and must be activated?

@sebastienros , @LombiqTechnologies , @Ermesx , @qt1 , @bleroy

mehranrezaei commented 11 months ago

Hello guys,

I saw this section in the documentation:

"Once Orchard has collected all the Module.txt files from the discovery phase, Orchard uses distinct strategies (or "Module Loaders") to load these modules in memory. Internally, the act of "loading a module" is an activity that takes a Module.txt file as input and returns a list of System.Type as output. Note that this is slightly more generic than simply returning a System.Assembly, as it allows Orchard to support multiple modules per assembly. For example, the Orchard.Core.dll assembly currently contains about 10 modules."

But how? When I put some modules in a class library that produces an assembly, they are not recognized and cannot be activated.

MatteoPiovanelli-Laser commented 11 months ago

I'm not entirely familiar with the details of module/feature loading.

Looking at how the Core folder is put, it has the csproj at it top level, while the module.txt files are in each subfolder. So you end up with one assembly from the project, and however many modules there are.

Regarding paths other than modules, I think you need something like

<appSettings>
    <add key="modules" value="path1,path2">
</appSettings>

in your web.config, but I have never tried it.

Notes:

mehranrezaei commented 11 months ago

Thanks for your response.

As I said above, I want something similar to core modules. And as I mentioned, I know about the web config settings. That setting doesn't solve my need because those settings only allow modules to be loaded from another location, but each module must have its own project and assembly file.

I need exactly what is mentioned in the documentation, that is, multiple modules per assembly.

The Core modules have their own loaders. I have also created a special loader for my modules. But the question is about how to introduce this loader to the system. Because it is apparently not possible through Autofac facilities. And I don't want to modify the OrchardStarter.cs file.

MatteoPiovanelli-Laser commented 11 months ago

The ExtensionHarvester should already be looking for module.txt in subfolders of your module. See https://github.com/OrchardCMS/Orchard/blob/9644ceda1f9b077d44aaa4ffaab103c19a59ddba/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs#L71C14-L71C14

That shouldn't need any additional code, by the looks of it, but I haven't tested it. Perhaps you have already and can say why that isn't working as I think it should?

mehranrezaei commented 11 months ago

You need two things to have a module and to be able to activate its features.

  1. Your module is discoverable. This can be done with the help of web config settings to determine additional locations for loading modules.

  2. You need a extension loader. Loaders that are implemented by default need an assembly with the same name as the module.

Therefore, because I want to reduce the number of assemblies and references, this feature is not useful for me. I want to have the MVC structure in each subfolder, but without the need for a .csproj file and creating a assembly, just with a module manifest file. Just like the case of the Orchard.Core module, where each subfolder is a module, but only has the manifest file, not the special project and assembly file.