How to Use ASP.NET Core Controllers and Razor Pages from Separate Project

This post shows how to use shared projects or shared assemblies for ASP.NET Core API Controllers or ASP.NET Core Razor Pages. Sometimes shared logic for different ASP.NET Web API or Web App projects can be implemented in a shared project. The shared project controllers, Razor Pages, services can be referenced and used in the host web application.

Using ASP.NET Core Controllers from a shared project

Using shared API Controllers in ASP.NET Core is fairly simple. To set this up, a .NET 5 class library was created to implement the shared Controllers for the ASP.NET Core API. The FrameworkReference Microsoft.AspNetCore.App is required and the Swashbuckle.AspNetCore Nuget package was added for the API definitions in the Controller.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
  </ItemGroup>
</Project>

The shared Controller was implemented using the ControllerBase class and the ApiController attribute. The controller uses a scoped service to get the data.

[ApiController]
[Route("[controller]")]
public class SharedApiController : ControllerBase
{
    private readonly ILogger<SharedApiController> _logger;
    private readonly SomeSharedService _someSharedService;

    public SharedApiController(SomeSharedService someSharedService,
        ILogger<SharedApiController> logger)
    {
        _logger = logger;
        _someSharedService = someSharedService;
    }

    [HttpGet]
    public ActionResult<string> Get()
    { 
        return Ok(_someSharedService.GetData());
    }
}

The SharedApiExtensions class is used to add all services to the IoC for the shared project. The extension method just adds a scoped service SomeSharedService.

public static class SharedApiExtensions
{

    public static IServiceCollection AddSharedServices(
        this IServiceCollection services)
    {
        services.AddScoped<SomeSharedService>();

        return services;
    }
}

The project was then added to the host Web API project as a project reference.

The ConfigureServices method of the host web application is used to call the AddSharedServices extension method and add the services to the IoC.

public void ConfigureServices(IServiceCollection services)
{

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { 
            Title = "AspNetCoreApi", Version = "v1" });
    });

    services.AddSharedServices();
}

When the application is started, the Controller from the shared project can be used. The Controller is discovered and no further code configuration is required which is pretty cool.

Using Razor Pages from a Shared Project

Using Razor Pages from a shared project is slightly different. You can create a Razor class library for the shared UI elements. This is a project of type Microsoft.NETSdk.Razor. The project again includes the FrameworkReference Microsoft.AspNetCore.App.

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

</Project>
When creating a Razor class library for Razor Pages in Visual Studio, you must check the checkbox Support pages and views.

The shared Razor Pages can be added as required inside the shared project. The example Razor Page uses a service to get the data.

namespace SharedRazorPages.MyFeature.Pages
{
    public class Page1Model : PageModel
    {
        private readonly SomeSharedPageService _someSharedPageService;

        public Page1Model(SomeSharedPageService someSharedPageService)
        {
            _someSharedPageService = someSharedPageService;
        }

        public List<string> Data = new List<string>();

        public void OnGet()
        {
            Data = _someSharedPageService.GetData();
        }
    }
}
_ViewStart.cshtml is required so that the default layout page can be used or a specific layout for the Razor Pages inside thed shared project.
@{
    Layout = "_Layout";
}

The SharedRazorPagesExtensions is used to register all the services required inside the shared project. The static class uses just one single scoped service.

using Microsoft.Extensions.DependencyInjection;
using SharedRazorPages.Services;

namespace SharedRazorPages
{
    public static class SharedRazorPagesExtensions
    {

        public static IServiceCollection AddSharedRazorPagesServices(
           this IServiceCollection services)
        {
            services.AddScoped<SomeSharedPageService>();

            return services;
        }
    } 
}

The AddSharedRazorPagesServices extension method can then be used in the host ASP.NET Core Razor Page application to add the services and the UI items from the shared project can be used.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddSharedRazorPagesServices();
}

When the application is run, the view can use either Razor Pages from the shared project, or it’s own.

ASP.NET Core supports other UI elements like static files, typescript and so on which can also be implemented inside a shared assembly, project. See the Microsoft docs for details.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *