Server naming fixes and cleanup

Server is now completely cleaned up and without warnings
This commit is contained in:
Pavel Vesely
2020-03-15 09:38:37 +01:00
parent ab3f0853a7
commit 5b3feaf26f
92 changed files with 1223 additions and 1273 deletions

View File

@ -7,6 +7,7 @@ using System.Xml;
using Oqtane.Shared;
using System;
using System.Diagnostics;
using Oqtane.Infrastructure.Interfaces;
namespace Oqtane.Infrastructure
{
@ -21,27 +22,27 @@ namespace Oqtane.Infrastructure
_environment = environment;
}
public void InstallPackages(string Folders, bool Restart)
public void InstallPackages(string folders, bool restart)
{
bool install = false;
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
foreach (string Folder in Folders.Split(','))
foreach (string folder in folders.Split(','))
{
string folder = Path.Combine(_environment.WebRootPath, Folder);
string sourceFolder = Path.Combine(_environment.WebRootPath, folder);
// create folder if it does not exist
if (!Directory.Exists(folder))
if (!Directory.Exists(sourceFolder))
{
Directory.CreateDirectory(folder);
Directory.CreateDirectory(sourceFolder);
}
// iterate through packages
foreach (string packagename in Directory.GetFiles(folder, "*.nupkg"))
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
{
string name = Path.GetFileNameWithoutExtension(packagename);
string[] segments = name.Split('.');
name = string.Join('.', segments, 0, segments.Length - 3);
string[] segments = name?.Split('.');
if (segments != null) name = string.Join('.', segments, 0, segments.Length - 3);
// iterate through files
using (ZipArchive archive = ZipFile.OpenRead(packagename))
@ -78,7 +79,7 @@ namespace Oqtane.Infrastructure
{
case ".pdb":
case ".dll":
entry.ExtractToFile(Path.Combine(binfolder, filename), true);
if (binFolder != null) entry.ExtractToFile(Path.Combine(binFolder, filename), true);
break;
case ".png":
case ".jpg":
@ -87,7 +88,7 @@ namespace Oqtane.Infrastructure
case ".svg":
case ".js":
case ".css":
filename = folder + "\\" + entry.FullName.Replace("wwwroot", name).Replace("/", "\\");
filename = sourceFolder + "\\" + entry.FullName.Replace("wwwroot", name).Replace("/", "\\");
if (!Directory.Exists(Path.GetDirectoryName(filename)))
{
Directory.CreateDirectory(Path.GetDirectoryName(filename));
@ -104,7 +105,7 @@ namespace Oqtane.Infrastructure
}
}
if (install && Restart)
if (install && restart)
{
// restart application
RestartApplication();
@ -165,26 +166,29 @@ namespace Oqtane.Infrastructure
private void FinishUpgrade()
{
string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
// check if upgrade application exists
if (File.Exists(Path.Combine(folder, "Oqtane.Upgrade.exe")))
if (folder == null || !File.Exists(Path.Combine(folder, "Oqtane.Upgrade.exe"))) return;
// run upgrade application
var process = new Process
{
// run upgrade application
var process = new Process();
process.StartInfo.FileName = Path.Combine(folder, "Oqtane.Upgrade.exe");
process.StartInfo.Arguments = "";
process.StartInfo.ErrorDialog = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = false;
process.StartInfo.RedirectStandardError = false;
process.Start();
process.Dispose();
StartInfo =
{
FileName = Path.Combine(folder, "Oqtane.Upgrade.exe"),
Arguments = "",
ErrorDialog = false,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = false,
RedirectStandardError = false
}
};
process.Start();
process.Dispose();
// stop application so upgrade application can proceed
RestartApplication();
}
// stop application so upgrade application can proceed
RestartApplication();
}
public void RestartApplication()

View File

@ -1,8 +1,8 @@
namespace Oqtane.Infrastructure
namespace Oqtane.Infrastructure.Interfaces
{
public interface IInstallationManager
{
void InstallPackages(string Folders, bool Restart);
void InstallPackages(string folders, bool restart);
void UpgradeFramework();
void RestartApplication();
}

View File

@ -1,15 +1,15 @@
using Oqtane.Models;
using System;
using Oqtane.Models;
using Oqtane.Shared;
using System;
namespace Oqtane.Infrastructure
namespace Oqtane.Infrastructure.Interfaces
{
public interface ILogManager
{
void Log(LogLevel Level, object Class, LogFunction Function, string Message, params object[] Args);
void Log(LogLevel Level, object Class, LogFunction Function, Exception Exception, string Message, params object[] Args);
void Log(int SiteId, LogLevel Level, object Class, LogFunction Function, string Message, params object[] Args);
void Log(int SiteId, LogLevel Level, object Class, LogFunction Function, Exception Exception, string Message, params object[] Args);
void Log(Log Log);
void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args);
void Log(LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args);
void Log(int siteId, LogLevel level, object @class, LogFunction function, string message, params object[] args);
void Log(int siteId, LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args);
void Log(Log log);
}
}

View File

@ -1,13 +1,12 @@
using Oqtane.Models;
using Oqtane.Shared;
using System;
using System;
using System.Collections.Generic;
using Oqtane.Models;
namespace Oqtane.Infrastructure
namespace Oqtane.Infrastructure.Interfaces
{
public interface ISyncManager
{
List<SyncEvent> GetSyncEvents(DateTime LastSyncDate);
void AddSyncEvent(string EntityName, int EntityId);
List<SyncEvent> GetSyncEvents(DateTime lastSyncDate);
void AddSyncEvent(string entityName, int entityId);
}
}

View File

@ -13,7 +13,7 @@ namespace Oqtane.Infrastructure
{
public abstract class HostedServiceBase : IHostedService, IDisposable
{
private Task ExecutingTask;
private Task _executingTask;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly IServiceScopeFactory _serviceScopeFactory;
@ -34,43 +34,43 @@ namespace Oqtane.Infrastructure
using (var scope = _serviceScopeFactory.CreateScope())
{
// get name of job
string JobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
string jobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
// load jobs and find current job
IJobRepository Jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
Job Job = Jobs.GetJobs().Where(item => item.JobType == JobType).FirstOrDefault();
if (Job != null && Job.IsEnabled && !Job.IsExecuting)
IJobRepository jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
Job job = jobs.GetJobs().Where(item => item.JobType == jobType).FirstOrDefault();
if (job != null && job.IsEnabled && !job.IsExecuting)
{
// set next execution date
if (Job.NextExecution == null)
if (job.NextExecution == null)
{
if (Job.StartDate != null)
if (job.StartDate != null)
{
Job.NextExecution = Job.StartDate;
job.NextExecution = job.StartDate;
}
else
{
Job.NextExecution = DateTime.UtcNow;
job.NextExecution = DateTime.UtcNow;
}
}
// determine if the job should be run
if (Job.NextExecution <= DateTime.UtcNow && (Job.EndDate == null || Job.EndDate >= DateTime.UtcNow))
if (job.NextExecution <= DateTime.UtcNow && (job.EndDate == null || job.EndDate >= DateTime.UtcNow))
{
IJobLogRepository JobLogs = scope.ServiceProvider.GetRequiredService<IJobLogRepository>();
IJobLogRepository jobLogs = scope.ServiceProvider.GetRequiredService<IJobLogRepository>();
// create a job log entry
JobLog log = new JobLog();
log.JobId = Job.JobId;
log.JobId = job.JobId;
log.StartDate = DateTime.UtcNow;
log.FinishDate = null;
log.Succeeded = false;
log.Notes = "";
log = JobLogs.AddJobLog(log);
log = jobLogs.AddJobLog(log);
// update the job to indicate it is running
Job.IsExecuting = true;
Jobs.UpdateJob(Job);
job.IsExecuting = true;
jobs.UpdateJob(job);
// execute the job
try
@ -86,19 +86,19 @@ namespace Oqtane.Infrastructure
// update the job log
log.FinishDate = DateTime.UtcNow;
JobLogs.UpdateJobLog(log);
jobLogs.UpdateJobLog(log);
// update the job
Job.NextExecution = CalculateNextExecution(Job.NextExecution.Value, Job.Frequency, Job.Interval);
Job.IsExecuting = false;
Jobs.UpdateJob(Job);
job.NextExecution = CalculateNextExecution(job.NextExecution.Value, job.Frequency, job.Interval);
job.IsExecuting = false;
jobs.UpdateJob(job);
// trim the job log
List<JobLog> logs = JobLogs.GetJobLogs().Where(item => item.JobId == Job.JobId)
List<JobLog> logs = jobLogs.GetJobLogs().Where(item => item.JobId == job.JobId)
.OrderByDescending(item => item.JobLogId).ToList();
for (int i = logs.Count; i > Job.RetentionHistory; i--)
for (int i = logs.Count; i > job.RetentionHistory; i--)
{
JobLogs.DeleteJobLog(logs[i - 1].JobLogId);
jobLogs.DeleteJobLog(logs[i - 1].JobLogId);
}
}
}
@ -115,28 +115,28 @@ namespace Oqtane.Infrastructure
}
private DateTime CalculateNextExecution(DateTime NextExecution, string Frequency, int Interval)
private DateTime CalculateNextExecution(DateTime nextExecution, string frequency, int interval)
{
switch (Frequency)
switch (frequency)
{
case "m": // minutes
NextExecution = NextExecution.AddMinutes(Interval);
nextExecution = nextExecution.AddMinutes(interval);
break;
case "H": // hours
NextExecution = NextExecution.AddHours(Interval);
nextExecution = nextExecution.AddHours(interval);
break;
case "d": // days
NextExecution = NextExecution.AddDays(Interval);
nextExecution = nextExecution.AddDays(interval);
break;
case "M": // months
NextExecution = NextExecution.AddMonths(Interval);
nextExecution = nextExecution.AddMonths(interval);
break;
}
if (NextExecution < DateTime.UtcNow)
if (nextExecution < DateTime.UtcNow)
{
NextExecution = DateTime.UtcNow;
nextExecution = DateTime.UtcNow;
}
return NextExecution;
return nextExecution;
}
public Task StartAsync(CancellationToken cancellationToken)
@ -146,14 +146,14 @@ namespace Oqtane.Infrastructure
// set IsExecuting to false in case this job was forcefully terminated previously
using (var scope = _serviceScopeFactory.CreateScope())
{
string JobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
IJobRepository Jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
Job Job = Jobs.GetJobs().Where(item => item.JobType == JobType).FirstOrDefault();
if (Job != null)
string jobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName);
IJobRepository jobs = scope.ServiceProvider.GetRequiredService<IJobRepository>();
Job job = jobs.GetJobs().Where(item => item.JobType == jobType).FirstOrDefault();
if (job != null)
{
Job.IsStarted = true;
Job.IsExecuting = false;
Jobs.UpdateJob(Job);
job.IsStarted = true;
job.IsExecuting = false;
jobs.UpdateJob(job);
}
}
}
@ -162,19 +162,19 @@ namespace Oqtane.Infrastructure
// can occur during the initial installation as there is no DBContext
}
ExecutingTask = ExecuteAsync(_cancellationTokenSource.Token);
_executingTask = ExecuteAsync(_cancellationTokenSource.Token);
if (ExecutingTask.IsCompleted)
if (_executingTask.IsCompleted)
{
return ExecutingTask;
return _executingTask;
}
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken CancellationToken)
public async Task StopAsync(CancellationToken cancellationToken)
{
if (ExecutingTask == null)
if (_executingTask == null)
{
return;
}
@ -185,7 +185,7 @@ namespace Oqtane.Infrastructure
}
finally
{
await Task.WhenAny(ExecutingTask, Task.Delay(Timeout.Infinite, CancellationToken));
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}

View File

@ -14,34 +14,34 @@ namespace Oqtane.Infrastructure
{
// JobType = "Oqtane.Infrastructure.NotificationJob, Oqtane.Server"
public NotificationJob(IServiceScopeFactory ServiceScopeFactory) : base(ServiceScopeFactory) {}
public NotificationJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory) {}
public override string ExecuteJob(IServiceProvider provider)
{
string log = "";
// iterate through aliases in this installation
var Aliases = provider.GetRequiredService<IAliasRepository>();
List<Alias> aliases = Aliases.GetAliases().ToList();
var aliasRepository = provider.GetRequiredService<IAliasRepository>();
List<Alias> aliases = aliasRepository.GetAliases().ToList();
foreach (Alias alias in aliases)
{
// use the SiteState to set the Alias explicitly so the tenant can be resolved
var sitestate = provider.GetRequiredService<SiteState>();
sitestate.Alias = alias;
var siteState = provider.GetRequiredService<SiteState>();
siteState.Alias = alias;
// get services which require tenant resolution
var Sites = provider.GetRequiredService<ISiteRepository>();
var Settings = provider.GetRequiredService<ISettingRepository>();
var Notifications = provider.GetRequiredService<INotificationRepository>();
var siteRepository = provider.GetRequiredService<ISiteRepository>();
var settingRepository = provider.GetRequiredService<ISettingRepository>();
var notificationRepository = provider.GetRequiredService<INotificationRepository>();
// iterate through sites
List<Site> sites = Sites.GetSites().ToList();
List<Site> sites = siteRepository.GetSites().ToList();
foreach (Site site in sites)
{
log += "Processing Notifications For Site: " + site.Name + "\n\n";
// get site settings
List<Setting> sitesettings = Settings.GetSettings("Site", site.SiteId).ToList();
List<Setting> sitesettings = settingRepository.GetSettings("Site", site.SiteId).ToList();
Dictionary<string, string> settings = GetSettings(sitesettings);
if (settings.ContainsKey("SMTPHost") && settings["SMTPHost"] != "")
{
@ -61,7 +61,7 @@ namespace Oqtane.Infrastructure
// iterate through notifications
int sent = 0;
List<Notification> notifications = Notifications.GetNotifications(site.SiteId, -1, -1).ToList();
List<Notification> notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList();
foreach (Notification notification in notifications)
{
MailMessage mailMessage = new MailMessage();
@ -75,7 +75,7 @@ namespace Oqtane.Infrastructure
{
mailMessage.Body = "From: " + site.Name + "\n";
}
mailMessage.Body += "Sent: " + notification.CreatedOn.ToString() + "\n";
mailMessage.Body += "Sent: " + notification.CreatedOn + "\n";
if (notification.ToUserId != null)
{
mailMessage.To.Add(new MailAddress(notification.ToUser.Email, notification.ToUser.DisplayName));
@ -96,15 +96,15 @@ namespace Oqtane.Infrastructure
sent = sent++;
notification.IsDelivered = true;
notification.DeliveredOn = DateTime.UtcNow;
Notifications.UpdateNotification(notification);
notificationRepository.UpdateNotification(notification);
}
catch (Exception ex)
{
// error
log += ex.Message.ToString() + "\n\n";
log += ex.Message + "\n\n";
}
}
log += "Notifications Delivered: " + sent.ToString() + "\n\n";
log += "Notifications Delivered: " + sent + "\n\n";
}
else
{
@ -117,10 +117,10 @@ namespace Oqtane.Infrastructure
}
private Dictionary<string, string> GetSettings(List<Setting> Settings)
private Dictionary<string, string> GetSettings(List<Setting> settings)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
foreach (Setting setting in Settings.OrderBy(item => item.SettingName).ToList())
foreach (Setting setting in settings.OrderBy(item => item.SettingName).ToList())
{
dictionary.Add(setting.SettingName, setting.SettingValue);
}

View File

@ -2,11 +2,14 @@
using System;
using Oqtane.Models;
using System.Text.Json;
using Oqtane.Repository;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using Oqtane.Infrastructure.Interfaces;
using Oqtane.Repository;
using Oqtane.Security;
// ReSharper disable StringIndexOfIsCultureSpecific.2
// ReSharper disable StringIndexOfIsCultureSpecific.1
namespace Oqtane.Infrastructure
{
@ -27,25 +30,25 @@ namespace Oqtane.Infrastructure
_accessor = accessor;
}
public void Log(LogLevel Level, object Class, LogFunction Function, string Message, params object[] Args)
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
{
Log(-1, Level, Class.GetType().AssemblyQualifiedName, Function, null, Message, Args);
Log(-1, level, @class.GetType().AssemblyQualifiedName, function, null, message, args);
}
public void Log(LogLevel Level, object Class, LogFunction Function, Exception Exception, string Message, params object[] Args)
public void Log(LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args)
{
Log(-1, Level, Class.GetType().AssemblyQualifiedName, Function, Exception, Message, Args);
Log(-1, level, @class.GetType().AssemblyQualifiedName, function, exception, message, args);
}
public void Log(int SiteId, LogLevel Level, object Class, LogFunction Function, string Message, params object[] Args)
public void Log(int siteId, LogLevel level, object @class, LogFunction function, string message, params object[] args)
{
Log(SiteId, Level, Class.GetType().AssemblyQualifiedName, Function, null, Message, Args);
Log(siteId, level, @class.GetType().AssemblyQualifiedName, function, null, message, args);
}
public void Log(int SiteId, LogLevel Level, object Class, LogFunction Function, Exception Exception, string Message, params object[] Args)
public void Log(int siteId, LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args)
{
Log log = new Log();
if (SiteId == -1)
if (siteId == -1)
{
log.SiteId = null;
Alias alias = _tenantResolver.GetAlias();
@ -56,7 +59,7 @@ namespace Oqtane.Infrastructure
}
else
{
log.SiteId = SiteId;
log.SiteId = siteId;
}
log.PageId = null;
log.ModuleId = null;
@ -69,10 +72,10 @@ namespace Oqtane.Infrastructure
HttpRequest request = _accessor.HttpContext.Request;
if (request != null)
{
log.Url = request.Scheme.ToString() + "://" + request.Host.ToString() + request.Path.ToString() + request.QueryString.ToString();
log.Url = $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
}
Type type = Type.GetType(Class.ToString());
Type type = @class.GetType();
if (type != null)
{
log.Category = type.AssemblyQualifiedName;
@ -80,20 +83,20 @@ namespace Oqtane.Infrastructure
}
else
{
log.Category = Class.ToString();
log.Category = @class.ToString();
log.Feature = log.Category;
}
log.Function = Enum.GetName(typeof(LogFunction), Function);
log.Level = Enum.GetName(typeof(LogLevel), Level);
if (Exception != null)
log.Function = Enum.GetName(typeof(LogFunction), function);
log.Level = Enum.GetName(typeof(LogLevel), level);
if (exception != null)
{
log.Exception = Exception.ToString();
log.Exception = exception.ToString();
}
log.Message = Message;
log.Message = message;
log.MessageTemplate = "";
try
{
log.Properties = JsonSerializer.Serialize(Args);
log.Properties = JsonSerializer.Serialize(args);
}
catch // serialization error occurred
{
@ -102,7 +105,7 @@ namespace Oqtane.Infrastructure
Log(log);
}
public void Log(Log Log)
public void Log(Log log)
{
LogLevel minlevel = LogLevel.Information;
var section = _config.GetSection("Logging:LogLevel:Default");
@ -111,15 +114,15 @@ namespace Oqtane.Infrastructure
minlevel = Enum.Parse<LogLevel>(_config.GetSection("Logging:LogLevel:Default").ToString());
}
if (Enum.Parse<LogLevel>(Log.Level) >= minlevel)
if (Enum.Parse<LogLevel>(log.Level) >= minlevel)
{
Log.LogDate = DateTime.UtcNow;
Log.Server = Environment.MachineName;
Log.MessageTemplate = Log.Message;
Log = ProcessStructuredLog(Log);
log.LogDate = DateTime.UtcNow;
log.Server = Environment.MachineName;
log.MessageTemplate = log.Message;
log = ProcessStructuredLog(log);
try
{
_logs.AddLog(Log);
_logs.AddLog(log);
}
catch
{
@ -128,16 +131,16 @@ namespace Oqtane.Infrastructure
}
}
private Log ProcessStructuredLog(Log Log)
private Log ProcessStructuredLog(Log log)
{
try
{
string message = Log.Message;
string message = log.Message;
string properties = "";
if (!string.IsNullOrEmpty(message) && message.Contains("{") && message.Contains("}") && !string.IsNullOrEmpty(Log.Properties))
if (!string.IsNullOrEmpty(message) && message.Contains("{") && message.Contains("}") && !string.IsNullOrEmpty(log.Properties))
{
// get the named holes in the message and replace values
object[] values = JsonSerializer.Deserialize<object[]>(Log.Properties);
object[] values = JsonSerializer.Deserialize<object[]>(log.Properties);
List<string> names = new List<string>();
int index = message.IndexOf("{");
while (index != -1)
@ -160,28 +163,28 @@ namespace Oqtane.Infrastructure
index = message.IndexOf("{", index + 1);
}
// rebuild properties into dictionary
Dictionary<string, object> propertydictionary = new Dictionary<string, object>();
Dictionary<string, object> propertyDictionary = new Dictionary<string, object>();
for (int i = 0; i < values.Length; i++)
{
if (i < names.Count)
{
propertydictionary.Add(names[i], values[i]);
propertyDictionary.Add(names[i], values[i]);
}
else
{
propertydictionary.Add("Property" + i.ToString(), values[i]);
propertyDictionary.Add("Property" + i.ToString(), values[i]);
}
}
properties = JsonSerializer.Serialize(propertydictionary);
properties = JsonSerializer.Serialize(propertyDictionary);
}
Log.Message = message;
Log.Properties = properties;
log.Message = message;
log.Properties = properties;
}
catch
{
Log.Properties = "";
log.Properties = "";
}
return Log;
return log;
}
}
}
}

View File

@ -1,20 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
using Oqtane.Models;
using Oqtane.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using Oqtane.Infrastructure.Interfaces;
using Oqtane.Repository;
namespace Oqtane.Infrastructure
{
public class SyncManager : ISyncManager
{
private readonly IServiceScopeFactory ServiceScopeFactory;
private readonly IServiceScopeFactory _serviceScopeFactory;
private List<SyncEvent> SyncEvents { get; set; }
public SyncManager(IServiceScopeFactory ServiceScopeFactory)
public SyncManager(IServiceScopeFactory serviceScopeFactory)
{
this.ServiceScopeFactory = ServiceScopeFactory;
this._serviceScopeFactory = serviceScopeFactory;
SyncEvents = new List<SyncEvent>();
}
@ -22,21 +23,21 @@ namespace Oqtane.Infrastructure
{
get
{
using (var scope = ServiceScopeFactory.CreateScope())
using (var scope = _serviceScopeFactory.CreateScope())
{
return scope.ServiceProvider.GetRequiredService<ITenantResolver>().GetTenant().TenantId;
}
}
}
public List<SyncEvent> GetSyncEvents(DateTime LastSyncDate)
public List<SyncEvent> GetSyncEvents(DateTime lastSyncDate)
{
return SyncEvents.Where(item => item.TenantId == TenantId && item.ModifiedOn >= LastSyncDate).ToList();
return SyncEvents.Where(item => item.TenantId == TenantId && item.ModifiedOn >= lastSyncDate).ToList();
}
public void AddSyncEvent(string EntityName, int EntityId)
public void AddSyncEvent(string entityName, int entityId)
{
SyncEvents.Add(new SyncEvent { TenantId = TenantId, EntityName = EntityName, EntityId = EntityId, ModifiedOn = DateTime.UtcNow });
SyncEvents.Add(new SyncEvent { TenantId = TenantId, EntityName = entityName, EntityId = entityId, ModifiedOn = DateTime.UtcNow });
// trim sync events
SyncEvents.RemoveAll(item => item.ModifiedOn < DateTime.UtcNow.AddHours(-1));
}