diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/LearningHubConfig.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/LearningHubConfig.cs
index efc4ba99c..81b91aa65 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/LearningHubConfig.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/LearningHubConfig.cs
@@ -47,6 +47,11 @@ public class LearningHubConfig
///
public bool UseRedisCache { get; set; } = false;
+ ///
+ /// Gets or sets .
+ ///
+ public int MaxDatabaseRetryAttempts { get; set; } = 0;
+
///
/// Gets or sets .
///
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/EntityFramework/ServiceMappings.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/EntityFramework/ServiceMappings.cs
index a3a35abcc..2b2dad930 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/EntityFramework/ServiceMappings.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/EntityFramework/ServiceMappings.cs
@@ -187,11 +187,21 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon
// External
services.AddSingleton();
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlServer(configuration.GetConnectionString("LearningHubDbConnection")).Options;
+ // Configure LearningHubDbContextOptions per scope (per request)
+ services.AddScoped(sp =>
+ {
+ var dbOptions = sp.GetRequiredService>();
+ var mappings = sp.GetServices();
+ return new LearningHubDbContextOptions(dbOptions, mappings);
+ });
- services.AddSingleton(dbContextOptions);
- services.AddSingleton();
+ // Configure DbContext
+ var maxDatabaseRetryAttempts = configuration.GetValue("LearningHub:MaxDatabaseRetryAttempts");
+ services.AddDbContext(options =>
+ options.UseSqlServer(
+ configuration.GetConnectionString("LearningHubDbConnection"),
+ sqlOptions => sqlOptions.EnableRetryOnFailure(maxDatabaseRetryAttempts)
+ ));
}
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Activity/ScormActivityRepository.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Activity/ScormActivityRepository.cs
index cfcef4ebb..800062297 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Activity/ScormActivityRepository.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Activity/ScormActivityRepository.cs
@@ -220,12 +220,13 @@ public async Task CheckUserScormActivitySuspendDataToBeCleared(int lastSco
private async Task UpdateScormActivityAsync(int userId, ScormActivity updatedScormActivity)
{
- var existingScormActivity = DbContext.ScormActivity.Where(s => s.Id == updatedScormActivity.Id)
+ var existingScormActivity = this.DbContext.ScormActivity.Where(s => s.Id == updatedScormActivity.Id)
.Include(sao => sao.ScormActivityObjective)
.Include(sao => sao.ScormActivityInteraction)
.ThenInclude(sai => sai.ScormActivityInteractionCorrectResponse)
.Include(sai => sai.ScormActivityInteraction)
.ThenInclude(sai => sai.ScormActivityInteractionObjective)
+ .AsSplitQuery()
.SingleOrDefault();
updatedScormActivity.ResourceActivityId = existingScormActivity.ResourceActivityId;
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/UserProfileRepository.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/UserProfileRepository.cs
index b3edc6e34..1d18d4eee 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/UserProfileRepository.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/UserProfileRepository.cs
@@ -26,9 +26,9 @@ public UserProfileRepository(LearningHubDbContext context, ITimezoneOffsetManage
///
/// The id.
/// The userProfile.
- public Task GetByIdAsync(int id)
+ public async Task GetByIdAsync(int id)
{
- return DbContext.UserProfile.AsNoTracking().SingleOrDefaultAsync(x => x.Id == id);
+ return await DbContext.UserProfile.AsNoTracking().SingleOrDefaultAsync(x => x.Id == id);
}
///
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
index 9c78cdb0d..b5f934976 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
@@ -543,7 +543,7 @@ public async Task GetCatalogueAsync(string reference, int us
await this.RecordNodeActivity(userId, catalogue);
var catalogueVM = this.mapper.Map(catalogue);
- var bookmark = this.bookmarkRepository.GetAll().Where(b => b.NodeId == catalogue.NodeId && b.UserId == userId).FirstOrDefault();
+ var bookmark = await this.bookmarkRepository.GetAll().Where(b => b.NodeId == catalogue.NodeId && b.UserId == userId).FirstOrDefaultAsync();
catalogueVM.BookmarkId = bookmark?.Id;
catalogueVM.IsBookmarked = !bookmark?.Deleted ?? false;
catalogueVM.Providers = await this.providerService.GetByCatalogueVersionIdAsync(catalogueVM.Id);
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/BookmarkController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/BookmarkController.cs
index 4adaebe2b..421047223 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/BookmarkController.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/BookmarkController.cs
@@ -37,15 +37,17 @@ public BookmarkController(IBookmarkService bookmarkService)
[Route("GetAllByParent/{parentId?}")]
public async Task GetAllByParent(int? parentId, bool? all = false)
{
- if (this.CurrentUserId.GetValueOrDefault() != null)
+ var userId = this.CurrentUserId;
+
+ if (userId.HasValue && userId.Value != 4)
{
- var bookmarks = await this.bookmarkService.GetAllByParent(this.CurrentUserId.GetValueOrDefault(), parentId, all);
+ var bookmarks = await this.bookmarkService.GetAllByParent(userId.Value, parentId, all);
return this.Ok(bookmarks);
}
- else
- {
- return this.Ok(await this.bookmarkService.GetAllByParent(this.TokenWithoutBearer));
- }
+
+ var fallbackBookmarks = await this.bookmarkService.GetAllByParent(this.TokenWithoutBearer);
+ return this.Ok(fallbackBookmarks);
+
}
///
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/OpenApiControllerBase.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/OpenApiControllerBase.cs
index d28333990..85ea14ce6 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/OpenApiControllerBase.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/OpenApiControllerBase.cs
@@ -11,6 +11,8 @@
///
public abstract class OpenApiControllerBase : ControllerBase, IDisposable
{
+ private const int PortalAdminId = 4;
+
///
/// Gets the current user's ID.
///
@@ -28,14 +30,14 @@ public int? CurrentUserId
}
else
{
- // If parsing fails, return null - for apikey this will be the name
- return null;
+ // If parsing fails, return PortalAdminId as default userId - for apikey this will be the name
+ return PortalAdminId;
}
}
else
{
// When authorizing by ApiKey we do not have a user for example
- return null;
+ return PortalAdminId;
}
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
index dfe34b2b8..68a10c876 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
@@ -84,10 +84,6 @@ public void ConfigureServices(IServiceCollection services)
services.AddRepositories(this.Configuration);
services.AddServices();
-
- services.AddDbContext(
- options =>
- options.UseSqlServer(this.Configuration.GetConnectionString("LearningHub")));
services.AddApplicationInsightsTelemetry();
services.AddControllers(options =>
{
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
index 7142f4b36..1be62cf11 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
@@ -76,6 +76,7 @@
"SupportPages": "https://support.learninghub.nhs.uk/",
"SupportForm": "https://support.learninghub.nhs.uk/support/tickets/new",
"UseRedisCache": true,
+ "MaxDatabaseRetryAttempts": 3,
"ResourcePublishQueueRouteName": "",
"HierarchyEditPublishQueueName": "",
"ContentManagementQueueName": "",
diff --git a/WebAPI/LearningHub.Nhs.Repository/Activity/ScormActivityRepository.cs b/WebAPI/LearningHub.Nhs.Repository/Activity/ScormActivityRepository.cs
index 6d9af606a..5f2fd0863 100644
--- a/WebAPI/LearningHub.Nhs.Repository/Activity/ScormActivityRepository.cs
+++ b/WebAPI/LearningHub.Nhs.Repository/Activity/ScormActivityRepository.cs
@@ -226,6 +226,7 @@ private async Task UpdateScormActivityAsync(int userId, ScormActivity updatedSco
.ThenInclude(sai => sai.ScormActivityInteractionCorrectResponse)
.Include(sai => sai.ScormActivityInteraction)
.ThenInclude(sai => sai.ScormActivityInteractionObjective)
+ .AsSplitQuery()
.SingleOrDefault();
updatedScormActivity.ResourceActivityId = existingScormActivity.ResourceActivityId;