diff --git a/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj b/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj
index 79b8cc4563..55b6bfda3e 100644
--- a/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj
+++ b/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj
@@ -27,7 +27,7 @@
-
+
diff --git a/Application/EdFi.Ods.Tests/EdFi.Ods.Api/Caching/StubSecurityContext.cs b/Application/EdFi.Ods.Tests/EdFi.Ods.Api/Caching/StubSecurityContext.cs
deleted file mode 100644
index 5a03eaebd1..0000000000
--- a/Application/EdFi.Ods.Tests/EdFi.Ods.Api/Caching/StubSecurityContext.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Licensed to the Ed-Fi Alliance under one or more agreements.
-// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
-// See the LICENSE and NOTICES files in the project root for more information.
-
-using System.Collections.Generic;
-using System.Data.Entity;
-using System.Data.Entity.Infrastructure;
-using System.Linq;
-using EdFi.Security.DataAccess.Contexts;
-using EdFi.Security.DataAccess.Models;
-using FakeItEasy;
-
-namespace EdFi.Ods.Tests.EdFi.Ods.Api.Caching
-{
- public class SecurityContextMock
- {
- ///
- /// Sets up a queryable fake security context with minimal data
- ///
- ///
- public static ISecurityContext GetMockedSecurityContext()
- {
- var securityContext = A.Fake();
- // The underlying SecurityRepository implementation expects this application, so force it to be there in the fake
- securityContext.Actions = GetFakeDbSet().SetupData();
- securityContext.ClaimSets = GetFakeDbSet().SetupData();
- securityContext.ResourceClaims = GetFakeDbSet().SetupData();
- securityContext.AuthorizationStrategies = GetFakeDbSet().SetupData();
- securityContext.ClaimSetResourceClaimActions = GetFakeDbSet().SetupData();
- securityContext.ResourceClaimActionAuthorizationStrategies = GetFakeDbSet().SetupData();
- securityContext.ResourceClaimActions = GetFakeDbSet().SetupData();
-
- return securityContext;
- }
-
- private static DbSet GetFakeDbSet() where T : class
- {
- return A.Fake>(o => o.Implements(typeof(IQueryable)).Implements(typeof(IDbAsyncEnumerable)));
- }
- }
-}
diff --git a/Application/EdFi.Security.DataAccess/Contexts/ISecurityContext.cs b/Application/EdFi.Security.DataAccess/Contexts/ISecurityContext.cs
index 4f16b814dc..2a869cab4b 100644
--- a/Application/EdFi.Security.DataAccess/Contexts/ISecurityContext.cs
+++ b/Application/EdFi.Security.DataAccess/Contexts/ISecurityContext.cs
@@ -4,7 +4,8 @@
// See the LICENSE and NOTICES files in the project root for more information.
using System;
-using System.Data.Entity;
+using System.Threading;
+using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using EdFi.Security.DataAccess.Models;
using Action = EdFi.Security.DataAccess.Models.Action;
@@ -32,6 +33,6 @@ public interface ISecurityContext : IDisposable
int SaveChanges();
- Task SaveChangesAsync();
+ Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
}
}
diff --git a/Application/EdFi.Security.DataAccess/Contexts/PostgresSecurityContext.cs b/Application/EdFi.Security.DataAccess/Contexts/PostgresSecurityContext.cs
index 8ce7189311..d0aa4dc6a2 100644
--- a/Application/EdFi.Security.DataAccess/Contexts/PostgresSecurityContext.cs
+++ b/Application/EdFi.Security.DataAccess/Contexts/PostgresSecurityContext.cs
@@ -3,58 +3,22 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
-using System.Data.Entity;
-using System.Data.Entity.Core.Metadata.Edm;
-using System.Data.Entity.Infrastructure;
-using System.Data.Entity.ModelConfiguration.Conventions;
-using EdFi.Common;
using EdFi.Common.Utils.Extensions;
+using Microsoft.EntityFrameworkCore;
namespace EdFi.Security.DataAccess.Contexts
{
public class PostgresSecurityContext : SecurityContext
{
- public PostgresSecurityContext(string connectionString)
- : base(connectionString) { }
+ public PostgresSecurityContext(DbContextOptions options)
+ : base(options) { }
- protected override void OnModelCreating(DbModelBuilder modelBuilder)
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
- modelBuilder.Conventions.Add();
- modelBuilder.Conventions.Add();
-
- modelBuilder.Properties().Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToLowerInvariant()));
- }
-
- private class TableLowerCaseNamingConvention : IStoreModelConvention
- {
- public void Apply(EntitySet entitySet, DbModel model)
- {
- Preconditions.ThrowIfNull(entitySet, nameof(entitySet));
- Preconditions.ThrowIfNull(model, nameof(model));
-
- entitySet.Table = entitySet.Table.ToLowerInvariant();
- }
- }
-
- private class ForeignKeyLowerCaseNamingConvention : IStoreModelConvention
- {
- public void Apply(AssociationType association, DbModel model)
- {
- Preconditions.ThrowIfNull(association, nameof(association));
- Preconditions.ThrowIfNull(model, nameof(model));
-
- if (!association.IsForeignKey)
- {
- return;
- }
-
- association.Constraint.FromProperties.ForEach(PropertyNamesToLowerInvariant);
- association.Constraint.ToProperties.ForEach(PropertyNamesToLowerInvariant);
-
- void PropertyNamesToLowerInvariant(EdmProperty property) => property.Name = property.Name.ToLowerInvariant();
- }
+ modelBuilder.Model.GetEntityTypes().ForEach(entityType =>
+ entityType.SetSchema("dbo"));
}
}
}
diff --git a/Application/EdFi.Security.DataAccess/Contexts/SecurityContext.cs b/Application/EdFi.Security.DataAccess/Contexts/SecurityContext.cs
index a2c2a38898..c962cb9b26 100644
--- a/Application/EdFi.Security.DataAccess/Contexts/SecurityContext.cs
+++ b/Application/EdFi.Security.DataAccess/Contexts/SecurityContext.cs
@@ -3,20 +3,15 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
-using System.Data.Entity;
+using Microsoft.EntityFrameworkCore;
using EdFi.Security.DataAccess.Models;
-using EdFi.Security.DataAccess.Utils;
namespace EdFi.Security.DataAccess.Contexts
{
public abstract class SecurityContext : DbContext, ISecurityContext
{
- protected SecurityContext(string connectionString)
- : base(connectionString)
- {
- Database.SetInitializer(new ValidateDatabase());
- Database.SetInitializer(new ValidateDatabase());
- }
+ protected SecurityContext(DbContextOptions options)
+ : base(options) { }
public DbSet Actions { get; set; }
@@ -33,13 +28,5 @@ protected SecurityContext(string connectionString)
public DbSet ClaimSetResourceClaimActionAuthorizationStrategyOverrides { get; set; }
public DbSet ResourceClaimActionAuthorizationStrategies { get; set; }
-
- protected override void OnModelCreating(DbModelBuilder modelBuilder)
- {
- modelBuilder.Entity()
- .HasOptional(rc => rc.ParentResourceClaim)
- .WithMany()
- .HasForeignKey(fk => fk.ParentResourceClaimId);
- }
}
}
diff --git a/Application/EdFi.Security.DataAccess/Contexts/SecurityContextFactory.cs b/Application/EdFi.Security.DataAccess/Contexts/SecurityContextFactory.cs
index c8dcc874f7..ee58e63120 100644
--- a/Application/EdFi.Security.DataAccess/Contexts/SecurityContextFactory.cs
+++ b/Application/EdFi.Security.DataAccess/Contexts/SecurityContextFactory.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using EdFi.Common.Configuration;
using EdFi.Security.DataAccess.Providers;
+using Microsoft.EntityFrameworkCore;
namespace EdFi.Security.DataAccess.Contexts
{
@@ -17,21 +18,49 @@ public class SecurityContextFactory : ISecurityContextFactory
private readonly IDictionary _securityContextTypeByDatabaseEngine =
new Dictionary
{
- {DatabaseEngine.SqlServer, typeof(SqlServerSecurityContext)},
- {DatabaseEngine.Postgres, typeof(PostgresSecurityContext)}
+ { DatabaseEngine.SqlServer, typeof(SqlServerSecurityContext) },
+ { DatabaseEngine.Postgres, typeof(PostgresSecurityContext) }
};
- public SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider, DatabaseEngine databaseEngine)
+ public SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider,
+ DatabaseEngine databaseEngine)
{
_connectionStringProvider = connectionStringProvider;
_databaseEngine = databaseEngine;
}
- public ISecurityContext CreateContext()
+ public Type GetSecurityContextType()
{
if (_securityContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType))
{
- return Activator.CreateInstance(contextType, _connectionStringProvider.GetConnectionString()) as ISecurityContext;
+ return contextType;
+ }
+
+ throw new InvalidOperationException(
+ $"No SecurityContext defined for database type {_databaseEngine.DisplayName}");
+ }
+
+ public ISecurityContext CreateContext()
+ {
+ if (_databaseEngine == DatabaseEngine.SqlServer)
+ {
+ return Activator.CreateInstance(
+ GetSecurityContextType(),
+ new DbContextOptionsBuilder()
+ .UseSqlServer(_connectionStringProvider.GetConnectionString())
+ .Options) as
+ ISecurityContext;
+ }
+
+ if (_databaseEngine == DatabaseEngine.Postgres)
+ {
+ return Activator.CreateInstance(
+ GetSecurityContextType(),
+ new DbContextOptionsBuilder()
+ .UseNpgsql(_connectionStringProvider.GetConnectionString())
+ .UseLowerCaseNamingConvention()
+ .Options) as
+ ISecurityContext;
}
throw new InvalidOperationException(
diff --git a/Application/EdFi.Security.DataAccess/Contexts/SqlServerSecurityContext.cs b/Application/EdFi.Security.DataAccess/Contexts/SqlServerSecurityContext.cs
index 09d520a57a..a3318c48e2 100644
--- a/Application/EdFi.Security.DataAccess/Contexts/SqlServerSecurityContext.cs
+++ b/Application/EdFi.Security.DataAccess/Contexts/SqlServerSecurityContext.cs
@@ -3,11 +3,13 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
+using Microsoft.EntityFrameworkCore;
+
namespace EdFi.Security.DataAccess.Contexts
{
public class SqlServerSecurityContext : SecurityContext
{
// The default behavior is appropriate for this sub-class.
- public SqlServerSecurityContext(string connectionString) : base(connectionString) { }
+ public SqlServerSecurityContext(DbContextOptions options) : base(options) { }
}
}
diff --git a/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj b/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj
index 5dd8879dff..3c294f9cb9 100644
--- a/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj
+++ b/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj
@@ -27,8 +27,10 @@
-
+
+
+
diff --git a/Application/EdFi.Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs b/Application/EdFi.Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs
index b59a0c138f..a63bc0aa78 100644
--- a/Application/EdFi.Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs
+++ b/Application/EdFi.Security.DataAccess/Models/ClaimSetResourceClaimActionAuthorizationStrategyOverrides.cs
@@ -1,11 +1,15 @@
-using System;
-using System.Collections.Generic;
+// SPDX-License-Identifier: Apache-2.0
+// Licensed to the Ed-Fi Alliance under one or more agreements.
+// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
+// See the LICENSE and NOTICES files in the project root for more information.
+
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
-using System.Text;
+using Microsoft.EntityFrameworkCore;
namespace EdFi.Security.DataAccess.Models
{
+ [Index(nameof(ClaimSetResourceClaimActionId), nameof(AuthorizationStrategyId), IsUnique = true)]
public class ClaimSetResourceClaimActionAuthorizationStrategyOverrides
{
[Key]
@@ -15,14 +19,12 @@ public class ClaimSetResourceClaimActionAuthorizationStrategyOverrides
public int ClaimSetResourceClaimActionId { get; set; }
[Required]
- [Index(IsUnique = true, Order = 1)]
[ForeignKey("ClaimSetResourceClaimActionId")]
public ClaimSetResourceClaimAction ClaimSetResourceClaimAction { get; set; }
public int AuthorizationStrategyId { get; set; }
[Required]
- [Index(IsUnique = true, Order = 2)]
[ForeignKey("AuthorizationStrategyId")]
public AuthorizationStrategy AuthorizationStrategy { get; set; }
}
diff --git a/Application/EdFi.Security.DataAccess/Models/ResourceClaim.cs b/Application/EdFi.Security.DataAccess/Models/ResourceClaim.cs
index dbf782ae06..6ef39e97d3 100644
--- a/Application/EdFi.Security.DataAccess/Models/ResourceClaim.cs
+++ b/Application/EdFi.Security.DataAccess/Models/ResourceClaim.cs
@@ -3,7 +3,6 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
-using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Application/EdFi.Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs b/Application/EdFi.Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs
index 9aa2f5576c..1e27767849 100644
--- a/Application/EdFi.Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs
+++ b/Application/EdFi.Security.DataAccess/Models/ResourceClaimActionAuthorizationStrategies.cs
@@ -1,8 +1,10 @@
-using System;
-using System.Collections.Generic;
+// SPDX-License-Identifier: Apache-2.0
+// Licensed to the Ed-Fi Alliance under one or more agreements.
+// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
+// See the LICENSE and NOTICES files in the project root for more information.
+
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
-using System.Text;
namespace EdFi.Security.DataAccess.Models
{
diff --git a/Application/EdFi.Security.DataAccess/Repositories/SecurityTableGateway.cs b/Application/EdFi.Security.DataAccess/Repositories/SecurityTableGateway.cs
index f21d29045f..f941720222 100644
--- a/Application/EdFi.Security.DataAccess/Repositories/SecurityTableGateway.cs
+++ b/Application/EdFi.Security.DataAccess/Repositories/SecurityTableGateway.cs
@@ -5,11 +5,11 @@
using System;
using System.Collections.Generic;
-using System.Data.Entity;
using System.Linq;
using EdFi.Common.Utils.Extensions;
using EdFi.Security.DataAccess.Contexts;
using EdFi.Security.DataAccess.Models;
+using Microsoft.EntityFrameworkCore;
using Action = EdFi.Security.DataAccess.Models.Action;
namespace EdFi.Security.DataAccess.Repositories;
@@ -60,8 +60,9 @@ public List GetClaimSetResourceClaimActions()
var claimSetResourceClaimActions = context.ClaimSetResourceClaimActions.Include(csrc => csrc.Action)
.Include(csrc => csrc.ClaimSet)
.Include(csrc => csrc.ResourceClaim)
- .Include(csrc => csrc.AuthorizationStrategyOverrides.Select(aso => aso.AuthorizationStrategy))
- .ToList();
+ .Include(csrc => csrc.AuthorizationStrategyOverrides)
+ .ThenInclude(aso => aso.AuthorizationStrategy)
+ .ToList();
// Replace empty lists with null since some consumers expect it that way
claimSetResourceClaimActions.Where(csrc => csrc.AuthorizationStrategyOverrides.Count == 0)
diff --git a/Application/EdFi.Security.DataAccess/Utils/ValidateDatabase.cs b/Application/EdFi.Security.DataAccess/Utils/ValidateDatabase.cs
deleted file mode 100644
index 6f953cf3cf..0000000000
--- a/Application/EdFi.Security.DataAccess/Utils/ValidateDatabase.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Licensed to the Ed-Fi Alliance under one or more agreements.
-// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
-// See the LICENSE and NOTICES files in the project root for more information.
-
-using System;
-using System.Configuration;
-using System.Data.Entity;
-using System.Transactions;
-using EdFi.Common;
-
-namespace EdFi.Security.DataAccess.Utils
-{
- public class ValidateDatabase : IDatabaseInitializer
- where TContext : DbContext
- {
- public void InitializeDatabase(TContext context)
- {
- Preconditions.ThrowIfNull(context, nameof(context));
-
- using (new TransactionScope(TransactionScopeOption.Suppress))
- {
- if (!context.Database.Exists())
- {
- throw new ConfigurationErrorsException("Unable to open connection to the Security database.");
- }
- }
- }
- }
-}
diff --git a/tests/EdFi.Security.DataAccess.UnitTests/Contexts/SecurityContextFactoryTests.cs b/tests/EdFi.Security.DataAccess.UnitTests/Contexts/SecurityContextFactoryTests.cs
index 5463c1d854..7140b368bd 100644
--- a/tests/EdFi.Security.DataAccess.UnitTests/Contexts/SecurityContextFactoryTests.cs
+++ b/tests/EdFi.Security.DataAccess.UnitTests/Contexts/SecurityContextFactoryTests.cs
@@ -22,12 +22,11 @@ public void Given_configured_for_SqlServer_then_create_SqlServerSecurityContext(
var connectionstringProvider = A.Fake();
A.CallTo(() => connectionstringProvider.GetConnectionString()).Returns(
- "Server=(local); Database=EdFi_Security; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;");
+ "Server=(local); Database=EdFi_Security; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;");
new SecurityContextFactory(connectionstringProvider, DatabaseEngine.SqlServer)
- .CreateContext()
- .ShouldBeOfType()
- .ShouldNotBeNull();
+ .GetSecurityContextType()
+ .ShouldBe(typeof(SqlServerSecurityContext));
}
[Test]
@@ -39,9 +38,8 @@ public void Given_configured_for_Postgres_then_create_PostgresSecurityContext()
"Host=localhost; Port=5432; Username=postgres; Database=EdFi_Security; Application Name=EdFi.Ods.WebApi;");
new SecurityContextFactory(connectionstringProvider, DatabaseEngine.Postgres)
- .CreateContext()
- .ShouldBeOfType()
- .ShouldNotBeNull();
+ .GetSecurityContextType()
+ .ShouldBe(typeof(PostgresSecurityContext));
}
private class UnsupportedDatabaseEngine : DatabaseEngine
diff --git a/tests/EdFi.Security.DataAccess.UnitTests/StubSecurityContext.cs b/tests/EdFi.Security.DataAccess.UnitTests/StubSecurityContext.cs
deleted file mode 100644
index 2de2fd0fb5..0000000000
--- a/tests/EdFi.Security.DataAccess.UnitTests/StubSecurityContext.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Licensed to the Ed-Fi Alliance under one or more agreements.
-// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
-// See the LICENSE and NOTICES files in the project root for more information.
-
-using System.Collections.Generic;
-using System.Data.Entity;
-using System.Data.Entity.Infrastructure;
-using System.Linq;
-using EdFi.Security.DataAccess.Contexts;
-using EdFi.Security.DataAccess.Models;
-using FakeItEasy;
-
-namespace EdFi.Security.DataAccess.UnitTests
-{
- public class SecurityContextMock
- {
- ///
- /// Sets up a queryable fake security context with minimal data
- ///
- ///
- public static ISecurityContext GetMockedSecurityContext()
- {
- var securityContext = A.Fake();
- // The underlying SecurityRepository implementation expects this application, so force it to be there in the fake
- securityContext.Actions = GetFakeDbSet().SetupData();
- securityContext.AuthorizationStrategies = GetFakeDbSet().SetupData();
- securityContext.ClaimSets = GetFakeDbSet().SetupData();
- securityContext.ClaimSetResourceClaimActions = GetFakeDbSet().SetupData();
- securityContext.ResourceClaims = GetFakeDbSet().SetupData();
- securityContext.ResourceClaimActions = GetFakeDbSet().SetupData();
- securityContext.ClaimSetResourceClaimActionAuthorizationStrategyOverrides = GetFakeDbSet().SetupData();
- securityContext.ResourceClaimActionAuthorizationStrategies = GetFakeDbSet().SetupData();
-
- return securityContext;
- }
-
- private static DbSet GetFakeDbSet() where T : class
- {
- return A.Fake>(o => o.Implements(typeof(IQueryable)).Implements(typeof(IDbAsyncEnumerable)));
- }
- }
-}