using CoreDatabase; using SecurityContract.BindingModels; using SecurityContract.Services; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.Serialization.Json; using ToolsModule.ManagmentEntity; using ToolsModule.ManagmentExtension; using ToolsModule.ManagmentSecurity; namespace SecurityDatabaseImplementation.Implementations { /// /// Реализация IBackupService для сохранения в JSON через JsonContract /// public class BackupJsonContractService : IBackupService { public OperationResultModel CreateBackUp(BackupBindingModel model) { try { var asm = typeof(DatabaseManager).Assembly; MethodInfo method = GetType().GetTypeInfo().GetDeclaredMethod("SaveToFile"); foreach (var t in asm.GetExportedTypes()) { if (t.IsClass && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntitySecurityExtenstion<>)) && t.GetCustomAttribute() != null) { MethodInfo generic = method.MakeGenericMethod(t); generic.Invoke(this, new object[] { model.FolderName, model.FullData, t }); } } if (model.CreateArchive) { var fileName = $"{model.FolderName}.zip"; if (File.Exists(fileName)) { File.Delete($"{model.FolderName}.zip"); } ZipFile.CreateFromDirectory(model.FolderName, fileName); } } catch (Exception ex) { return OperationResultModel.Error(ex); } return OperationResultModel.Success(null); } public OperationResultModel RestoreBackUp(BackupBindingModel model) { try { if (model.ArchiveFileName.IsNotEmpty()) { if(model.FolderName.IsEmpty()) { model.FolderName = $"{Path.GetDirectoryName(model.ArchiveFileName)}{Path.GetFileNameWithoutExtension(model.ArchiveFileName)}"; } ZipFile.ExtractToDirectory(model.ArchiveFileName, model.FolderName); } var asm = typeof(DatabaseManager).Assembly; #region вытаскиваем все типы-сущности (они должны быть унаследованы от IEntitySecurityExtenstion и иметь атрибут EntityDescription) List types = new(); foreach (var t in asm.GetExportedTypes()) { if (t.IsClass && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntitySecurityExtenstion<>)) && t.GetCustomAttribute() != null) { types.Add(t); } } #endregion #region формиурем зависимости (в каком порядке загружать данные) Dictionary typesWithLevel = new(); while (types.Count > 0) { for (int i = 0; i < types.Count; ++i) { var depends = types[i].GetCustomAttributes(); if ((depends == null || !depends.Any()) && !typesWithLevel.ContainsKey(types[i])) { typesWithLevel.Add(types[i], 0); types.RemoveAt(i--); continue; } int? level = null; foreach (var depend in depends) { var type = typesWithLevel.Keys.FirstOrDefault(x => x.Name == depend.ClassName); if (type != null) { if (!level.HasValue) { level = typesWithLevel[type]; } else if (level < typesWithLevel[type]) { level = typesWithLevel[type]; } } else { level = null; break; } } if (level.HasValue) { typesWithLevel.Add(types[i], level.Value + 1); types.RemoveAt(i--); continue; } } } #endregion #region Удаляем записи сначала из тех, на которые никкто не ссылается и в последнюю оередь, те, на которые все ссылаются var deleteOrder = typesWithLevel.OrderByDescending(x => x.Value); MethodInfo delMethod = GetType().GetTypeInfo().GetDeclaredMethod("DeleteFromDB"); foreach (var delElem in deleteOrder) { if (File.Exists(string.Format("{0}/{1}.json", model.FolderName, delElem.Key.Name))) { MethodInfo generic = delMethod.MakeGenericMethod(delElem.Key); generic.Invoke(this, null); } } #endregion #region Заполняем в порядке - сначала те, у которых нет родителей, потом их потомство MethodInfo method = GetType().GetTypeInfo().GetDeclaredMethod("LoadFromFile"); foreach (var delElem in typesWithLevel.OrderBy(x => x.Value)) { MethodInfo generic = method.MakeGenericMethod(delElem.Key); generic.Invoke(this, new object[] { model.FolderName, delElem.Key }); } #endregion } catch (Exception ex) { return OperationResultModel.Error(ex); } return OperationResultModel.Success(null); } /// /// Сохранение списка сущности из БД в файл (вызывается через рефлексию) /// /// /// /// /// private void SaveToFile(string folderName, bool allowFullData, Type t) where T : class, IEntitySecurityExtenstion, new() { using var context = DatabaseManager.GetContext; var records = context.Set().Select(x => x.SecurityCheck(x, allowFullData)); DataContractJsonSerializer jsonFormatter = new(typeof(List)); using FileStream fs = new(string.Format("{0}/{1}.json", folderName, t.Name), FileMode.OpenOrCreate); jsonFormatter.WriteObject(fs, records); } /// /// Отчистка записей сущности в БД (вызывается через рефлексию) /// /// private void DeleteFromDB() where T : class, new() { using var context = DatabaseManager.GetContext; context.Set().RemoveRange(context.Set()); context.SaveChanges(); } /// /// Загрузка списка сущности из файла в БД (вызывается через рефлексию) /// /// /// /// private void LoadFromFile(string folderName, Type t) where T : class, new() { using var context = DatabaseManager.GetContext; if (File.Exists(string.Format("{0}/{1}.json", folderName, t.Name))) { DataContractJsonSerializer jsonFormatter = new(typeof(List)); using FileStream fs = new(string.Format("{0}/{1}.json", folderName, t.Name), FileMode.Open); List records = (List)jsonFormatter.ReadObject(fs); context.Set().AddRange(records); context.SaveChanges(); } } } }