Lukas Hieronimus Adler
Lukas Hieronimus Adler

Reputation: 1094

Different projects with controllers and views

I should write a big software for a company. This company has many different departments, but each department needs the same base-functions and also some specific department features. Therefore i would like to split the functions by using different project libraries and add them to the base to minimalize the code in the base. This basic idea is shown in the image below.enter image description here

To minimalize the complexity i have a sample figure which has in the basic project (base functions) the web-views /home/drawing and /home/workschedule. There are also two different departments which need some special functions which are availabe under /departmentA/special or /departmentB/special. What i would like to do is the following by code:

enter image description here

I would like to build one solution with a .net-core mvc project which is called basic project. There should be the functions which are necessary for each department. No other code instead of code which is general should be their. If a department needs some special features i would like to create a new project in this solution for each Department, in our example for department A and B. Each of this projects should provide controllers with views which were routed to if we call for example /departmentA/special.

Now i have different problems: 1. How could i call controllers by linked projects like DepartmentA project and deliver Views? I read something about application parts in asp.net core, but i could only access the controller-functions which could not deliver the view. I did it like the following: enter image description here

I got the following error:

enter image description here

  1. How could i compile only some departments into the basic project?

The solution is like Chris Pratt desribed for the previous problem. But now i have the same project structure like before but also need some special JavaScript and CSS Files for DepartmentA and DepartmentB.

This works with CommonUI (Embedded Resources + a specific resource file provider). The example therefore is the following:

  1. Edit the .csproj file with the ItemGroup (Location where the Javascript/CSS Files are located) and the GenerateEmbeddedFilesManifest

    <Project Sdk="Microsoft.NET.Sdk.Razor">
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
        <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
        <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0" />
        <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.0" />
      </ItemGroup>
      <ItemGroup>
        <EmbeddedResource Include="wwwroot\**\*" />
      </ItemGroup>
    </Project>

  1. Create a CommonUI Resource File Provider like the following:

2.1 First create a static class for the Startup-Call which is necessary to load initial the embedded ressources

    public static class CommonUIServiceCollectionExtensions
    {
        public static void AddCommonUI(this IServiceCollection services)
        {
            services.ConfigureOptions(typeof(CommonUIConfigureOptions));
        }
    }

2.2 Second create a class which reads the embedded-resource folder

internal class CommonUIConfigureOptions : IPostConfigureOptions<StaticFileOptions>
    {
        public CommonUIConfigureOptions(IHostingEnvironment environment)
        {
            Environment = environment;
        }
        public IHostingEnvironment Environment { get; }

        public void PostConfigure(string name, StaticFileOptions options)
        {
            name = name ?? throw new ArgumentNullException(nameof(name));
            options = options ?? throw new ArgumentNullException(nameof(options));

            // Basic initialization in case the options weren't initialized by any other component
            options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();
            if (options.FileProvider == null && Environment.WebRootFileProvider == null)
            {
                throw new InvalidOperationException("Missing FileProvider.");
            }

            options.FileProvider = options.FileProvider ?? Environment.WebRootFileProvider;

            // Add our provider
            var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, "wwwroot");
            options.FileProvider = new CompositeFileProvider(options.FileProvider, filesProvider);
        }
    }
  1. Now i have to include it in the Startup in my main MVC Project in the ConfigureServices Method with this call:

    services.AddCommonUI();

But there is the big problem. Because i have to add a using with the Razor Class Library reference. So when i switch the dependency from deployment departmentA to departmentB i have also to change the using in the basic project. Maybe someone could give me a hint.

Upvotes: 0

Views: 481

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239290

It looks like you've got just a standard class library, where you're attempt to add views to and share from. That's not possible. The views will not be compiled into the class library, and therefore are not available to reference from that class library.

What you can do is create a Razor Class Library. Despite the name, it has more in common with an ASP.NET Core application than a class library, only there's no Program and no Startup (i.e. it doesn't run on its own). However, with that, the views will be embedded into the library and thus available to projects that reference it. The docs specifically focus on Razor Pages, but MVC-style views and controllers work just as well.

Upvotes: 3

Related Questions