5

How to separate asp.net core mvc project into multiple assembly (.dll)?

I have 3 projects

  • MyApp Project
    • Controllers
      • HomeController.cs
    • Models
    • Views
      • Home
        • Index.cshtml
  • HR Project

    • Controllers
      • EmployeeController.cs
    • Models
      • EMPLOYEE.cs
    • Views
      • Employee
        • Index.cshtml
  • ACC Project

    • Controllers
      • ChartAccountController.cs
    • Models
      • ACCOUNT.cs
    • Views
      • ChartAccount
        • Index.cshtml

I want to compile into dll

  • HR Project
    • HR.dll
    • HR.Views.dll
  • ACC Project
    • ACC.dll
    • ACC.Views.dll

I want to add reference those dll (HR.dll, HR.Views.dll, ACC.dll, ACC.Views.dll) into MyApp Project.

And then run MyApp project can access Employee & Chart Account module too.

Sophairk
  • 253
  • 3
  • 11
  • but how will you manage the routing and all if all the things are separate project, I am really curious to know the answer for this question. By the way why scenario is in such a way why cant you have specific Areas to each modules. – Samaritan_Learner May 17 '19 at 11:46
  • I want to do like this because I think easy to separate to different developer, when a developer done just compile and paste into IIS folder. – Sophairk May 17 '19 at 12:51
  • MVC itself comes with separation of concerns but you are separating that too. But I am not sure how feasible this will be because you may need to handle the routing and all properly. Instead of that why cant you go for AREAS in MVC and make use of it. – Samaritan_Learner May 17 '19 at 13:07
  • 2
    "When a developer is done just compile and paste into IIS folder" - this is not a good idea. That leads to poor traceability. Instead, you should set up a proper build and release pipeline that enables your team to deploy with no outage and gives you full traceability as to what changes are in what environment. – mason May 17 '19 at 13:22
  • How to separate project to different developers ? or I need to consolidate project very time? – Sophairk May 17 '19 at 13:53

2 Answers2

3

*** Original Answer (Update below)

If you want to do this you'll need to do the following 2 steps:

  1. You need to load the controllers from the external dlls

There is already a solution for this on stackoverflow: How to use a controller in another assembly in ASP.NET Core MVC 2.0?

It says the following:

Inside the ConfigureServices method of the Startup class you have to call the following:

services.AddMvc().AddApplicationPart(assembly).AddControllersAsServices();
  1. You need to load the your compiled Razor views, I guess this is what you have in your HR.Views.dll and ACC.Views.dll.

There is also already a solution for this on stackoverflow:

How CompiledRazorAssemblyPart should be used to load Razor Views?

Loading Razor Class Libraries as plugins

This is one possible solution from the links above:

What you need to do is:

services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.ConfigureApplicationPartManager(ConfigureApplicationParts);

and configure the parts like this

    private void ConfigureApplicationParts(ApplicationPartManager apm)
    {
        var rootPath = HostingEnvironment.ContentRootPath;
        var pluginsPath = Path.Combine(rootPath, "Plugins");

        var assemblyFiles = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
        foreach (var assemblyFile in assemblyFiles)
        {
            try
            {
                var assembly = Assembly.LoadFile(assemblyFile);
                if (assemblyFile.EndsWith(".Views.dll"))
                    apm.ApplicationParts.Add(new CompiledRazorAssemblyPart(assembly));
                else
                    apm.ApplicationParts.Add(new AssemblyPart(assembly));
            }
            catch (Exception e) { }
        }
    }

If you also have javascript and css files in our separate MVC projects, you will need to embed this to your dll otherwise your main app wont see it. So in your HR and ACC project, you'll need to add this in your .csproj file:

  <ItemGroup>
    <EmbeddedResource Include="wwwroot\**" />
  </ItemGroup>

And just to be clear, I agree with the other comments, I don't think it is a good architecture, but it is possible to do it if you want.

*** Updated (Worked)

Just a step:

Edit Startup.cs in ConfigureServices method

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApplicationPartManager(ConfigureApplicationParts);

and method:

private void ConfigureApplicationParts(ApplicationPartManager apm)
    {
        var rootPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

        var assemblyFiles = Directory.GetFiles(rootPath , "*.dll");
        foreach (var assemblyFile in assemblyFiles)
        {
            try
            {
                var assembly = Assembly.LoadFile(assemblyFile);
                if (assemblyFile.EndsWith(this.GetType().Namespace + ".Views.dll") || assemblyFile.EndsWith(this.GetType().Namespace + ".dll"))
                    continue;
                else if (assemblyFile.EndsWith(".Views.dll"))
                    apm.ApplicationParts.Add(new CompiledRazorAssemblyPart(assembly));
                else
                    apm.ApplicationParts.Add(new AssemblyPart(assembly));
            }
            catch (Exception e) { }
        }
    }
Sophairk
  • 253
  • 3
  • 11
hujtomi
  • 1,540
  • 2
  • 17
  • 23
  • Code in your answer is not work. but I can edit your code to work. Big Thank for guide me. I want to tick green your answer but your code need change. – Sophairk May 31 '19 at 16:19
  • I haven't seen any code in your question, so I was not able to give you the exact code as response, this is why I copied the code from other stackoverflow answers, so it can guide you how to solve your problem. This is just a skeleton, based on this you should be able to solve your problem. – hujtomi Jun 01 '19 at 12:58
  • Thank you, I edited you answer by added a work solution below your answer but need "peer reviewed". After complete changed I will tick verify answer. – Sophairk Jun 03 '19 at 06:49
  • Curious why must one have the views in a sep dll the point of this is to reduce the amount of dlls so a plugin can combine all elements of mvc @Sophairk – c-sharp-and-swiftui-devni Dec 04 '20 at 11:02
1

What you're wanting is not possible, or perhaps better said: it's not a good idea, for sure.

In general, you need to use Razor Class Libraries. All common functionality would then go into those RCLs. Your entire HR and ACC projects could be RCLs, unless you need to run those independently, as full web apps, as well. In which case, you'd need a structure more like:

  • HR RCL
  • HR Web App (depends on HR RCL)
  • ACC RCL
  • ACC Web App (depends on ACC RCL)
  • Main App (depends on HR RCL and ACC RCL)

In either case, you'd put all the controllers, views, and static resources that need to be shared in the RCL, so if you do have actual HR/ACC web apps, those would be pretty light: mostly just consisting of Program and Startup and a dependency on their respective RCLs.

For more information, see the documentation on Razor Class Libraries.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444