0

We want to move our composition root out of our UI layer and into another project. That means moving the Startup class out of the UI layer. How can we configure routes when the Startup class is not in the UI layer's project?

We currently have this setup.

  • The DAL depends on the BLL, because the DAL implements the BLL interfaces.
  • The UI depends on the BLL, because the UI controllers call into BLL interfaces.
  • The UI depends on the DAL, because the UI's Startup contains the composition root.

Current Dependency Graph

+---------+ UI.xproj 
|              +     
|              |     
|              |     
|              |     
|              v     
|           BLL.xproj
|              ^     
|              |     
|              |     
|              |     
|              +     
+---------> DAL.xproj

Based on this article and numerous examples in the aspnet GitHub account, we're wiring up our dependencies within the UI.Startup class. The article states:

Register all dependencies in the application startup method, before doing anything else.

That's what we're doing in the UI.Startup class. What we'd like to do, though, is to move our Startup class into a fourth project, so that we can eliminate the dependency of the UI on the DAL.

Desired Dependency Graph

      +--------------------> UI.xproj 
      |                         +     
      |                         |     
      |                         |     
      |                         |     
      +                         v     
Application.xproj +--------> BLL.xproj
      +                         ^     
      |                         |     
      |                         |     
      |                         |     
      |                         +     
      +--------------------> DAL.xproj

Our current UI uses ASP.NET MVC and the routing just works, as if by magic, with two simple steps:

  1. Inside UI.Startup, we simply call services.AddMvc() and app.UseMvc().
  2. Onto our controller we add [Route("api/[controller]")].

When we run the project within Visual Studio, we can browse to /api/my-controller/ and see the expected action result. Groovy.

In our desired setup, the UI will no longer have a Startup class, because that call will now be in the Application. The Application will not only be responsible for configuring the dependencies, it will also need to configure routes.

How can we configure the routes to point to the controllers within the UI layer?

(Graphs courtesy of ASCIIFlow)

Community
  • 1
  • 1
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467

1 Answers1

0

Magic reigned supreme. It just worked and is really quite nice. All I had to do was:

  1. Cut and paste the Startup.cs from the UI.xproj into the new Application.xproj
  2. Add a dependency on UI into the new Application.xproj.

Voila, routes and dependency injection still all work within Startup.cs.

Application Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        this.ConfigurePersistenceServices(services);
    }

    public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
    {
        app.UseMvc();
        this.ConfigurePersistence(serviceProvider);
        app.Run(async context => { await context.Response.WriteAsync("Hello!"); });
    }

    private void ConfigurePersistence(IServiceProvider serviceProvider)
    {
        var unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
        unitOfWork.Create(new TodoItem("Test"));
        unitOfWork.Save();
    }

    private void ConfigurePersistenceServices(IServiceCollection services)
    {
        services
            .AddEntityFramework()
            .AddInMemoryStore()
            .AddDbContext<FarmContext>(options =>
            {
                options.UseInMemoryStore(persist: true);
            });
        // TODO: Use per request not singleton!
        services.AddSingleton<IUnitOfWork, UnitOfWork>();
    }
}

Application project.json

  "dependencies": {
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta6-*",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta6-*",
    "Microsoft.AspNet.Mvc": "6.0.0-beta6-*",
    "DAL": "1.0.0-*",
    "BLL": "1.0.0-*",
    "UI": "1.0.0-*",
    "EntityFramework": "7.0.0-beta6-*",
    "EntityFramework.SqlServer": "7.0.0-beta6-*",
    "EntityFramework.InMemory": "7.0.0-beta6-*"
  }

UI project.json

  "dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta6-*",
    "BLL": "1.0.0-*"
  }

BLL project.json

  "dependencies": {
  }

DAL project.json

  "dependencies": {
    "EntityFramework": "7.0.0-beta6-*",
    "BLL": "1.0.0-*"
  }
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • just wondering, where you end up having your views and what's your startup project? which one has the wwwroot ? – Bart Calixto Jun 19 '15 at 03:12
  • The Application.xproj has the `Startup` and the wwwroot right now. For the time being, we don't have any views, because we're doing a REST api, but we'd put them in the UI.xproj. – Shaun Luttin Jun 19 '15 at 14:22
  • 1
    I don't think that mvc will pick the views from the UI xproj without some modification on the razor engine for locating views. (can be wrong) Let me know how it goes. thanks. – Bart Calixto Jun 22 '15 at 22:54