diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 1e4c8716..40474361 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -30,11 +30,12 @@ namespace Oqtane.Controllers private readonly IMemoryCache _cache; private readonly IHttpContextAccessor _accessor; private readonly IAliasRepository _aliases; + private readonly ISiteRepository _sites; private readonly ILogger _filelogger; private readonly ITenantManager _tenantManager; private readonly IServerStateManager _serverState; - public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger filelogger, ITenantManager tenantManager, IServerStateManager serverState) + public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ISiteRepository sites, ILogger filelogger, ITenantManager tenantManager, IServerStateManager serverState) { _configManager = configManager; _installationManager = installationManager; @@ -43,6 +44,7 @@ namespace Oqtane.Controllers _cache = cache; _accessor = accessor; _aliases = aliases; + _sites = sites; _filelogger = filelogger; _tenantManager = tenantManager; _serverState = serverState; @@ -108,6 +110,70 @@ namespace Oqtane.Controllers return GetAssemblyList().Select(item => item.HashedName).ToList(); } + private List GetAssemblyList() + { + var alias = _tenantManager.GetAlias(); + + return _cache.GetOrCreate($"assemblieslist:{alias.SiteKey}", entry => + { + var assemblyList = new List(); + + var site = _sites.GetSite(alias.SiteId); + if (site != null && site.Runtime == "WebAssembly") + { + var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + + // testmode setting is used for validating that the API is downloading the appropriate assemblies to the client + bool hashfilename = true; + if (_configManager.GetSetting($"{SettingKeys.TestModeKey}", "false") == "true") + { + hashfilename = false; + } + + // get site assemblies which should be downloaded to client + var assemblies = _serverState.GetServerState(alias.SiteKey).Assemblies; + + // populate assembly list + foreach (var assembly in assemblies) + { + if (assembly != Constants.ClientId) + { + var filepath = Path.Combine(binFolder, assembly) + ".dll"; + if (System.IO.File.Exists(filepath)) + { + assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, assembly + ".dll"), hashfilename)); + } + } + } + + // insert satellite assemblies at beginning of list + foreach (var culture in _localizationManager.GetInstalledCultures()) + { + if (culture != Constants.DefaultCulture) + { + var assembliesFolderPath = Path.Combine(binFolder, culture); + if (Directory.Exists(assembliesFolderPath)) + { + foreach (var assembly in assemblies) + { + var filepath = Path.Combine(assembliesFolderPath, assembly) + ".resources.dll"; + if (System.IO.File.Exists(filepath)) + { + assemblyList.Insert(0, new ClientAssembly(Path.Combine(assembliesFolderPath, assembly + ".resources.dll"), hashfilename)); + } + } + } + else + { + _filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist")); + } + } + } + } + return assemblyList; + }); + } + // GET api//load?list=x,y [HttpGet("load")] public IActionResult Load(string list = "*") @@ -115,126 +181,79 @@ namespace Oqtane.Controllers return File(GetAssemblies(list), System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.dll"); } - private List GetAssemblyList() - { - var siteKey = _tenantManager.GetAlias().SiteKey; - - return _cache.GetOrCreate($"assemblieslist:{siteKey}", entry => - { - var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - var assemblyList = new List(); - - // testmode setting is used for validating that the API is downloading the appropriate assemblies to the client - bool hashfilename = true; - if (_configManager.GetSetting($"{SettingKeys.TestModeKey}", "false") == "true") - { - hashfilename = false; - } - - // get site assemblies which should be downloaded to client - var assemblies = _serverState.GetServerState(siteKey).Assemblies; - - // populate assembly list - foreach (var assembly in assemblies) - { - if (assembly != Constants.ClientId) - { - var filepath = Path.Combine(binFolder, assembly) + ".dll"; - if (System.IO.File.Exists(filepath)) - { - assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, assembly + ".dll"), hashfilename)); - } - } - } - - // insert satellite assemblies at beginning of list - foreach (var culture in _localizationManager.GetInstalledCultures()) - { - if (culture != Constants.DefaultCulture) - { - var assembliesFolderPath = Path.Combine(binFolder, culture); - if (Directory.Exists(assembliesFolderPath)) - { - foreach (var assembly in assemblies) - { - var filepath = Path.Combine(assembliesFolderPath, assembly) + ".resources.dll"; - if (System.IO.File.Exists(filepath)) - { - assemblyList.Insert(0, new ClientAssembly(Path.Combine(assembliesFolderPath, assembly + ".resources.dll"), hashfilename)); - } - } - } - else - { - _filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist")); - } - } - } - - return assemblyList; - }); - } - private byte[] GetAssemblies(string list) { - var siteKey = _tenantManager.GetAlias().SiteKey; + var alias = _tenantManager.GetAlias(); if (list == "*") { - return _cache.GetOrCreate($"assemblies:{siteKey}", entry => + return _cache.GetOrCreate($"assemblies:{alias.SiteKey}", entry => { - return GetZIP(list); + return GetZIP(list, alias); }); } else { - return GetZIP(list); + return GetZIP(list, alias); } } - private byte[] GetZIP(string list) + private byte[] GetZIP(string list, Alias alias) { - var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - - // get list of assemblies which should be downloaded to client - List assemblies = GetAssemblyList(); - if (list != "*") + var site = _sites.GetSite(alias.SiteId); + if (site != null && site.Runtime == "WebAssembly") { - var filter = list.Split(',').ToList(); - assemblies.RemoveAll(item => !filter.Contains(item.HashedName)); - } + var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - // create zip file containing assemblies and debug symbols - using (var memoryStream = new MemoryStream()) - { - using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) + // get list of assemblies which should be downloaded to client + List assemblies = GetAssemblyList(); + if (list != "*") { - foreach (var assembly in assemblies) + var filter = list.Split(',').ToList(); + assemblies.RemoveAll(item => !filter.Contains(item.HashedName)); + } + + // create zip file containing assemblies and debug symbols + using (var memoryStream = new MemoryStream()) + { + using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) { - if (Path.GetFileNameWithoutExtension(assembly.FilePath) != Constants.ClientId) + foreach (var assembly in assemblies) { - if (System.IO.File.Exists(assembly.FilePath)) + if (Path.GetFileNameWithoutExtension(assembly.FilePath) != Constants.ClientId) { - using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read)) - using (var entrystream = archive.CreateEntry(assembly.HashedName).Open()) + if (System.IO.File.Exists(assembly.FilePath)) { - filestream.CopyTo(entrystream); + using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read)) + using (var entrystream = archive.CreateEntry(assembly.HashedName).Open()) + { + filestream.CopyTo(entrystream); + } } - } - var pdb = assembly.FilePath.Replace(".dll", ".pdb"); - if (System.IO.File.Exists(pdb)) - { - using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read)) - using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open()) + var pdb = assembly.FilePath.Replace(".dll", ".pdb"); + if (System.IO.File.Exists(pdb)) { - filestream.CopyTo(entrystream); + using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read)) + using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open()) + { + filestream.CopyTo(entrystream); + } } } } } - } - return memoryStream.ToArray(); + return memoryStream.ToArray(); + } + } + else + { + // return empty zip + using (var memoryStream = new MemoryStream()) + { + using (var zip = new ZipArchive(memoryStream, ZipArchiveMode.Create)) {} + return memoryStream.ToArray(); + } } } diff --git a/Oqtane.Server/Infrastructure/EventSubscribers/CacheInvalidationEventSubscriber.cs b/Oqtane.Server/Infrastructure/EventSubscribers/CacheInvalidationEventSubscriber.cs index 41dab17d..5bf1fd14 100644 --- a/Oqtane.Server/Infrastructure/EventSubscribers/CacheInvalidationEventSubscriber.cs +++ b/Oqtane.Server/Infrastructure/EventSubscribers/CacheInvalidationEventSubscriber.cs @@ -15,10 +15,18 @@ namespace Oqtane.Infrastructure.EventSubscribers public void EntityChanged(SyncEvent syncEvent) { + // when site entities change (ie. site, pages, modules, etc...) a site refresh event is raised and the site cache item needs to be refreshed if (syncEvent.EntityName == EntityNames.Site && syncEvent.Action == SyncEventActions.Refresh) { _cache.Remove($"site:{syncEvent.TenantId}:{syncEvent.EntityId}"); } + + // when a site entity is updated the hosting model may have changed, so the client assemblies cache items need to be refreshed + if (syncEvent.EntityName == EntityNames.Site && syncEvent.Action == SyncEventActions.Update) + { + _cache.Remove($"assemblieslist:{syncEvent.TenantId}:{syncEvent.EntityId}"); + _cache.Remove($"assemblies:{syncEvent.TenantId}:{syncEvent.EntityId}"); + } } } }