optimized updating new tags

This commit is contained in:
Maksim Chegulov 2023-08-30 14:13:18 +03:00
parent 4eb5aaa2c0
commit 4632b44767
3 changed files with 215 additions and 163 deletions

View File

@ -46,6 +46,7 @@ public interface ITagDao<T>
Task<TagInfo> SaveTagInfoAsync(TagInfo tagInfo);
Task UpdateNewTags(IEnumerable<Tag> tag, Guid createdBy = default);
Task UpdateNewTags(Tag tag);
Task IncrementNewTagsAsync(IEnumerable<Tag> tags, Guid createdBy = default);
Task RemoveTagsAsync(IEnumerable<int> tagsIds);
Task RemoveTagsAsync(FileEntry<T> entry, IEnumerable<int> tagsIds);
Task RemoveTags(IEnumerable<Tag> tag);

View File

@ -468,6 +468,45 @@ internal abstract class BaseTagDao<T> : AbstractDao
return t;
}
public async Task IncrementNewTagsAsync(IEnumerable<Tag> tags, Guid createdBy = default)
{
if (tags == null || !tags.Any())
{
return;
}
try
{
await _semaphore.WaitAsync();
await using var filesDbContext = _dbContextFactory.CreateDbContext();
var strategy = filesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var internalFilesDbContext = _dbContextFactory.CreateDbContext();
await using var tx = await internalFilesDbContext.Database.BeginTransactionAsync();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var tenantId = TenantID;
foreach (var tagsGroup in tags.GroupBy(t => new { t.EntryId, t.EntryType }))
{
var mappedId = (await MappingIDAsync(tagsGroup.Key.EntryId)).ToString();
await Queries.IncrementNewTagsAsync(filesDbContext, tenantId, tagsGroup.Select(t => t.Id), tagsGroup.Key.EntryType,
mappedId, createdBy, createOn);
}
await tx.CommitAsync();
});
}
finally
{
_semaphore.Release();
}
}
public async Task UpdateNewTags(IEnumerable<Tag> tags, Guid createdBy = default)
{
if (tags == null || !tags.Any())
@ -1323,4 +1362,18 @@ static file class Queries
.Where(r => r.TenantId == tenantId)
.Where(r => tagsIds.Contains(r.Id))
.ExecuteDelete());
public static readonly Func<FilesDbContext, int, IEnumerable<int>, FileEntryType, string, Guid, DateTime, Task<int>>
IncrementNewTagsAsync = Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<int> tagsIds, FileEntryType tagEntryType, string mappedId, Guid createdBy,
DateTime createOn) =>
ctx.TagLink
.Where(r => r.TenantId == tenantId)
.Where(r => tagsIds.Contains(r.TagId))
.Where(r => r.EntryType == tagEntryType)
.Where(r => r.EntryId == mappedId)
.ExecuteUpdate(f => f
.SetProperty(p => p.CreateBy, createdBy)
.SetProperty(p => p.CreateOn, createOn)
.SetProperty(p => p.Count, p => p.Count + 1)));
}

View File

@ -25,7 +25,7 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Files.Utils;
[Singletone]
public class FileMarkerHelper
{
@ -33,7 +33,7 @@ public class FileMarkerHelper
private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger;
public DistributedTaskQueue Tasks { get; set; }
public FileMarkerHelper(
IServiceProvider serviceProvider,
ILogger<FileMarkerHelper> logger,
@ -43,12 +43,12 @@ public class FileMarkerHelper
_logger = logger;
Tasks = queueFactory.CreateQueue(CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME);
}
internal void Add<T>(AsyncTaskData<T> taskData)
{
Tasks.EnqueueTask(async (d, c) => await ExecMarkFileAsNewAsync(taskData), taskData);
}
private async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj)
{
try
@ -64,14 +64,14 @@ public class FileMarkerHelper
}
}
}
[Scope(Additional = typeof(FileMarkerExtention))]
public class FileMarker
{
private readonly ICache _cache;
private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}";
private readonly TenantManager _tenantManager;
private readonly UserManager _userManager;
private readonly IDaoFactory _daoFactory;
@ -106,14 +106,14 @@ public class FileMarker
_roomsNotificationSettingsHelper = roomsNotificationSettingsHelper;
_cache = cache;
}
internal async Task ExecMarkFileAsNewAsync<T>(AsyncTaskData<T> obj, SocketManager socketManager)
{
await _tenantManager.SetCurrentTenantAsync(obj.TenantID);
var folderDao = _daoFactory.GetFolderDao<T>();
T parentFolderId;
if (obj.FileEntry.FileEntryType == FileEntryType.File)
{
parentFolderId = ((File<T>)obj.FileEntry).ParentId;
@ -122,26 +122,26 @@ public class FileMarker
{
parentFolderId = ((Folder<T>)obj.FileEntry).Id;
}
var parentFolders = await folderDao.GetParentFoldersAsync(parentFolderId).Reverse().ToListAsync();
var userIDs = obj.UserIDs;
var userEntriesData = new Dictionary<Guid, List<FileEntry>>();
if (obj.FileEntry.RootFolderType == FolderType.BUNCH)
{
if (userIDs.Count == 0)
{
return;
}
var projectsFolder = await _globalFolder.GetFolderProjectsAsync<T>(_daoFactory);
parentFolders.Add(await folderDao.GetFolderAsync(projectsFolder));
var entries = new List<FileEntry> { obj.FileEntry };
entries = entries.Concat(parentFolders).ToList();
userIDs.ForEach(userID =>
{
if (userEntriesData.TryGetValue(userID, out var value))
@ -152,19 +152,20 @@ public class FileMarker
{
userEntriesData.Add(userID, entries);
}
RemoveFromCahce(projectsFolder, userID);
});
}
else
{
var filesSecurity = _fileSecurity;
if (userIDs.Count == 0)
{
var guids = await filesSecurity.WhoCanReadAsync(obj.FileEntry);
userIDs = guids.Where(x => x != obj.CurrentAccountId).ToList();
}
if (obj.FileEntry.ProviderEntry)
{
userIDs = await userIDs.ToAsyncEnumerable().WhereAwait(async u => !await _userManager.IsUserAsync(u)).ToListAsync();
@ -203,15 +204,15 @@ public class FileMarker
{
userEntriesData.Add(id, new List<FileEntry> { parentFolder });
}
}
}
}
if (obj.FileEntry.RootFolderType == FolderType.USER)
{
var folderDaoInt = _daoFactory.GetFolderDao<int>();
var folderShare = await folderDaoInt.GetFolderAsync(await _globalFolder.GetFolderShareAsync(_daoFactory));
foreach (var userID in userIDs)
{
var userFolderId = await folderDaoInt.GetFolderIDUserAsync(false, userID);
@ -219,13 +220,13 @@ public class FileMarker
{
continue;
}
Folder<int> rootFolder = null;
if (obj.FileEntry.ProviderEntry)
{
rootFolder = obj.FileEntry.RootCreateBy == userID
? await folderDaoInt.GetFolderAsync(userFolderId)
: folderShare;
? await folderDaoInt.GetFolderAsync(userFolderId)
: folderShare;
}
else if (!Equals(obj.FileEntry.RootId, userFolderId))
{
@ -235,12 +236,12 @@ public class FileMarker
{
RemoveFromCahce(userFolderId, userID);
}
if (rootFolder == null)
{
continue;
}
if (userEntriesData.TryGetValue(userID, out var value))
{
value.Add(rootFolder);
@ -249,7 +250,7 @@ public class FileMarker
{
userEntriesData.Add(userID, new List<FileEntry> { rootFolder });
}
RemoveFromCahce(rootFolder.Id, userID);
}
}
@ -257,7 +258,7 @@ public class FileMarker
{
var commonFolderId = await _globalFolder.GetFolderCommonAsync(this, _daoFactory);
userIDs.ForEach(userID => RemoveFromCahce(commonFolderId, userID));
if (obj.FileEntry.ProviderEntry)
{
var commonFolder = await folderDao.GetFolderAsync(await _globalFolder.GetFolderCommonAsync<T>(this, _daoFactory));
@ -271,7 +272,7 @@ public class FileMarker
{
userEntriesData.Add(userID, new List<FileEntry> { commonFolder });
}
RemoveFromCahce(commonFolderId, userID);
});
}
@ -338,7 +339,7 @@ public class FileMarker
RemoveFromCahce(rootFolder.Id, userID);
}
}
userIDs.ForEach(userID =>
{
if (userEntriesData.TryGetValue(userID, out var value))
@ -351,67 +352,64 @@ public class FileMarker
}
});
}
var tagDao = _daoFactory.GetTagDao<T>();
var newTags = new List<Tag>();
var updateTags = new List<Tag>();
try
{
await _semaphore.WaitAsync();
foreach (var userID in userEntriesData.Keys)
{
if (await tagDao.GetNewTagsAsync(userID, obj.FileEntry).AnyAsync())
foreach (var userId in userEntriesData.Keys)
{
continue;
}
var entries = userEntriesData[userID].Distinct().ToList();
await GetNewTagsAsync(userID, entries.OfType<FileEntry<int>>().ToList());
await GetNewTagsAsync(userID, entries.OfType<FileEntry<string>>().ToList());
}
if (await tagDao.GetNewTagsAsync(userId, obj.FileEntry).AnyAsync())
{
continue;
}
if (updateTags.Count > 0)
{
await tagDao.UpdateNewTags(updateTags, obj.CurrentAccountId);
}
if (newTags.Count > 0)
{
await tagDao.SaveTags(newTags, obj.CurrentAccountId);
}
}
catch
{
throw;
var entries = userEntriesData[userId].Distinct().ToList();
await GetNewTagsAsync(userId, entries.OfType<FileEntry<int>>().ToList());
await GetNewTagsAsync(userId, entries.OfType<FileEntry<string>>().ToList());
}
if (updateTags.Count > 0)
{
await tagDao.IncrementNewTagsAsync(updateTags, obj.CurrentAccountId);
}
if (newTags.Count > 0)
{
await tagDao.SaveTags(newTags, obj.CurrentAccountId);
}
}
finally
{
_semaphore.Release();
}
await Task.WhenAll(ExecMarkAsNewRequest(updateTags.Concat(newTags), socketManager));
async Task GetNewTagsAsync<T1>(Guid userID, List<FileEntry<T1>> entries)
return;
async Task GetNewTagsAsync<T1>(Guid userId, List<FileEntry<T1>> entries)
{
var tagDao1 = _daoFactory.GetTagDao<T1>();
var exist = await tagDao1.GetNewTagsAsync(userID, entries).ToListAsync();
var exist = await tagDao1.GetNewTagsAsync(userId, entries).ToListAsync();
var update = exist.Where(t => t.EntryType == FileEntryType.Folder).ToList();
update.ForEach(t => t.Count++);
updateTags.AddRange(update);
entries.ForEach(entry =>
{
if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.Id)))
{
newTags.Add(Tag.New(userID, entry));
newTags.Add(Tag.New(userId, entry));
}
});
}
}
public async ValueTask MarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null)
{
if (fileEntry == null)
@ -420,36 +418,36 @@ public class FileMarker
}
userIDs ??= new List<Guid>();
var taskData = _serviceProvider.GetService<AsyncTaskData<T>>();
taskData.FileEntry = (FileEntry<T>)fileEntry.Clone();
taskData.UserIDs = userIDs;
if (fileEntry.RootFolderType == FolderType.BUNCH && userIDs.Count == 0)
{
var folderDao = _daoFactory.GetFolderDao<T>();
var path = await folderDao.GetBunchObjectIDAsync(fileEntry.RootId);
var projectID = path.Split('/').Last();
if (string.IsNullOrEmpty(projectID))
{
return;
}
var whoCanRead = await _fileSecurity.WhoCanReadAsync(fileEntry);
var projectTeam = whoCanRead.Where(x => x != _authContext.CurrentAccount.ID).ToList();
if (projectTeam.Count == 0)
{
return;
}
taskData.UserIDs = projectTeam;
}
_serviceProvider.GetService<FileMarkerHelper>().Add(taskData);
}
public async ValueTask RemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default)
{
if (fileEntry == null)
@ -458,41 +456,41 @@ public class FileMarker
}
userID = userID.Equals(default) ? _authContext.CurrentAccount.ID : userID;
var tagDao = _daoFactory.GetTagDao<T>();
var internalFolderDao = _daoFactory.GetFolderDao<int>();
var folderDao = _daoFactory.GetFolderDao<T>();
if (!await tagDao.GetNewTagsAsync(userID, fileEntry).AnyAsync())
{
return;
}
T folderID;
int valueNew;
var userFolderId = await internalFolderDao.GetFolderIDUserAsync(false, userID);
var privacyFolderId = await internalFolderDao.GetFolderIDPrivacyAsync(false, userID);
var removeTags = new List<Tag>();
if (fileEntry.FileEntryType == FileEntryType.File)
{
folderID = ((File<T>)fileEntry).ParentId;
removeTags.Add(Tag.New(userID, fileEntry));
valueNew = 1;
}
else
{
folderID = fileEntry.Id;
var listTags = await tagDao.GetNewTagsAsync(userID, (Folder<T>)fileEntry, true).ToListAsync();
valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.Id)).Count;
if (Equals(fileEntry.Id, userFolderId) || Equals(fileEntry.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) || Equals(fileEntry.Id, await _globalFolder.GetFolderShareAsync(_daoFactory)))
{
var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder);
foreach (var tag in folderTags)
{
var folderEntry = await folderDao.GetFolderAsync((T)tag.EntryId);
@ -500,15 +498,15 @@ public class FileMarker
{
listTags.Remove(tag);
listTags.AddRange(await tagDao.GetNewTagsAsync(userID, folderEntry, true).ToListAsync());
}
}
}
}
}
removeTags.AddRange(listTags);
}
var parentFolders = await folderDao.GetParentFoldersAsync(folderID).Reverse().ToListAsync();
var rootFolder = parentFolders.LastOrDefault();
int rootFolderId = default;
int cacheFolderId = default;
@ -561,24 +559,24 @@ public class FileMarker
{
cacheFolderId = await _globalFolder.GetFolderShareAsync(_daoFactory);
}
var updateTags = new List<Tag>();
if (!rootFolderId.Equals(default))
{
await UpdateRemoveTags(await internalFolderDao.GetFolderAsync(rootFolderId));
}
if (!cacheFolderId.Equals(default))
{
RemoveFromCahce(cacheFolderId, userID);
}
foreach (var parentFolder in parentFolders)
{
await UpdateRemoveTags(parentFolder);
}
if (updateTags.Count > 0)
{
await tagDao.UpdateNewTags(updateTags);
@ -604,11 +602,11 @@ public class FileMarker
var tagDao = _daoFactory.GetTagDao<TFolder>();
var newTags = tagDao.GetNewTagsAsync(userID, folder);
var parentTag = await newTags.FirstOrDefaultAsync();
if (parentTag != null)
{
parentTag.Count -= valueNew;
if (parentTag.Count > 0)
{
updateTags.Add(parentTag);
@ -620,21 +618,21 @@ public class FileMarker
}
}
}
public async Task RemoveMarkAsNewForAllAsync<T>(FileEntry<T> fileEntry)
{
IAsyncEnumerable<Guid> userIDs;
var tagDao = _daoFactory.GetTagDao<T>();
var tags = tagDao.GetTagsAsync(fileEntry.Id, fileEntry.FileEntryType == FileEntryType.File ? FileEntryType.File : FileEntryType.Folder, TagType.New);
userIDs = tags.Select(tag => tag.Owner).Distinct();
await foreach (var userID in userIDs)
{
await RemoveMarkAsNewAsync(fileEntry, userID);
}
}
public async Task<int> GetRootFoldersIdMarkedAsNewAsync<T>(T rootId)
{
@ -647,24 +645,24 @@ public class FileMarker
var requestTag = await requestTags.FirstOrDefaultAsync(tag => tag.EntryId.Equals(rootId));
var count = requestTag == null ? 0 : requestTag.Count;
InsertToCahce(rootId, count);
return count;
}
else if (fromCache > 0)
{
return fromCache;
}
return 0;
}
public IAsyncEnumerable<FileEntry> MarkedItemsAsync<T>(Folder<T> folder)
{
if (folder == null)
{
throw new ArgumentNullException(nameof(folder), FilesCommonResource.ErrorMassage_FolderNotFound);
}
return InternalMarkedItemsAsync(folder);
}
@ -675,67 +673,67 @@ public class FileMarker
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);
}
if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.Id, await _globalFolder.GetFolderTrashAsync(_daoFactory)))
{
throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);
}
if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.Id, await _globalFolder.GetFolderTrashAsync(_daoFactory)))
{
throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);
}
var tagDao = _daoFactory.GetTagDao<T>();
var providerFolderDao = _daoFactory.GetFolderDao<string>();
var providerTagDao = _daoFactory.GetTagDao<string>();
var tags = await (tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>()).ToListAsync();
var tagDao = _daoFactory.GetTagDao<T>();
var providerFolderDao = _daoFactory.GetFolderDao<string>();
var providerTagDao = _daoFactory.GetTagDao<string>();
var tags = await (tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>()).ToListAsync();
if (!tags.Any())
{
yield break;
}
if (Equals(folder.Id, await _globalFolder.GetFolderMyAsync(this, _daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderCommonAsync(this, _daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderShareAsync(_daoFactory)) ||
Equals(folder.Id, await _globalFolder.GetFolderVirtualRoomsAsync(_daoFactory)))
{
var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder && (tag.EntryId is string));
var providerFolderTags = new List<KeyValuePair<Tag, Folder<string>>>();
foreach (var tag in folderTags)
{
var pair = new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString()));
if (pair.Value != null && pair.Value.ProviderEntry)
{
providerFolderTags.Add(pair);
}
}
providerFolderTags.Reverse();
foreach (var providerFolderTag in providerFolderTags)
var providerFolderTags = new List<KeyValuePair<Tag, Folder<string>>>();
foreach (var tag in folderTags)
{
tags.AddRange(await providerTagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, providerFolderTag.Value, true).ToListAsync());
var pair = new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString()));
if (pair.Value != null && pair.Value.ProviderEntry)
{
providerFolderTags.Add(pair);
}
}
providerFolderTags.Reverse();
foreach (var providerFolderTag in providerFolderTags)
{
tags.AddRange(await providerTagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, providerFolderTag.Value, true).ToListAsync());
}
}
tags = tags
.Where(r => !Equals(r.EntryId, folder.Id))
.Distinct()
.Distinct()
.ToList();
//TODO: refactoring
var entryTagsProvider = await GetEntryTagsAsync<string>(tags.Where(r => r.EntryId is string).ToAsyncEnumerable());
var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int).ToAsyncEnumerable());
var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int).ToAsyncEnumerable());
foreach (var entryTag in entryTagsInternal)
{
var parentEntry = entryTagsInternal.Keys
.FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId));
if (parentEntry != null)
{
entryTagsInternal[parentEntry].Count -= entryTag.Value.Count;
}
}
foreach (var entryTag in entryTagsProvider)
{
if (int.TryParse(entryTag.Key.ParentId, out var fId))
@ -746,20 +744,20 @@ public class FileMarker
if (parentEntryInt != null)
{
entryTagsInternal[parentEntryInt].Count -= entryTag.Value.Count;
}
}
continue;
}
var parentEntry = entryTagsProvider.Keys
.FirstOrDefault(entryCountTag => Equals(entryCountTag.Id, entryTag.Key.ParentId));
if (parentEntry != null)
{
entryTagsProvider[parentEntry].Count -= entryTag.Value.Count;
}
}
}
await foreach (var r in GetResultAsync(entryTagsInternal))
{
yield return r;
@ -772,28 +770,28 @@ public class FileMarker
async IAsyncEnumerable<FileEntry> GetResultAsync<TEntry>(Dictionary<FileEntry<TEntry>, Tag> entryTags)
{
foreach (var entryTag in entryTags)
{
if (!string.IsNullOrEmpty(entryTag.Key.Error))
{
await RemoveMarkAsNewAsync(entryTag.Key);
continue;
}
if (entryTag.Value.Count > 0)
foreach (var entryTag in entryTags)
{
if (!string.IsNullOrEmpty(entryTag.Key.Error))
{
yield return entryTag.Key;
}
}
}
await RemoveMarkAsNewAsync(entryTag.Key);
continue;
}
if (entryTag.Value.Count > 0)
{
yield return entryTag.Key;
}
}
}
}
private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IAsyncEnumerable<Tag> tags)
{
var fileDao = _daoFactory.GetFileDao<T>();
var folderDao = _daoFactory.GetFolderDao<T>();
var entryTags = new Dictionary<FileEntry<T>, Tag>();
await foreach (var tag in tags)
{
var entry = tag.EntryType == FileEntryType.File
@ -817,7 +815,7 @@ public class FileMarker
var tagDao = _daoFactory.GetTagDao<T>();
var folderDao = _daoFactory.GetFolderDao<T>();
var totalTags = await tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, parent, false).ToListAsync();
if (totalTags.Count <= 0)
{
return;
@ -977,13 +975,13 @@ public class FileMarker
}
}
}
private void InsertToCahce(object folderId, int count)
{
var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId);
_cache.Insert(key, count.ToString(), TimeSpan.FromMinutes(10));
}
private int GetCountFromCahce(object folderId)
{
var key = string.Format(CacheKeyFormat, _authContext.CurrentAccount.ID, folderId);
@ -991,12 +989,12 @@ public class FileMarker
return count == null ? -1 : int.Parse(count);
}
private void RemoveFromCahce(object folderId)
{
RemoveFromCahce(folderId, _authContext.CurrentAccount.ID);
}
private void RemoveFromCahce(object folderId, Guid userId)
{
var key = string.Format(CacheKeyFormat, userId, folderId);
@ -1018,7 +1016,7 @@ public class FileMarker
}
}
}
[Transient]
public class AsyncTaskData<T> : DistributedTask
{
@ -1027,13 +1025,13 @@ public class AsyncTaskData<T> : DistributedTask
TenantID = tenantManager.GetCurrentTenant().Id;
CurrentAccountId = authContext.CurrentAccount.ID;
}
public int TenantID { get; private set; }
public FileEntry<T> FileEntry { get; set; }
public List<Guid> UserIDs { get; set; }
public Guid CurrentAccountId { get; set; }
}
public static class FileMarkerExtention
{
public static void Register(DIHelper services)
@ -1043,4 +1041,4 @@ public static class FileMarkerExtention
services.TryAdd<AsyncTaskData<string>>();
}
}
}