Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Infrastructure Dependency on Web #54

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7f9cad1
Generic paramter on repository lowered to methods so 1 repo instance …
Aug 1, 2018
edb658a
Fixed code to use new repository method signatures.
Aug 1, 2018
6189c0e
Merge branch 'repo-generics'
Aug 1, 2018
5da8296
Merge remote-tracking branch 'upstream/master'
Sep 26, 2018
af361e6
Merge remote-tracking branch 'upstream/master'
Sep 27, 2018
55d263a
Merge remote-tracking branch 'upstream/master'
Feb 20, 2019
ac46b1a
No longer require explicit Infrastructure reference for registering A…
Feb 21, 2019
b9dc946
Move AppDbContext references to Infrastructure, and remove Infrastruc…
Feb 21, 2019
9e2685e
web.config change on run (meaningless change).
Feb 21, 2019
c104eb9
Add support for SQL Server database connection in DatabaseModule for …
Feb 21, 2019
f540117
Minor refactor.
Feb 21, 2019
e2258db
Another minor refactor.
Feb 21, 2019
9ac90fe
Yet another minor refactor.
Feb 21, 2019
8136fac
Trying xcopy instead of copy for post-build Infrastructure copy.
Feb 22, 2019
0473e50
Merge remote-tracking branch 'upstream/master'
Jul 3, 2019
93e7d1b
Merge remote-tracking branch 'upstream/master'
Aug 22, 2019
a1161d7
Merge branch 'master' into scott/remove-infrastructure-dependency
Aug 22, 2019
364ec98
Made solution build after pulling in recent changes. Left TODO in Sta…
Aug 22, 2019
e841260
Broke off Database setup to Registrar class in Infrastructure, where …
Aug 22, 2019
2990ab6
Refactoring Startup to not do so much work creating multiple containers.
Aug 22, 2019
dd8e188
Distinct methods for registering DB as InMemory, SQLite, or SQL Server.
Aug 22, 2019
f98b049
.NET Core auto-updated web.config module to V2.
Aug 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CleanArchitecture.Core/CleanArchitecture.Core.csproj
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="1.2.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
7 changes: 7 additions & 0 deletions src/CleanArchitecture.Core/Interfaces/IDatabaseInitializer.cs
@@ -0,0 +1,7 @@
namespace CleanArchitecture.Core.Interfaces
{
public interface IDatabaseInitializer
{
void Initialize();
}
}
11 changes: 11 additions & 0 deletions src/CleanArchitecture.Core/Interfaces/IDatabaseRegistrar.cs
@@ -0,0 +1,11 @@
using Microsoft.Extensions.DependencyInjection;

namespace CleanArchitecture.Core.Interfaces
{
public interface IDatabaseRegistrar
{
void RegisterInMemory(IServiceCollection services, string dbName = null);
void RegisterSQLite(IServiceCollection services);
void RegisterSQLServer(IServiceCollection services, string connectionString);
}
}
Expand Up @@ -10,13 +10,22 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Ardalis.EFCore.Extensions" Version="1.0.1" />
<PackageReference Include="Ardalis.EFCore.Extensions" Version="1.1.0" />
<PackageReference Include="Autofac" Version="4.9.3" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.6" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
<PackageReference Include="SQLite" Version="3.13.0" />
</ItemGroup>

<ItemGroup>
<Folder Include="Data\Config\" />
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="xcopy &quot;$(TargetDir)$(TargetName).dll&quot; &quot;$(SolutionDir)src\CleanArchitecture.Web\$(OutDir)\*&quot; /Y /R" />
</Target>
</Project>
21 changes: 21 additions & 0 deletions src/CleanArchitecture.Infrastructure/Data/DatabaseInitializer.cs
@@ -0,0 +1,21 @@
using CleanArchitecture.Core.Interfaces;

namespace CleanArchitecture.Infrastructure.Data
{
public class DatabaseInitializer : IDatabaseInitializer
{
private readonly AppDbContext _dbContext;

public DatabaseInitializer(AppDbContext dbContext)
{
_dbContext = dbContext;
}

public void Initialize()
{
// _dbContext.Database.Migrate();
_dbContext.Database.EnsureCreated();
SeedData.Initialize(_dbContext);
}
}
}
35 changes: 35 additions & 0 deletions src/CleanArchitecture.Infrastructure/Data/DatabaseModule.cs
@@ -0,0 +1,35 @@
using Autofac;
using CleanArchitecture.Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;

namespace CleanArchitecture.Infrastructure.Data
{
public class DatabaseModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(context =>
{
DbContextOptions<AppDbContext> dbContextOptions = GetInMemoryDbContextOptions();
// DbContextOptions<AppDbContext> dbContextOptions = GetSqlServerDbContextOptions(context);
return new AppDbContext(dbContextOptions, context.Resolve<IDomainEventDispatcher>());
}).SingleInstance();
}

private static DbContextOptions<AppDbContext> GetInMemoryDbContextOptions()
{
string dbName = Guid.NewGuid().ToString();
var option = new DbContextOptionsBuilder<AppDbContext>();
return option.UseInMemoryDatabase(dbName).Options;
}

private static DbContextOptions<AppDbContext> GetSqlServerDbContextOptions(IComponentContext context)
{
IConfiguration config = context.Resolve<IConfiguration>();
var option = new DbContextOptionsBuilder<AppDbContext>();
return option.UseSqlServer(config.GetConnectionString("DefaultConnection")).Options;
}
}
}
29 changes: 29 additions & 0 deletions src/CleanArchitecture.Infrastructure/Data/DatabaseRegistrar.cs
@@ -0,0 +1,29 @@
using Ardalis.GuardClauses;
using CleanArchitecture.Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace CleanArchitecture.Infrastructure.Data
{
public class DatabaseRegistrar : IDatabaseRegistrar
{
public void RegisterInMemory(IServiceCollection services, string dbName)
{
string databaseName = dbName ?? Guid.NewGuid().ToString();
services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase(databaseName));
}

public void RegisterSQLite(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options => options.UseSqlite("Data Source=database.sqlite")); // will be created in web project root
}

public void RegisterSQLServer(IServiceCollection services, string connectionString)
{
Guard.Against.NullOrWhiteSpace(connectionString, nameof(connectionString));

services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
}
}
}
@@ -1,11 +1,7 @@
using CleanArchitecture.Core.Entities;
using CleanArchitecture.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;

namespace CleanArchitecture.Web
namespace CleanArchitecture.Infrastructure.Data
{
public static class SeedData
{
Expand All @@ -25,22 +21,17 @@ public static class SeedData
Description = "Make sure all the tests run and review what they are doing."
};

public static void Initialize(IServiceProvider serviceProvider)
public static void Initialize(AppDbContext dbContext)
{
using (var dbContext = new AppDbContext(
serviceProvider.GetRequiredService<DbContextOptions<AppDbContext>>(), null))
// Look for any TODO items.
if (dbContext.ToDoItems.Any())
{
// Look for any TODO items.
if (dbContext.ToDoItems.Any())
{
return; // DB has been seeded
}

PopulateTestData(dbContext);


return; // DB has been seeded
}

PopulateTestData(dbContext);
}

public static void PopulateTestData(AppDbContext dbContext)
{
foreach (var item in dbContext.ToDoItems)
Expand Down
4 changes: 2 additions & 2 deletions src/CleanArchitecture.Web/CleanArchitecture.Web.csproj
Expand Up @@ -15,10 +15,10 @@

<ItemGroup>
<ProjectReference Include="..\CleanArchitecture.Core\CleanArchitecture.Core.csproj" />
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Ardalis.EFCore.Extensions" Version="1.1.0" />
<PackageReference Include="Autofac" Version="4.9.3" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.4.0" />
<PackageReference Include="Dapper" Version="1.60.6" />
Expand All @@ -30,7 +30,7 @@
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.0.76" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
<PackageReference Include="SQLite" Version="3.13.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
</ItemGroup>

<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
Expand Down
11 changes: 4 additions & 7 deletions src/CleanArchitecture.Web/Program.cs
@@ -1,7 +1,6 @@
using CleanArchitecture.Infrastructure.Data;
using CleanArchitecture.Core.Interfaces;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
Expand All @@ -20,15 +19,13 @@ public static void Main(string[] args)

try
{
var context = services.GetRequiredService<AppDbContext>();
// context.Database.Migrate();
context.Database.EnsureCreated();
SeedData.Initialize(services);
var initializer = services.GetRequiredService<IDatabaseInitializer>();
initializer.Initialize();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
logger.LogError(ex, "An error occurred initializing the DB.");
}
}

Expand Down
52 changes: 36 additions & 16 deletions src/CleanArchitecture.Web/Startup.cs
@@ -1,17 +1,16 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Core.SharedKernel;
using CleanArchitecture.Infrastructure.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace CleanArchitecture.Web
Expand All @@ -33,13 +32,6 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
// TODO: Add DbContext and IOC
string dbName = Guid.NewGuid().ToString();

services.AddDbContext<AppDbContext>(options =>
options.UseSqlite("Data Source=database.sqlite")); // will be created in web project root
// options.UseInMemoryDatabase(dbName));
//options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddMvc()
.AddControllersAsServices()
Expand All @@ -50,25 +42,53 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});

AddDbContextToServices(services);

return BuildDependencyInjectionProvider(services);
}

private void AddDbContextToServices(IServiceCollection services)
{
// Create lightweight container just so we can get IDatabaseRegistrar instance.
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(GetAssembliesToRegister(false)).AsImplementedInterfaces();
IDatabaseRegistrar databaseRegistrar = builder.Build().Resolve<IDatabaseRegistrar>();
databaseRegistrar.RegisterSQLite(services);
// databaseRegistrar.RegisterInMemory(services);
// databaseRegistrar.RegisterSQLServer(services, Configuration.GetConnectionString("DefaultConnection"));
}

private static IServiceProvider BuildDependencyInjectionProvider(IServiceCollection services)
{
var builder = new ContainerBuilder();
ContainerBuilder builder = new ContainerBuilder();

// Populate the container using the service collection
builder.Populate(services);

Assembly webAssembly = Assembly.GetExecutingAssembly();
Assembly coreAssembly = Assembly.GetAssembly(typeof(BaseEntity));
Assembly infrastructureAssembly = Assembly.GetAssembly(typeof(EfRepository)); // TODO: Move to Infrastucture Registry
builder.RegisterAssemblyTypes(webAssembly, coreAssembly, infrastructureAssembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(GetAssembliesToRegister()).AsImplementedInterfaces();

IContainer applicationContainer = builder.Build();
return new AutofacServiceProvider(applicationContainer);
}

private static Assembly[] GetAssembliesToRegister(bool includeWeb = true)
{
List<Assembly> assemblies = new List<Assembly>();
if (includeWeb)
{
assemblies.Add(Assembly.GetExecutingAssembly());
}
assemblies.Add(Assembly.GetAssembly(typeof(BaseEntity)));
assemblies.Add(GetInfrastructureAssembly());
return assemblies.ToArray();
}

private static Assembly GetInfrastructureAssembly()
{
string location = AppDomain.CurrentDomain.BaseDirectory;
const string infrastructureDll = "CleanArchitecture.Infrastructure.dll";
sdepouw marked this conversation as resolved.
Show resolved Hide resolved
return Assembly.LoadFile($"{location}{infrastructureDll}");
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
Expand Down
2 changes: 1 addition & 1 deletion src/CleanArchitecture.Web/web.config
Expand Up @@ -5,7 +5,7 @@
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" startupTimeLimit="3600" requestTimeout="23:00:00">
<environmentVariables />
Expand Down
4 changes: 4 additions & 0 deletions tests/CleanArchitecture.Tests/CleanArchitecture.Tests.csproj
Expand Up @@ -51,4 +51,8 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>

<ItemGroup>
<Folder Include="Integration\Web\Api\" />
</ItemGroup>

</Project>
@@ -1,4 +1,5 @@
using CleanArchitecture.Core.Entities;
using CleanArchitecture.Infrastructure.Data;
using CleanArchitecture.Web;
using Newtonsoft.Json;
using System.Collections.Generic;
Expand Down