Search code examples
asp.net-coreasp.net-core-mvcasp.net-core-webapirazor-pagesasp.net-core-5.0

ASP.NET Core 5 MVC/RazorPages and WebAPI projects in same solution


Many sites are split in two:

  • www.example.com: a public MVC / RazorPages server-rendered app for guests
  • app.example.com: a private WebAPI app for customers and admins (accessible by a SPA)

These two apps share lots of stuff, e.g. code, database, styling, so it would be best to have them within a single solution, possibly split into multiple projects. I expect it's possible to do this by somehow tweaking the standard config (e.g. Startup.cs).

The docs do not cover this scenario. There are various solutions to this problem but they are for older versions of the framework.

How is this done for ASP.NET Core 5?


Solution

  • I would say that you can do that in different ways, related to your requirements and how you want to style the architecture of your solution, the testing, deployment process, etc.


    One only application

    In a simple manner, you can expose both a Web API and an application with front-end in the same web project. Then, for example, by mapping your controllers, you can specify which is which.

    • API controller scaffold example:
    [ApiController]
    [Area("api")]
    [Route("[area]/[controller]")]
    public class ResourceController : ControllerBase
    {
        ...
    }
    
    • WebApp controller scaffold example:
    public class FeatureController : Controller
    {
        ...
    }
    

    (Please, note that an MVC controller requires the Controller base class. For an API controller, the ControllerBase is enough.)

    Regarding the Startup of the application, performing a default mapping between controllers and routes may be enough:

    app.UseEndpoints(endpoint =>
    {
        endpoint.MapDefaultControllerRoute();
    });
    

    With this approach, you can even, for example, map different middleware classes depending on the route:

    app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>
       {
           appBuilder.UseMiddleware<ApiRelatedMiddleware>();
       })
       .UseWhen(context => !context.Request.Path.StartsWithSegments("/api"), appBuilder =>
       {
           appBuilder.UseMiddleware<FrontEndRelatedMiddleware>();
       });
    

    As for other needs of the application, you can register the services you need.


    Separated applications:

    However, that "simple" approach may bring excessive complexity to your application, because it is only one app, but things like authentication, authorization, logging or deployment may have different requirements, for example. Testing can be different, too.

    Moreover, managing the access and visibility of each route would also have to be ensured upstream.

    For these reasons and for a more comprehensible architecture, in most cases, I would prefer to split the projects.

    Following a scheme of multiple layers or even clean architecture (Microsoft doc here) would solve most of the problems.

    The common parts between the applications would naturally seat in common layers, since they would be linked to business logic or infrastructure, for example. Then, both the web applications can refer the required projects.