diff --git a/src/Libraries/Nop.Core/CommonHelper.cs b/src/Libraries/Nop.Core/CommonHelper.cs index 7887d615eee..53eaac5bcf8 100644 --- a/src/Libraries/Nop.Core/CommonHelper.cs +++ b/src/Libraries/Nop.Core/CommonHelper.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; -using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Security.Cryptography; using System.Text.RegularExpressions; -using System.Threading; +using Nop.Core.Infrastructure; namespace Nop.Core { @@ -34,29 +33,6 @@ static CommonHelper() #endregion - #region Utilities - - private static void DeleteDirectoryRecursive(string path) - { - Directory.Delete(path, true); - const int maxIterationToWait = 10; - var curIteration = 0; - - //according to the documentation(https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa365488.aspx) - //System.IO.Directory.Delete method ultimately (after removing the files) calls native - //RemoveDirectory function which marks the directory as "deleted". That's why we wait until - //the directory is actually deleted. For more details see https://stackoverflow.com/a/4245121 - while (Directory.Exists(path)) - { - curIteration += 1; - if (curIteration > maxIterationToWait) - return; - Thread.Sleep(100); - } - } - - #endregion - #region Methods /// @@ -338,17 +314,6 @@ public static int GetDifferenceInYears(DateTime startDate, DateTime endDate) return age; } - /// - /// Maps a virtual path to a physical disk path. - /// - /// The path to map. E.g. "~/bin" - /// The physical path. E.g. "c:\inetpub\wwwroot\bin" - public static string MapPath(string path) - { - path = path.Replace("~/", "").TrimStart('/').Replace('/', '\\'); - return Path.Combine(BaseDirectory??string.Empty, path); - } - /// /// Get private fields property value /// @@ -387,46 +352,15 @@ public static object GetPrivateFieldValue(object target, string fieldName) return fi.GetValue(target); } - /// - /// Depth-first recursive delete, with handling for descendant directories open in Windows Explorer. - /// - /// Directory path - public static void DeleteDirectory(string path) - { - if (string.IsNullOrEmpty(path)) - throw new ArgumentNullException(path); - - //find more info about directory deletion - //and why we use this approach at https://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true - - foreach (var directory in Directory.GetDirectories(path)) - { - DeleteDirectory(directory); - } - - try - { - DeleteDirectoryRecursive(path); - } - catch (IOException) - { - DeleteDirectoryRecursive(path); - } - catch (UnauthorizedAccessException) - { - DeleteDirectoryRecursive(path); - } - } - #endregion #region Properties /// - /// Gets or sets application base path + /// Gets or sets the default file provider /// - internal static string BaseDirectory { get; set; } - + public static INopFileProvider DefaultFileProvider { get; set; } + #endregion } } diff --git a/src/Libraries/Nop.Core/Data/DataSettingsHelper.cs b/src/Libraries/Nop.Core/Data/DataSettingsHelper.cs index 25788ae2ca6..56eb3ee2635 100644 --- a/src/Libraries/Nop.Core/Data/DataSettingsHelper.cs +++ b/src/Libraries/Nop.Core/Data/DataSettingsHelper.cs @@ -13,12 +13,13 @@ public partial class DataSettingsHelper /// public static bool DatabaseIsInstalled() { - if (!_databaseIsInstalled.HasValue) - { - var manager = new DataSettingsManager(); - var settings = manager.LoadSettings(reloadSettings:true); - _databaseIsInstalled = settings != null && !string.IsNullOrEmpty(settings.DataConnectionString); - } + if (_databaseIsInstalled.HasValue) + return _databaseIsInstalled.Value; + + var manager = new DataSettingsManager(); + + var settings = manager.LoadSettings(reloadSettings:true); + _databaseIsInstalled = !string.IsNullOrEmpty(settings?.DataConnectionString); return _databaseIsInstalled.Value; } diff --git a/src/Libraries/Nop.Core/Data/DataSettingsManager.cs b/src/Libraries/Nop.Core/Data/DataSettingsManager.cs index c170fab0354..764c2a8d73a 100644 --- a/src/Libraries/Nop.Core/Data/DataSettingsManager.cs +++ b/src/Libraries/Nop.Core/Data/DataSettingsManager.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text; using Newtonsoft.Json; using Nop.Core.Infrastructure; @@ -12,8 +13,14 @@ public partial class DataSettingsManager { #region Const - private const string ObsoleteDataSettingsFilePath = "~/App_Data/Settings.txt"; - private const string DataSettingsFilePath_ = "~/App_Data/dataSettings.json"; + private const string OBSOLETE_DATA_SETTINGS_FILE_PATH = "~/App_Data/Settings.txt"; + private const string DATA_SETTINGS_FILE_PATH_ = "~/App_Data/dataSettings.json"; + + #endregion + + #region Fields + + protected INopFileProvider _fileProvider; #endregion @@ -22,7 +29,16 @@ public partial class DataSettingsManager /// /// Gets the path to file that contains data settings /// - public static string DataSettingsFilePath => DataSettingsFilePath_; + public static string DataSettingsFilePath => DATA_SETTINGS_FILE_PATH_; + + #endregion + + #region Ctor + + public DataSettingsManager(INopFileProvider fileProvider = null) + { + this._fileProvider = fileProvider ?? CommonHelper.DefaultFileProvider; + } #endregion @@ -39,21 +55,21 @@ public virtual DataSettings LoadSettings(string filePath = null, bool reloadSett if (!reloadSettings && Singleton.Instance != null) return Singleton.Instance; - filePath = filePath ?? CommonHelper.MapPath(DataSettingsFilePath); + filePath = filePath ?? _fileProvider.MapPath(DataSettingsFilePath); //check whether file exists - if (!File.Exists(filePath)) + if (!_fileProvider.FileExists(filePath)) { //if not, try to parse the file that was used in previous nopCommerce versions - filePath = CommonHelper.MapPath(ObsoleteDataSettingsFilePath); - if (!File.Exists(filePath)) + filePath = _fileProvider.MapPath(OBSOLETE_DATA_SETTINGS_FILE_PATH); + if (!_fileProvider.FileExists(filePath)) return new DataSettings(); //get data settings from the old txt file var dataSettings = new DataSettings(); - using (var reader = new StringReader(File.ReadAllText(filePath))) + using (var reader = new StringReader(_fileProvider.ReadAllText(filePath, Encoding.UTF8))) { - var settingsLine = string.Empty; + string settingsLine; while ((settingsLine = reader.ReadLine()) != null) { var separatorIndex = settingsLine.IndexOf(':'); @@ -82,13 +98,13 @@ public virtual DataSettings LoadSettings(string filePath = null, bool reloadSett SaveSettings(dataSettings); //and delete the old one - File.Delete(filePath); + _fileProvider.DeleteFile(filePath); Singleton.Instance = dataSettings; return Singleton.Instance; } - var text = File.ReadAllText(filePath); + var text = _fileProvider.ReadAllText(filePath, Encoding.UTF8); if (string.IsNullOrEmpty(text)) return new DataSettings(); @@ -104,19 +120,15 @@ public virtual DataSettings LoadSettings(string filePath = null, bool reloadSett public virtual void SaveSettings(DataSettings settings) { Singleton.Instance = settings ?? throw new ArgumentNullException(nameof(settings)); - - var filePath = CommonHelper.MapPath(DataSettingsFilePath); + + var filePath = _fileProvider.MapPath(DataSettingsFilePath); //create file if not exists - if (!File.Exists(filePath)) - { - //we use 'using' to close the file after it's created - using (File.Create(filePath)) { } - } + _fileProvider.CreateFile(filePath); //save data settings to the file var text = JsonConvert.SerializeObject(Singleton.Instance, Formatting.Indented); - File.WriteAllText(filePath, text); + _fileProvider.WriteAllText(filePath, text, Encoding.UTF8); } #endregion diff --git a/src/Libraries/Nop.Core/Infrastructure/AppDomainTypeFinder.cs b/src/Libraries/Nop.Core/Infrastructure/AppDomainTypeFinder.cs index b314866ac4a..473ec0553c5 100644 --- a/src/Libraries/Nop.Core/Infrastructure/AppDomainTypeFinder.cs +++ b/src/Libraries/Nop.Core/Infrastructure/AppDomainTypeFinder.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Reflection; using System.Text.RegularExpressions; @@ -17,11 +16,17 @@ public class AppDomainTypeFinder : ITypeFinder { #region Fields - private bool ignoreReflectionErrors = true; - private bool loadAppDomainAssemblies = true; - private string assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^AjaxControlToolkit|^Antlr3|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EntityFramework|^EPPlus|^FluentValidation|^ImageResizer|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^MvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^Telerik|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebActivator|^WebDev|^WebGrease"; - private string assemblyRestrictToLoadingPattern = ".*"; - private IList assemblyNames = new List(); + private bool _ignoreReflectionErrors = true; + protected INopFileProvider _fileProvider; + + #endregion + + #region Ctor + + public AppDomainTypeFinder(INopFileProvider fileProvider = null) + { + this._fileProvider = fileProvider ?? CommonHelper.DefaultFileProvider; + } #endregion @@ -106,17 +111,18 @@ protected virtual bool Matches(string assemblyFullName, string pattern) protected virtual void LoadMatchingAssemblies(string directoryPath) { var loadedAssemblyNames = new List(); + foreach (var a in GetAssemblies()) { loadedAssemblyNames.Add(a.FullName); } - if (!Directory.Exists(directoryPath)) + if (!_fileProvider.DirectoryExists(directoryPath)) { return; } - foreach (var dllPath in Directory.GetFiles(directoryPath, "*.dll")) + foreach (var dllPath in _fileProvider.GetFiles(directoryPath, "*.dll")) { try { @@ -228,7 +234,7 @@ public IEnumerable FindClassesOfType(Type assignTypeFrom, IEnumerableGets or sets whether Nop should iterate assemblies in the app domain when loading Nop types. Loading patterns are applied when loading these assemblies. - public bool LoadAppDomainAssemblies - { - get { return loadAppDomainAssemblies; } - set { loadAppDomainAssemblies = value; } - } + public bool LoadAppDomainAssemblies { get; set; } = true; /// Gets or sets assemblies loaded a startup in addition to those loaded in the AppDomain. - public IList AssemblyNames - { - get { return assemblyNames; } - set { assemblyNames = value; } - } + public IList AssemblyNames { get; set; } = new List(); /// Gets the pattern for dlls that we know don't need to be investigated. - public string AssemblySkipLoadingPattern - { - get { return assemblySkipLoadingPattern; } - set { assemblySkipLoadingPattern = value; } - } + public string AssemblySkipLoadingPattern { get; set; } = "^System|^mscorlib|^Microsoft|^AjaxControlToolkit|^Antlr3|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EntityFramework|^EPPlus|^FluentValidation|^ImageResizer|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^MvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^Telerik|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebActivator|^WebDev|^WebGrease"; /// Gets or sets the pattern for dll that will be investigated. For ease of use this defaults to match all but to increase performance you might want to configure a pattern that includes assemblies and your own. /// If you change this so that Nop assemblies aren't investigated (e.g. by not including something like "^Nop|..." you may break core functionality. - public string AssemblyRestrictToLoadingPattern - { - get { return assemblyRestrictToLoadingPattern; } - set { assemblyRestrictToLoadingPattern = value; } - } + public string AssemblyRestrictToLoadingPattern { get; set; } = ".*"; #endregion diff --git a/src/Libraries/Nop.Core/Infrastructure/INopFileProvider.cs b/src/Libraries/Nop.Core/Infrastructure/INopFileProvider.cs new file mode 100644 index 00000000000..5dc826e3cd3 --- /dev/null +++ b/src/Libraries/Nop.Core/Infrastructure/INopFileProvider.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections.Generic; +using System.Security.AccessControl; +using System.Text; +using Microsoft.Extensions.FileProviders; + +namespace Nop.Core.Infrastructure +{ + /// + /// A file provider abstraction + /// + public interface INopFileProvider : IFileProvider + { + /// + /// Combines an array of strings into a path + /// + /// An array of parts of the path + /// The combined paths + string Combine(params string[] paths); + + /// + /// Creates all directories and subdirectories in the specified path unless they already exist + /// + /// The directory to create + void CreateDirectory(string path); + + /// + /// Creates or overwrites a file in the specified path + /// + /// The path and name of the file to create + void CreateFile(string path); + + /// + /// Depth-first recursive delete, with handling for descendant directories open in Windows Explorer. + /// + /// Directory path + void DeleteDirectory(string path); + + /// + /// Deletes the specified file + /// + /// The name of the file to be deleted. Wildcard characters are not supported + void DeleteFile(string filePath); + + /// + /// Determines whether the given path refers to an existing directory on disk + /// + /// The path to test + /// + /// true if path refers to an existing directory; false if the directory does not exist or an error occurs when + /// trying to determine if the specified file exists + /// + bool DirectoryExists(string path); + + /// + /// Moves a file or a directory and its contents to a new location + /// + /// The path of the file or directory to move + /// + /// The path to the new location for sourceDirName. If sourceDirName is a file, then destDirName + /// must also be a file name + /// + void DirectoryMove(string sourceDirName, string destDirName); + + /// + /// Returns an enumerable collection of file names that match a search pattern in + /// a specified path, and optionally searches subdirectories. + /// + /// The path to the directory to search + /// + /// The search string to match against the names of files in path. This parameter + /// can contain a combination of valid literal path and wildcard (* and ?) characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An enumerable collection of the full names (including paths) for the files in + /// the directory specified by path and that match the specified search pattern + /// + IEnumerable EnumerateFiles(string directoryPath, string searchPattern, bool topDirectoryOnly = true); + + /// + /// Copies an existing file to a new file. Overwriting a file of the same name is allowed + /// + /// The file to copy + /// The name of the destination file. This cannot be a directory + /// true if the destination file can be overwritten; otherwise, false + void FileCopy(string sourceFileName, string destFileName, bool overwrite = false); + + /// + /// Determines whether the specified file exists + /// + /// The file to check + /// + /// True if the caller has the required permissions and path contains the name of an existing file; otherwise, + /// false. + /// + bool FileExists(string filePath); + + /// + /// Gets the length of the file in bytes, or -1 for a directory or non-existing files + /// + /// File path + /// The length of the file + long FileLength(string path); + + /// + /// Moves a specified file to a new location, providing the option to specify a new file name + /// + /// The name of the file to move. Can include a relative or absolute path + /// The new path and name for the file + void FileMove(string sourceFileName, string destFileName); + + /// + /// Returns the absolute path to the directory + /// + /// An array of parts of the path + /// The absolute path to the directory + string GetAbsolutePath(params string[] paths); + + /// + /// Gets a System.Security.AccessControl.DirectorySecurity object that encapsulates the access control list (ACL) entries for a specified directory + /// + /// The path to a directory containing a System.Security.AccessControl.DirectorySecurity object that describes the file's access control list (ACL) information + /// An object that encapsulates the access control rules for the file described by the path parameter + DirectorySecurity GetAccessControl(string path); + + /// + /// Returns the creation date and time of the specified file or directory + /// + /// The file or directory for which to obtain creation date and time information + /// + /// A System.DateTime structure set to the creation date and time for the specified file or directory. This value + /// is expressed in local time + /// + DateTime GetCreationTime(string path); + + /// + /// Returns the names of the subdirectories (including their paths) that match the + /// specified search pattern in the specified directory + /// + /// The path to the directory to search + /// + /// The search string to match against the names of subdirectories in path. This + /// parameter can contain a combination of valid literal and wildcard characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An array of the full names (including paths) of the subdirectories that match + /// the specified criteria, or an empty array if no directories are found + /// + string[] GetDirectories(string path, string searchPattern = "", bool topDirectoryOnly = true); + + /// + /// Returns the directory information for the specified path string + /// + /// The path of a file or directory + /// + /// Directory information for path, or null if path denotes a root directory or is null. Returns + /// System.String.Empty if path does not contain directory information + /// + string GetDirectoryName(string path); + + /// + /// Returns the directory name only for the specified path string + /// + /// The path of directory + /// The directory name + string GetDirectoryNameOnly(string path); + + /// + /// Returns the extension of the specified path string + /// + /// The path string from which to get the extension + /// The extension of the specified path (including the period ".") + string GetFileExtension(string filePath); + + /// + /// Returns the file name and extension of the specified path string + /// + /// The path string from which to obtain the file name and extension + /// The characters after the last directory character in path + string GetFileName(string path); + + /// + /// Returns the file name of the specified path string without the extension + /// + /// The path of the file + /// The file name, minus the last period (.) and all characters following it + string GetFileNameWithoutExtension(string filePath); + + /// + /// Returns the names of files (including their paths) that match the specified search + /// pattern in the specified directory, using a value to determine whether to search subdirectories. + /// + /// The path to the directory to search + /// + /// The search string to match against the names of files in path. This parameter + /// can contain a combination of valid literal path and wildcard (* and ?) characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An array of the full names (including paths) for the files in the specified directory + /// that match the specified search pattern, or an empty array if no files are found. + /// + string[] GetFiles(string directoryPath, string searchPattern = "", bool topDirectoryOnly = true); + + /// + /// Returns the date and time the specified file or directory was last accessed + /// + /// The file or directory for which to obtain access date and time information + /// A System.DateTime structure set to the date and time that the specified file + DateTime GetLastAccessTime(string path); + + /// + /// Returns the date and time the specified file or directory was last written to + /// + /// The file or directory for which to obtain write date and time information + /// + /// A System.DateTime structure set to the date and time that the specified file or directory was last written to. + /// This value is expressed in local time + /// + DateTime GetLastWriteTime(string path); + + /// + /// Returns the date and time, in coordinated universal time (UTC), that the specified file or directory was last + /// written to + /// + /// The file or directory for which to obtain write date and time information + /// + /// A System.DateTime structure set to the date and time that the specified file or directory was last written to. + /// This value is expressed in UTC time + /// + DateTime GetLastWriteTimeUtc(string path); + + /// + /// Retrieves the parent directory of the specified path + /// + /// The path for which to retrieve the parent directory + /// The parent directory, or null if path is the root directory, including the root of a UNC server or share name + string GetParentDirectory(string directoryPath); + + /// + /// Checks if the path is directory + /// + /// Path for check + /// True, if the path is a directory, otherwise false + bool IsDirectory(string path); + + /// + /// Maps a virtual path to a physical disk path. + /// + /// The path to map. E.g. "~/bin" + /// The physical path. E.g. "c:\inetpub\wwwroot\bin" + string MapPath(string path); + + /// + /// Reads the contents of the file into a byte array + /// + /// The file for reading + /// A byte array containing the contents of the file + byte[] ReadAllBytes(string filePath); + + /// + /// Opens a file, reads all lines of the file with the specified encoding, and then closes the file. + /// + /// The file to open for reading + /// The encoding applied to the contents of the file + /// A string containing all lines of the file + string ReadAllText(string path, Encoding encoding); + + /// + /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last written to + /// + /// The file for which to set the date and time information + /// + /// A System.DateTime containing the value to set for the last write date and time of path. + /// This value is expressed in UTC time + /// + void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc); + + /// + /// Writes the specified byte array to the file + /// + /// The file to write to + /// The bytes to write to the file + void WriteAllBytes(string filePath, byte[] bytes); + + /// + /// Creates a new file, writes the specified string to the file using the specified encoding, + /// and then closes the file. If the target file already exists, it is overwritten. + /// + /// The file to write to + /// The string to write to the file + /// The encoding to apply to the string + void WriteAllText(string path, string contents, Encoding encoding); + } +} \ No newline at end of file diff --git a/src/Libraries/Nop.Core/Infrastructure/NopEngine.cs b/src/Libraries/Nop.Core/Infrastructure/NopEngine.cs index d134f243a53..d2600d0af06 100644 --- a/src/Libraries/Nop.Core/Infrastructure/NopEngine.cs +++ b/src/Libraries/Nop.Core/Infrastructure/NopEngine.cs @@ -147,13 +147,12 @@ public void Initialize(IServiceCollection services) //most of API providers require TLS 1.2 nowadays ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - //set base application path var provider = services.BuildServiceProvider(); var hostingEnvironment = provider.GetRequiredService(); - var nopConfig = provider.GetRequiredService(); - CommonHelper.BaseDirectory = hostingEnvironment.ContentRootPath; + CommonHelper.DefaultFileProvider = new NopFileProvider(hostingEnvironment); //initialize plugins + var nopConfig = provider.GetRequiredService(); var mvcCoreBuilder = services.AddMvcCore(); PluginManager.Initialize(mvcCoreBuilder.PartManager, nopConfig); } @@ -208,7 +207,8 @@ public IServiceProvider ConfigureServices(IServiceCollection services, IConfigur AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; //set App_Data path as base data directory (required to create and save SQL Server Compact database file in App_Data folder) - AppDomain.CurrentDomain.SetData("DataDirectory", CommonHelper.MapPath("~/App_Data/")); + var fileProvider = Resolve(); + AppDomain.CurrentDomain.SetData("DataDirectory", fileProvider.MapPath("~/App_Data/")); return _serviceProvider; } diff --git a/src/Libraries/Nop.Core/Infrastructure/NopFileProvider.cs b/src/Libraries/Nop.Core/Infrastructure/NopFileProvider.cs new file mode 100644 index 00000000000..4c28faf39cd --- /dev/null +++ b/src/Libraries/Nop.Core/Infrastructure/NopFileProvider.cs @@ -0,0 +1,499 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.AccessControl; +using System.Text; +using System.Threading; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.FileProviders; + +namespace Nop.Core.Infrastructure +{ + /// + /// IO functions using the on-disk file system + /// + public class NopFileProvider : PhysicalFileProvider, INopFileProvider + { + /// + /// Initializes a new instance of a NopFileProvider + /// + /// Hosting environment + public NopFileProvider(IHostingEnvironment hostingEnvironment) + : base(File.Exists(hostingEnvironment.WebRootPath) ? Path.GetDirectoryName(hostingEnvironment.WebRootPath) : hostingEnvironment.WebRootPath) + { + var path = hostingEnvironment.ContentRootPath ?? string.Empty; + if (File.Exists(path)) + path = Path.GetDirectoryName(path); + + BaseDirectory = path; + } + + #region Utilities + + private static void DeleteDirectoryRecursive(string path) + { + Directory.Delete(path, true); + const int maxIterationToWait = 10; + var curIteration = 0; + + //according to the documentation(https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa365488.aspx) + //System.IO.Directory.Delete method ultimately (after removing the files) calls native + //RemoveDirectory function which marks the directory as "deleted". That's why we wait until + //the directory is actually deleted. For more details see https://stackoverflow.com/a/4245121 + while (Directory.Exists(path)) + { + curIteration += 1; + if (curIteration > maxIterationToWait) + return; + Thread.Sleep(100); + } + } + + #endregion + + /// + /// Combines an array of strings into a path + /// + /// An array of parts of the path + /// The combined paths + public virtual string Combine(params string[] paths) + { + return Path.Combine(paths); + } + + /// + /// Creates all directories and subdirectories in the specified path unless they already exist + /// + /// The directory to create + public virtual void CreateDirectory(string path) + { + if (!DirectoryExists(path)) + Directory.CreateDirectory(path); + } + + /// + /// Creates or overwrites a file in the specified path + /// + /// The path and name of the file to create + public virtual void CreateFile(string path) + { + if (FileExists(path)) + return; + + //we use 'using' to close the file after it's created + using (File.Create(path)) { } + } + + /// + /// Depth-first recursive delete, with handling for descendant directories open in Windows Explorer. + /// + /// Directory path + public void DeleteDirectory(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentNullException(path); + + //find more info about directory deletion + //and why we use this approach at https://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true + + foreach (var directory in Directory.GetDirectories(path)) + { + DeleteDirectory(directory); + } + + try + { + DeleteDirectoryRecursive(path); + } + catch (IOException) + { + DeleteDirectoryRecursive(path); + } + catch (UnauthorizedAccessException) + { + DeleteDirectoryRecursive(path); + } + } + + + /// + /// Deletes the specified file + /// + /// The name of the file to be deleted. Wildcard characters are not supported + public virtual void DeleteFile(string filePath) + { + if (!FileExists(filePath)) + return; + + File.Delete(filePath); + } + + /// + /// Determines whether the given path refers to an existing directory on disk + /// + /// The path to test + /// + /// true if path refers to an existing directory; false if the directory does not exist or an error occurs when + /// trying to determine if the specified file exists + /// + public virtual bool DirectoryExists(string path) + { + return Directory.Exists(path); + } + + /// + /// Moves a file or a directory and its contents to a new location + /// + /// The path of the file or directory to move + /// + /// The path to the new location for sourceDirName. If sourceDirName is a file, then destDirName + /// must also be a file name + /// + public virtual void DirectoryMove(string sourceDirName, string destDirName) + { + Directory.Move(sourceDirName, destDirName); + } + + /// + /// Returns an enumerable collection of file names that match a search pattern in + /// a specified path, and optionally searches subdirectories. + /// + /// The path to the directory to search + /// + /// The search string to match against the names of files in path. This parameter + /// can contain a combination of valid literal path and wildcard (* and ?) characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An enumerable collection of the full names (including paths) for the files in + /// the directory specified by path and that match the specified search pattern + /// + public virtual IEnumerable EnumerateFiles(string directoryPath, string searchPattern, + bool topDirectoryOnly = true) + { + return Directory.EnumerateFiles(directoryPath, searchPattern, + topDirectoryOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories); + } + + /// + /// Copies an existing file to a new file. Overwriting a file of the same name is allowed + /// + /// The file to copy + /// The name of the destination file. This cannot be a directory + /// true if the destination file can be overwritten; otherwise, false + public virtual void FileCopy(string sourceFileName, string destFileName, bool overwrite = false) + { + File.Copy(sourceFileName, destFileName, overwrite); + } + + /// + /// Determines whether the specified file exists + /// + /// The file to check + /// + /// True if the caller has the required permissions and path contains the name of an existing file; otherwise, + /// false. + /// + public virtual bool FileExists(string filePath) + { + return File.Exists(filePath); + } + + /// + /// Gets the length of the file in bytes, or -1 for a directory or non-existing files + /// + /// File path + /// The length of the file + public virtual long FileLength(string path) + { + if (!FileExists(path)) + return -1; + + return new FileInfo(path).Length; + } + + /// + /// Moves a specified file to a new location, providing the option to specify a new file name + /// + /// The name of the file to move. Can include a relative or absolute path + /// The new path and name for the file + public virtual void FileMove(string sourceFileName, string destFileName) + { + File.Move(sourceFileName, destFileName); + } + + /// + /// Returns the absolute path to the directory + /// + /// An array of parts of the path + /// The absolute path to the directory + public virtual string GetAbsolutePath(params string[] paths) + { + var allPaths = paths.ToList(); + allPaths.Insert(0, Root); + + return Path.Combine(allPaths.ToArray()); + } + + /// + /// Gets a System.Security.AccessControl.DirectorySecurity object that encapsulates the access control list (ACL) entries for a specified directory + /// + /// The path to a directory containing a System.Security.AccessControl.DirectorySecurity object that describes the file's access control list (ACL) information + /// An object that encapsulates the access control rules for the file described by the path parameter + public virtual DirectorySecurity GetAccessControl(string path) + { + return Directory.GetAccessControl(path); + } + + /// + /// Returns the creation date and time of the specified file or directory + /// + /// The file or directory for which to obtain creation date and time information + /// + /// A System.DateTime structure set to the creation date and time for the specified file or directory. This value + /// is expressed in local time + /// + public virtual DateTime GetCreationTime(string path) + { + return File.GetCreationTime(path); + } + + /// + /// Returns the names of the subdirectories (including their paths) that match the + /// specified search pattern in the specified directory + /// + /// The path to the directory to search + /// + /// The search string to match against the names of subdirectories in path. This + /// parameter can contain a combination of valid literal and wildcard characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An array of the full names (including paths) of the subdirectories that match + /// the specified criteria, or an empty array if no directories are found + /// + public virtual string[] GetDirectories(string path, string searchPattern = "", bool topDirectoryOnly = true) + { + if (string.IsNullOrEmpty(searchPattern)) + searchPattern = "*"; + + return Directory.GetDirectories(path, searchPattern, + topDirectoryOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories); + } + + /// + /// Returns the directory information for the specified path string + /// + /// The path of a file or directory + /// + /// Directory information for path, or null if path denotes a root directory or is null. Returns + /// System.String.Empty if path does not contain directory information + /// + public virtual string GetDirectoryName(string path) + { + return Path.GetDirectoryName(path); + } + + /// + /// Returns the directory name only for the specified path string + /// + /// The path of directory + /// The directory name + public virtual string GetDirectoryNameOnly(string path) + { + return new DirectoryInfo(path).Name; + } + + /// + /// Returns the extension of the specified path string + /// + /// The path string from which to get the extension + /// The extension of the specified path (including the period ".") + public virtual string GetFileExtension(string filePath) + { + return Path.GetExtension(filePath); + } + + /// + /// Returns the file name and extension of the specified path string + /// + /// The path string from which to obtain the file name and extension + /// The characters after the last directory character in path + public virtual string GetFileName(string path) + { + return Path.GetFileName(path); + } + + /// + /// Returns the file name of the specified path string without the extension + /// + /// The path of the file + /// The file name, minus the last period (.) and all characters following it + public virtual string GetFileNameWithoutExtension(string filePath) + { + return Path.GetFileNameWithoutExtension(filePath); + } + + /// + /// Returns the names of files (including their paths) that match the specified search + /// pattern in the specified directory, using a value to determine whether to search subdirectories. + /// + /// The path to the directory to search + /// + /// The search string to match against the names of files in path. This parameter + /// can contain a combination of valid literal path and wildcard (* and ?) characters + /// , but doesn't support regular expressions. + /// + /// + /// Specifies whether to search the current directory, or the current directory and all + /// subdirectories + /// + /// + /// An array of the full names (including paths) for the files in the specified directory + /// that match the specified search pattern, or an empty array if no files are found. + /// + public virtual string[] GetFiles(string directoryPath, string searchPattern = "", bool topDirectoryOnly = true) + { + if (string.IsNullOrEmpty(searchPattern)) + searchPattern = "*.*"; + + return Directory.GetFiles(directoryPath, searchPattern, + topDirectoryOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories); + } + + /// + /// Returns the date and time the specified file or directory was last accessed + /// + /// The file or directory for which to obtain access date and time information + /// A System.DateTime structure set to the date and time that the specified file + public virtual DateTime GetLastAccessTime(string path) + { + return File.GetLastAccessTime(path); + } + + /// + /// Returns the date and time the specified file or directory was last written to + /// + /// The file or directory for which to obtain write date and time information + /// + /// A System.DateTime structure set to the date and time that the specified file or directory was last written to. + /// This value is expressed in local time + /// + public virtual DateTime GetLastWriteTime(string path) + { + return File.GetLastWriteTime(path); + } + + /// + /// Returns the date and time, in coordinated universal time (UTC), that the specified file or directory was last + /// written to + /// + /// The file or directory for which to obtain write date and time information + /// + /// A System.DateTime structure set to the date and time that the specified file or directory was last written to. + /// This value is expressed in UTC time + /// + public virtual DateTime GetLastWriteTimeUtc(string path) + { + return File.GetLastWriteTimeUtc(path); + } + + /// + /// Retrieves the parent directory of the specified path + /// + /// The path for which to retrieve the parent directory + /// The parent directory, or null if path is the root directory, including the root of a UNC server or share name + public virtual string GetParentDirectory(string directoryPath) + { + return Directory.GetParent(directoryPath).FullName; + } + + /// + /// Checks if the path is directory + /// + /// Path for check + /// True, if the path is a directory, otherwise false + public virtual bool IsDirectory(string path) + { + return DirectoryExists(path); + } + + /// + /// Maps a virtual path to a physical disk path. + /// + /// The path to map. E.g. "~/bin" + /// The physical path. E.g. "c:\inetpub\wwwroot\bin" + public virtual string MapPath(string path) + { + path = path.Replace("~/", "").TrimStart('/').Replace('/', '\\'); + return Path.Combine(BaseDirectory ?? string.Empty, path); + } + + /// + /// Reads the contents of the file into a byte array + /// + /// The file for reading + /// A byte array containing the contents of the file + public virtual byte[] ReadAllBytes(string filePath) + { + return File.Exists(filePath) ? File.ReadAllBytes(filePath) : new byte[0]; + } + + /// + /// Opens a file, reads all lines of the file with the specified encoding, and then closes the file. + /// + /// The file to open for reading + /// The encoding applied to the contents of the file + /// A string containing all lines of the file + public virtual string ReadAllText(string path, Encoding encoding) + { + return File.ReadAllText(path, encoding); + } + + /// + /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last written to + /// + /// The file for which to set the date and time information + /// + /// A System.DateTime containing the value to set for the last write date and time of path. + /// This value is expressed in UTC time + /// + public virtual void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) + { + File.SetLastWriteTimeUtc(path, lastWriteTimeUtc); + } + + /// + /// Writes the specified byte array to the file + /// + /// The file to write to + /// The bytes to write to the file + public virtual void WriteAllBytes(string filePath, byte[] bytes) + { + File.WriteAllBytes(filePath, bytes); + } + + /// + /// Creates a new file, writes the specified string to the file using the specified encoding, + /// and then closes the file. If the target file already exists, it is overwritten. + /// + /// The file to write to + /// The string to write to the file + /// The encoding to apply to the string + public virtual void WriteAllText(string path, string contents, Encoding encoding) + { + File.WriteAllText(path, contents, encoding); + } + + protected string BaseDirectory { get; } + } +} \ No newline at end of file diff --git a/src/Libraries/Nop.Core/Infrastructure/WebAppTypeFinder.cs b/src/Libraries/Nop.Core/Infrastructure/WebAppTypeFinder.cs index a659e40fc39..f18a903f30f 100644 --- a/src/Libraries/Nop.Core/Infrastructure/WebAppTypeFinder.cs +++ b/src/Libraries/Nop.Core/Infrastructure/WebAppTypeFinder.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Reflection; namespace Nop.Core.Infrastructure @@ -16,6 +17,14 @@ public class WebAppTypeFinder : AppDomainTypeFinder #endregion + #region Ctor + + public WebAppTypeFinder(INopFileProvider fileProvider = null) : base(fileProvider) + { + } + + #endregion + #region Properties /// @@ -37,7 +46,7 @@ public bool EnsureBinFolderAssembliesLoaded /// The physical path. E.g. "c:\inetpub\wwwroot\bin" public virtual string GetBinDirectory() { - return System.AppContext.BaseDirectory; + return AppContext.BaseDirectory; } /// diff --git a/src/Libraries/Nop.Core/Plugins/PluginDescriptor.cs b/src/Libraries/Nop.Core/Plugins/PluginDescriptor.cs index d7554a3c7af..97cac537665 100644 --- a/src/Libraries/Nop.Core/Plugins/PluginDescriptor.cs +++ b/src/Libraries/Nop.Core/Plugins/PluginDescriptor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Reflection; using Newtonsoft.Json; using Nop.Core.Infrastructure; @@ -200,7 +199,7 @@ public override int GetHashCode() /// Gets or sets the original assembly file that a shadow copy was made from it /// [JsonIgnore] - public virtual FileInfo OriginalAssemblyFile { get; internal set; } + public virtual string OriginalAssemblyFile { get; internal set; } /// /// Gets or sets the assembly that has been shadow copied that is active in the application diff --git a/src/Libraries/Nop.Core/Plugins/PluginExtensions.cs b/src/Libraries/Nop.Core/Plugins/PluginExtensions.cs index bf99b632ecf..8647f73f27e 100644 --- a/src/Libraries/Nop.Core/Plugins/PluginExtensions.cs +++ b/src/Libraries/Nop.Core/Plugins/PluginExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using Nop.Core.Infrastructure; namespace Nop.Core.Plugins { @@ -31,18 +31,21 @@ public static string GetLogoUrl(this PluginDescriptor pluginDescriptor, IWebHelp if (webHelper == null) throw new ArgumentNullException(nameof(webHelper)); - if (pluginDescriptor.OriginalAssemblyFile == null || pluginDescriptor.OriginalAssemblyFile.Directory == null) + var fileProvider = EngineContext.Current.Resolve(); + + var pluginDirectory = fileProvider.GetDirectoryName(pluginDescriptor.OriginalAssemblyFile); + + if (string.IsNullOrEmpty(pluginDirectory)) { return null; } - var pluginDirectory = pluginDescriptor.OriginalAssemblyFile.Directory; - - var logoExtension = SupportedLogoImageExtensions.FirstOrDefault(ext => File.Exists(Path.Combine(pluginDirectory.FullName, "logo." + ext))); + var logoExtension = SupportedLogoImageExtensions.FirstOrDefault(ext => fileProvider.FileExists(fileProvider.Combine(pluginDirectory, "logo." + ext))); - if (string.IsNullOrWhiteSpace(logoExtension)) return null; //No logo file was found with any of the supported extensions. + if (string.IsNullOrWhiteSpace(logoExtension)) + return null; //No logo file was found with any of the supported extensions. - var logoUrl = $"{webHelper.GetStoreLocation()}plugins/{pluginDirectory.Name}/logo.{logoExtension}"; + var logoUrl = $"{webHelper.GetStoreLocation()}plugins/{fileProvider.GetDirectoryNameOnly(pluginDirectory)}/logo.{logoExtension}"; return logoUrl; } } diff --git a/src/Libraries/Nop.Core/Plugins/PluginManager.cs b/src/Libraries/Nop.Core/Plugins/PluginManager.cs index d2d28ffdeed..4d29fca5a47 100644 --- a/src/Libraries/Nop.Core/Plugins/PluginManager.cs +++ b/src/Libraries/Nop.Core/Plugins/PluginManager.cs @@ -4,11 +4,13 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Threading; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Newtonsoft.Json; using Nop.Core.ComponentModel; using Nop.Core.Configuration; +using Nop.Core.Infrastructure; //Contributor: Umbraco (http://www.umbraco.com). Thanks a lot! //SEE THIS POST for full details of what this does - http://shazwazza.com/post/Developing-a-plugin-framework-in-ASPNET-with-medium-trust.aspx @@ -30,9 +32,10 @@ public class PluginManager #region Fields private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); - private static DirectoryInfo _shadowCopyFolder; - private static readonly List BaseAppLibraries; - private static DirectoryInfo _reserveShadowCopyFolder; + private static string _shadowCopyFolder; + private static readonly List _baseAppLibraries; + private static string _reserveShadowCopyFolder; + private static readonly INopFileProvider _fileProvider; #endregion @@ -40,18 +43,20 @@ public class PluginManager static PluginManager() { + //we use the default file provider, since the DI isn't initialized yet + _fileProvider = CommonHelper.DefaultFileProvider; + //get all libraries from /bin/{version}/ directory - BaseAppLibraries = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory) - .GetFiles("*.dll", SearchOption.TopDirectoryOnly).Select(fi => fi.Name).ToList(); + _baseAppLibraries =_fileProvider.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll").Select(fi => _fileProvider.GetFileName(fi)).ToList(); //get all libraries from base site directory if(!AppDomain.CurrentDomain.BaseDirectory.Equals(Environment.CurrentDirectory, StringComparison.InvariantCultureIgnoreCase)) - BaseAppLibraries.AddRange(new DirectoryInfo(Environment.CurrentDirectory).GetFiles("*.dll", SearchOption.TopDirectoryOnly).Select(fi => fi.Name)); + _baseAppLibraries.AddRange(_fileProvider.GetFiles(Environment.CurrentDirectory, "*.dll").Select(fi => _fileProvider.GetFileName(fi))); //get all libraries from refs directory - var refsPathName = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, RefsPathName)); - if(refsPathName.Exists) - BaseAppLibraries.AddRange(refsPathName.GetFiles("*.dll", SearchOption.TopDirectoryOnly).Select(fi => fi.Name)); + var refsPathName = _fileProvider.Combine(Environment.CurrentDirectory, RefsPathName); + if(_fileProvider.DirectoryExists(refsPathName)) + _baseAppLibraries.AddRange(_fileProvider.GetFiles(refsPathName, "*.dll").Select(fi => _fileProvider.GetFileName(fi))); } #endregion @@ -63,25 +68,25 @@ static PluginManager() /// /// Plugin directory info /// Original and parsed description files - private static IEnumerable> GetDescriptionFilesAndDescriptors(DirectoryInfo pluginFolder) + private static IEnumerable> GetDescriptionFilesAndDescriptors(string pluginFolder) { if (pluginFolder == null) throw new ArgumentNullException(nameof(pluginFolder)); //create list () - var result = new List>(); + var result = new List>(); //add display order and path to list - foreach (var descriptionFile in pluginFolder.GetFiles(PluginDescriptionFileName, SearchOption.AllDirectories)) + foreach (var descriptionFile in _fileProvider.GetFiles(pluginFolder, PluginDescriptionFileName, false)) { - if (!IsPackagePluginFolder(descriptionFile.Directory)) + if (!IsPackagePluginFolder(_fileProvider.GetDirectoryName(descriptionFile))) continue; //parse file - var pluginDescriptor = GetPluginDescriptorFromFile(descriptionFile.FullName); + var pluginDescriptor = GetPluginDescriptorFromFile(descriptionFile); //populate list - result.Add(new KeyValuePair(descriptionFile, pluginDescriptor)); + result.Add(new KeyValuePair(descriptionFile, pluginDescriptor)); } //sort list by display order. NOTE: Lowest DisplayOrder will be first i.e 0 , 1, 1, 1, 5, 10 @@ -98,16 +103,16 @@ private static IEnumerable> GetDescript private static IList GetInstalledPluginNames(string filePath) { //check whether file exists - if (!File.Exists(filePath)) + if (!_fileProvider.FileExists(filePath)) { //if not, try to parse the file that was used in previous nopCommerce versions - filePath = CommonHelper.MapPath(ObsoleteInstalledPluginsFilePath); - if (!File.Exists(filePath)) + filePath = _fileProvider.MapPath(ObsoleteInstalledPluginsFilePath); + if (!_fileProvider.FileExists(filePath)) return new List(); //get plugin system names from the old txt file var pluginSystemNames = new List(); - using (var reader = new StringReader(File.ReadAllText(filePath))) + using (var reader = new StringReader(_fileProvider.ReadAllText(filePath, Encoding.UTF8))) { string pluginName; while ((pluginName = reader.ReadLine()) != null) @@ -118,15 +123,15 @@ private static IList GetInstalledPluginNames(string filePath) } //save system names of installed plugins to the new file - SaveInstalledPluginNames(pluginSystemNames, CommonHelper.MapPath(InstalledPluginsFilePath)); + SaveInstalledPluginNames(pluginSystemNames, _fileProvider.MapPath(InstalledPluginsFilePath)); //and delete the old one - File.Delete(filePath); + _fileProvider.DeleteFile(filePath); return pluginSystemNames; } - var text = File.ReadAllText(filePath); + var text = _fileProvider.ReadAllText(filePath, Encoding.UTF8); if (string.IsNullOrEmpty(text)) return new List(); @@ -143,23 +148,23 @@ private static void SaveInstalledPluginNames(IList pluginSystemNames, st { //save the file var text = JsonConvert.SerializeObject(pluginSystemNames, Formatting.Indented); - File.WriteAllText(filePath, text); + _fileProvider.WriteAllText(filePath, text, Encoding.UTF8); } /// /// Indicates whether assembly file is already loaded /// - /// File info - /// Result - private static bool IsAlreadyLoaded(FileInfo fileInfo) + /// File path + /// True if assembly file is already loaded; otherwise false + private static bool IsAlreadyLoaded(string filePath) { //search library file name in base directory to ignore already existing (loaded) libraries //(we do it because not all libraries are loaded immediately after application start) - if (BaseAppLibraries.Any(sli => sli.Equals(fileInfo.Name, StringComparison.InvariantCultureIgnoreCase))) + if (_baseAppLibraries.Any(sli => sli.Equals(_fileProvider.GetFileName(filePath), StringComparison.InvariantCultureIgnoreCase))) return true; //compare full assembly name - //var fileAssemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName); + //var fileAssemblyName = AssemblyName.GetAssemblyName(filePath); //foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) //{ // if (a.FullName.Equals(fileAssemblyName.FullName, StringComparison.InvariantCultureIgnoreCase)) @@ -170,9 +175,9 @@ private static bool IsAlreadyLoaded(FileInfo fileInfo) //do not compare the full assembly name, just filename try { - var fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileInfo.FullName); + var fileNameWithoutExt = _fileProvider.GetFileNameWithoutExtension(filePath); if (string.IsNullOrEmpty(fileNameWithoutExt)) - throw new Exception($"Cannot get file extension for {fileInfo.Name}"); + throw new Exception($"Cannot get file extension for {_fileProvider.GetFileName(filePath)}"); foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) { @@ -196,20 +201,22 @@ private static bool IsAlreadyLoaded(FileInfo fileInfo) /// Config /// Shadow copy path /// Assembly - private static Assembly PerformFileDeploy(FileInfo plug, ApplicationPartManager applicationPartManager, NopConfig config, string shadowCopyPath="") + private static Assembly PerformFileDeploy(string plug, ApplicationPartManager applicationPartManager, NopConfig config, string shadowCopyPath="") { - if (plug.Directory?.Parent == null) - throw new InvalidOperationException($"The plugin directory for the {plug.Name} file exists in a folder outside of the allowed nopCommerce folder hierarchy"); + var parent = string.IsNullOrEmpty(plug) ? string.Empty : _fileProvider.GetParentDirectory(plug); + + if (string.IsNullOrEmpty(parent)) + throw new InvalidOperationException($"The plugin directory for the {_fileProvider.GetFileName(plug)} file exists in a folder outside of the allowed nopCommerce folder hierarchy"); if (!config.UsePluginsShadowCopy) return RegisterPluginDefinition(config, applicationPartManager, plug); //in order to avoid possible issues we still copy libraries into ~/Plugins/bin/ directory if (string.IsNullOrEmpty(shadowCopyPath)) - shadowCopyPath = _shadowCopyFolder.FullName; + shadowCopyPath = _shadowCopyFolder; - var shadowCopyPlugFolder = Directory.CreateDirectory(shadowCopyPath); - var shadowCopiedPlug = ShadowCopyFile(plug, shadowCopyPlugFolder); + _fileProvider.CreateDirectory(shadowCopyPath); + var shadowCopiedPlug = ShadowCopyFile(plug, shadowCopyPath); Assembly shadowCopiedAssembly = null; @@ -219,11 +226,11 @@ private static Assembly PerformFileDeploy(FileInfo plug, ApplicationPartManager } catch (FileLoadException) { - if (!config.CopyLockedPluginAssembilesToSubdirectoriesOnStartup || !shadowCopyPath.Equals(_shadowCopyFolder.FullName)) + if (!config.CopyLockedPluginAssembilesToSubdirectoriesOnStartup || !shadowCopyPath.Equals(_shadowCopyFolder)) throw; } - return shadowCopiedAssembly ?? PerformFileDeploy(plug, applicationPartManager, config, _reserveShadowCopyFolder.FullName); + return shadowCopiedAssembly ?? PerformFileDeploy(plug, applicationPartManager, config, _reserveShadowCopyFolder); } /// @@ -232,11 +239,11 @@ private static Assembly PerformFileDeploy(FileInfo plug, ApplicationPartManager /// Config /// Application part manager /// Plugin file info - /// - private static Assembly RegisterPluginDefinition(NopConfig config, ApplicationPartManager applicationPartManager, FileInfo plug) + /// Assembly + private static Assembly RegisterPluginDefinition(NopConfig config, ApplicationPartManager applicationPartManager, string plug) { //we can now register the plugin definition - var assemblyName = AssemblyName.GetAssemblyName(plug.FullName); + var assemblyName = AssemblyName.GetAssemblyName(plug); Assembly pluginAssembly; try { @@ -252,7 +259,7 @@ private static Assembly RegisterPluginDefinition(NopConfig config, ApplicationPa //you can use the UnsafeLoadFrom method to load a local assembly that the operating system has flagged as //having been loaded from the web. //see http://go.microsoft.com/fwlink/?LinkId=155569 for more information. - pluginAssembly = Assembly.UnsafeLoadFrom(plug.FullName); + pluginAssembly = Assembly.UnsafeLoadFrom(plug); } else { @@ -269,23 +276,23 @@ private static Assembly RegisterPluginDefinition(NopConfig config, ApplicationPa /// /// Copy the plugin file to shadow copy directory /// - /// - /// - /// - private static FileInfo ShadowCopyFile(FileInfo plug, DirectoryInfo shadowCopyPlugFolder) + /// Plugin file path + /// Path to shadow copy folder + /// File path to shadow copy of plugin file + private static string ShadowCopyFile(string pluginFilePath, string shadowCopyPlugFolder) { var shouldCopy = true; - var shadowCopiedPlug = new FileInfo(Path.Combine(shadowCopyPlugFolder.FullName, plug.Name)); + var shadowCopiedPlug = _fileProvider.Combine(shadowCopyPlugFolder, _fileProvider.GetFileName(pluginFilePath)); //check if a shadow copied file already exists and if it does, check if it's updated, if not don't copy - if (shadowCopiedPlug.Exists) + if (_fileProvider.FileExists(shadowCopiedPlug)) { //it's better to use LastWriteTimeUTC, but not all file systems have this property //maybe it is better to compare file hash? - var areFilesIdentical = shadowCopiedPlug.CreationTimeUtc.Ticks >= plug.CreationTimeUtc.Ticks; + var areFilesIdentical = _fileProvider.GetCreationTime(shadowCopiedPlug).ToUniversalTime().Ticks >= _fileProvider.GetCreationTime(pluginFilePath).ToUniversalTime().Ticks; if (areFilesIdentical) { - Debug.WriteLine("Not copying; files appear identical: '{0}'", shadowCopiedPlug.Name); + Debug.WriteLine("Not copying; files appear identical: '{0}'", _fileProvider.GetFileName(shadowCopiedPlug)); shouldCopy = false; } else @@ -293,8 +300,8 @@ private static FileInfo ShadowCopyFile(FileInfo plug, DirectoryInfo shadowCopyPl //delete an existing file //More info: https://www.nopcommerce.com/boards/t/11511/access-error-nopplugindiscountrulesbillingcountrydll.aspx?p=4#60838 - Debug.WriteLine("New plugin found; Deleting the old file: '{0}'", shadowCopiedPlug.Name); - File.Delete(shadowCopiedPlug.FullName); + Debug.WriteLine("New plugin found; Deleting the old file: '{0}'", _fileProvider.GetFileName(shadowCopiedPlug)); + _fileProvider.DeleteFile(shadowCopiedPlug); } } @@ -303,25 +310,25 @@ private static FileInfo ShadowCopyFile(FileInfo plug, DirectoryInfo shadowCopyPl try { - File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); + _fileProvider.FileCopy(pluginFilePath, shadowCopiedPlug, true); } catch (IOException) { - Debug.WriteLine(shadowCopiedPlug.FullName + " is locked, attempting to rename"); + Debug.WriteLine(shadowCopiedPlug + " is locked, attempting to rename"); //this occurs when the files are locked, //for some reason devenv locks plugin files some times and for another crazy reason you are allowed to rename them //which releases the lock, so that it what we are doing here, once it's renamed, we can re-shadow copy try { - var oldFile = shadowCopiedPlug.FullName + Guid.NewGuid().ToString("N") + ".old"; - File.Move(shadowCopiedPlug.FullName, oldFile); + var oldFile = shadowCopiedPlug + Guid.NewGuid().ToString("N") + ".old"; + _fileProvider.FileMove(shadowCopiedPlug, oldFile); } catch (IOException exc) { - throw new IOException(shadowCopiedPlug.FullName + " rename failed, cannot initialize plugin", exc); + throw new IOException(shadowCopiedPlug + " rename failed, cannot initialize plugin", exc); } //OK, we've made it this far, now retry the shadow copy - File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); + _fileProvider.FileCopy(pluginFilePath, shadowCopiedPlug, true); } return shadowCopiedPlug; @@ -330,12 +337,20 @@ private static FileInfo ShadowCopyFile(FileInfo plug, DirectoryInfo shadowCopyPl /// /// Determines if the folder is a bin plugin folder for a package /// - /// - /// - private static bool IsPackagePluginFolder(DirectoryInfo folder) + /// Folder + /// True if the folder is a bin plugin folder for a package; otherwise false + private static bool IsPackagePluginFolder(string folder) { - if (folder?.Parent == null) return false; - if (!folder.Parent.Name.Equals(PluginsPathName, StringComparison.InvariantCultureIgnoreCase)) return false; + if (string.IsNullOrEmpty(folder)) + return false; + + var parent = _fileProvider.GetParentDirectory(folder); + + if (string.IsNullOrEmpty(parent)) + return false; + + if (!_fileProvider.GetDirectoryNameOnly(parent).Equals(PluginsPathName, StringComparison.InvariantCultureIgnoreCase)) + return false; return true; } @@ -361,54 +376,54 @@ public static void Initialize(ApplicationPartManager applicationPartManager, Nop { // TODO: Add verbose exception handling / raising here since this is happening on app startup and could // prevent app from starting altogether - var pluginFolder = new DirectoryInfo(CommonHelper.MapPath(PluginsPath)); - _shadowCopyFolder = new DirectoryInfo(CommonHelper.MapPath(ShadowCopyPath)); - _reserveShadowCopyFolder = new DirectoryInfo(Path.Combine(CommonHelper.MapPath(ShadowCopyPath), $"{RESERVE_SHADOW_COPY_FOLDER_NAME}{DateTime.Now.ToFileTimeUtc()}")); - + var pluginFolder = _fileProvider.MapPath(PluginsPath); + _shadowCopyFolder = _fileProvider.MapPath(ShadowCopyPath); + _reserveShadowCopyFolder = _fileProvider.Combine(_fileProvider.MapPath(ShadowCopyPath), $"{RESERVE_SHADOW_COPY_FOLDER_NAME}{DateTime.Now.ToFileTimeUtc()}"); + var referencedPlugins = new List(); var incompatiblePlugins = new List(); try { - var installedPluginSystemNames = GetInstalledPluginNames(CommonHelper.MapPath(InstalledPluginsFilePath)); + var installedPluginSystemNames = GetInstalledPluginNames(_fileProvider.MapPath(InstalledPluginsFilePath)); Debug.WriteLine("Creating shadow copy folder and querying for DLLs"); //ensure folders are created - Directory.CreateDirectory(pluginFolder.FullName); - Directory.CreateDirectory(_shadowCopyFolder.FullName); + _fileProvider.CreateDirectory(pluginFolder); + _fileProvider.CreateDirectory(_shadowCopyFolder); //get list of all files in bin - var binFiles = _shadowCopyFolder.GetFiles("*", SearchOption.AllDirectories); + var binFiles = _fileProvider.GetFiles(_shadowCopyFolder, "*", false); if (config.ClearPluginShadowDirectoryOnStartup) { //clear out shadow copied plugins foreach (var f in binFiles) { - if(f.Name.Equals("placeholder.txt", StringComparison.InvariantCultureIgnoreCase)) + if(_fileProvider.GetFileName(f).Equals("placeholder.txt", StringComparison.InvariantCultureIgnoreCase)) continue; - Debug.WriteLine("Deleting " + f.Name); + Debug.WriteLine("Deleting " + f); try { //ignore index.htm - var fileName = Path.GetFileName(f.FullName); + var fileName = _fileProvider.GetFileName(f); if (fileName.Equals("index.htm", StringComparison.InvariantCultureIgnoreCase)) continue; - File.Delete(f.FullName); + _fileProvider.DeleteFile(f); } catch (Exception exc) { - Debug.WriteLine("Error deleting file " + f.Name + ". Exception: " + exc); + Debug.WriteLine("Error deleting file " + f + ". Exception: " + exc); } } //delete all reserve folders - foreach (var directory in _shadowCopyFolder.GetDirectories(RESERVE_SHADOW_COPY_FOLDER_NAME_PATTERN, SearchOption.TopDirectoryOnly)) + foreach (var directory in _fileProvider.GetDirectories(_shadowCopyFolder, RESERVE_SHADOW_COPY_FOLDER_NAME_PATTERN)) { try { - CommonHelper.DeleteDirectory(directory.FullName); + _fileProvider.DeleteDirectory(directory); } catch { @@ -432,7 +447,7 @@ public static void Initialize(ApplicationPartManager applicationPartManager, Nop //some validation if (string.IsNullOrWhiteSpace(pluginDescriptor.SystemName)) - throw new Exception($"A plugin '{descriptionFile.FullName}' has no system name. Try assigning the plugin a unique name and recompiling."); + throw new Exception($"A plugin '{descriptionFile}' has no system name. Try assigning the plugin a unique name and recompiling."); if (referencedPlugins.Contains(pluginDescriptor)) throw new Exception($"A plugin with '{pluginDescriptor.SystemName}' system name is already defined"); @@ -442,19 +457,20 @@ public static void Initialize(ApplicationPartManager applicationPartManager, Nop try { - if (descriptionFile.Directory == null) - throw new Exception($"Directory cannot be resolved for '{descriptionFile.Name}' description file"); + var directoryName = _fileProvider.GetDirectoryName(descriptionFile); + if (string.IsNullOrEmpty(directoryName)) + throw new Exception($"Directory cannot be resolved for '{_fileProvider.GetFileName(descriptionFile)}' description file"); //get list of all DLLs in plugins (not in bin!) - var pluginFiles = descriptionFile.Directory.GetFiles("*.dll", SearchOption.AllDirectories) + var pluginFiles = _fileProvider.GetFiles(directoryName, "*.dll", false) //just make sure we're not registering shadow copied plugins - .Where(x => !binFiles.Select(q => q.FullName).Contains(x.FullName)) - .Where(x => IsPackagePluginFolder(x.Directory)) + .Where(x => !binFiles.Select(q => q).Contains(x)) + .Where(x => IsPackagePluginFolder(_fileProvider.GetDirectoryName(x))) .ToList(); //other plugin description info var mainPluginFile = pluginFiles - .FirstOrDefault(x => x.Name.Equals(pluginDescriptor.AssemblyFileName, StringComparison.InvariantCultureIgnoreCase)); + .FirstOrDefault(x => _fileProvider.GetFileName(x).Equals(pluginDescriptor.AssemblyFileName, StringComparison.InvariantCultureIgnoreCase)); //plugin have wrong directory if (mainPluginFile == null) @@ -470,7 +486,7 @@ public static void Initialize(ApplicationPartManager applicationPartManager, Nop //load all other referenced assemblies now foreach (var plugin in pluginFiles - .Where(x => !x.Name.Equals(mainPluginFile.Name, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !_fileProvider.GetFileName(x).Equals(_fileProvider.GetFileName(mainPluginFile), StringComparison.InvariantCultureIgnoreCase)) .Where(x => !IsAlreadyLoaded(x))) PerformFileDeploy(plugin, applicationPartManager, config); @@ -530,14 +546,10 @@ public static void MarkPluginAsInstalled(string systemName) if (string.IsNullOrEmpty(systemName)) throw new ArgumentNullException(nameof(systemName)); - var filePath = CommonHelper.MapPath(InstalledPluginsFilePath); + var filePath = _fileProvider.MapPath(InstalledPluginsFilePath); //create file if not exists - if (!File.Exists(filePath)) - { - //we use 'using' to close the file after it's created - using (File.Create(filePath)) { } - } + _fileProvider.CreateFile(filePath); //get installed plugin names var installedPluginSystemNames = GetInstalledPluginNames(filePath); @@ -560,14 +572,10 @@ public static void MarkPluginAsUninstalled(string systemName) if (string.IsNullOrEmpty(systemName)) throw new ArgumentNullException(nameof(systemName)); - var filePath = CommonHelper.MapPath(InstalledPluginsFilePath); + var filePath = _fileProvider.MapPath(InstalledPluginsFilePath); //create file if not exists - if (!File.Exists(filePath)) - { - //we use 'using' to close the file after it's created - using (File.Create(filePath)) { } - } + _fileProvider.CreateFile(filePath); //get installed plugin names var installedPluginSystemNames = GetInstalledPluginNames(filePath); @@ -586,9 +594,9 @@ public static void MarkPluginAsUninstalled(string systemName) /// public static void MarkAllPluginsAsUninstalled() { - var filePath = CommonHelper.MapPath(InstalledPluginsFilePath); - if (File.Exists(filePath)) - File.Delete(filePath); + var filePath = _fileProvider.MapPath(InstalledPluginsFilePath); + if (_fileProvider.FileExists(filePath)) + _fileProvider.DeleteFile(filePath); } /// @@ -601,11 +609,9 @@ public static PluginDescriptor FindPlugin(Type typeInAssembly) if (typeInAssembly == null) throw new ArgumentNullException(nameof(typeInAssembly)); - if (ReferencedPlugins == null) - return null; - - return ReferencedPlugins.FirstOrDefault(plugin => plugin.ReferencedAssembly != null - && plugin.ReferencedAssembly.FullName.Equals(typeInAssembly.Assembly.FullName, StringComparison.InvariantCultureIgnoreCase)); + return ReferencedPlugins?.FirstOrDefault(plugin => + plugin.ReferencedAssembly != null && + plugin.ReferencedAssembly.FullName.Equals(typeInAssembly.Assembly.FullName, StringComparison.InvariantCultureIgnoreCase)); } /// @@ -615,7 +621,7 @@ public static PluginDescriptor FindPlugin(Type typeInAssembly) /// Plugin descriptor public static PluginDescriptor GetPluginDescriptorFromFile(string filePath) { - var text = File.ReadAllText(filePath); + var text = _fileProvider.ReadAllText(filePath, Encoding.UTF8); return GetPluginDescriptorFromText(text); } @@ -653,13 +659,13 @@ public static void SavePluginDescriptor(PluginDescriptor pluginDescriptor) if (pluginDescriptor.OriginalAssemblyFile == null) throw new Exception($"Cannot load original assembly path for {pluginDescriptor.SystemName} plugin."); - var filePath = Path.Combine(pluginDescriptor.OriginalAssemblyFile.Directory.FullName, PluginDescriptionFileName); - if (!File.Exists(filePath)) + var filePath = _fileProvider.Combine(_fileProvider.GetDirectoryName(pluginDescriptor.OriginalAssemblyFile), PluginDescriptionFileName); + if (!_fileProvider.FileExists(filePath)) throw new Exception($"Description file for {pluginDescriptor.SystemName} plugin does not exist. {filePath}"); //save the file var text = JsonConvert.SerializeObject(pluginDescriptor, Formatting.Indented); - File.WriteAllText(filePath, text); + _fileProvider.WriteAllText(filePath, text, Encoding.UTF8); } /// @@ -677,8 +683,10 @@ public static bool DeletePlugin(PluginDescriptor pluginDescriptor) if (pluginDescriptor.Installed) return false; - if (pluginDescriptor.OriginalAssemblyFile.Directory.Exists) - CommonHelper.DeleteDirectory(pluginDescriptor.OriginalAssemblyFile.DirectoryName); + var directoryName = _fileProvider.GetDirectoryName(pluginDescriptor.OriginalAssemblyFile); + + if ( _fileProvider.DirectoryExists(directoryName)) + _fileProvider.DeleteDirectory(directoryName); return true; } diff --git a/src/Libraries/Nop.Core/WebHelper.cs b/src/Libraries/Nop.Core/WebHelper.cs index 0efa8fd270a..2e7aa79c2a1 100644 --- a/src/Libraries/Nop.Core/WebHelper.cs +++ b/src/Libraries/Nop.Core/WebHelper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Net; using System.Text; @@ -30,6 +29,7 @@ public partial class WebHelper : IWebHelper private readonly IHttpContextAccessor _httpContextAccessor; private readonly HostingConfig _hostingConfig; + private readonly INopFileProvider _fileProvider; #endregion @@ -40,10 +40,13 @@ public partial class WebHelper : IWebHelper /// /// Hosting config /// HTTP context accessor - public WebHelper(HostingConfig hostingConfig, IHttpContextAccessor httpContextAccessor) + /// File provider + public WebHelper(HostingConfig hostingConfig, IHttpContextAccessor httpContextAccessor, + INopFileProvider fileProvider) { this._hostingConfig = hostingConfig; this._httpContextAccessor = httpContextAccessor; + this._fileProvider = fileProvider; } #endregion @@ -90,7 +93,7 @@ protected virtual bool TryWriteWebConfig() { try { - File.SetLastWriteTimeUtc(CommonHelper.MapPath("~/web.config"), DateTime.UtcNow); + _fileProvider.SetLastWriteTimeUtc(_fileProvider.MapPath("~/web.config"), DateTime.UtcNow); return true; } catch diff --git a/src/Libraries/Nop.Data/Initializers/SqlCeInitializer.cs b/src/Libraries/Nop.Data/Initializers/SqlCeInitializer.cs index 0d880afdb26..678a6bb7904 100644 --- a/src/Libraries/Nop.Data/Initializers/SqlCeInitializer.cs +++ b/src/Libraries/Nop.Data/Initializers/SqlCeInitializer.cs @@ -1,7 +1,7 @@ using System; using System.Data.Entity; using System.Data.SqlServerCe; -using System.IO; +using Nop.Core.Infrastructure; namespace Nop.Data.Initializers { @@ -57,11 +57,12 @@ private static string ReplaceDataDirectory(string inputString) data = string.Empty; } var length = "|DataDirectory|".Length; - if ((inputString.Length > "|DataDirectory|".Length) && ('\\' == inputString["|DataDirectory|".Length])) + if (inputString.Length > "|DataDirectory|".Length && ('\\' == inputString["|DataDirectory|".Length])) { length++; } - return Path.Combine(data, inputString.Substring(length)); + var fileProvider = EngineContext.Current.Resolve(); + return fileProvider.Combine(data, inputString.Substring(length)); } #endregion diff --git a/src/Libraries/Nop.Data/SqlServerDataProvider.cs b/src/Libraries/Nop.Data/SqlServerDataProvider.cs index d6e262544cc..c995bbfffa3 100644 --- a/src/Libraries/Nop.Data/SqlServerDataProvider.cs +++ b/src/Libraries/Nop.Data/SqlServerDataProvider.cs @@ -6,8 +6,8 @@ using System.Data.SqlClient; using System.IO; using System.Text; -using Nop.Core; using Nop.Core.Data; +using Nop.Core.Infrastructure; using Nop.Data.Initializers; namespace Nop.Data @@ -27,7 +27,9 @@ public class SqlServerDataProvider : IDataProvider /// protected virtual string[] ParseCommands(string filePath, bool throwExceptionIfNonExists) { - if (!File.Exists(filePath)) + var fileProvider = EngineContext.Current.Resolve(); + + if (!fileProvider.FileExists(filePath)) { if (throwExceptionIfNonExists) throw new ArgumentException($"Specified file doesn't exist - {filePath}"); @@ -36,8 +38,7 @@ protected virtual string[] ParseCommands(string filePath, bool throwExceptionIfN } var statements = new List(); - using (var stream = File.OpenRead(filePath)) - using (var reader = new StreamReader(stream)) + using (var reader = new StreamReader(filePath)) { string statement; while ((statement = ReadNextStatementFromStream(reader)) != null) @@ -112,9 +113,11 @@ public virtual void SetDatabaseInitializer() //custom commands (stored procedures, indexes) + var fileProvider = EngineContext.Current.Resolve(); + var customCommands = new List(); - customCommands.AddRange(ParseCommands(CommonHelper.MapPath("~/App_Data/Install/SqlServer.Indexes.sql"), false)); - customCommands.AddRange(ParseCommands(CommonHelper.MapPath("~/App_Data/Install/SqlServer.StoredProcedures.sql"), false)); + customCommands.AddRange(ParseCommands(fileProvider.MapPath("~/App_Data/Install/SqlServer.Indexes.sql"), false)); + customCommands.AddRange(ParseCommands(fileProvider.MapPath("~/App_Data/Install/SqlServer.StoredProcedures.sql"), false)); var initializer = new CreateTablesIfNotExist(tablesToValidate, customCommands.ToArray()); Database.SetInitializer(initializer); diff --git a/src/Libraries/Nop.Services/Common/IMaintenanceService.cs b/src/Libraries/Nop.Services/Common/IMaintenanceService.cs index 8cbc93076f6..c2ed20e5edf 100644 --- a/src/Libraries/Nop.Services/Common/IMaintenanceService.cs +++ b/src/Libraries/Nop.Services/Common/IMaintenanceService.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.IO; using Nop.Core; namespace Nop.Services.Common @@ -27,7 +26,7 @@ public partial interface IMaintenanceService /// Gets all backup files /// /// Backup file collection - IList GetAllBackupFiles(); + IList GetAllBackupFiles(); /// /// Creates a backup of the database diff --git a/src/Libraries/Nop.Services/Common/MaintenanceService.cs b/src/Libraries/Nop.Services/Common/MaintenanceService.cs index 7127ffc5dab..2cfa4e7bfa7 100644 --- a/src/Libraries/Nop.Services/Common/MaintenanceService.cs +++ b/src/Libraries/Nop.Services/Common/MaintenanceService.cs @@ -5,10 +5,10 @@ using System.Data.SqlClient; using System.IO; using System.Linq; -using Microsoft.AspNetCore.Hosting; using Nop.Core; using Nop.Core.Data; using Nop.Core.Domain.Common; +using Nop.Core.Infrastructure; using Nop.Data; namespace Nop.Services.Common @@ -23,7 +23,7 @@ public partial class MaintenanceService : IMaintenanceService private readonly IDataProvider _dataProvider; private readonly IDbContext _dbContext; private readonly CommonSettings _commonSettings; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly INopFileProvider _fileProvider; #endregion @@ -35,14 +35,14 @@ public partial class MaintenanceService : IMaintenanceService /// Data provider /// Database Context /// Common settings - /// Hosting environment + /// File provider public MaintenanceService(IDataProvider dataProvider, IDbContext dbContext, - CommonSettings commonSettings, IHostingEnvironment hostingEnvironment) + CommonSettings commonSettings, INopFileProvider fileProvider) { this._dataProvider = dataProvider; this._dbContext = dbContext; this._commonSettings = commonSettings; - this._hostingEnvironment = hostingEnvironment; + this._fileProvider = fileProvider; } #endregion @@ -56,9 +56,9 @@ public MaintenanceService(IDataProvider dataProvider, IDbContext dbContext, /// protected virtual string GetBackupDirectoryPath(bool ensureFolderCreated = true) { - var path = Path.Combine(_hostingEnvironment.WebRootPath, "db_backups\\"); + var path = _fileProvider.GetAbsolutePath("db_backups\\"); if (ensureFolderCreated) - System.IO.Directory.CreateDirectory(path); + _fileProvider.CreateDirectory(path); return path; } @@ -83,16 +83,14 @@ protected virtual void CheckBackupSupported() /// Integer ident; null if cannot get the result public virtual int? GetTableIdent() where T: BaseEntity { - if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduredSupported) - { - //stored procedures are enabled and supported by the database - var tableName = _dbContext.GetTableName(); - var result = _dbContext.SqlQuery($"SELECT IDENT_CURRENT('[{tableName}]')").FirstOrDefault(); - return result.HasValue ? Convert.ToInt32(result) : 1; - } - //stored procedures aren't supported - return null; + if (!_commonSettings.UseStoredProceduresIfSupported || !_dataProvider.StoredProceduredSupported) + return null; + + //stored procedures are enabled and supported by the database + var tableName = _dbContext.GetTableName(); + var result = _dbContext.SqlQuery($"SELECT IDENT_CURRENT('[{tableName}]')").FirstOrDefault(); + return result.HasValue ? Convert.ToInt32(result) : 1; } /// @@ -104,14 +102,13 @@ public virtual void SetTableIdent(int ident) where T : BaseEntity { if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduredSupported) { - //stored procedures are enabled and supported by the database. - var currentIdent = GetTableIdent(); - if (currentIdent.HasValue && ident > currentIdent.Value) - { - var tableName = _dbContext.GetTableName(); - _dbContext.ExecuteSqlCommand($"DBCC CHECKIDENT([{tableName}], RESEED, {ident})"); - } + if (!currentIdent.HasValue || ident <= currentIdent.Value) + return; + + //stored procedures are enabled and supported by the database. + var tableName = _dbContext.GetTableName(); + _dbContext.ExecuteSqlCommand($"DBCC CHECKIDENT([{tableName}], RESEED, {ident})"); } else { @@ -123,16 +120,17 @@ public virtual void SetTableIdent(int ident) where T : BaseEntity /// Gets all backup files /// /// Backup file collection - public virtual IList GetAllBackupFiles() + public virtual IList GetAllBackupFiles() { var path = GetBackupDirectoryPath(); - if (!System.IO.Directory.Exists(path)) + if (!_fileProvider.DirectoryExists(path)) { throw new IOException("Backup directory not exists"); } - - return System.IO.Directory.GetFiles(path, "*.bak").Select(fullPath => new FileInfo(fullPath)).OrderByDescending(p => p.CreationTime).ToList(); + + return _fileProvider.GetFiles(path, "*.bak") + .OrderByDescending(p => _fileProvider.GetLastWriteTime(p)).ToList(); } /// @@ -141,17 +139,9 @@ public virtual IList GetAllBackupFiles() public virtual void BackupDatabase() { CheckBackupSupported(); - var fileName = string.Format( - "{0}database_{1}_{2}.bak", - GetBackupDirectoryPath(), - DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"), - CommonHelper.GenerateRandomDigitCode(10)); - - var commandText = string.Format( - "BACKUP DATABASE [{0}] TO DISK = '{1}' WITH FORMAT", - _dbContext.DbName(), - fileName); + var fileName = $"{GetBackupDirectoryPath()}database_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}_{CommonHelper.GenerateRandomDigitCode(10)}.bak"; + var commandText = $"BACKUP DATABASE [{_dbContext.DbName()}] TO DISK = '{fileName}' WITH FORMAT"; _dbContext.ExecuteSqlCommand(commandText, true); } @@ -163,7 +153,7 @@ public virtual void BackupDatabase() public virtual void RestoreDatabase(string backupFileName) { CheckBackupSupported(); - var settings = new DataSettingsManager(); + var settings = new DataSettingsManager(_fileProvider); var conn = new SqlConnectionStringBuilder(settings.LoadSettings().DataConnectionString) { InitialCatalog = "master" @@ -206,7 +196,7 @@ public virtual void RestoreDatabase(string backupFileName) /// The path to the backup file public virtual string GetBackupPath(string backupFileName) { - return Path.Combine(GetBackupDirectoryPath(), backupFileName); + return _fileProvider.Combine(GetBackupDirectoryPath(), backupFileName); } #endregion diff --git a/src/Libraries/Nop.Services/Common/PdfService.cs b/src/Libraries/Nop.Services/Common/PdfService.cs index 55c6c772338..1b988c8730b 100644 --- a/src/Libraries/Nop.Services/Common/PdfService.cs +++ b/src/Libraries/Nop.Services/Common/PdfService.cs @@ -17,6 +17,7 @@ using Nop.Core.Domain.Tax; using Nop.Core.Domain.Vendors; using Nop.Core.Html; +using Nop.Core.Infrastructure; using Nop.Services.Catalog; using Nop.Services.Configuration; using Nop.Services.Directory; @@ -61,6 +62,7 @@ public partial class PdfService : IPdfService private readonly AddressSettings _addressSettings; private readonly IVendorService _vendorService; private readonly VendorSettings _vendorSettings; + private readonly INopFileProvider _fileProvider; #endregion @@ -93,6 +95,7 @@ public partial class PdfService : IPdfService /// Address settings /// Vendor service /// Vendor settings + /// File provider public PdfService(ILocalizationService localizationService, ILanguageService languageService, IWorkContext workContext, @@ -116,7 +119,8 @@ public PdfService(ILocalizationService localizationService, TaxSettings taxSettings, AddressSettings addressSettings, IVendorService vendorService, - VendorSettings vendorSettings) + VendorSettings vendorSettings, + INopFileProvider fileProvider) { this._localizationService = localizationService; this._languageService = languageService; @@ -142,6 +146,7 @@ public PdfService(ILocalizationService localizationService, this._addressSettings = addressSettings; this._vendorService = vendorService; this._vendorSettings = vendorSettings; + this._fileProvider = fileProvider; } #endregion @@ -169,7 +174,7 @@ protected virtual Font GetFont(string fontFileName) if (fontFileName == null) throw new ArgumentNullException(nameof(fontFileName)); - var fontPath = Path.Combine(CommonHelper.MapPath("~/App_Data/Pdf/"), fontFileName); + var fontPath = _fileProvider.Combine(_fileProvider.MapPath("~/App_Data/Pdf/"), fontFileName); var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); var font = new Font(baseFont, 10, Font.NORMAL); return font; @@ -1178,7 +1183,7 @@ public virtual string PrintOrderToPdf(Order order, int languageId = 0, int vendo throw new ArgumentNullException(nameof(order)); var fileName = $"order_{order.OrderGuid}_{CommonHelper.GenerateRandomDigitCode(4)}.pdf"; - var filePath = Path.Combine(CommonHelper.MapPath("~/wwwroot/files/exportimport"), fileName); + var filePath = _fileProvider.Combine(_fileProvider.MapPath("~/wwwroot/files/exportimport"), fileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { var orders = new List {order}; diff --git a/src/Libraries/Nop.Services/Directory/GeoLookupService.cs b/src/Libraries/Nop.Services/Directory/GeoLookupService.cs index 3e4bdac822b..800e3ffac05 100644 --- a/src/Libraries/Nop.Services/Directory/GeoLookupService.cs +++ b/src/Libraries/Nop.Services/Directory/GeoLookupService.cs @@ -4,7 +4,7 @@ using MaxMind.GeoIP2; using MaxMind.GeoIP2.Exceptions; using MaxMind.GeoIP2.Responses; -using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Services.Logging; namespace Nop.Services.Directory @@ -17,6 +17,7 @@ public partial class GeoLookupService : IGeoLookupService #region Fields private readonly ILogger _logger; + private readonly INopFileProvider _fileProvider; #endregion @@ -26,9 +27,11 @@ public partial class GeoLookupService : IGeoLookupService /// Ctor /// /// Logger - public GeoLookupService(ILogger logger) + /// File provider + public GeoLookupService(ILogger logger, INopFileProvider fileProvider) { this._logger = logger; + this._fileProvider = fileProvider; } #endregion @@ -48,7 +51,7 @@ protected virtual CountryResponse GetInformation(string ipAddress) try { //This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com - var databasePath = CommonHelper.MapPath("~/App_Data/GeoLite2-Country.mmdb"); + var databasePath = _fileProvider.MapPath("~/App_Data/GeoLite2-Country.mmdb"); var reader = new DatabaseReader(databasePath); var omni = reader.Country(ipAddress); return omni; diff --git a/src/Libraries/Nop.Services/ExportImport/ImportManager.cs b/src/Libraries/Nop.Services/ExportImport/ImportManager.cs index 0babaf163d7..a5cd8eaa8bf 100644 --- a/src/Libraries/Nop.Services/ExportImport/ImportManager.cs +++ b/src/Libraries/Nop.Services/ExportImport/ImportManager.cs @@ -29,6 +29,7 @@ using System.Net; using Microsoft.Extensions.DependencyInjection; using Nop.Services.Stores; +using Nop.Core.Infrastructure; namespace Nop.Services.ExportImport { @@ -77,6 +78,7 @@ public partial class ImportManager : IImportManager private readonly ISpecificationAttributeService _specificationAttributeService; private readonly ILogger _logger; private readonly IStoreMappingService _storeMappingService; + private readonly INopFileProvider _fileProvider; #endregion @@ -110,7 +112,8 @@ public ImportManager(IProductService productService, ISpecificationAttributeService specificationAttributeService, ILogger logger, IServiceScopeFactory serviceScopeFactory, - IStoreMappingService storeMappingService) + IStoreMappingService storeMappingService, + INopFileProvider fileProvider) { this._productService = productService; this._categoryService = categoryService; @@ -141,6 +144,7 @@ public ImportManager(IProductService productService, this._logger = logger; this._serviceScopeFactory = serviceScopeFactory; this._storeMappingService = storeMappingService; + this._fileProvider = fileProvider; } #endregion @@ -223,11 +227,11 @@ protected virtual string GetMimeTypeFromFilePath(string filePath) /// The image or null if the image has not changed protected virtual Picture LoadPicture(string picturePath, string name, int? picId = null) { - if (string.IsNullOrEmpty(picturePath) || !File.Exists(picturePath)) + if (string.IsNullOrEmpty(picturePath) || !_fileProvider.FileExists(picturePath)) return null; var mimeType = GetMimeTypeFromFilePath(picturePath); - var newPictureBinary = File.ReadAllBytes(picturePath); + var newPictureBinary = _fileProvider.ReadAllBytes(picturePath); var pictureAlreadyExists = false; if (picId != null) { @@ -254,9 +258,11 @@ protected virtual Picture LoadPicture(string picturePath, string name, int? picI private void LogPictureInsertError(string picturePath, Exception ex) { - var fi = new FileInfo(picturePath); - var point = string.IsNullOrEmpty(fi.Extension) ? string.Empty : "."; - var fileName = fi.Exists ? $"{fi.Name}{point}{fi.Extension}" : string.Empty; + var extension = _fileProvider.GetFileExtension(picturePath); + var name = _fileProvider.GetFileNameWithoutExtension(picturePath); + + var point = string.IsNullOrEmpty(extension) ? string.Empty : "."; + var fileName = _fileProvider.FileExists(picturePath) ? $"{name}{point}{extension}" : string.Empty; _logger.Error($"Insert picture failed (file name: {fileName})", ex); } @@ -270,7 +276,7 @@ protected virtual void ImportProductImagesUsingServices(IList downloadedFiles) return string.Empty; //ensure that temp directory is created - var tempDirectory = CommonHelper.MapPath(UPLOADS_TEMP_PATH); - System.IO.Directory.CreateDirectory(new DirectoryInfo(tempDirectory).FullName); + var tempDirectory = _fileProvider.MapPath(UPLOADS_TEMP_PATH); + _fileProvider.CreateDirectory(tempDirectory); - var fileName = Path.GetFileName(urlString); + var fileName = _fileProvider.GetFileName(urlString); if (string.IsNullOrEmpty(fileName)) return string.Empty; - var filePath = Path.Combine(tempDirectory, fileName); + var filePath = _fileProvider.Combine(tempDirectory, fileName); try { WebRequest.Create(urlString); @@ -1044,7 +1050,7 @@ private void ImportProductsFromSplitedXlsx(ExcelWorksheet worksheet, ImportProdu try { - File.Delete(path); + _fileProvider.DeleteFile(path); } catch { @@ -1071,7 +1077,7 @@ private IList SplitProductFile(ExcelWorksheet worksheet, ImportProductMe ? metadata.ProductsInFile[curIndex - 1] : metadata.EndRow; - var filePath = $"{CommonHelper.MapPath(UPLOADS_TEMP_PATH)}/{fileName}_part_{fileIndex}.xlsx"; + var filePath = $"{_fileProvider.MapPath(UPLOADS_TEMP_PATH)}/{fileName}_part_{fileIndex}.xlsx"; CopyDataToNewFile(metadata, worksheet, filePath, startRow, endRow, endCell); @@ -1702,12 +1708,12 @@ public virtual void ImportProductsFromXlsx(Stream stream) foreach (var downloadedFile in downloadedFiles) { - if(!File.Exists(downloadedFile)) + if(!_fileProvider.FileExists(downloadedFile)) continue; try { - File.Delete(downloadedFile); + _fileProvider.DeleteFile(downloadedFile); } catch { diff --git a/src/Libraries/Nop.Services/Helpers/BrowscapXmlParser.cs b/src/Libraries/Nop.Services/Helpers/BrowscapXmlParser.cs index ee5eb99725e..a643623ff4d 100644 --- a/src/Libraries/Nop.Services/Helpers/BrowscapXmlParser.cs +++ b/src/Libraries/Nop.Services/Helpers/BrowscapXmlParser.cs @@ -5,6 +5,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Xml.Linq; +using Nop.Core.Infrastructure; namespace Nop.Services.Helpers { @@ -14,15 +15,18 @@ namespace Nop.Services.Helpers public class BrowscapXmlHelper { private readonly List _crawlerUserAgentsRegexp; + private readonly INopFileProvider _fileProvider; /// /// Ctor /// /// User agent file path /// User agent with crawlers only file path - public BrowscapXmlHelper(string userAgentStringsPath, string crawlerOnlyUserAgentStringsPath) + /// File provider + public BrowscapXmlHelper(string userAgentStringsPath, string crawlerOnlyUserAgentStringsPath, INopFileProvider fileProvider) { - _crawlerUserAgentsRegexp = new List(); + this._crawlerUserAgentsRegexp = new List(); + this._fileProvider = fileProvider; Initialize(userAgentStringsPath, crawlerOnlyUserAgentStringsPath); } @@ -32,7 +36,7 @@ private void Initialize(string userAgentStringsPath, string crawlerOnlyUserAgent List crawlerItems = null; var needSaveCrawlerOnly = false; - if (!string.IsNullOrEmpty(crawlerOnlyUserAgentStringsPath) && File.Exists(crawlerOnlyUserAgentStringsPath)) + if (!string.IsNullOrEmpty(crawlerOnlyUserAgentStringsPath) && _fileProvider.FileExists(crawlerOnlyUserAgentStringsPath)) { //try to load crawler list from crawlers only file using (var sr = new StreamReader(crawlerOnlyUserAgentStringsPath)) @@ -63,7 +67,7 @@ private void Initialize(string userAgentStringsPath, string crawlerOnlyUserAgent .Select(e => e.Value) .Select(ToRegexp)); - if ((string.IsNullOrEmpty(crawlerOnlyUserAgentStringsPath) || File.Exists(crawlerOnlyUserAgentStringsPath)) && !needSaveCrawlerOnly) + if ((string.IsNullOrEmpty(crawlerOnlyUserAgentStringsPath) || _fileProvider.FileExists(crawlerOnlyUserAgentStringsPath)) && !needSaveCrawlerOnly) return; //try to write crawlers file diff --git a/src/Libraries/Nop.Services/Helpers/UserAgentHelper.cs b/src/Libraries/Nop.Services/Helpers/UserAgentHelper.cs index e371ec0087a..bb99beb9fd8 100644 --- a/src/Libraries/Nop.Services/Helpers/UserAgentHelper.cs +++ b/src/Libraries/Nop.Services/Helpers/UserAgentHelper.cs @@ -3,7 +3,6 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; -using Nop.Core; using Nop.Core.Configuration; using Nop.Core.Infrastructure; @@ -18,6 +17,7 @@ public partial class UserAgentHelper : IUserAgentHelper private readonly NopConfig _nopConfig; private readonly IHttpContextAccessor _httpContextAccessor; + private readonly INopFileProvider _fileProvider; private static readonly object _locker = new object(); #endregion @@ -29,10 +29,12 @@ public partial class UserAgentHelper : IUserAgentHelper /// /// Config /// HTTP context accessor - public UserAgentHelper(NopConfig nopConfig, IHttpContextAccessor httpContextAccessor) + /// File provider + public UserAgentHelper(NopConfig nopConfig, IHttpContextAccessor httpContextAccessor, INopFileProvider fileProvider) { this._nopConfig = nopConfig; this._httpContextAccessor = httpContextAccessor; + this._fileProvider = fileProvider; } #endregion @@ -60,12 +62,12 @@ protected virtual BrowscapXmlHelper GetBrowscapXmlHelper() if (Singleton.Instance != null) return Singleton.Instance; - var userAgentStringsPath = CommonHelper.MapPath(_nopConfig.UserAgentStringsPath); + var userAgentStringsPath = _fileProvider.MapPath(_nopConfig.UserAgentStringsPath); var crawlerOnlyUserAgentStringsPath = !string.IsNullOrEmpty(_nopConfig.CrawlerOnlyUserAgentStringsPath) - ? CommonHelper.MapPath(_nopConfig.CrawlerOnlyUserAgentStringsPath) + ? _fileProvider.MapPath(_nopConfig.CrawlerOnlyUserAgentStringsPath) : string.Empty; - var browscapXmlHelper = new BrowscapXmlHelper(userAgentStringsPath, crawlerOnlyUserAgentStringsPath); + var browscapXmlHelper = new BrowscapXmlHelper(userAgentStringsPath, crawlerOnlyUserAgentStringsPath, _fileProvider); Singleton.Instance = browscapXmlHelper; return Singleton.Instance; diff --git a/src/Libraries/Nop.Services/Installation/CodeFirstInstallationService.cs b/src/Libraries/Nop.Services/Installation/CodeFirstInstallationService.cs index 9588fd199ae..3602e7774a6 100644 --- a/src/Libraries/Nop.Services/Installation/CodeFirstInstallationService.cs +++ b/src/Libraries/Nop.Services/Installation/CodeFirstInstallationService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using System.Text; using Microsoft.AspNetCore.Hosting; using Nop.Core; using Nop.Core.Data; @@ -105,6 +105,7 @@ public partial class CodeFirstInstallationService : IInstallationService private readonly IGenericAttributeService _genericAttributeService; private readonly IWebHelper _webHelper; private readonly IHostingEnvironment _hostingEnvironment; + private readonly INopFileProvider _fileProvider; #endregion @@ -165,7 +166,8 @@ public CodeFirstInstallationService(IRepository storeRepository, IRepository stockQuantityHistoryRepository, IGenericAttributeService genericAttributeService, IWebHelper webHelper, - IHostingEnvironment hostingEnvironment) + IHostingEnvironment hostingEnvironment, + INopFileProvider fileProvider) { this._storeRepository = storeRepository; this._measureDimensionRepository = measureDimensionRepository; @@ -223,6 +225,7 @@ public CodeFirstInstallationService(IRepository storeRepository, this._genericAttributeService = genericAttributeService; this._webHelper = webHelper; this._hostingEnvironment = hostingEnvironment; + this._fileProvider = fileProvider; } #endregion @@ -231,7 +234,7 @@ public CodeFirstInstallationService(IRepository storeRepository, protected virtual string GetSamplesPath() { - return Path.Combine(_hostingEnvironment.WebRootPath, "images\\samples\\"); + return _fileProvider.GetAbsolutePath("images\\samples\\"); } protected virtual void InstallStores() @@ -383,9 +386,9 @@ protected virtual void InstallLocaleResources() var language = _languageRepository.Table.Single(l => l.Name == "English"); //save resources - foreach (var filePath in System.IO.Directory.EnumerateFiles(CommonHelper.MapPath("~/App_Data/Localization/"), "*.nopres.xml", SearchOption.TopDirectoryOnly)) + foreach (var filePath in _fileProvider.EnumerateFiles(_fileProvider.MapPath("~/App_Data/Localization/"), "*.nopres.xml")) { - var localesXml = File.ReadAllText(filePath); + var localesXml = _fileProvider.ReadAllText(filePath, Encoding.UTF8); var localizationService = EngineContext.Current.Resolve(); localizationService.ImportResourcesFromXml(language, localesXml); } @@ -6745,7 +6748,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_computers.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Computers")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_computers.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Computers")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 1, @@ -6763,7 +6766,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryComputers.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_desktops.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Desktops")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_desktops.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Desktops")).Id, PriceRanges = "-1000;1000-1200;1200-;", IncludeInTopMenu = true, Published = true, @@ -6782,7 +6785,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryComputers.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_notebooks.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Notebooks")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_notebooks.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Notebooks")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 2, @@ -6800,7 +6803,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryComputers.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_software.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Software")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_software.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Software")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 3, @@ -6817,7 +6820,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_electronics.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Electronics")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_electronics.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Electronics")).Id, IncludeInTopMenu = true, Published = true, ShowOnHomePage = true, @@ -6836,7 +6839,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryElectronics.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_camera_photo.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Camera, photo")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_camera_photo.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Camera, photo")).Id, PriceRanges = "-500;500-;", IncludeInTopMenu = true, Published = true, @@ -6855,7 +6858,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryElectronics.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_cell_phones.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Cell phones")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_cell_phones.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Cell phones")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 2, @@ -6873,7 +6876,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryElectronics.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_accessories.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Accessories")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_accessories.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Accessories")).Id, IncludeInTopMenu = true, PriceRanges = "-100;100-;", Published = true, @@ -6891,7 +6894,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_apparel.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Apparel")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_apparel.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Apparel")).Id, IncludeInTopMenu = true, Published = true, ShowOnHomePage = true, @@ -6910,7 +6913,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryApparel.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_shoes.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Shoes")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_shoes.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Shoes")).Id, PriceRanges = "-500;500-;", IncludeInTopMenu = true, Published = true, @@ -6929,7 +6932,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryApparel.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_clothing.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Clothing")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_clothing.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Clothing")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 2, @@ -6947,7 +6950,7 @@ protected virtual void InstallCategories() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", ParentCategoryId = categoryApparel.Id, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_apparel_accessories.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Apparel Accessories")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_apparel_accessories.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Apparel Accessories")).Id, IncludeInTopMenu = true, PriceRanges = "-100;100-;", Published = true, @@ -6965,7 +6968,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_digital_downloads.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Digital downloads")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_digital_downloads.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Digital downloads")).Id, IncludeInTopMenu = true, Published = true, ShowOnHomePage = true, @@ -6985,7 +6988,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_book.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Book")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_book.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Book")).Id, PriceRanges = "-25;25-50;50-;", IncludeInTopMenu = true, Published = true, @@ -7003,7 +7006,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_jewelry.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Jewelry")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_jewelry.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Jewelry")).Id, PriceRanges = "0-500;500-700;700-3000;", IncludeInTopMenu = true, Published = true, @@ -7021,7 +7024,7 @@ protected virtual void InstallCategories() PageSize = 6, AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_gift_cards.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Gift Cards")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "category_gift_cards.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Gift Cards")).Id, IncludeInTopMenu = true, Published = true, DisplayOrder = 7, @@ -7064,7 +7067,7 @@ protected virtual void InstallManufacturers() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", Published = true, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_apple.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Apple")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "manufacturer_apple.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Apple")).Id, DisplayOrder = 1, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow @@ -7080,7 +7083,7 @@ protected virtual void InstallManufacturers() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", Published = true, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_hp.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Hp")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "manufacturer_hp.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Hp")).Id, DisplayOrder = 5, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow @@ -7096,7 +7099,7 @@ protected virtual void InstallManufacturers() AllowCustomersToSelectPageSize = true, PageSizeOptions = "6, 3, 9", Published = true, - PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_nike.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Nike")).Id, + PictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "manufacturer_nike.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Nike")).Id, DisplayOrder = 5, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow @@ -7336,12 +7339,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productBuildComputer); productBuildComputer.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Desktops_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBuildComputer.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Desktops_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBuildComputer.Name)), DisplayOrder = 1, }); productBuildComputer.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Desktops_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBuildComputer.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Desktops_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBuildComputer.Name)), DisplayOrder = 2, }); _productRepository.Insert(productBuildComputer); @@ -7388,7 +7391,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productDigitalStorm); productDigitalStorm.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_DigitalStorm.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productDigitalStorm.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_DigitalStorm.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productDigitalStorm.Name)), DisplayOrder = 1, }); _productRepository.Insert(productDigitalStorm); @@ -7435,7 +7438,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productLenovoIdeaCentre); productLenovoIdeaCentre.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_LenovoIdeaCentre.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLenovoIdeaCentre.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_LenovoIdeaCentre.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLenovoIdeaCentre.Name)), DisplayOrder = 1, }); _productRepository.Insert(productLenovoIdeaCentre); @@ -7527,12 +7530,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productAppleMacBookPro); productAppleMacBookPro.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_macbook_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleMacBookPro.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_macbook_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleMacBookPro.Name)), DisplayOrder = 1, }); productAppleMacBookPro.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_macbook_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleMacBookPro.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_macbook_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleMacBookPro.Name)), DisplayOrder = 2, }); _productRepository.Insert(productAppleMacBookPro); @@ -7610,7 +7613,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productAsusN551JK); productAsusN551JK.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_asuspc_N551JK.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAsusN551JK.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_asuspc_N551JK.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAsusN551JK.Name)), DisplayOrder = 1, }); _productRepository.Insert(productAsusN551JK); @@ -7689,7 +7692,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productSamsungSeries); productSamsungSeries.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_SamsungNP900X4C.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productSamsungSeries.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_SamsungNP900X4C.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productSamsungSeries.Name)), DisplayOrder = 1, }); _productRepository.Insert(productSamsungSeries); @@ -7775,12 +7778,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productHpSpectre); productHpSpectre.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HPSpectreXT_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpSpectre.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HPSpectreXT_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpSpectre.Name)), DisplayOrder = 1, }); productHpSpectre.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HPSpectreXT_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpSpectre.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HPSpectreXT_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpSpectre.Name)), DisplayOrder = 2, }); _productRepository.Insert(productHpSpectre); @@ -7866,7 +7869,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productHpEnvy); productHpEnvy.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HpEnvy6.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpEnvy.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HpEnvy6.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHpEnvy.Name)), DisplayOrder = 1, }); _productRepository.Insert(productHpEnvy); @@ -7930,7 +7933,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productLenovoThinkpad); productLenovoThinkpad.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_LenovoThinkpad.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLenovoThinkpad.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_LenovoThinkpad.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLenovoThinkpad.Name)), DisplayOrder = 1, }); _productRepository.Insert(productLenovoThinkpad); @@ -7981,7 +7984,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productAdobePhotoshop); productAdobePhotoshop.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_AdobePhotoshop.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAdobePhotoshop.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_AdobePhotoshop.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAdobePhotoshop.Name)), DisplayOrder = 1, }); _productRepository.Insert(productAdobePhotoshop); @@ -8028,7 +8031,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productWindows8Pro); productWindows8Pro.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Windows8.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productWindows8Pro.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Windows8.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productWindows8Pro.Name)), DisplayOrder = 1, }); _productRepository.Insert(productWindows8Pro); @@ -8079,7 +8082,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productSoundForge); productSoundForge.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_SoundForge.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productSoundForge.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_SoundForge.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productSoundForge.Name)), DisplayOrder = 1, }); _productRepository.Insert(productSoundForge); @@ -8131,12 +8134,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikonD5500DSLR); productNikonD5500DSLR.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikonCamera_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNikonD5500DSLR.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikonCamera_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNikonD5500DSLR.Name)), DisplayOrder = 1, }); productNikonD5500DSLR.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikonCamera_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNikonD5500DSLR.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikonCamera_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNikonD5500DSLR.Name)), DisplayOrder = 2, }); _productRepository.Insert(productNikonD5500DSLR); @@ -8173,7 +8176,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikonD5500DSLR_associated_1); productNikonD5500DSLR_associated_1.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikonCamera_black.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Canon Digital SLR Camera - Black")), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikonCamera_black.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Canon Digital SLR Camera - Black")), DisplayOrder = 1, }); _productRepository.Insert(productNikonD5500DSLR_associated_1); @@ -8210,7 +8213,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikonD5500DSLR_associated_2); productNikonD5500DSLR_associated_2.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikonCamera_red.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Canon Digital SLR Camera - Silver")), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikonCamera_red.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName("Canon Digital SLR Camera - Silver")), DisplayOrder = 1, }); _productRepository.Insert(productNikonD5500DSLR_associated_2); @@ -8257,7 +8260,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productLeica); productLeica.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_LeicaT.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLeica.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_LeicaT.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productLeica.Name)), DisplayOrder = 1, }); _productRepository.Insert(productLeica); @@ -8312,7 +8315,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productAppleICam); productAppleICam.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_iCam.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleICam.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_iCam.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productAppleICam.Name)), DisplayOrder = 1, }); _productRepository.Insert(productAppleICam); @@ -8365,7 +8368,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productHtcOne); productHtcOne.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HTC_One_M8.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOne.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HTC_One_M8.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOne.Name)), DisplayOrder = 1, }); _productRepository.Insert(productHtcOne); @@ -8413,12 +8416,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productHtcOneMini); productHtcOneMini.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HTC_One_Mini_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOneMini.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HTC_One_Mini_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOneMini.Name)), DisplayOrder = 1, }); productHtcOneMini.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_HTC_One_Mini_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOneMini.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_HTC_One_Mini_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productHtcOneMini.Name)), DisplayOrder = 2, }); _productRepository.Insert(productHtcOneMini); @@ -8465,7 +8468,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNokiaLumia); productNokiaLumia.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Lumia1020.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNokiaLumia.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Lumia1020.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNokiaLumia.Name)), DisplayOrder = 1, }); _productRepository.Insert(productNokiaLumia); @@ -8539,12 +8542,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productBeatsPill); productBeatsPill.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_PillBeats_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBeatsPill.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_PillBeats_1.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBeatsPill.Name)), DisplayOrder = 1, }); productBeatsPill.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_PillBeats_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBeatsPill.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_PillBeats_2.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBeatsPill.Name)), DisplayOrder = 2, }); _productRepository.Insert(productBeatsPill); @@ -8591,7 +8594,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productUniversalTabletCover); productUniversalTabletCover.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_TabletCover.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productUniversalTabletCover.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_TabletCover.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productUniversalTabletCover.Name)), DisplayOrder = 1, }); _productRepository.Insert(productUniversalTabletCover); @@ -8638,7 +8641,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productPortableSoundSpeakers); productPortableSoundSpeakers.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Speakers.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productPortableSoundSpeakers.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Speakers.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productPortableSoundSpeakers.Name)), DisplayOrder = 1, }); _productRepository.Insert(productPortableSoundSpeakers); @@ -8745,14 +8748,14 @@ protected virtual void InstallProducts(string defaultUserEmail) AttributeValueType = AttributeValueType.Simple, Name = "Natural", DisplayOrder = 1, - ImageSquaresPictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "p_attribute_print_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Natural Print")).Id, + ImageSquaresPictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "p_attribute_print_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Natural Print")).Id, }, new ProductAttributeValue { AttributeValueType = AttributeValueType.Simple, Name = "Fresh", DisplayOrder = 2, - ImageSquaresPictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "p_attribute_print_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Fresh Print")).Id, + ImageSquaresPictureId = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "p_attribute_print_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName("Fresh Print")).Id, }, } } @@ -8789,12 +8792,12 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikeFloral); productNikeFloral.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikeFloralShoe_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeFloral.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikeFloralShoe_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeFloral.Name)), DisplayOrder = 1, }); productNikeFloral.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikeFloralShoe_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeFloral.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikeFloralShoe_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeFloral.Name)), DisplayOrder = 2, }); _productRepository.Insert(productNikeFloral); @@ -8943,17 +8946,17 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productAdidas); productAdidas.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_adidas.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_adidas.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), DisplayOrder = 1, }); productAdidas.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_adidas_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_adidas_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), DisplayOrder = 2, }); productAdidas.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_adidas_3.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_adidas_3.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productAdidas.Name)), DisplayOrder = 3, }); @@ -9027,7 +9030,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikeZoom); productNikeZoom.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikeZoom.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeZoom.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikeZoom.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeZoom.Name)), DisplayOrder = 1, }); _productRepository.Insert(productNikeZoom); @@ -9134,7 +9137,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNikeTailwind); productNikeTailwind.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NikeShirt.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeTailwind.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NikeShirt.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productNikeTailwind.Name)), DisplayOrder = 1, }); _productRepository.Insert(productNikeTailwind); @@ -9200,7 +9203,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productOversizedWomenTShirt); productOversizedWomenTShirt.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_WomenTShirt.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productOversizedWomenTShirt.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_WomenTShirt.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productOversizedWomenTShirt.Name)), DisplayOrder = 1, }); _productRepository.Insert(productOversizedWomenTShirt); @@ -9257,7 +9260,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productCustomTShirt); productCustomTShirt.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_CustomTShirt.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productCustomTShirt.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_CustomTShirt.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productCustomTShirt.Name)), DisplayOrder = 1, }); _productRepository.Insert(productCustomTShirt); @@ -9325,12 +9328,12 @@ protected virtual void InstallProducts(string defaultUserEmail) productLeviJeans.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_LeviJeans_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productLeviJeans.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_LeviJeans_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productLeviJeans.Name)), DisplayOrder = 1, }); productLeviJeans.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_LeviJeans_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productLeviJeans.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_LeviJeans_2.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productLeviJeans.Name)), DisplayOrder = 2, }); _productRepository.Insert(productLeviJeans); @@ -9417,7 +9420,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productObeyHat); productObeyHat.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_hat.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productObeyHat.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_hat.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productObeyHat.Name)), DisplayOrder = 1, }); _productRepository.Insert(productObeyHat); @@ -9465,7 +9468,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productBelt); productBelt.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Belt.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBelt.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Belt.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productBelt.Name)), DisplayOrder = 1, }); _productRepository.Insert(productBelt); @@ -9512,7 +9515,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productSunglasses); productSunglasses.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Sunglasses.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productSunglasses.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Sunglasses.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productSunglasses.Name)), DisplayOrder = 1, }); _productRepository.Insert(productSunglasses); @@ -9525,7 +9528,7 @@ protected virtual void InstallProducts(string defaultUserEmail) { DownloadGuid = Guid.NewGuid(), ContentType = MimeTypes.ApplicationXZipCo, - DownloadBinary = File.ReadAllBytes(sampleDownloadsPath + "product_NightVision_1.zip"), + DownloadBinary = _fileProvider.ReadAllBytes(sampleDownloadsPath + "product_NightVision_1.zip"), Extension = ".zip", Filename = "Night_Vision_1", IsNew = true, @@ -9535,7 +9538,7 @@ protected virtual void InstallProducts(string defaultUserEmail) { DownloadGuid = Guid.NewGuid(), ContentType = MimeTypes.TextPlain, - DownloadBinary = File.ReadAllBytes(sampleDownloadsPath + "product_NightVision_2.txt"), + DownloadBinary = _fileProvider.ReadAllBytes(sampleDownloadsPath + "product_NightVision_2.txt"), Extension = ".txt", Filename = "Night_Vision_1", IsNew = true, @@ -9585,7 +9588,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productNightVision); productNightVision.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_NightVisions.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNightVision.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_NightVisions.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productNightVision.Name)), DisplayOrder = 1, }); _productRepository.Insert(productNightVision); @@ -9594,7 +9597,7 @@ protected virtual void InstallProducts(string defaultUserEmail) { DownloadGuid = Guid.NewGuid(), ContentType = MimeTypes.ApplicationXZipCo, - DownloadBinary = File.ReadAllBytes(sampleDownloadsPath + "product_IfYouWait_1.zip"), + DownloadBinary = _fileProvider.ReadAllBytes(sampleDownloadsPath + "product_IfYouWait_1.zip"), Extension = ".zip", Filename = "If_You_Wait_1", IsNew = true, @@ -9604,7 +9607,7 @@ protected virtual void InstallProducts(string defaultUserEmail) { DownloadGuid = Guid.NewGuid(), ContentType = MimeTypes.TextPlain, - DownloadBinary = File.ReadAllBytes(sampleDownloadsPath + "product_IfYouWait_2.txt"), + DownloadBinary = _fileProvider.ReadAllBytes(sampleDownloadsPath + "product_IfYouWait_2.txt"), Extension = ".txt", Filename = "If_You_Wait_1", IsNew = true, @@ -9657,7 +9660,7 @@ protected virtual void InstallProducts(string defaultUserEmail) productIfYouWait.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_IfYouWait.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productIfYouWait.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_IfYouWait.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productIfYouWait.Name)), DisplayOrder = 1, }); _productRepository.Insert(productIfYouWait); @@ -9666,7 +9669,7 @@ protected virtual void InstallProducts(string defaultUserEmail) { DownloadGuid = Guid.NewGuid(), ContentType = MimeTypes.ApplicationXZipCo, - DownloadBinary = File.ReadAllBytes(sampleDownloadsPath + "product_ScienceAndFaith_1.zip"), + DownloadBinary = _fileProvider.ReadAllBytes(sampleDownloadsPath + "product_ScienceAndFaith_1.zip"), Extension = ".zip", Filename = "Science_And_Faith", IsNew = true, @@ -9717,7 +9720,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productScienceAndFaith); productScienceAndFaith.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_ScienceAndFaith.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productScienceAndFaith.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_ScienceAndFaith.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productScienceAndFaith.Name)), DisplayOrder = 1, }); _productRepository.Insert(productScienceAndFaith); @@ -9770,7 +9773,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productFahrenheit); productFahrenheit.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_Fahrenheit451.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productFahrenheit.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_Fahrenheit451.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productFahrenheit.Name)), DisplayOrder = 1, }); _productRepository.Insert(productFahrenheit); @@ -9818,7 +9821,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productFirstPrizePies); productFirstPrizePies.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_FirstPrizePies.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productFirstPrizePies.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_FirstPrizePies.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productFirstPrizePies.Name)), DisplayOrder = 1, }); _productRepository.Insert(productFirstPrizePies); @@ -9866,7 +9869,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productPrideAndPrejudice); productPrideAndPrejudice.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_PrideAndPrejudice.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productPrideAndPrejudice.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_PrideAndPrejudice.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(productPrideAndPrejudice.Name)), DisplayOrder = 1, }); _productRepository.Insert(productPrideAndPrejudice); @@ -9921,7 +9924,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productElegantGemstoneNecklace); productElegantGemstoneNecklace.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_GemstoneNecklaces.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productElegantGemstoneNecklace.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_GemstoneNecklaces.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productElegantGemstoneNecklace.Name)), DisplayOrder = 1, }); _productRepository.Insert(productElegantGemstoneNecklace); @@ -9969,7 +9972,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productFlowerGirlBracelet); productFlowerGirlBracelet.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_FlowerBracelet.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productFlowerGirlBracelet.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_FlowerBracelet.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productFlowerGirlBracelet.Name)), DisplayOrder = 1, }); _productRepository.Insert(productFlowerGirlBracelet); @@ -10016,7 +10019,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(productEngagementRing); productEngagementRing.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_EngagementRing_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productEngagementRing.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_EngagementRing_1.jpg"), MimeTypes.ImagePJpeg, pictureService.GetPictureSeName(productEngagementRing.Name)), DisplayOrder = 1, }); _productRepository.Insert(productEngagementRing); @@ -10061,7 +10064,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(product25GiftCard); product25GiftCard.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_25giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product25GiftCard.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_25giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product25GiftCard.Name)), DisplayOrder = 1, }); _productRepository.Insert(product25GiftCard); @@ -10109,7 +10112,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(product50GiftCard); product50GiftCard.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_50giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product50GiftCard.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_50giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product50GiftCard.Name)), DisplayOrder = 1, }); _productRepository.Insert(product50GiftCard); @@ -10155,7 +10158,7 @@ protected virtual void InstallProducts(string defaultUserEmail) allProducts.Add(product100GiftCard); product100GiftCard.ProductPictures.Add(new ProductPicture { - Picture = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "product_100giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product100GiftCard.Name)), + Picture = pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "product_100giftcart.jpeg"), MimeTypes.ImageJpeg, pictureService.GetPictureSeName(product100GiftCard.Name)), DisplayOrder = 1, }); _productRepository.Insert(product100GiftCard); diff --git a/src/Libraries/Nop.Services/Installation/SqlFileInstallationService.cs b/src/Libraries/Nop.Services/Installation/SqlFileInstallationService.cs index 9ab1f1ccf9d..9f6648b86b4 100644 --- a/src/Libraries/Nop.Services/Installation/SqlFileInstallationService.cs +++ b/src/Libraries/Nop.Services/Installation/SqlFileInstallationService.cs @@ -27,6 +27,7 @@ public partial class SqlFileInstallationService : IInstallationService private readonly IRepository _storeRepository; private readonly IDbContext _dbContext; private readonly IWebHelper _webHelper; + private readonly INopFileProvider _fileProvider; #endregion @@ -40,17 +41,20 @@ public partial class SqlFileInstallationService : IInstallationService /// Store repository /// DB context /// Web helper + /// File provider public SqlFileInstallationService(IRepository languageRepository, IRepository customerRepository, IRepository storeRepository, IDbContext dbContext, - IWebHelper webHelper) + IWebHelper webHelper, + INopFileProvider fileProvider) { this._languageRepository = languageRepository; this._customerRepository = customerRepository; this._storeRepository = storeRepository; this._dbContext = dbContext; this._webHelper = webHelper; + this._fileProvider = fileProvider; } #endregion @@ -66,9 +70,9 @@ protected virtual void InstallLocaleResources() var language = _languageRepository.Table.Single(l => l.Name == "English"); //save resources - foreach (var filePath in System.IO.Directory.EnumerateFiles(CommonHelper.MapPath("~/App_Data/Localization/"), "*.nopres.xml", SearchOption.TopDirectoryOnly)) + foreach (var filePath in _fileProvider.EnumerateFiles(_fileProvider.MapPath("~/App_Data/Localization/"), "*.nopres.xml")) { - var localesXml = File.ReadAllText(filePath); + var localesXml = _fileProvider.ReadAllText(filePath, Encoding.UTF8); var localizationService = EngineContext.Current.Resolve(); localizationService.ImportResourcesFromXml(language, localesXml); } @@ -115,9 +119,8 @@ protected virtual void UpdateDefaultStoreUrl() protected virtual void ExecuteSqlFile(string path) { var statements = new List(); - - using (var stream = File.OpenRead(path)) - using (var reader = new StreamReader(stream)) + + using (var reader = new StreamReader(path)) { string statement; while ((statement = ReadNextStatementFromStream(reader)) != null) @@ -169,14 +172,14 @@ protected virtual string ReadNextStatementFromStream(StreamReader reader) public virtual void InstallData(string defaultUserEmail, string defaultUserPassword, bool installSampleData = true) { - ExecuteSqlFile(CommonHelper.MapPath("~/App_Data/Install/Fast/create_required_data.sql")); + ExecuteSqlFile(_fileProvider.MapPath("~/App_Data/Install/Fast/create_required_data.sql")); InstallLocaleResources(); UpdateDefaultCustomer(defaultUserEmail, defaultUserPassword); UpdateDefaultStoreUrl(); if (installSampleData) { - ExecuteSqlFile(CommonHelper.MapPath("~/App_Data/Install/Fast/create_sample_data.sql")); + ExecuteSqlFile(_fileProvider.MapPath("~/App_Data/Install/Fast/create_sample_data.sql")); } } diff --git a/src/Libraries/Nop.Services/Media/AzurePictureService.cs b/src/Libraries/Nop.Services/Media/AzurePictureService.cs index 13dea78ce21..ffc44b8ff61 100644 --- a/src/Libraries/Nop.Services/Media/AzurePictureService.cs +++ b/src/Libraries/Nop.Services/Media/AzurePictureService.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using Nop.Core; @@ -10,6 +9,7 @@ using Nop.Core.Data; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Media; +using Nop.Core.Infrastructure; using Nop.Data; using Nop.Services.Configuration; using Nop.Services.Events; @@ -64,7 +64,7 @@ public partial class AzurePictureService : PictureService /// Media settings /// Config /// Data provider - /// Hosting environment + /// File provider public AzurePictureService(IRepository pictureRepository, IRepository productPictureRepository, ISettingService settingService, @@ -76,7 +76,7 @@ public AzurePictureService(IRepository pictureRepository, MediaSettings mediaSettings, NopConfig config, IDataProvider dataProvider, - IHostingEnvironment hostingEnvironment) + INopFileProvider fileProvider) : base(pictureRepository, productPictureRepository, settingService, @@ -86,7 +86,7 @@ public AzurePictureService(IRepository pictureRepository, eventPublisher, mediaSettings, dataProvider, - hostingEnvironment) + fileProvider) { this._cacheManager = cacheManager; this._mediaSettings = mediaSettings; diff --git a/src/Libraries/Nop.Services/Media/PictureService.cs b/src/Libraries/Nop.Services/Media/PictureService.cs index ca80c45dc8a..a7197d714ff 100644 --- a/src/Libraries/Nop.Services/Media/PictureService.cs +++ b/src/Libraries/Nop.Services/Media/PictureService.cs @@ -5,11 +5,11 @@ using System.Linq; using System.Threading; using ImageResizer; -using Microsoft.AspNetCore.Hosting; using Nop.Core; using Nop.Core.Data; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Media; +using Nop.Core.Infrastructure; using Nop.Data; using Nop.Services.Configuration; using Nop.Services.Events; @@ -26,6 +26,7 @@ public partial class PictureService : IPictureService #region Const private const int MULTIPLE_THUMB_DIRECTORIES_LENGTH = 3; + private const string THUMBS_PATH = @"images\thumbs"; #endregion @@ -40,7 +41,7 @@ public partial class PictureService : IPictureService private readonly IEventPublisher _eventPublisher; private readonly MediaSettings _mediaSettings; private readonly IDataProvider _dataProvider; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly INopFileProvider _fileProvider; #endregion @@ -58,7 +59,7 @@ public partial class PictureService : IPictureService /// Event publisher /// Media settings /// Data provider - /// Hosting environment + /// File provider public PictureService(IRepository pictureRepository, IRepository productPictureRepository, ISettingService settingService, @@ -68,7 +69,7 @@ public PictureService(IRepository pictureRepository, IEventPublisher eventPublisher, MediaSettings mediaSettings, IDataProvider dataProvider, - IHostingEnvironment hostingEnvironment) + INopFileProvider fileProvider) { this._pictureRepository = pictureRepository; this._productPictureRepository = productPictureRepository; @@ -79,7 +80,7 @@ public PictureService(IRepository pictureRepository, this._eventPublisher = eventPublisher; this._mediaSettings = mediaSettings; this._dataProvider = dataProvider; - this._hostingEnvironment = hostingEnvironment; + this._fileProvider = fileProvider; } #endregion @@ -179,9 +180,8 @@ protected virtual byte[] LoadPictureFromFile(int pictureId, string mimeType) var lastPart = GetFileExtensionFromMimeType(mimeType); var fileName = $"{pictureId:0000000}_0.{lastPart}"; var filePath = GetPictureLocalPath(fileName); - if (!File.Exists(filePath)) - return new byte[0]; - return File.ReadAllBytes(filePath); + + return _fileProvider.ReadAllBytes(filePath); } /// @@ -194,7 +194,7 @@ protected virtual void SavePictureInFile(int pictureId, byte[] pictureBinary, st { var lastPart = GetFileExtensionFromMimeType(mimeType); var fileName = $"{pictureId:0000000}_0.{lastPart}"; - File.WriteAllBytes(GetPictureLocalPath(fileName), pictureBinary); + _fileProvider.WriteAllBytes(GetPictureLocalPath(fileName), pictureBinary); } /// @@ -209,10 +209,7 @@ protected virtual void DeletePictureOnFileSystem(Picture picture) var lastPart = GetFileExtensionFromMimeType(picture.MimeType); var fileName = $"{picture.Id:0000000}_0.{lastPart}"; var filePath = GetPictureLocalPath(fileName); - if (File.Exists(filePath)) - { - File.Delete(filePath); - } + _fileProvider.DeleteFile(filePath); } /// @@ -222,12 +219,11 @@ protected virtual void DeletePictureOnFileSystem(Picture picture) protected virtual void DeletePictureThumbs(Picture picture) { var filter = $"{picture.Id:0000000}*.*"; - var thumbDirectoryPath = Path.Combine(_hostingEnvironment.WebRootPath, "images\\thumbs"); - var currentFiles = System.IO.Directory.GetFiles(thumbDirectoryPath, filter, SearchOption.AllDirectories); + var currentFiles = _fileProvider.GetFiles(_fileProvider.GetAbsolutePath(THUMBS_PATH), filter, false); foreach (var currentFileName in currentFiles) { var thumbFilePath = GetThumbLocalPath(currentFileName); - File.Delete(thumbFilePath); + _fileProvider.DeleteFile(thumbFilePath); } } @@ -238,22 +234,21 @@ protected virtual void DeletePictureThumbs(Picture picture) /// Local picture thumb path protected virtual string GetThumbLocalPath(string thumbFileName) { - var thumbsDirectoryPath = Path.Combine(_hostingEnvironment.WebRootPath, "images\\thumbs"); + var thumbsDirectoryPath = _fileProvider.GetAbsolutePath(THUMBS_PATH); + if (_mediaSettings.MultipleThumbDirectories) { //get the first two letters of the file name - var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(thumbFileName); + var fileNameWithoutExtension = _fileProvider.GetFileNameWithoutExtension(thumbFileName); if (fileNameWithoutExtension != null && fileNameWithoutExtension.Length > MULTIPLE_THUMB_DIRECTORIES_LENGTH) { var subDirectoryName = fileNameWithoutExtension.Substring(0, MULTIPLE_THUMB_DIRECTORIES_LENGTH); - thumbsDirectoryPath = Path.Combine(thumbsDirectoryPath, subDirectoryName); - if (!System.IO.Directory.Exists(thumbsDirectoryPath)) - { - System.IO.Directory.CreateDirectory(thumbsDirectoryPath); - } + thumbsDirectoryPath = _fileProvider.GetAbsolutePath(THUMBS_PATH, subDirectoryName); + _fileProvider.CreateDirectory(thumbsDirectoryPath); } } - var thumbFilePath = Path.Combine(thumbsDirectoryPath, thumbFileName); + + var thumbFilePath = _fileProvider.Combine(thumbsDirectoryPath, thumbFileName); return thumbFilePath; } @@ -273,7 +268,7 @@ protected virtual string GetThumbUrl(string thumbFileName, string storeLocation if (_mediaSettings.MultipleThumbDirectories) { //get the first two letters of the file name - var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(thumbFileName); + var fileNameWithoutExtension = _fileProvider.GetFileNameWithoutExtension(thumbFileName); if (fileNameWithoutExtension != null && fileNameWithoutExtension.Length > MULTIPLE_THUMB_DIRECTORIES_LENGTH) { var subDirectoryName = fileNameWithoutExtension.Substring(0, MULTIPLE_THUMB_DIRECTORIES_LENGTH); @@ -292,7 +287,7 @@ protected virtual string GetThumbUrl(string thumbFileName, string storeLocation /// Local picture path protected virtual string GetPictureLocalPath(string fileName) { - return Path.Combine(_hostingEnvironment.WebRootPath, "images", fileName); + return _fileProvider.GetAbsolutePath("images", fileName); } /// @@ -320,7 +315,7 @@ protected virtual byte[] LoadPictureBinary(Picture picture, bool fromDb) /// Result protected virtual bool GeneratedThumbExists(string thumbFilePath, string thumbFileName) { - return File.Exists(thumbFilePath); + return _fileProvider.FileExists(thumbFilePath); } /// @@ -333,12 +328,11 @@ protected virtual bool GeneratedThumbExists(string thumbFilePath, string thumbFi protected virtual void SaveThumb(string thumbFilePath, string thumbFileName, string mimeType, byte[] binary) { //ensure \thumb directory exists - var thumbsDirectoryPath = Path.Combine(_hostingEnvironment.WebRootPath, "images\\thumbs"); - if (!System.IO.Directory.Exists(thumbsDirectoryPath)) - System.IO.Directory.CreateDirectory(thumbsDirectoryPath); + var thumbsDirectoryPath = _fileProvider.GetAbsolutePath(THUMBS_PATH); + _fileProvider.CreateDirectory(thumbsDirectoryPath); //save - File.WriteAllBytes(thumbFilePath, binary); + _fileProvider.WriteAllBytes(thumbFilePath, binary); } #endregion @@ -388,7 +382,7 @@ public virtual string GetDefaultPictureUrl(int targetSize = 0, break; } var filePath = GetPictureLocalPath(defaultImageFileName); - if (!File.Exists(filePath)) + if (!_fileProvider.FileExists(filePath)) { return ""; } @@ -404,8 +398,8 @@ public virtual string GetDefaultPictureUrl(int targetSize = 0, } else { - var fileExtension = Path.GetExtension(filePath); - var thumbFileName = $"{Path.GetFileNameWithoutExtension(filePath)}_{targetSize}{fileExtension}"; + var fileExtension =_fileProvider.GetFileExtension(filePath); + var thumbFileName = $"{_fileProvider.GetFileNameWithoutExtension(filePath)}_{targetSize}{fileExtension}"; var thumbFilePath = GetThumbLocalPath(thumbFileName); if (!GeneratedThumbExists(thumbFilePath, thumbFileName)) { @@ -527,9 +521,9 @@ public virtual string GetPictureUrl(Picture picture, //resizing required if (targetSize != 0) { + Bitmap b = null; using (var stream = new MemoryStream(pictureBinary)) { - Bitmap b = null; try { //try-catch to ensure that picture binary is really OK. Otherwise, we can get "Parameter is not valid" exception if binary is corrupted for some reasons @@ -537,29 +531,28 @@ public virtual string GetPictureUrl(Picture picture, } catch (ArgumentException exc) { - _logger.Error($"Error generating picture thumb. ID={picture.Id}", - exc); + _logger.Error($"Error generating picture thumb. ID={picture.Id}", exc); } + } - if (b == null) - { - //bitmap could not be loaded for some reasons - return url; - } + if (b == null) + { + //bitmap could not be loaded for some reasons + return url; + } - using (var destStream = new MemoryStream()) + using (var destStream = new MemoryStream()) + { + var newSize = CalculateDimensions(b.Size, targetSize); + ImageBuilder.Current.Build(b, destStream, new ResizeSettings { - var newSize = CalculateDimensions(b.Size, targetSize); - ImageBuilder.Current.Build(b, destStream, new ResizeSettings - { - Width = newSize.Width, - Height = newSize.Height, - Scale = ScaleMode.Both, - Quality = _mediaSettings.DefaultImageQuality - }); - pictureBinaryResized = destStream.ToArray(); - b.Dispose(); - } + Width = newSize.Width, + Height = newSize.Height, + Scale = ScaleMode.Both, + Quality = _mediaSettings.DefaultImageQuality + }); + pictureBinaryResized = destStream.ToArray(); + b.Dispose(); } } else @@ -592,7 +585,7 @@ public virtual string GetThumbLocalPath(Picture picture, int targetSize = 0, boo if (string.IsNullOrEmpty(url)) return string.Empty; - return GetThumbLocalPath(Path.GetFileName(url)); + return GetThumbLocalPath(_fileProvider.GetFileName(url)); } #endregion diff --git a/src/Libraries/Nop.Services/Messages/EmailSender.cs b/src/Libraries/Nop.Services/Messages/EmailSender.cs index 0c9394c9bff..687ff6c1b81 100644 --- a/src/Libraries/Nop.Services/Messages/EmailSender.cs +++ b/src/Libraries/Nop.Services/Messages/EmailSender.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Mail; using Nop.Core.Domain.Messages; +using Nop.Core.Infrastructure; using Nop.Services.Media; namespace Nop.Services.Messages @@ -15,14 +16,18 @@ namespace Nop.Services.Messages public partial class EmailSender : IEmailSender { private readonly IDownloadService _downloadService; + private readonly INopFileProvider _fileProvider; /// /// Ctor /// /// Download service - public EmailSender(IDownloadService downloadService) + /// File provider + public EmailSender(IDownloadService downloadService, + INopFileProvider fileProvider) { this._downloadService = downloadService; + this._fileProvider = fileProvider; } /// @@ -93,12 +98,12 @@ public virtual void SendEmail(EmailAccount emailAccount, string subject, string //create the file attachment for this e-mail message if (!string.IsNullOrEmpty(attachmentFilePath) && - File.Exists(attachmentFilePath)) + _fileProvider.FileExists(attachmentFilePath)) { var attachment = new Attachment(attachmentFilePath); - attachment.ContentDisposition.CreationDate = File.GetCreationTime(attachmentFilePath); - attachment.ContentDisposition.ModificationDate = File.GetLastWriteTime(attachmentFilePath); - attachment.ContentDisposition.ReadDate = File.GetLastAccessTime(attachmentFilePath); + attachment.ContentDisposition.CreationDate = _fileProvider.GetCreationTime(attachmentFilePath); + attachment.ContentDisposition.ModificationDate = _fileProvider.GetLastWriteTime(attachmentFilePath); + attachment.ContentDisposition.ReadDate = _fileProvider.GetLastAccessTime(attachmentFilePath); if (!string.IsNullOrEmpty(attachmentFileName)) { attachment.Name = attachmentFileName; diff --git a/src/Libraries/Nop.Services/Plugins/UploadService.cs b/src/Libraries/Nop.Services/Plugins/UploadService.cs index d764701fa9b..53f4bf41c74 100644 --- a/src/Libraries/Nop.Services/Plugins/UploadService.cs +++ b/src/Libraries/Nop.Services/Plugins/UploadService.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; using Nop.Services.Themes; @@ -21,14 +22,17 @@ public class UploadService : IUploadService #region Fields protected readonly IThemeProvider _themeProvider; + protected readonly INopFileProvider _fileProvider; #endregion #region Ctor - public UploadService(IThemeProvider themeProvider) + public UploadService(IThemeProvider themeProvider, + INopFileProvider fileProvider) { this._themeProvider = themeProvider; + this._fileProvider = fileProvider; } #endregion @@ -47,7 +51,7 @@ protected virtual IList GetUploadedItems(string archivePath) //try to get the entry containing information about the uploaded items var uploadedItemsFileEntry = archive.Entries .FirstOrDefault(entry => entry.Name.Equals(UploadedItemsFileName, StringComparison.InvariantCultureIgnoreCase) - && string.IsNullOrEmpty(Path.GetDirectoryName(entry.FullName))); + && string.IsNullOrEmpty(_fileProvider.GetDirectoryName(entry.FullName))); if (uploadedItemsFileEntry == null) return null; @@ -66,12 +70,12 @@ protected virtual IList GetUploadedItems(string archivePath) protected virtual IDescriptor UploadSingleItem(string archivePath) { //get path to the plugins directory - var pluginsDirectory = CommonHelper.MapPath(PluginManager.PluginsPath); + var pluginsDirectory = _fileProvider.MapPath(PluginManager.PluginsPath); //get path to the themes directory var themesDirectory = string.Empty; if (!string.IsNullOrEmpty(_themeProvider.ThemesPath)) - themesDirectory = CommonHelper.MapPath(_themeProvider.ThemesPath); + themesDirectory = _fileProvider.MapPath(_themeProvider.ThemesPath); IDescriptor descriptor = null; var uploadedItemDirectoryName = string.Empty; @@ -135,13 +139,13 @@ protected virtual IDescriptor UploadSingleItem(string archivePath) //get path to upload var directoryPath = descriptor is PluginDescriptor ? pluginsDirectory : themesDirectory; - var pathToUpload = Path.Combine(directoryPath, uploadedItemDirectoryName); + var pathToUpload = _fileProvider.Combine(directoryPath, uploadedItemDirectoryName); //ensure it's a new directory (e.g. some old files are not required when re-uploading a plugin) //furthermore, zip extract functionality cannot override existing files //but there could deletion issues (related to file locking, etc). In such cases the directory should be deleted manually - if (System.IO.Directory.Exists(pathToUpload)) - CommonHelper.DeleteDirectory(pathToUpload); + if (_fileProvider.DirectoryExists(pathToUpload)) + _fileProvider.DeleteDirectory(pathToUpload); //unzip archive ZipFile.ExtractToDirectory(archivePath, directoryPath); @@ -158,12 +162,12 @@ protected virtual IDescriptor UploadSingleItem(string archivePath) protected virtual IList UploadMultipleItems(string archivePath, IList uploadedItems) { //get path to the plugins directory - var pluginsDirectory = CommonHelper.MapPath(PluginManager.PluginsPath); + var pluginsDirectory = _fileProvider.MapPath(PluginManager.PluginsPath); //get path to the themes directory var themesDirectory = string.Empty; if (!string.IsNullOrEmpty(_themeProvider.ThemesPath)) - themesDirectory = CommonHelper.MapPath(_themeProvider.ThemesPath); + themesDirectory = _fileProvider.MapPath(_themeProvider.ThemesPath); //get descriptors of items contained in the archive var descriptors = new List(); @@ -217,14 +221,14 @@ protected virtual IList UploadMultipleItems(string archivePath, ILi continue; //get path to upload - var uploadedItemDirectoryName = Path.GetFileName(itemPath.TrimEnd('/')); - var pathToUpload = Path.Combine(item.Type == UploadedItemType.Plugin ? pluginsDirectory : themesDirectory, uploadedItemDirectoryName); + var uploadedItemDirectoryName = _fileProvider.GetFileName(itemPath.TrimEnd('/')); + var pathToUpload = _fileProvider.Combine(item.Type == UploadedItemType.Plugin ? pluginsDirectory : themesDirectory, uploadedItemDirectoryName); //ensure it's a new directory (e.g. some old files are not required when re-uploading a plugin or a theme) //furthermore, zip extract functionality cannot override existing files //but there could deletion issues (related to file locking, etc). In such cases the directory should be deleted manually - if (System.IO.Directory.Exists(pathToUpload)) - CommonHelper.DeleteDirectory(pathToUpload); + if (_fileProvider.DirectoryExists(pathToUpload)) + _fileProvider.DeleteDirectory(pathToUpload); //unzip entries into files var entries = archive.Entries.Where(entry => entry.FullName.StartsWith(itemPath, StringComparison.InvariantCultureIgnoreCase)); @@ -235,12 +239,12 @@ protected virtual IList UploadMultipleItems(string archivePath, ILi if (string.IsNullOrEmpty(fileName)) continue; - var filePath = Path.Combine(pathToUpload, fileName.Replace("/", "\\")); - var directoryPath = Path.GetDirectoryName(filePath); + var filePath = _fileProvider.Combine(pathToUpload, fileName.Replace("/", "\\")); + var directoryPath = _fileProvider.GetDirectoryName(filePath); //whether the file directory is already exists, otherwise create the new one - if (!System.IO.Directory.Exists(directoryPath)) - System.IO.Directory.CreateDirectory(directoryPath); + if (!_fileProvider.DirectoryExists(directoryPath)) + _fileProvider.CreateDirectory(directoryPath); //unzip entry to the file (ignore directory entries) if (!filePath.Equals($"{directoryPath}\\", StringComparison.InvariantCultureIgnoreCase)) @@ -274,15 +278,15 @@ public virtual IList UploadPluginsAndThemes(IFormFile archivefile) try { //only zip archives are supported - if (!Path.GetExtension(archivefile.FileName)?.Equals(".zip", StringComparison.InvariantCultureIgnoreCase) ?? true) + if (!_fileProvider.GetFileExtension(archivefile.FileName)?.Equals(".zip", StringComparison.InvariantCultureIgnoreCase) ?? true) throw new Exception("Only zip archives are supported"); //ensure that temp directory is created - var tempDirectory = CommonHelper.MapPath(UploadsTempPath); - System.IO.Directory.CreateDirectory(new DirectoryInfo(tempDirectory).FullName); + var tempDirectory = _fileProvider.MapPath(UploadsTempPath); + _fileProvider.CreateDirectory(tempDirectory); //copy original archive to the temp directory - zipFilePath = Path.Combine(tempDirectory, archivefile.FileName); + zipFilePath = _fileProvider.Combine(tempDirectory, archivefile.FileName); using (var fileStream = new FileStream(zipFilePath, FileMode.Create)) archivefile.CopyTo(fileStream); @@ -301,7 +305,7 @@ public virtual IList UploadPluginsAndThemes(IFormFile archivefile) { //delete temporary file if (!string.IsNullOrEmpty(zipFilePath)) - File.Delete(zipFilePath); + _fileProvider.DeleteFile(zipFilePath); } return descriptors; diff --git a/src/Libraries/Nop.Services/Seo/SitemapGenerator.cs b/src/Libraries/Nop.Services/Seo/SitemapGenerator.cs index cbcddf3d49e..cbd75d6733e 100644 --- a/src/Libraries/Nop.Services/Seo/SitemapGenerator.cs +++ b/src/Libraries/Nop.Services/Seo/SitemapGenerator.cs @@ -27,12 +27,12 @@ public partial class SitemapGenerator : ISitemapGenerator { #region Constants - private const string DateFormat = @"yyyy-MM-dd"; + private const string DATE_FORMAT = @"yyyy-MM-dd"; /// /// At now each provided sitemap file must have no more than 50000 URLs /// - private const int maxSitemapUrlNumber = 50000; + private const int MAX_SITEMAP_URL_NUMBER = 50000; #endregion @@ -340,7 +340,7 @@ protected virtual void WriteSitemapIndex(Stream stream, int sitemapNumber) writer.WriteStartElement("sitemap"); writer.WriteElementString("loc", location); - writer.WriteElementString("lastmod", DateTime.UtcNow.ToString(DateFormat)); + writer.WriteElementString("lastmod", DateTime.UtcNow.ToString(DATE_FORMAT)); writer.WriteEndElement(); } @@ -355,7 +355,6 @@ protected virtual void WriteSitemapIndex(Stream stream, int sitemapNumber) /// List of sitemap URLs protected virtual void WriteSitemap(Stream stream, IList sitemapUrls) { - var urlHelper = GetUrlHelper(); using (var writer = new XmlTextWriter(stream, Encoding.UTF8)) { writer.Formatting = Formatting.Indented; @@ -373,7 +372,7 @@ protected virtual void WriteSitemap(Stream stream, IList sitemapUrls writer.WriteElementString("loc", location); writer.WriteElementString("changefreq", url.UpdateFrequency.ToString().ToLowerInvariant()); - writer.WriteElementString("lastmod", url.UpdatedOn.ToString(DateFormat, CultureInfo.InvariantCulture)); + writer.WriteElementString("lastmod", url.UpdatedOn.ToString(DATE_FORMAT, CultureInfo.InvariantCulture)); writer.WriteEndElement(); } @@ -413,7 +412,7 @@ public virtual void Generate(Stream stream, int? id) //split URLs into separate lists based on the max size var sitemaps = sitemapUrls.Select((url, index) => new { Index = index, Value = url }) - .GroupBy(group => group.Index / maxSitemapUrlNumber).Select(group => group.Select(url => url.Value).ToList()).ToList(); + .GroupBy(group => group.Index / MAX_SITEMAP_URL_NUMBER).Select(group => group.Select(url => url.Value).ToList()).ToList(); if (!sitemaps.Any()) return; @@ -431,7 +430,7 @@ public virtual void Generate(Stream stream, int? id) else { //URLs more than the maximum allowable, so generate a sitemap index file - if (sitemapUrls.Count >= maxSitemapUrlNumber) + if (sitemapUrls.Count >= MAX_SITEMAP_URL_NUMBER) { //write a sitemap index file into the stream WriteSitemapIndex(stream, sitemaps.Count); diff --git a/src/Libraries/Nop.Services/Themes/ThemeProvider.cs b/src/Libraries/Nop.Services/Themes/ThemeProvider.cs index 3878ac9f95e..7c5019f0e6e 100644 --- a/src/Libraries/Nop.Services/Themes/ThemeProvider.cs +++ b/src/Libraries/Nop.Services/Themes/ThemeProvider.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using System.Text; using Newtonsoft.Json; -using Nop.Core; +using Nop.Core.Infrastructure; namespace Nop.Services.Themes { @@ -15,9 +15,15 @@ public partial class ThemeProvider : IThemeProvider #region Fields private IList _themeDescriptors; + private readonly INopFileProvider _fileProvider; #endregion + public ThemeProvider(INopFileProvider fileProvider) + { + this._fileProvider = fileProvider; + } + #region Methods /// /// Get theme descriptor from the description text @@ -42,26 +48,26 @@ public ThemeDescriptor GetThemeDescriptorFromText(string text) /// List of the theme descriptor public IList GetThemes() { - if (_themeDescriptors == null) + if (_themeDescriptors != null) + return _themeDescriptors; + + //load all theme descriptors + _themeDescriptors = new List(); + + foreach (var descriptionFile in _fileProvider.GetFiles(_fileProvider.MapPath(ThemesPath), ThemeDescriptionFileName, false)) { - //load all theme descriptors - var themeFolder = new DirectoryInfo(CommonHelper.MapPath(ThemesPath)); - _themeDescriptors = new List(); - foreach (var descriptionFile in themeFolder.GetFiles(ThemeDescriptionFileName, SearchOption.AllDirectories)) - { - var text = File.ReadAllText(descriptionFile.FullName); - if (string.IsNullOrEmpty(text)) - continue; - - //get theme descriptor - var themeDescriptor = GetThemeDescriptorFromText(text); - - //some validation - if (string.IsNullOrEmpty(themeDescriptor?.SystemName)) - throw new Exception($"A theme descriptor '{descriptionFile.FullName}' has no system name"); - - _themeDescriptors.Add(themeDescriptor); - } + var text = _fileProvider.ReadAllText(descriptionFile, Encoding.UTF8); + if (string.IsNullOrEmpty(text)) + continue; + + //get theme descriptor + var themeDescriptor = GetThemeDescriptorFromText(text); + + //some validation + if (string.IsNullOrEmpty(themeDescriptor?.SystemName)) + throw new Exception($"A theme descriptor '{descriptionFile}' has no system name"); + + _themeDescriptors.Add(themeDescriptor); } return _themeDescriptors; diff --git a/src/Plugins/Nop.Plugin.Widgets.NivoSlider/NivoSliderPlugin.cs b/src/Plugins/Nop.Plugin.Widgets.NivoSlider/NivoSliderPlugin.cs index 7f2ef0c89b7..1d49f42d9a8 100644 --- a/src/Plugins/Nop.Plugin.Widgets.NivoSlider/NivoSliderPlugin.cs +++ b/src/Plugins/Nop.Plugin.Widgets.NivoSlider/NivoSliderPlugin.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using System.IO; using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; using Nop.Services.Cms; using Nop.Services.Configuration; @@ -18,13 +18,15 @@ public class NivoSliderPlugin : BasePlugin, IWidgetPlugin private readonly IPictureService _pictureService; private readonly ISettingService _settingService; private readonly IWebHelper _webHelper; + private readonly INopFileProvider _fileProvider; public NivoSliderPlugin(IPictureService pictureService, - ISettingService settingService, IWebHelper webHelper) + ISettingService settingService, IWebHelper webHelper, INopFileProvider fileProvider) { this._pictureService = pictureService; this._settingService = settingService; this._webHelper = webHelper; + this._fileProvider = fileProvider; } /// @@ -60,17 +62,17 @@ public string GetWidgetViewComponentName(string widgetZone) public override void Install() { //pictures - var sampleImagesPath = CommonHelper.MapPath("~/Plugins/Widgets.NivoSlider/Content/nivoslider/sample-images/"); + var sampleImagesPath = _fileProvider.MapPath("~/Plugins/Widgets.NivoSlider/Content/nivoslider/sample-images/"); //settings var settings = new NivoSliderSettings { - Picture1Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner1.jpg"), MimeTypes.ImagePJpeg, "banner_1").Id, + Picture1Id = _pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "banner1.jpg"), MimeTypes.ImagePJpeg, "banner_1").Id, Text1 = "", Link1 = _webHelper.GetStoreLocation(false), - Picture2Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner2.jpg"), MimeTypes.ImagePJpeg, "banner_2").Id, + Picture2Id = _pictureService.InsertPicture(_fileProvider.ReadAllBytes(sampleImagesPath + "banner2.jpg"), MimeTypes.ImagePJpeg, "banner_2").Id, Text2 = "", - Link2 = _webHelper.GetStoreLocation(false), + Link2 = _webHelper.GetStoreLocation(false) //Picture3Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner3.jpg"), MimeTypes.ImagePJpeg, "banner_3").Id, //Text3 = "", //Link3 = _webHelper.GetStoreLocation(false), diff --git a/src/Plugins/Nop.Plugin.Widgets.NivoSlider/plugin.json b/src/Plugins/Nop.Plugin.Widgets.NivoSlider/plugin.json index 385424a1531..63406836e42 100644 --- a/src/Plugins/Nop.Plugin.Widgets.NivoSlider/plugin.json +++ b/src/Plugins/Nop.Plugin.Widgets.NivoSlider/plugin.json @@ -2,7 +2,7 @@ "Group": "Widgets", "FriendlyName": "Nivo Slider", "SystemName": "Widgets.NivoSlider", - "Version": "1.28", + "Version": "1.29", "SupportedVersions": [ "4.10" ], "Author": "nopCommerce team", "DisplayOrder": 1, diff --git a/src/Presentation/Nop.Web.Framework/Infrastructure/DependencyRegistrar.cs b/src/Presentation/Nop.Web.Framework/Infrastructure/DependencyRegistrar.cs index a674bbd1bfd..953b75a226d 100644 --- a/src/Presentation/Nop.Web.Framework/Infrastructure/DependencyRegistrar.cs +++ b/src/Presentation/Nop.Web.Framework/Infrastructure/DependencyRegistrar.cs @@ -68,6 +68,9 @@ public class DependencyRegistrar : IDependencyRegistrar /// Config public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config) { + //file provider + builder.RegisterType().As().InstancePerLifetimeScope(); + //web helper builder.RegisterType().As().InstancePerLifetimeScope(); @@ -81,7 +84,7 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, N builder.Register(x => new EfDataProviderManager(x.Resolve())).As().InstancePerDependency(); builder.Register(x => x.Resolve().LoadDataProvider()).As().InstancePerDependency(); - + if (dataProviderSettings != null && dataProviderSettings.IsValid()) { var efDataProviderManager = new EfDataProviderManager(dataSettingsManager.LoadSettings()); diff --git a/src/Presentation/Nop.Web.Framework/Infrastructure/Extensions/ServiceCollectionExtensions.cs b/src/Presentation/Nop.Web.Framework/Infrastructure/Extensions/ServiceCollectionExtensions.cs index b739df0b0e2..787c02004da 100644 --- a/src/Presentation/Nop.Web.Framework/Infrastructure/Extensions/ServiceCollectionExtensions.cs +++ b/src/Presentation/Nop.Web.Framework/Infrastructure/Extensions/ServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Linq; using FluentValidation.AspNetCore; using Microsoft.AspNetCore.DataProtection; @@ -163,17 +162,16 @@ public static void AddNopDataProtection(this IServiceCollection services) if (nopConfig.RedisCachingEnabled && nopConfig.PersistDataProtectionKeysToRedis) { //store keys in Redis - services.AddDataProtection().PersistKeysToRedis( - () => - { - var redisConnectionWrapper = EngineContext.Current.Resolve(); - return redisConnectionWrapper.GetDatabase(); - }, RedisConfiguration.DataProtectionKeysName); + services.AddDataProtection().PersistKeysToRedis(() => + { + var redisConnectionWrapper = EngineContext.Current.Resolve(); + return redisConnectionWrapper.GetDatabase(); + }, RedisConfiguration.DataProtectionKeysName); } else { - var dataProtectionKeysPath = CommonHelper.MapPath("~/App_Data/DataProtectionKeys"); - var dataProtectionKeysFolder = new DirectoryInfo(dataProtectionKeysPath); + var dataProtectionKeysPath = CommonHelper.DefaultFileProvider.MapPath("~/App_Data/DataProtectionKeys"); + var dataProtectionKeysFolder = new System.IO.DirectoryInfo(dataProtectionKeysPath); //configure the data protection system to persist keys to the specified directory services.AddDataProtection().PersistKeysToFileSystem(dataProtectionKeysFolder); @@ -218,7 +216,7 @@ public static void AddNopAuthentication(this IServiceCollection services) options.Cookie.SecurePolicy = DataSettingsHelper.DatabaseIsInstalled() && EngineContext.Current.Resolve().ForceSslForAllPages ? CookieSecurePolicy.SameAsRequest : CookieSecurePolicy.None; }); - + //register and configure external authentication plugins now var typeFinder = new WebAppTypeFinder(); var externalAuthConfigurations = typeFinder.FindClassesOfType(); diff --git a/src/Presentation/Nop.Web.Framework/Infrastructure/NopCommonStartup.cs b/src/Presentation/Nop.Web.Framework/Infrastructure/NopCommonStartup.cs index a69f15eefd6..babe1600cd0 100644 --- a/src/Presentation/Nop.Web.Framework/Infrastructure/NopCommonStartup.cs +++ b/src/Presentation/Nop.Web.Framework/Infrastructure/NopCommonStartup.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Linq; +using System.Linq; using ImageResizer.Configuration; using ImageResizer.Plugins.PrettyGifs; using Microsoft.AspNetCore.Builder; @@ -66,6 +65,7 @@ public void ConfigureServices(IServiceCollection services, IConfigurationRoot co public void Configure(IApplicationBuilder application) { var nopConfig = EngineContext.Current.Resolve(); + var fileProvider = EngineContext.Current.Resolve(); //compression if (nopConfig.UseResponseCompression) @@ -89,7 +89,7 @@ public void Configure(IApplicationBuilder application) //themes application.UseStaticFiles(new StaticFileOptions { - FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"Themes")), + FileProvider = new PhysicalFileProvider(fileProvider.MapPath(@"Themes")), RequestPath = new PathString("/Themes"), OnPrepareResponse = ctx => { @@ -101,7 +101,7 @@ public void Configure(IApplicationBuilder application) //plugins var staticFileOptions = new StaticFileOptions { - FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"Plugins")), + FileProvider = new PhysicalFileProvider(fileProvider.MapPath(@"Plugins")), RequestPath = new PathString("/Plugins"), OnPrepareResponse = ctx => { @@ -133,11 +133,14 @@ public void Configure(IApplicationBuilder application) application.UseStaticFiles(staticFileOptions); //add support for backups - var provider = new FileExtensionContentTypeProvider(); - provider.Mappings[".bak"] = MimeTypes.ApplicationOctetStream; + var provider = new FileExtensionContentTypeProvider + { + Mappings = {[".bak"] = MimeTypes.ApplicationOctetStream} + }; + application.UseStaticFiles(new StaticFileOptions { - FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "db_backups")), + FileProvider = new PhysicalFileProvider(fileProvider.GetAbsolutePath("db_backups")), RequestPath = new PathString("/db_backups"), ContentTypeProvider = provider }); diff --git a/src/Presentation/Nop.Web.Framework/Menu/XmlSiteMap.cs b/src/Presentation/Nop.Web.Framework/Menu/XmlSiteMap.cs index 5a5dad5268e..eed10b076fa 100644 --- a/src/Presentation/Nop.Web.Framework/Menu/XmlSiteMap.cs +++ b/src/Presentation/Nop.Web.Framework/Menu/XmlSiteMap.cs @@ -3,9 +3,9 @@ using System; using System.IO; using System.Linq; +using System.Text; using System.Xml; using Microsoft.AspNetCore.Routing; -using Nop.Core; using Nop.Core.Infrastructure; using Nop.Services.Localization; using Nop.Services.Security; @@ -36,8 +36,10 @@ public XmlSiteMap() /// Filepath to load a sitemap public virtual void LoadFrom(string physicalPath) { - var filePath = CommonHelper.MapPath(physicalPath); - var content = File.ReadAllText(filePath); + var fileProvider = EngineContext.Current.Resolve(); + + var filePath = fileProvider.MapPath(physicalPath); + var content = fileProvider.ReadAllText(filePath, Encoding.UTF8); if (!string.IsNullOrEmpty(content)) { diff --git a/src/Presentation/Nop.Web.Framework/Security/FilePermissionHelper.cs b/src/Presentation/Nop.Web.Framework/Security/FilePermissionHelper.cs index 894455b4bd2..e7da045d7fd 100644 --- a/src/Presentation/Nop.Web.Framework/Security/FilePermissionHelper.cs +++ b/src/Presentation/Nop.Web.Framework/Security/FilePermissionHelper.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; -using System.IO; + using System.Security.AccessControl; using System.Security.Principal; -using Nop.Core; using Nop.Core.Data; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; namespace Nop.Web.Framework.Security @@ -36,7 +36,8 @@ public static bool CheckPermissions(string path, bool checkRead, bool checkWrite AuthorizationRuleCollection rules; try { - rules = Directory.GetAccessControl(path).GetAccessRules(true, true, typeof(SecurityIdentifier)); + var fileProvider = EngineContext.Current.Resolve(); + rules = fileProvider.GetAccessControl(path).GetAccessRules(true, true, typeof(SecurityIdentifier)); } catch { @@ -142,7 +143,7 @@ public static bool CheckPermissions(string path, bool checkRead, bool checkWrite } return flag13; } - catch (IOException) + catch (System.IO.IOException) { } return false; @@ -154,20 +155,25 @@ public static bool CheckPermissions(string path, bool checkRead, bool checkWrite /// Result public static IEnumerable GetDirectoriesWrite() { - var rootDir = CommonHelper.MapPath("~/"); - var dirsToCheck = new List(); - //dirsToCheck.Add(rootDir); - dirsToCheck.Add(Path.Combine(rootDir, "App_Data")); - dirsToCheck.Add(Path.Combine(rootDir, "bin")); - dirsToCheck.Add(Path.Combine(rootDir, "log")); - dirsToCheck.Add(Path.Combine(rootDir, "plugins")); - dirsToCheck.Add(Path.Combine(rootDir, "plugins\\bin")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\bundles")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\db_backups")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\files\\exportimport")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\images")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\images\\thumbs")); - dirsToCheck.Add(Path.Combine(rootDir, "wwwroot\\images\\uploaded")); + var fileProvider = EngineContext.Current.Resolve(); + + var rootDir = fileProvider.MapPath("~/"); + + var dirsToCheck = new List + { + fileProvider.Combine(rootDir, "App_Data"), + fileProvider.Combine(rootDir, "bin"), + fileProvider.Combine(rootDir, "log"), + fileProvider.Combine(rootDir, "plugins"), + fileProvider.Combine(rootDir, "plugins\\bin"), + fileProvider.Combine(rootDir, "wwwroot\\bundles"), + fileProvider.Combine(rootDir, "wwwroot\\db_backups"), + fileProvider.Combine(rootDir, "wwwroot\\files\\exportimport"), + fileProvider.Combine(rootDir, "wwwroot\\images"), + fileProvider.Combine(rootDir, "wwwroot\\images\\thumbs"), + fileProvider.Combine(rootDir, "wwwroot\\images\\uploaded") + }; + return dirsToCheck; } @@ -177,10 +183,12 @@ public static IEnumerable GetDirectoriesWrite() /// Result public static IEnumerable GetFilesWrite() { + var fileProvider = EngineContext.Current.Resolve(); + return new List { - CommonHelper.MapPath(PluginManager.InstalledPluginsFilePath), - CommonHelper.MapPath(DataSettingsManager.DataSettingsFilePath) + fileProvider.MapPath(PluginManager.InstalledPluginsFilePath), + fileProvider.MapPath(DataSettingsManager.DataSettingsFilePath) }; } } diff --git a/src/Presentation/Nop.Web.Framework/UI/PageHeadBuilder.cs b/src/Presentation/Nop.Web.Framework/UI/PageHeadBuilder.cs index 6fb4162f380..7e8e6d92a32 100644 --- a/src/Presentation/Nop.Web.Framework/UI/PageHeadBuilder.cs +++ b/src/Presentation/Nop.Web.Framework/UI/PageHeadBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -12,6 +11,7 @@ using Nop.Core; using Nop.Core.Caching; using Nop.Core.Domain.Seo; +using Nop.Core.Infrastructure; using Nop.Services.Seo; namespace Nop.Web.Framework.UI @@ -28,6 +28,7 @@ public partial class PageHeadBuilder : IPageHeadBuilder private readonly SeoSettings _seoSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IStaticCacheManager _cacheManager; + private readonly INopFileProvider _fileProvider; private BundleFileProcessor _processor; private readonly List _titleParts; @@ -55,13 +56,16 @@ public partial class PageHeadBuilder : IPageHeadBuilder /// SEO settings /// Hosting environment /// Cache manager + /// File provider public PageHeadBuilder(SeoSettings seoSettings, IHostingEnvironment hostingEnvironment, - IStaticCacheManager cacheManager) + IStaticCacheManager cacheManager, + INopFileProvider fileProvider) { this._seoSettings = seoSettings; this._hostingEnvironment = hostingEnvironment; this._cacheManager = cacheManager; + this._fileProvider = fileProvider; this._processor = new BundleFileProcessor(); this._titleParts = new List(); @@ -340,7 +344,7 @@ public virtual string GenerateScripts(IUrlHelper urlHelper, ResourceLocation loc if (partsToBundle.Any()) { //ensure \bundles directory exists - Directory.CreateDirectory(Path.Combine(_hostingEnvironment.WebRootPath, "bundles")); + _fileProvider.CreateDirectory(_fileProvider.GetAbsolutePath("bundles")); var bundle = new Bundle(); foreach (var item in partsToBundle) @@ -350,13 +354,13 @@ public virtual string GenerateScripts(IUrlHelper urlHelper, ResourceLocation loc var src = path.Value.TrimStart('/'); //check whether this file exists, if not it should be stored into /wwwroot directory - if (!File.Exists(Path.Combine(_hostingEnvironment.ContentRootPath, src.Replace("/", "\\")))) + if (!_fileProvider.FileExists(_fileProvider.MapPath(path))) src = $"wwwroot/{src}"; bundle.InputFiles.Add(src); } //output file - var outputFileName = GetBundleFileName(partsToBundle.Select(x => { return debugModel ? x.DebugSrc : x.Src; }).ToArray()); + var outputFileName = GetBundleFileName(partsToBundle.Select(x => debugModel ? x.DebugSrc : x.Src).ToArray()); bundle.OutputFileName = "wwwroot/bundles/" + outputFileName + ".js"; //save var configFilePath = _hostingEnvironment.ContentRootPath + "\\" + outputFileName + ".json"; @@ -367,7 +371,7 @@ public virtual string GenerateScripts(IUrlHelper urlHelper, ResourceLocation loc //we periodically re-check already bundles file //so if we have minification enabled, it could take up to several minutes to see changes in updated resource files (or just reset the cache or restart the site) var cacheKey = $"Nop.minification.shouldrebuild.js-{outputFileName}"; - var shouldRebuild = _cacheManager.Get(cacheKey, RecheckBundledFilesPeriod, () => true); + var shouldRebuild = _cacheManager.Get(cacheKey, RecheckBundledFilesPeriod, () => true); if (shouldRebuild) { //store json file to see a generated config file (for debugging purposes) @@ -556,7 +560,7 @@ public virtual string GenerateCssFiles(IUrlHelper urlHelper, ResourceLocation lo if (partsToBundle.Any()) { //ensure \bundles directory exists - Directory.CreateDirectory(Path.Combine(_hostingEnvironment.WebRootPath, "bundles")); + _fileProvider.CreateDirectory(_fileProvider.GetAbsolutePath("bundles")); var bundle = new Bundle(); foreach (var item in partsToBundle) @@ -564,8 +568,8 @@ public virtual string GenerateCssFiles(IUrlHelper urlHelper, ResourceLocation lo var src = debugModel ? item.DebugSrc : item.Src; src = urlHelper.Content(src); //check whether this file exists - var srcPath = Path.Combine(_hostingEnvironment.ContentRootPath, src.Remove(0, 1).Replace("/", "\\")); - if (File.Exists(srcPath)) + var srcPath = _fileProvider.Combine(_hostingEnvironment.ContentRootPath, src.Remove(0, 1).Replace("/", "\\")); + if (_fileProvider.FileExists(srcPath)) { //remove starting / src = src.Remove(0, 1); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/CommonController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/CommonController.cs index ffcacce9f0d..47c2d9cd1ea 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/CommonController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/CommonController.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using Microsoft.AspNetCore.Hosting; +using System.Reflection; using Microsoft.AspNetCore.Mvc; using Nop.Core; using Nop.Core.Caching; +using Nop.Core.Infrastructure; using Nop.Services.Common; using Nop.Services.Customers; using Nop.Services.Helpers; @@ -15,13 +16,19 @@ using Nop.Services.Seo; using Nop.Web.Areas.Admin.Factories; using Nop.Web.Areas.Admin.Models.Common; -using Nop.Web.Framework; using Nop.Web.Framework.Controllers; +using Nop.Web.Framework; namespace Nop.Web.Areas.Admin.Controllers { public partial class CommonController : BaseAdminController { + #region Const + + private const string EXPORT_IMPORT_PATH = @"files\exportimport"; + + #endregion + #region Fields private readonly ICommonModelFactory _commonModelFactory; @@ -37,6 +44,7 @@ public partial class CommonController : BaseAdminController private readonly IUrlRecordService _urlRecordService; private readonly IWebHelper _webHelper; private readonly IWorkContext _workContext; + private readonly INopFileProvider _fileProvider; #endregion @@ -54,7 +62,8 @@ public CommonController(ICommonModelFactory commonModelFactory, IStaticCacheManager cacheManager, IUrlRecordService urlRecordService, IWebHelper webHelper, - IWorkContext workContext) + IWorkContext workContext, + INopFileProvider fileProvider) { this._commonModelFactory = commonModelFactory; this._customerService = customerService; @@ -69,6 +78,7 @@ public CommonController(ICommonModelFactory commonModelFactory, this._urlRecordService = urlRecordService; this._webHelper = webHelper; this._workContext = workContext; + this._fileProvider = fileProvider; } #endregion @@ -154,20 +164,21 @@ public virtual IActionResult MaintenanceDeleteFiles(MaintenanceModel model) model.DeleteExportedFiles.NumberOfDeletedFiles = 0; - var path = Path.Combine(_hostingEnvironment.WebRootPath, "files\\exportimport"); - foreach (var fullPath in Directory.GetFiles(path)) + + foreach (var fullPath in _fileProvider.GetFiles(_fileProvider.GetAbsolutePath(EXPORT_IMPORT_PATH))) { try { - var fileName = Path.GetFileName(fullPath); + var fileName = _fileProvider.GetFileName(fullPath); if (fileName.Equals("index.htm", StringComparison.InvariantCultureIgnoreCase)) continue; - var info = new FileInfo(fullPath); - if ((!startDateValue.HasValue || startDateValue.Value < info.CreationTimeUtc) && - (!endDateValue.HasValue || info.CreationTimeUtc < endDateValue.Value)) + var info = _fileProvider.GetFileInfo(_fileProvider.Combine(EXPORT_IMPORT_PATH, fileName)); + var lastModifiedTimeUtc = info.LastModified.UtcDateTime; + if ((!startDateValue.HasValue || startDateValue.Value < lastModifiedTimeUtc) && + (!endDateValue.HasValue || lastModifiedTimeUtc < endDateValue.Value)) { - System.IO.File.Delete(fullPath); + _fileProvider.DeleteFile(fullPath); model.DeleteExportedFiles.NumberOfDeletedFiles++; } } @@ -230,7 +241,7 @@ public virtual IActionResult BackupAction(MaintenanceModel model) { case "delete-backup": { - System.IO.File.Delete(backupPath); + _fileProvider.DeleteFile(backupPath); SuccessNotification(string.Format(_localizationService.GetResource("Admin.System.Maintenance.BackupDatabase.BackupDeleted"), fileName)); } break; diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/DownloadController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/DownloadController.cs index 7c72e2b4515..8a19ecbbf63 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/DownloadController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/DownloadController.cs @@ -1,9 +1,9 @@ using System; -using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; using Nop.Core; using Nop.Core.Domain.Media; +using Nop.Core.Infrastructure; using Nop.Services.Media; using Nop.Web.Framework.Mvc.Filters; @@ -14,14 +14,17 @@ public partial class DownloadController : BaseAdminController #region Fields private readonly IDownloadService _downloadService; + private readonly INopFileProvider _fileProvider; #endregion #region Ctor - public DownloadController(IDownloadService downloadService) + public DownloadController(IDownloadService downloadService, + INopFileProvider fileProvider) { this._downloadService = downloadService; + this._fileProvider = fileProvider; } #endregion @@ -92,11 +95,11 @@ public virtual IActionResult AsyncUpload() if (string.IsNullOrEmpty(fileName) && Request.Form.ContainsKey(qqFileNameParameter)) fileName = Request.Form[qqFileNameParameter].ToString(); //remove path (passed in IE) - fileName = Path.GetFileName(fileName); + fileName = _fileProvider.GetFileName(fileName); var contentType = httpPostedFile.ContentType; - var fileExtension = Path.GetExtension(fileName); + var fileExtension = _fileProvider.GetFileExtension(fileName); if (!string.IsNullOrEmpty(fileExtension)) fileExtension = fileExtension.ToLowerInvariant(); @@ -108,7 +111,7 @@ public virtual IActionResult AsyncUpload() DownloadBinary = fileBinary, ContentType = contentType, //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), + Filename = _fileProvider.GetFileNameWithoutExtension(fileName), Extension = fileExtension, IsNew = true }; diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/JbimagesController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/JbimagesController.cs index 200718b80a8..7bc99748aad 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/JbimagesController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/JbimagesController.cs @@ -3,7 +3,7 @@ using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; -using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Services.Security; using Nop.Web.Framework.Mvc.Filters; @@ -16,11 +16,19 @@ namespace Nop.Web.Areas.Admin.Controllers [AdminAntiForgery(true)] public partial class JbimagesController : BaseAdminController { + #region Fields + private readonly IPermissionService _permissionService; + private readonly INopFileProvider _fileProvider; + + #endregion - public JbimagesController(IPermissionService permissionService) + + public JbimagesController(IPermissionService permissionService, + INopFileProvider fileProvider) { this._permissionService = permissionService; + this._fileProvider = fileProvider; } protected virtual IList GetAllowedFileTypes() @@ -49,7 +57,7 @@ public virtual IActionResult Upload() return View(); } - var fileName = Path.GetFileName(uploadFile.FileName); + var fileName = _fileProvider.GetFileName(uploadFile.FileName); if (string.IsNullOrEmpty(fileName)) { ViewData["resultCode"] = "failed"; @@ -58,9 +66,9 @@ public virtual IActionResult Upload() } var directory = "~/wwwroot/images/uploaded/"; - var filePath = Path.Combine(CommonHelper.MapPath(directory), fileName); + var filePath = _fileProvider.Combine(_fileProvider.MapPath(directory), fileName); - var fileExtension = Path.GetExtension(filePath); + var fileExtension = _fileProvider.GetFileExtension(filePath); if (!GetAllowedFileTypes().Contains(fileExtension)) { ViewData["resultCode"] = "failed"; @@ -72,7 +80,7 @@ public virtual IActionResult Upload() { uploadFile.CopyTo(fileStream); } - + ViewData["resultCode"] = "success"; ViewData["result"] = "success"; ViewData["filename"] = this.Url.Content($"{directory}{fileName}"); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/LanguageController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/LanguageController.cs index 587d999632f..f4821fb74d4 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/LanguageController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/LanguageController.cs @@ -2,11 +2,11 @@ using System.IO; using System.Linq; using System.Text; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Nop.Core.Domain.Localization; +using Nop.Core.Infrastructure; using Nop.Services.Localization; using Nop.Services.Logging; using Nop.Services.Security; @@ -22,38 +22,44 @@ namespace Nop.Web.Areas.Admin.Controllers { public partial class LanguageController : BaseAdminController { + #region Const + + private const string FLAGS_PATH = @"images\flags"; + + #endregion + #region Fields private readonly ICustomerActivityService _customerActivityService; - private readonly IHostingEnvironment _hostingEnvironment; private readonly ILanguageModelFactory _languageModelFactory; private readonly ILanguageService _languageService; private readonly ILocalizationService _localizationService; private readonly IPermissionService _permissionService; private readonly IStoreMappingService _storeMappingService; private readonly IStoreService _storeService; + private readonly INopFileProvider _fileProvider; #endregion #region Ctor public LanguageController(ICustomerActivityService customerActivityService, - IHostingEnvironment hostingEnvironment, ILanguageModelFactory languageModelFactory, ILanguageService languageService, ILocalizationService localizationService, IPermissionService permissionService, IStoreMappingService storeMappingService, - IStoreService storeService) + IStoreService storeService, + INopFileProvider fileProvider) { this._customerActivityService = customerActivityService; - this._hostingEnvironment = hostingEnvironment; this._languageModelFactory = languageModelFactory; this._languageService = languageService; this._localizationService = localizationService; this._permissionService = permissionService; this._storeMappingService = storeMappingService; this._storeService = storeService; + this._fileProvider = fileProvider; } #endregion @@ -270,9 +276,9 @@ public virtual JsonResult GetAvailableFlagFileNames() if (!_permissionService.Authorize(StandardPermissionProvider.ManageLanguages)) return Json("Access denied"); - var flagNames = Directory - .EnumerateFiles(Path.Combine(_hostingEnvironment.WebRootPath, "images\\flags"), "*.png", SearchOption.TopDirectoryOnly) - .Select(Path.GetFileName) + var flagNames = _fileProvider + .EnumerateFiles(_fileProvider.GetAbsolutePath(FLAGS_PATH), "*.png") + .Select(_fileProvider.GetFileName) .ToList(); var availableFlagFileNames = flagNames.Select(flagName => new SelectListItem @@ -429,15 +435,13 @@ public virtual IActionResult ImportXml(int id, IFormFile importxmlfile) { using (var sr = new StreamReader(importxmlfile.OpenReadStream(), Encoding.UTF8)) { - var content = sr.ReadToEnd(); - _localizationService.ImportResourcesFromXml(language, content); + _localizationService.ImportResourcesFromXml(language, sr.ReadToEnd()); } - } else { ErrorNotification(_localizationService.GetResource("Admin.Common.UploadFile")); - return RedirectToAction("Edit", new { id = language.Id }); + return RedirectToAction("Edit", new {id = language.Id}); } SuccessNotification(_localizationService.GetResource("Admin.Configuration.Languages.Imported")); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/PictureController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/PictureController.cs index 531e2f4672d..5528df41227 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/PictureController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/PictureController.cs @@ -1,8 +1,8 @@ using System; -using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Services.Media; using Nop.Web.Framework.Mvc.Filters; @@ -11,10 +11,13 @@ namespace Nop.Web.Areas.Admin.Controllers public partial class PictureController : BaseAdminController { private readonly IPictureService _pictureService; + private readonly INopFileProvider _fileProvider; - public PictureController(IPictureService pictureService) + public PictureController(IPictureService pictureService, + INopFileProvider fileProvider) { this._pictureService = pictureService; + this._fileProvider = fileProvider; } [HttpPost] @@ -43,11 +46,11 @@ public virtual IActionResult AsyncUpload() if (string.IsNullOrEmpty(fileName) && Request.Form.ContainsKey(qqFileNameParameter)) fileName = Request.Form[qqFileNameParameter].ToString(); //remove path (passed in IE) - fileName = Path.GetFileName(fileName); + fileName = _fileProvider.GetFileName(fileName); var contentType = httpPostedFile.ContentType; - var fileExtension = Path.GetExtension(fileName); + var fileExtension = _fileProvider.GetFileExtension(fileName); if (!string.IsNullOrEmpty(fileExtension)) fileExtension = fileExtension.ToLowerInvariant(); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/ProductController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/ProductController.cs index edd6b464790..92efadbcd3b 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/ProductController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/ProductController.cs @@ -12,6 +12,7 @@ using Nop.Core.Domain.Media; using Nop.Core.Domain.Orders; using Nop.Core.Domain.Vendors; +using Nop.Core.Infrastructure; using Nop.Services.Catalog; using Nop.Services.Common; using Nop.Services.Configuration; @@ -70,6 +71,7 @@ public partial class ProductController : BaseAdminController private readonly IUrlRecordService _urlRecordService; private readonly IWorkContext _workContext; private readonly VendorSettings _vendorSettings; + private readonly INopFileProvider _fileProvider; #endregion @@ -105,7 +107,8 @@ public ProductController(IAclService aclService, IStoreService storeService, IUrlRecordService urlRecordService, IWorkContext workContext, - VendorSettings vendorSettings) + VendorSettings vendorSettings, + INopFileProvider fileProvider) { this._aclService = aclService; this._backInStockSubscriptionService = backInStockSubscriptionService; @@ -138,6 +141,7 @@ public ProductController(IAclService aclService, this._urlRecordService = urlRecordService; this._workContext = workContext; this._vendorSettings = vendorSettings; + this._fileProvider = fileProvider; } #endregion @@ -425,7 +429,7 @@ protected virtual string GetAttributesXmlForProductAttributeCombination(IFormCol DateTime? selectedDate = null; try { - selectedDate = new DateTime(Int32.Parse(year), Int32.Parse(month), Int32.Parse(date)); + selectedDate = new DateTime(int.Parse(year), int.Parse(month), int.Parse(date)); } catch { @@ -465,8 +469,8 @@ protected virtual string GetAttributesXmlForProductAttributeCombination(IFormCol DownloadUrl = "", DownloadBinary = httpPostedFile.GetDownloadBits(), ContentType = httpPostedFile.ContentType, - Filename = Path.GetFileNameWithoutExtension(httpPostedFile.FileName), - Extension = Path.GetExtension(httpPostedFile.FileName), + Filename = _fileProvider.GetFileNameWithoutExtension(httpPostedFile.FileName), + Extension = _fileProvider.GetFileExtension(httpPostedFile.FileName), IsNew = true }; _downloadService.InsertDownload(download); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/RoxyFilemanController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/RoxyFilemanController.cs index ab7d38d4830..a3866956845 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/RoxyFilemanController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/RoxyFilemanController.cs @@ -7,6 +7,7 @@ using System.IO; using System.IO.Compression; using System.Net; +using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; @@ -14,6 +15,7 @@ using Microsoft.Extensions.Primitives; using Newtonsoft.Json; using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Services.Security; using Nop.Web.Framework.Mvc.Filters; @@ -53,6 +55,7 @@ public class RoxyFilemanController : BaseAdminController private readonly IHostingEnvironment _hostingEnvironment; private readonly IPermissionService _permissionService; private readonly IWorkContext _workContext; + private readonly INopFileProvider _fileProvider; #endregion @@ -60,11 +63,13 @@ public class RoxyFilemanController : BaseAdminController public RoxyFilemanController(IHostingEnvironment hostingEnvironment, IPermissionService permissionService, - IWorkContext workContext) + IWorkContext workContext, + INopFileProvider fileProvider) { this._hostingEnvironment = hostingEnvironment; this._permissionService = permissionService; this._workContext = workContext; + this._fileProvider = fileProvider; } #endregion @@ -77,16 +82,12 @@ public RoxyFilemanController(IHostingEnvironment hostingEnvironment, public virtual void CreateConfiguration() { var filePath = GetFullPath(CONFIGURATION_FILE); - + //create file if not exists - if (!System.IO.File.Exists(filePath)) - { - //we use 'using' to close the file after it's created - using (System.IO.File.Create(filePath)) { } - } + _fileProvider.CreateFile(filePath); //try to read existing configuration - var existingText = System.IO.File.ReadAllText(filePath); + var existingText = _fileProvider.ReadAllText(filePath, Encoding.UTF8); var existingConfiguration = JsonConvert.DeserializeAnonymousType(existingText, new { FILES_ROOT = string.Empty, @@ -173,7 +174,7 @@ public virtual void CreateConfiguration() //save the file var text = JsonConvert.SerializeObject(configuration, Formatting.Indented); - System.IO.File.WriteAllText(filePath, text); + _fileProvider.WriteAllText(filePath, text, Encoding.UTF8); } /// @@ -358,7 +359,7 @@ protected virtual string GetLanguageFile() var languageCode = GetSetting("LANG"); var languageFile = $"{LANGUAGE_DIRECTORY}/{languageCode}.json"; - if (!System.IO.File.Exists(GetFullPath(languageFile))) + if (!_fileProvider.FileExists(GetFullPath(languageFile))) languageFile = $"{LANGUAGE_DIRECTORY}/en.json"; return GetFullPath(languageFile); @@ -375,7 +376,7 @@ protected virtual Dictionary ParseJson(string file) var json = string.Empty; try { - json = System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8)?.Trim(); + json = _fileProvider.ReadAllText(file, Encoding.UTF8)?.Trim(); } catch { } @@ -430,7 +431,7 @@ protected virtual string GetFileType(string fileExtension) protected virtual bool CanHandleFile(string path) { var result = false; - var fileExtension = new FileInfo(path).Extension.Replace(".", "").ToLower(); + var fileExtension = _fileProvider.GetFileExtension(path).Replace(".", "").ToLower(); var forbiddenUploads = GetSetting("FORBIDDEN_UPLOADS").Trim().ToLower(); if (!string.IsNullOrEmpty(forbiddenUploads)) @@ -488,19 +489,19 @@ protected virtual string GetErrorResponse(string message = null) protected virtual async Task GetDirectoriesAsync(string type) { var rootDirectoryPath = GetFullPath(GetVirtualPath(null)); - var rootDirectory = new DirectoryInfo(rootDirectoryPath); - if (!rootDirectory.Exists) + + if (!_fileProvider.DirectoryExists(rootDirectoryPath)) throw new Exception("Invalid files root directory. Check your configuration."); - var allDirectories = GetDirectories(rootDirectory.FullName); - allDirectories.Insert(0, rootDirectory.FullName); + var allDirectories = GetDirectories(rootDirectoryPath); + allDirectories.Insert(0, rootDirectoryPath); var localPath = GetFullPath(null); await HttpContext.Response.WriteAsync("["); for (var i = 0; i < allDirectories.Count; i++) { var directoryPath = (string)allDirectories[i]; - await HttpContext.Response.WriteAsync($"{{\"p\":\"/{directoryPath.Replace(localPath, string.Empty).Replace("\\", "/").TrimStart('/')}\",\"f\":\"{GetFiles(directoryPath, type).Count}\",\"d\":\"{Directory.GetDirectories(directoryPath).Length}\"}}"); + await HttpContext.Response.WriteAsync($"{{\"p\":\"/{directoryPath.Replace(localPath, string.Empty).Replace("\\", "/").TrimStart('/')}\",\"f\":\"{GetFiles(directoryPath, type).Count}\",\"d\":\"{_fileProvider.GetDirectories(directoryPath).Length}\"}}"); if (i < allDirectories.Count - 1) await HttpContext.Response.WriteAsync(","); } @@ -516,7 +517,7 @@ protected virtual ArrayList GetDirectories(string parentDirectoryPath) { var directories = new ArrayList(); - var directoryNames = Directory.GetDirectories(parentDirectoryPath); + var directoryNames = _fileProvider.GetDirectories(parentDirectoryPath); foreach (var directory in directoryNames) { directories.Add(directory); @@ -542,12 +543,13 @@ protected virtual async Task GetFilesAsync(string directoryPath, string type) { var width = 0; var height = 0; - var file = new FileInfo(files[i]); - if (GetFileType(file.Extension) == "image") + var physicalPath = files[i]; + + if (GetFileType(_fileProvider.GetFileExtension(files[i])) == "image") { try { - using (var stream = new FileStream(file.FullName, FileMode.Open)) + using (var stream = new FileStream(physicalPath, FileMode.Open)) { using (var image = Image.FromStream(stream)) { @@ -561,7 +563,7 @@ protected virtual async Task GetFilesAsync(string directoryPath, string type) throw ex; } } - await HttpContext.Response.WriteAsync($"{{\"p\":\"{directoryPath.TrimEnd('/')}/{file.Name}\",\"t\":\"{Math.Ceiling(GetTimestamp(file.LastWriteTime))}\",\"s\":\"{file.Length}\",\"w\":\"{width}\",\"h\":\"{height}\"}}"); + await HttpContext.Response.WriteAsync($"{{\"p\":\"{directoryPath.TrimEnd('/')}/{_fileProvider.GetFileName(physicalPath)}\",\"t\":\"{Math.Ceiling(GetTimestamp(_fileProvider.GetLastWriteTime(physicalPath)))}\",\"s\":\"{_fileProvider.FileLength(physicalPath)}\",\"w\":\"{width}\",\"h\":\"{height}\"}}"); if (i < files.Count - 1) await HttpContext.Response.WriteAsync(","); @@ -581,9 +583,9 @@ protected virtual List GetFiles(string directoryPath, string type) type = string.Empty; var files = new List(); - foreach (var fileName in Directory.GetFiles(directoryPath)) + foreach (var fileName in _fileProvider.GetFiles(directoryPath)) { - if (string.IsNullOrEmpty(type) || GetFileType(new FileInfo(fileName).Extension) == type) + if (string.IsNullOrEmpty(type) || GetFileType(_fileProvider.GetFileExtension(fileName)) == type) files.Add(fileName); } @@ -609,16 +611,16 @@ protected virtual double GetTimestamp(DateTime date) protected virtual async Task CopyDirectoryAsync(string sourcePath, string destinationPath) { var directoryPath = GetFullPath(GetVirtualPath(sourcePath)); - var directory = new DirectoryInfo(directoryPath); - if (!directory.Exists) + + if (!_fileProvider.DirectoryExists(directoryPath)) throw new Exception(GetLanguageResource("E_CopyDirInvalidPath")); - var newDirectoryPath = GetFullPath(GetVirtualPath($"{destinationPath.TrimEnd('/')}/{directory.Name}")); - var newDirectory = new DirectoryInfo(newDirectoryPath); - if (newDirectory.Exists) + var newDirectoryPath = GetFullPath(GetVirtualPath($"{destinationPath.TrimEnd('/')}/{_fileProvider.GetDirectoryName(directoryPath)}")); + + if (_fileProvider.DirectoryExists(newDirectoryPath)) throw new Exception(GetLanguageResource("E_DirAlreadyExists")); - CopyDirectory(directory.FullName, newDirectory.FullName); + CopyDirectory(directoryPath, newDirectoryPath); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } @@ -630,22 +632,22 @@ protected virtual async Task CopyDirectoryAsync(string sourcePath, string destin /// Path to the destination directory protected virtual void CopyDirectory(string sourcePath, string destinationPath) { - var existingFiles = Directory.GetFiles(sourcePath); - var existingDirectories = Directory.GetDirectories(sourcePath); - - if (!Directory.Exists(destinationPath)) - Directory.CreateDirectory(destinationPath); + var existingFiles = _fileProvider.GetFiles(sourcePath); + var existingDirectories = _fileProvider.GetDirectories(sourcePath); + + if (!_fileProvider.DirectoryExists(destinationPath)) + _fileProvider.CreateDirectory(destinationPath); foreach (var file in existingFiles) { - var filePath = Path.Combine(destinationPath, new FileInfo(file).Name); - if (!System.IO.File.Exists(filePath)) - System.IO.File.Copy(file, filePath); + var filePath = _fileProvider.Combine(destinationPath, _fileProvider.GetFileName(file)); + if (!_fileProvider.FileExists(filePath)) + _fileProvider.FileCopy(file, filePath); } foreach (var directory in existingDirectories) { - var directoryPath = Path.Combine(destinationPath, new DirectoryInfo(directory).Name); + var directoryPath = _fileProvider.Combine(destinationPath, _fileProvider.GetDirectoryName(directory)); CopyDirectory(directory, directoryPath); } } @@ -659,15 +661,15 @@ protected virtual void CopyDirectory(string sourcePath, string destinationPath) protected virtual async Task CopyFileAsync(string sourcePath, string destinationPath) { var filePath = GetFullPath(GetVirtualPath(sourcePath)); - var file = new FileInfo(filePath); - if (!file.Exists) + + if (!_fileProvider.FileExists(filePath)) throw new Exception(GetLanguageResource("E_CopyFileInvalisPath")); destinationPath = GetFullPath(GetVirtualPath(destinationPath)); - var newFileName = GetUniqueFileName(destinationPath, file.Name); + var newFileName = GetUniqueFileName(destinationPath, _fileProvider.GetFileName(filePath)); try { - System.IO.File.Copy(file.FullName, Path.Combine(destinationPath, newFileName)); + _fileProvider.FileCopy(filePath, _fileProvider.Combine(destinationPath, newFileName)); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -687,9 +689,9 @@ protected virtual string GetUniqueFileName(string directoryPath, string fileName var uniqueFileName = fileName; var i = 0; - while (System.IO.File.Exists(Path.Combine(directoryPath, uniqueFileName))) + while (_fileProvider.FileExists(_fileProvider.Combine(directoryPath, uniqueFileName))) { - uniqueFileName = $"{Path.GetFileNameWithoutExtension(fileName)}-Copy-{++i}{Path.GetExtension(fileName)}"; + uniqueFileName = $"{_fileProvider.GetFileNameWithoutExtension(fileName)}-Copy-{++i}{_fileProvider.GetFileExtension(fileName)}"; } return uniqueFileName; @@ -704,14 +706,13 @@ protected virtual string GetUniqueFileName(string directoryPath, string fileName protected virtual async Task CreateDirectoryAsync(string parentDirectoryPath, string name) { parentDirectoryPath = GetFullPath(GetVirtualPath(parentDirectoryPath)); - if (!Directory.Exists(parentDirectoryPath)) + if (!_fileProvider.DirectoryExists(parentDirectoryPath)) throw new Exception(GetLanguageResource("E_CreateDirInvalidPath")); try { - var path = Path.Combine(parentDirectoryPath, name); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); + var path = _fileProvider.Combine(parentDirectoryPath, name); + _fileProvider.CreateDirectory(path); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } @@ -733,15 +734,15 @@ protected virtual async Task DeleteDirectoryAsync(string path) throw new Exception(GetLanguageResource("E_CannotDeleteRoot")); path = GetFullPath(path); - if (!Directory.Exists(path)) + if (!_fileProvider.DirectoryExists(path)) throw new Exception(GetLanguageResource("E_DeleteDirInvalidPath")); - if (Directory.GetDirectories(path).Length > 0 || Directory.GetFiles(path).Length > 0) + if (_fileProvider.GetDirectories(path).Length > 0 || _fileProvider.GetFiles(path).Length > 0) throw new Exception(GetLanguageResource("E_DeleteNonEmpty")); try { - Directory.Delete(path); + _fileProvider.DeleteDirectory(path); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -758,12 +759,12 @@ protected virtual async Task DeleteDirectoryAsync(string path) protected virtual async Task DeleteFileAsync(string path) { path = GetFullPath(GetVirtualPath(path)); - if (!System.IO.File.Exists(path)) + if (!_fileProvider.FileExists(path)) throw new Exception(GetLanguageResource("E_DeleteFileInvalidPath")); try { - System.IO.File.Delete(path); + _fileProvider.DeleteFile(path); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -781,17 +782,17 @@ public async Task DownloadDirectoryAsync(string path) { path = GetVirtualPath(path).TrimEnd('/'); var fullPath = GetFullPath(path); - if (!Directory.Exists(fullPath)) + if (!_fileProvider.DirectoryExists(fullPath)) throw new Exception(GetLanguageResource("E_CreateArchive")); - var zipName = new FileInfo(fullPath).Name + ".zip"; + var zipName = _fileProvider.GetFileName(fullPath) + ".zip"; var zipPath = $"/{zipName}"; if (path != GetRootDirectory()) zipPath = GetVirtualPath(zipPath); zipPath = GetFullPath(zipPath); - if (System.IO.File.Exists(zipPath)) - System.IO.File.Delete(zipPath); + if (_fileProvider.FileExists(zipPath)) + _fileProvider.DeleteFile(zipPath); ZipFile.CreateFromDirectory(fullPath, zipPath, CompressionLevel.Fastest, true); @@ -800,7 +801,7 @@ public async Task DownloadDirectoryAsync(string path) HttpContext.Response.ContentType = MimeTypes.ApplicationForceDownload; await HttpContext.Response.SendFileAsync(zipPath); - System.IO.File.Delete(zipPath); + _fileProvider.DeleteFile(zipPath); } /// @@ -811,13 +812,12 @@ public async Task DownloadDirectoryAsync(string path) protected virtual async Task DownloadFileAsync(string path) { var filePath = GetFullPath(GetVirtualPath(path)); - var file = new FileInfo(filePath); - if (file.Exists) + if (_fileProvider.FileExists(filePath)) { HttpContext.Response.Clear(); - HttpContext.Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{WebUtility.UrlEncode(file.Name)}\""); + HttpContext.Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{WebUtility.UrlEncode(_fileProvider.GetFileName(filePath))}\""); HttpContext.Response.ContentType = MimeTypes.ApplicationForceDownload; - await HttpContext.Response.SendFileAsync(file.FullName); + await HttpContext.Response.SendFileAsync(filePath); } } @@ -830,21 +830,21 @@ protected virtual async Task DownloadFileAsync(string path) protected virtual async Task MoveDirectoryAsync(string sourcePath, string destinationPath) { var fullSourcePath = GetFullPath(GetVirtualPath(sourcePath)); - var sourceDirectory = new DirectoryInfo(fullSourcePath); - destinationPath = GetFullPath(GetVirtualPath(Path.Combine(destinationPath, sourceDirectory.Name))); - var destinationDirectory = new DirectoryInfo(destinationPath); - if (destinationDirectory.FullName.IndexOf(sourceDirectory.FullName) == 0) + + destinationPath = GetFullPath(GetVirtualPath(_fileProvider.Combine(destinationPath, _fileProvider.GetDirectoryName(fullSourcePath)))); + + if (destinationPath.IndexOf(fullSourcePath, StringComparison.InvariantCulture) == 0) throw new Exception(GetLanguageResource("E_CannotMoveDirToChild")); - if (!sourceDirectory.Exists) + if (!_fileProvider.DirectoryExists(fullSourcePath)) throw new Exception(GetLanguageResource("E_MoveDirInvalisPath")); - if (destinationDirectory.Exists) + if (_fileProvider.DirectoryExists(destinationPath)) throw new Exception(GetLanguageResource("E_DirAlreadyExists")); try { - sourceDirectory.MoveTo(destinationDirectory.FullName); + _fileProvider.DirectoryMove(fullSourcePath, destinationPath); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -862,21 +862,21 @@ protected virtual async Task MoveDirectoryAsync(string sourcePath, string destin protected virtual async Task MoveFileAsync(string sourcePath, string destinationPath) { var fullSourcePath = GetFullPath(GetVirtualPath(sourcePath)); - var sourceFile = new FileInfo(fullSourcePath); - if (!sourceFile.Exists) + + if (!_fileProvider.FileExists(fullSourcePath)) throw new Exception(GetLanguageResource("E_MoveFileInvalisPath")); destinationPath = GetFullPath(GetVirtualPath(destinationPath)); - var destinationFile = new FileInfo(destinationPath); - if (destinationFile.Exists) + + if (_fileProvider.FileExists(destinationPath)) throw new Exception(GetLanguageResource("E_MoveFileAlreadyExists")); - if (!CanHandleFile(destinationFile.Name)) + if (!CanHandleFile(_fileProvider.GetFileName(destinationPath))) throw new Exception(GetLanguageResource("E_FileExtensionForbidden")); try { - sourceFile.MoveTo(destinationFile.FullName); + _fileProvider.FileMove(fullSourcePath, destinationPath); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -894,20 +894,20 @@ protected virtual async Task MoveFileAsync(string sourcePath, string destination protected virtual async Task RenameDirectoryAsync(string sourcePath, string newName) { var fullSourcePath = GetFullPath(GetVirtualPath(sourcePath)); - var sourceDirectory = new DirectoryInfo(fullSourcePath); - var destinationDirectory = new DirectoryInfo(Path.Combine(sourceDirectory.Parent.FullName, newName)); + + var destinationDirectory =_fileProvider.Combine(_fileProvider.GetParentDirectory(fullSourcePath), newName); if (GetVirtualPath(sourcePath) == GetRootDirectory()) throw new Exception(GetLanguageResource("E_CannotRenameRoot")); - if (!sourceDirectory.Exists) + if (!_fileProvider.DirectoryExists(fullSourcePath)) throw new Exception(GetLanguageResource("E_RenameDirInvalidPath")); - if (destinationDirectory.Exists) + if (_fileProvider.DirectoryExists(destinationDirectory)) throw new Exception(GetLanguageResource("E_DirAlreadyExists")); try { - sourceDirectory.MoveTo(destinationDirectory.FullName); + _fileProvider.DirectoryMove(fullSourcePath, destinationDirectory); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -925,8 +925,7 @@ protected virtual async Task RenameDirectoryAsync(string sourcePath, string newN protected virtual async Task RenameFileAsync(string sourcePath, string newName) { var fullSourcePath = GetFullPath(GetVirtualPath(sourcePath)); - var sourceFile = new FileInfo(fullSourcePath); - if (!sourceFile.Exists) + if (!_fileProvider.FileExists(fullSourcePath)) throw new Exception(GetLanguageResource("E_RenameFileInvalidPath")); if (!CanHandleFile(newName)) @@ -934,9 +933,8 @@ protected virtual async Task RenameFileAsync(string sourcePath, string newName) try { - var destinationPath = Path.Combine(sourceFile.Directory.FullName, newName); - var destinationFile = new FileInfo(destinationPath); - sourceFile.MoveTo(destinationFile.FullName); + var destinationPath = _fileProvider.Combine(_fileProvider.GetDirectoryName(fullSourcePath), newName); + _fileProvider.FileMove(fullSourcePath, destinationPath); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch @@ -1009,7 +1007,7 @@ protected virtual void CreateThumbnail(string path, int width, int height) /// Image format protected virtual ImageFormat GetImageFormat(string path) { - var fileExtension = new FileInfo(path).Extension.ToLower(); + var fileExtension = _fileProvider.GetFileExtension(path).ToLower(); switch (fileExtension) { case ".png": @@ -1088,14 +1086,13 @@ protected virtual async Task UploadFilesAsync(string directoryPath) var fileName = HttpContext.Request.Form.Files[i].FileName; if (CanHandleFile(fileName)) { - var file = new FileInfo(fileName); - var uniqueFileName = GetUniqueFileName(directoryPath, file.Name); - var destinationFile = Path.Combine(directoryPath, uniqueFileName); + var uniqueFileName = GetUniqueFileName(directoryPath, _fileProvider.GetFileName(fileName)); + var destinationFile = _fileProvider.Combine(directoryPath, uniqueFileName); using (var stream = new FileStream(destinationFile, FileMode.OpenOrCreate)) { HttpContext.Request.Form.Files[i].CopyTo(stream); } - if (GetFileType(new FileInfo(uniqueFileName).Extension) == "image") + if (GetFileType(_fileProvider.GetFileExtension(uniqueFileName)) == "image") { int.TryParse(GetSetting("MAX_IMAGE_WIDTH"), out int w); int.TryParse(GetSetting("MAX_IMAGE_HEIGHT"), out int h); diff --git a/src/Presentation/Nop.Web/Areas/Admin/Factories/CommonModelFactory.cs b/src/Presentation/Nop.Web/Areas/Admin/Factories/CommonModelFactory.cs index a62ce530999..abc802375a9 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Factories/CommonModelFactory.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Factories/CommonModelFactory.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Security.Principal; @@ -15,6 +14,7 @@ using Nop.Core.Domain.Customers; using Nop.Core.Domain.Directory; using Nop.Core.Domain.Orders; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; using Nop.Services.Catalog; using Nop.Services.Common; @@ -62,7 +62,8 @@ public partial class CommonModelFactory : ICommonModelFactory private readonly IUrlRecordService _urlRecordService; private readonly IWebHelper _webHelper; private readonly IWorkContext _workContext; - private readonly MeasureSettings _measureSettings; + private readonly MeasureSettings _measureSettings; + private readonly INopFileProvider _fileProvider; #endregion @@ -90,7 +91,8 @@ public CommonModelFactory(CatalogSettings catalogSettings, IUrlRecordService urlRecordService, IWebHelper webHelper, IWorkContext workContext, - MeasureSettings measureSettings) + MeasureSettings measureSettings, + INopFileProvider fileProvider) { this._catalogSettings = catalogSettings; this._currencySettings = currencySettings; @@ -115,6 +117,7 @@ public CommonModelFactory(CatalogSettings catalogSettings, this._webHelper = webHelper; this._workContext = workContext; this._measureSettings = measureSettings; + this._fileProvider = fileProvider; } #endregion @@ -506,8 +509,8 @@ public virtual SystemInfoModel PrepareSystemInfoModel(SystemInfoModel model) //https://stackoverflow.com/questions/2050396/getting-the-date-of-a-net-assembly //we use a simple method because the more Jeff Atwood's solution doesn't work anymore //more info at https://blog.codinghorror.com/determining-build-date-the-hard-way/ - loadedAssemblyModel.BuildDate = assembly.IsDynamic ? null : - (DateTime?)TimeZoneInfo.ConvertTimeFromUtc(File.GetLastWriteTimeUtc(assembly.Location), TimeZoneInfo.Local); + loadedAssemblyModel.BuildDate = assembly.IsDynamic ? null : (DateTime?)TimeZoneInfo.ConvertTimeFromUtc(_fileProvider.GetLastWriteTimeUtc(assembly.Location), TimeZoneInfo.Local); + } catch { } model.LoadedAssemblies.Add(loadedAssemblyModel); @@ -595,12 +598,12 @@ public virtual BackupFileListModel PrepareBackupFileListModel(BackupFileSearchMo //fill in model values from the entity var backupFileModel = new BackupFileModel { - Name = file.Name + Name = _fileProvider.GetFileName(file) }; //fill in additional values (not existing in the entity) - backupFileModel.Length = $"{file.Length / 1024f / 1024f:F2} Mb"; - backupFileModel.Link = $"{_webHelper.GetStoreLocation(false)}db_backups/{file.Name}"; + backupFileModel.Length = $"{_fileProvider.FileLength(file) / 1024f / 1024f:F2} Mb"; + backupFileModel.Link = $"{_webHelper.GetStoreLocation(false)}db_backups/{backupFileModel.Name}"; return backupFileModel; }), diff --git a/src/Presentation/Nop.Web/Areas/Admin/Helpers/TinyMceHelper.cs b/src/Presentation/Nop.Web/Areas/Admin/Helpers/TinyMceHelper.cs index 31bd56a533f..1cec090bfec 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Helpers/TinyMceHelper.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Helpers/TinyMceHelper.cs @@ -1,5 +1,4 @@ -using System.IO; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Nop.Core; using Nop.Core.Infrastructure; @@ -22,25 +21,26 @@ public static string GetTinyMceLanguage() var workContext = EngineContext.Current.Resolve(); var hostingEnvironment = EngineContext.Current.Resolve(); + var fileProvider = EngineContext.Current.Resolve(); var languageCulture = workContext.WorkingLanguage.LanguageCulture; var langFile = $"{languageCulture}.js"; - var directoryPath = Path.Combine(hostingEnvironment.WebRootPath, @"lib\tinymce\langs"); - var fileExists = File.Exists($"{directoryPath}\\{langFile}"); + var directoryPath = fileProvider.Combine(hostingEnvironment.WebRootPath, @"lib\tinymce\langs"); + var fileExists = fileProvider.FileExists($"{directoryPath}\\{langFile}"); if (!fileExists) { languageCulture = languageCulture.Replace('-', '_'); langFile = $"{languageCulture}.js"; - fileExists = File.Exists($"{directoryPath}\\{langFile}"); + fileExists = fileProvider.FileExists($"{directoryPath}\\{langFile}"); } if (!fileExists) { languageCulture = languageCulture.Split('_', '-')[0]; langFile = $"{languageCulture}.js"; - fileExists = File.Exists($"{directoryPath}\\{langFile}"); + fileExists = fileProvider.FileExists($"{directoryPath}\\{langFile}"); } return fileExists ? languageCulture : string.Empty; diff --git a/src/Presentation/Nop.Web/Controllers/InstallController.cs b/src/Presentation/Nop.Web/Controllers/InstallController.cs index a966a848224..7dc9781c9b3 100644 --- a/src/Presentation/Nop.Web/Controllers/InstallController.cs +++ b/src/Presentation/Nop.Web/Controllers/InstallController.cs @@ -27,15 +27,19 @@ public partial class InstallController : Controller private readonly IInstallationLocalizationService _locService; private readonly NopConfig _config; + private readonly INopFileProvider _fileProvider; #endregion #region Ctor - public InstallController(IInstallationLocalizationService locService, NopConfig config) + public InstallController(IInstallationLocalizationService locService, + NopConfig config, + INopFileProvider fileProvider) { this._locService = locService; this._config = config; + this._fileProvider = fileProvider; } #endregion @@ -288,7 +292,7 @@ public virtual IActionResult Index(InstallModel model) if (ModelState.IsValid) { - var settingsManager = new DataSettingsManager(); + var settingsManager = new DataSettingsManager(_fileProvider); try { string connectionString; @@ -343,10 +347,10 @@ public virtual IActionResult Index(InstallModel model) connectionString = "Data Source=" + databasePath + ";Persist Security Info=False"; //drop database if exists - var databaseFullPath = CommonHelper.MapPath("~/App_Data/") + databaseFileName; - if (System.IO.File.Exists(databaseFullPath)) + var databaseFullPath = _fileProvider.MapPath("~/App_Data/") + databaseFileName; + if (_fileProvider.FileExists(databaseFullPath)) { - System.IO.File.Delete(databaseFullPath); + _fileProvider.DeleteFile(databaseFullPath); } } @@ -394,8 +398,7 @@ public virtual IActionResult Index(InstallModel model) //register default permissions //var permissionProviders = EngineContext.Current.Resolve().FindClassesOfType(); - var permissionProviders = new List(); - permissionProviders.Add(typeof(StandardPermissionProvider)); + var permissionProviders = new List {typeof(StandardPermissionProvider)}; foreach (var providerType in permissionProviders) { var provider = (IPermissionProvider)Activator.CreateInstance(providerType); diff --git a/src/Presentation/Nop.Web/Controllers/ReturnRequestController.cs b/src/Presentation/Nop.Web/Controllers/ReturnRequestController.cs index 05b1989f57e..81d37cae7e3 100644 --- a/src/Presentation/Nop.Web/Controllers/ReturnRequestController.cs +++ b/src/Presentation/Nop.Web/Controllers/ReturnRequestController.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; using Nop.Core; @@ -7,6 +6,7 @@ using Nop.Core.Domain.Localization; using Nop.Core.Domain.Media; using Nop.Core.Domain.Orders; +using Nop.Core.Infrastructure; using Nop.Services.Customers; using Nop.Services.Localization; using Nop.Services.Media; @@ -36,6 +36,7 @@ public partial class ReturnRequestController : BasePublicController private readonly IDownloadService _downloadService; private readonly LocalizationSettings _localizationSettings; private readonly OrderSettings _orderSettings; + private readonly INopFileProvider _fileProvider; #endregion @@ -53,7 +54,8 @@ public ReturnRequestController(IReturnRequestModelFactory returnRequestModelFact ICustomNumberFormatter customNumberFormatter, IDownloadService downloadService, LocalizationSettings localizationSettings, - OrderSettings orderSettings) + OrderSettings orderSettings, + INopFileProvider fileProvider) { this._returnRequestModelFactory = returnRequestModelFactory; this._returnRequestService = returnRequestService; @@ -68,6 +70,7 @@ public ReturnRequestController(IReturnRequestModelFactory returnRequestModelFact this._downloadService = downloadService; this._localizationSettings = localizationSettings; this._orderSettings = orderSettings; + this._fileProvider = fileProvider; } #endregion @@ -206,11 +209,11 @@ public virtual IActionResult UploadFileReturnRequest() if (string.IsNullOrEmpty(fileName) && Request.Form.ContainsKey(qqFileNameParameter)) fileName = Request.Form[qqFileNameParameter].ToString(); //remove path (passed in IE) - fileName = Path.GetFileName(fileName); + fileName = _fileProvider.GetFileName(fileName); var contentType = httpPostedFile.ContentType; - var fileExtension = Path.GetExtension(fileName); + var fileExtension = _fileProvider.GetFileExtension(fileName); if (!string.IsNullOrEmpty(fileExtension)) fileExtension = fileExtension.ToLowerInvariant(); @@ -238,7 +241,7 @@ public virtual IActionResult UploadFileReturnRequest() DownloadBinary = fileBinary, ContentType = contentType, //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), + Filename = _fileProvider.GetFileNameWithoutExtension(fileName), Extension = fileExtension, IsNew = true }; diff --git a/src/Presentation/Nop.Web/Controllers/ShoppingCartController.cs b/src/Presentation/Nop.Web/Controllers/ShoppingCartController.cs index 02ffd4bb208..744836881ec 100644 --- a/src/Presentation/Nop.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/Nop.Web/Controllers/ShoppingCartController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; using System.Text; using Microsoft.AspNetCore.Http; @@ -14,6 +13,7 @@ using Nop.Core.Domain.Media; using Nop.Core.Domain.Orders; using Nop.Core.Html; +using Nop.Core.Infrastructure; using Nop.Services.Catalog; using Nop.Services.Common; using Nop.Services.Customers; @@ -70,6 +70,7 @@ public partial class ShoppingCartController : BasePublicController private readonly IWebHelper _webHelper; private readonly ICustomerActivityService _customerActivityService; private readonly IGenericAttributeService _genericAttributeService; + private readonly INopFileProvider _fileProvider; private readonly MediaSettings _mediaSettings; private readonly ShoppingCartSettings _shoppingCartSettings; @@ -110,7 +111,8 @@ public ShoppingCartController(IShoppingCartModelFactory shoppingCartModelFactory ShoppingCartSettings shoppingCartSettings, OrderSettings orderSettings, CaptchaSettings captchaSettings, - CustomerSettings customerSettings) + CustomerSettings customerSettings, + INopFileProvider fileProvider) { this._shoppingCartModelFactory = shoppingCartModelFactory; this._productService = productService; @@ -138,6 +140,7 @@ public ShoppingCartController(IShoppingCartModelFactory shoppingCartModelFactory this._webHelper = webHelper; this._customerActivityService = customerActivityService; this._genericAttributeService = genericAttributeService; + this._fileProvider = fileProvider; this._mediaSettings = mediaSettings; this._shoppingCartSettings = shoppingCartSettings; @@ -1136,11 +1139,11 @@ public virtual IActionResult UploadFileProductAttribute(int attributeId) if (string.IsNullOrEmpty(fileName) && Request.Form.ContainsKey(qqFileNameParameter)) fileName = Request.Form[qqFileNameParameter].ToString(); //remove path (passed in IE) - fileName = Path.GetFileName(fileName); + fileName = _fileProvider.GetFileName(fileName); var contentType = httpPostedFile.ContentType; - var fileExtension = Path.GetExtension(fileName); + var fileExtension = _fileProvider.GetFileExtension(fileName); if (!string.IsNullOrEmpty(fileExtension)) fileExtension = fileExtension.ToLowerInvariant(); @@ -1169,7 +1172,7 @@ public virtual IActionResult UploadFileProductAttribute(int attributeId) DownloadBinary = fileBinary, ContentType = contentType, //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), + Filename = _fileProvider.GetFileNameWithoutExtension(fileName), Extension = fileExtension, IsNew = true }; @@ -1217,11 +1220,11 @@ public virtual IActionResult UploadFileCheckoutAttribute(int attributeId) if (string.IsNullOrEmpty(fileName) && Request.Form.ContainsKey(qqFileNameParameter)) fileName = Request.Form[qqFileNameParameter].ToString(); //remove path (passed in IE) - fileName = Path.GetFileName(fileName); + fileName = _fileProvider.GetFileName(fileName); var contentType = httpPostedFile.ContentType; - var fileExtension = Path.GetExtension(fileName); + var fileExtension = _fileProvider.GetFileExtension(fileName); if (!string.IsNullOrEmpty(fileExtension)) fileExtension = fileExtension.ToLowerInvariant(); @@ -1250,7 +1253,7 @@ public virtual IActionResult UploadFileCheckoutAttribute(int attributeId) DownloadBinary = fileBinary, ContentType = contentType, //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), + Filename = _fileProvider.GetFileNameWithoutExtension(fileName), Extension = fileExtension, IsNew = true }; diff --git a/src/Presentation/Nop.Web/Factories/CommonModelFactory.cs b/src/Presentation/Nop.Web/Factories/CommonModelFactory.cs index a0fb8d899e0..e9bb15580c6 100644 --- a/src/Presentation/Nop.Web/Factories/CommonModelFactory.cs +++ b/src/Presentation/Nop.Web/Factories/CommonModelFactory.cs @@ -19,6 +19,7 @@ using Nop.Core.Domain.News; using Nop.Core.Domain.Orders; using Nop.Core.Domain.Vendors; +using Nop.Core.Infrastructure; using Nop.Services.Catalog; using Nop.Services.Common; using Nop.Services.Customers; @@ -69,6 +70,7 @@ public partial class CommonModelFactory : ICommonModelFactory private readonly IProductTagService _productTagService; private readonly IUrlHelperFactory _urlHelperFactory; private readonly IActionContextAccessor _actionContextAccessor; + private readonly INopFileProvider _fileProvider; private readonly CatalogSettings _catalogSettings; private readonly StoreInformationSettings _storeInformationSettings; @@ -117,7 +119,8 @@ public CommonModelFactory(ICategoryService categoryService, CaptchaSettings captchaSettings, VendorSettings vendorSettings, IProductTagService productTagService, - DisplayDefaultFooterItemSettings displayDefaultFooterItemSettings) + DisplayDefaultFooterItemSettings displayDefaultFooterItemSettings, + INopFileProvider fileProvider) { this._categoryService = categoryService; this._productService = productService; @@ -152,6 +155,7 @@ public CommonModelFactory(ICategoryService categoryService, this._vendorSettings = vendorSettings; this._productTagService = productTagService; this._displayDefaultFooterItemSettings = displayDefaultFooterItemSettings; + this._fileProvider = fileProvider; } #endregion @@ -716,13 +720,13 @@ public virtual FaviconModel PrepareFaviconModel() //try loading a store specific favicon var faviconFileName = $"favicon-{_storeContext.CurrentStore.Id}.ico"; - var localFaviconPath = System.IO.Path.Combine(_hostingEnvironment.WebRootPath, faviconFileName); - if (!System.IO.File.Exists(localFaviconPath)) + var localFaviconPath = _fileProvider.Combine(_hostingEnvironment.WebRootPath, faviconFileName); + if (!_fileProvider.FileExists(localFaviconPath)) { //try loading a generic favicon faviconFileName = "favicon.ico"; - localFaviconPath = System.IO.Path.Combine(_hostingEnvironment.WebRootPath, faviconFileName); - if (!System.IO.File.Exists(localFaviconPath)) + localFaviconPath = _fileProvider.Combine(_hostingEnvironment.WebRootPath, faviconFileName); + if (!_fileProvider.FileExists(localFaviconPath)) { return model; } @@ -741,11 +745,11 @@ public virtual string PrepareRobotsTextFile() var sb = new StringBuilder(); //if robots.custom.txt exists, let's use it instead of hard-coded data below - var robotsFilePath = System.IO.Path.Combine(CommonHelper.MapPath("~/"), "robots.custom.txt"); - if (System.IO.File.Exists(robotsFilePath)) + var robotsFilePath = _fileProvider.Combine(_fileProvider.MapPath("~/"), "robots.custom.txt"); + if (_fileProvider.FileExists(robotsFilePath)) { //the robots.txt file exists - var robotsFileContent = System.IO.File.ReadAllText(robotsFilePath); + var robotsFileContent = _fileProvider.ReadAllText(robotsFilePath, Encoding.UTF8); sb.Append(robotsFileContent); } else @@ -871,10 +875,10 @@ public virtual string PrepareRobotsTextFile() } //load and add robots.txt additions to the end of file. - var robotsAdditionsFile = System.IO.Path.Combine(CommonHelper.MapPath("~/"), "robots.additions.txt"); - if (System.IO.File.Exists(robotsAdditionsFile)) + var robotsAdditionsFile = _fileProvider.Combine(_fileProvider.MapPath("~/"), "robots.additions.txt"); + if (_fileProvider.FileExists(robotsAdditionsFile)) { - var robotsFileContent = System.IO.File.ReadAllText(robotsAdditionsFile); + var robotsFileContent = _fileProvider.ReadAllText(robotsAdditionsFile, Encoding.UTF8); sb.Append(robotsFileContent); } } diff --git a/src/Presentation/Nop.Web/Infrastructure/Installation/InstallationLocalizationService.cs b/src/Presentation/Nop.Web/Infrastructure/Installation/InstallationLocalizationService.cs index 9c9b4d6e96f..16db896362d 100644 --- a/src/Presentation/Nop.Web/Infrastructure/Installation/InstallationLocalizationService.cs +++ b/src/Presentation/Nop.Web/Infrastructure/Installation/InstallationLocalizationService.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Xml; using Microsoft.AspNetCore.Http; using Nop.Core; +using Nop.Core.Infrastructure; namespace Nop.Web.Infrastructure.Installation { @@ -17,6 +17,7 @@ public partial class InstallationLocalizationService : IInstallationLocalization #region Fields private readonly IHttpContextAccessor _httpContextAccessor; + private readonly INopFileProvider _fileProvider; #endregion @@ -31,9 +32,11 @@ public partial class InstallationLocalizationService : IInstallationLocalization #region Ctor - public InstallationLocalizationService(IHttpContextAccessor httpContextAccessor) + public InstallationLocalizationService(IHttpContextAccessor httpContextAccessor, + INopFileProvider fileProvider) { this._httpContextAccessor = httpContextAccessor; + this._fileProvider = fileProvider; } #endregion @@ -139,7 +142,7 @@ public virtual IList GetAvailableLanguages() return _availableLanguages; _availableLanguages = new List(); - foreach (var filePath in Directory.EnumerateFiles(CommonHelper.MapPath("~/App_Data/Localization/Installation/"), "*.xml")) + foreach (var filePath in _fileProvider.EnumerateFiles(_fileProvider.MapPath("~/App_Data/Localization/Installation/"), "*.xml")) { var xmlDocument = new XmlDocument(); xmlDocument.Load(filePath); @@ -148,7 +151,7 @@ public virtual IList GetAvailableLanguages() var languageCode = ""; //we file name format: installation.{languagecode}.xml var r = new Regex(Regex.Escape("installation.") + "(.*?)" + Regex.Escape(".xml")); - var matches = r.Matches(Path.GetFileName(filePath)); + var matches = r.Matches(_fileProvider.GetFileName(filePath)); foreach (Match match in matches) languageCode = match.Groups[1].Value; diff --git a/src/Tests/Nop.Core.Tests/Infrastructure/TypeFinderTests.cs b/src/Tests/Nop.Core.Tests/Infrastructure/TypeFinderTests.cs index 3ee20751dd7..ddccf039ca8 100644 --- a/src/Tests/Nop.Core.Tests/Infrastructure/TypeFinderTests.cs +++ b/src/Tests/Nop.Core.Tests/Infrastructure/TypeFinderTests.cs @@ -1,7 +1,9 @@ using System.Linq; +using Microsoft.AspNetCore.Hosting; using Nop.Core.Infrastructure; using Nop.Tests; using NUnit.Framework; +using Rhino.Mocks; namespace Nop.Core.Tests.Infrastructure { @@ -11,8 +13,11 @@ public class TypeFinderTests [Test] public void TypeFinder_Benchmark_Findings() { + var hostingEnvironment = MockRepository.GenerateMock(); + hostingEnvironment.Expect(x => x.ContentRootPath).Return(System.Reflection.Assembly.GetExecutingAssembly().Location); + hostingEnvironment.Expect(x => x.WebRootPath).Return(System.IO.Directory.GetCurrentDirectory()); + CommonHelper.DefaultFileProvider = new NopFileProvider(hostingEnvironment); var finder = new AppDomainTypeFinder(); - var type = finder.FindClassesOfType(); type.Count().ShouldEqual(1); typeof(ISomeInterface).IsAssignableFrom(type.FirstOrDefault()).ShouldBeTrue(); diff --git a/src/Tests/Nop.Core.Tests/WebHelperTests.cs b/src/Tests/Nop.Core.Tests/WebHelperTests.cs index 0e45a3f820d..5671f459c8a 100644 --- a/src/Tests/Nop.Core.Tests/WebHelperTests.cs +++ b/src/Tests/Nop.Core.Tests/WebHelperTests.cs @@ -1,9 +1,10 @@ using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; using Nop.Core.Configuration; +using Nop.Core.Infrastructure; using Nop.Tests; using NUnit.Framework; +using Rhino.Mocks; namespace Nop.Core.Tests { @@ -11,6 +12,7 @@ namespace Nop.Core.Tests public class WebHelperTests { private DefaultHttpContext _httpContext; + private INopFileProvider _fileProvider; private IWebHelper _webHelper; [SetUp] @@ -22,7 +24,10 @@ public void SetUp() queryString = queryString.Add("Key2", "Value2"); _httpContext.Request.QueryString = queryString; _httpContext.Request.Headers.Add(HeaderNames.Host, "www.Example.com"); - _webHelper = new WebHelper(new HostingConfig(), new FakeHttpContextAccessor(_httpContext)); + + _fileProvider = MockRepository.GenerateMock(); + + _webHelper = new WebHelper(new HostingConfig(), new FakeHttpContextAccessor(_httpContext), _fileProvider); } [Test] diff --git a/src/Tests/Nop.Data.Tests/PersistenceTest.cs b/src/Tests/Nop.Data.Tests/PersistenceTest.cs index db042a43dd8..2de05572b38 100644 --- a/src/Tests/Nop.Data.Tests/PersistenceTest.cs +++ b/src/Tests/Nop.Data.Tests/PersistenceTest.cs @@ -1,7 +1,10 @@ using System.Data.Entity; using System.Data.Entity.Infrastructure; +using Microsoft.AspNetCore.Hosting; using Nop.Core; +using Nop.Core.Infrastructure; using NUnit.Framework; +using Rhino.Mocks; namespace Nop.Data.Tests { @@ -23,7 +26,12 @@ public virtual void SetUp() protected string GetTestDbName() { - var testDbName = "Data Source=" + System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\\Nop.Data.Tests.Db.sdf;Persist Security Info=False"; + var hostingEnvironment = MockRepository.GenerateMock(); + hostingEnvironment.Expect(x => x.ContentRootPath).Return(System.Reflection.Assembly.GetExecutingAssembly().Location); + hostingEnvironment.Expect(x => x.WebRootPath).Return(System.Reflection.Assembly.GetExecutingAssembly().Location); + var fileProvider = new NopFileProvider(hostingEnvironment); + + var testDbName = "Data Source=" + fileProvider.GetAbsolutePath() + @"\\Nop.Data.Tests.Db.sdf;Persist Security Info=False"; return testDbName; } diff --git a/src/Tests/Nop.Services.Tests/ServiceTest.cs b/src/Tests/Nop.Services.Tests/ServiceTest.cs index 42b80bfbb1e..89406bd97fa 100644 --- a/src/Tests/Nop.Services.Tests/ServiceTest.cs +++ b/src/Tests/Nop.Services.Tests/ServiceTest.cs @@ -1,4 +1,7 @@ using System.Collections.Generic; +using Microsoft.AspNetCore.Hosting; +using Nop.Core; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; using Nop.Services.Tests.Directory; using Nop.Services.Tests.Discounts; @@ -6,6 +9,7 @@ using Nop.Services.Tests.Shipping; using Nop.Services.Tests.Tax; using NUnit.Framework; +using Rhino.Mocks; namespace Nop.Services.Tests { @@ -21,6 +25,11 @@ public void SetUp() private void InitPlugins() { + var hostingEnvironment = MockRepository.GenerateMock(); + hostingEnvironment.Expect(x => x.ContentRootPath).Return(System.Reflection.Assembly.GetExecutingAssembly().Location); + hostingEnvironment.Expect(x => x.WebRootPath).Return(System.IO.Directory.GetCurrentDirectory()); + CommonHelper.DefaultFileProvider = new NopFileProvider(hostingEnvironment); + PluginManager.ReferencedPlugins = new List { new PluginDescriptor(typeof(FixedRateTestTaxProvider).Assembly) diff --git a/src/Tests/Nop.Web.MVC.Tests/Events/EventsTests.cs b/src/Tests/Nop.Web.MVC.Tests/Events/EventsTests.cs index 7d99bf71847..71764246738 100644 --- a/src/Tests/Nop.Web.MVC.Tests/Events/EventsTests.cs +++ b/src/Tests/Nop.Web.MVC.Tests/Events/EventsTests.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Nop.Core; using Nop.Core.Configuration; +using Nop.Core.Infrastructure; using Nop.Core.Plugins; using Nop.Services.Events; using NUnit.Framework; @@ -17,7 +20,12 @@ public class EventsTests [OneTimeSetUp] public void SetUp() { + var hostingEnvironment = MockRepository.GenerateMock(); + hostingEnvironment.Expect(x => x.ContentRootPath).Return(System.Reflection.Assembly.GetExecutingAssembly().Location); + hostingEnvironment.Expect(x => x.WebRootPath).Return(System.IO.Directory.GetCurrentDirectory()); + CommonHelper.DefaultFileProvider = new NopFileProvider(hostingEnvironment); PluginManager.Initialize(new ApplicationPartManager(), new NopConfig()); + var subscriptionService = MockRepository.GenerateMock(); var consumers = new List> {new DateTimeConsumer()}; subscriptionService.Expect(c => c.GetSubscriptions()).Return(consumers);