DurnyklyYol/FileSystemData/BusinessObjects/FileSystemStoreObject.cs

162 lines
7.2 KiB
C#

using System;
using System.IO;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.Persistent.Base;
using DevExpress.ExpressApp.Utils;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using System.Linq;
namespace FileSystemData.BusinessObjects {
/// <summary>
/// This class enables you to store uploaded files in a centralized file system location instead of the database. You can configure the file system store location via the static FileSystemDataModule.FileSystemStoreLocation property.
/// </summary>
[DefaultProperty(nameof(FileName))]
public class FileSystemStoreObject : BaseObject, IFileData, IEmptyCheckable {
private Stream tempSourceStream;
private string tempFileName = string.Empty;
private static object syncRoot = new object();
public FileSystemStoreObject(Session session) : base(session) { }
public string RealFileName {
get {
if (!string.IsNullOrEmpty(FileName) && Oid != Guid.Empty)
return Path.Combine(FileSystemDataModule.FileSystemStoreLocation, string.Format("{0}-{1}", Oid, FileName));
return null;
}
}
protected virtual void SaveFileToStore() {
if(!string.IsNullOrEmpty(RealFileName) && TempSourceStream != null) {
try {
using(Stream destination = File.Create(RealFileName)) { //T582918
FileSystemDataModule.CopyStream(TempSourceStream, destination);
Size = (int)destination.Length;
}
}
catch(DirectoryNotFoundException exc) {
throw new UserFriendlyException(exc);
}
}
}
private void RemoveOldFileFromStore() {
//Dennis: We need to remove the old file from the store when saving the current object.
if (!string.IsNullOrEmpty(tempFileName) && tempFileName != RealFileName) {//B222892
try {
File.Delete(tempFileName);
tempFileName = string.Empty;
} catch (DirectoryNotFoundException exc) {
throw new UserFriendlyException(exc);
}
}
}
protected override void OnSaving() {
base.OnSaving();
Guard.ArgumentNotNullOrEmpty(FileSystemDataModule.FileSystemStoreLocation, "FileSystemStoreLocation");
lock (syncRoot) {
if (!Directory.Exists(FileSystemDataModule.FileSystemStoreLocation))
Directory.CreateDirectory(FileSystemDataModule.FileSystemStoreLocation);
}
SaveFileToStore();
RemoveOldFileFromStore();
}
protected override void OnDeleting() {
//Dennis: We need to remove the old file from the store.
Clear();
base.OnDeleting();
}
protected override void Invalidate(bool disposing) {
if (disposing && TempSourceStream != null) {
TempSourceStream.Close();
TempSourceStream = null;
}
base.Invalidate(disposing);
}
#region IFileData Members
public void Clear() {
//Dennis: When clearing the file name property we need to save the name of the old file to remove it from the store in the future. You can also setup a separate service for that.
if (string.IsNullOrEmpty(tempFileName))
tempFileName = RealFileName;
FileName = string.Empty;
Size = 0;
}
[Size(260)]
public string FileName {
get { return GetPropertyValue<string>(nameof(FileName)); }
set { SetPropertyValue(nameof(FileName), value); }
}
[Browsable(false)]
public Stream TempSourceStream {
get { return tempSourceStream; }
set {
//Michael: The original Stream might be closed after a while (on the web too - T160753)
if (value == null) {
tempSourceStream = null;
} else {
if (value.Length > (long)int.MaxValue) throw new UserFriendlyException("File is too long");
tempSourceStream = new MemoryStream((int)value.Length);
FileSystemDataModule.CopyStream(value, tempSourceStream);
tempSourceStream.Position = 0;
}
}
}
//Dennis: Fires when uploading a file.
void IFileData.LoadFromStream(string fileName,Stream source) {
if (source.Length > 524288)
{ // 512 KB
throw new UserFriendlyException("The file size must be less than or equal to 512 KB.");
}
// Validate file type (only images)
string fileExtension = Path.GetExtension(fileName)?.ToLower();
string[] allowedExtensions = { ".jpg", ".jpeg", ".png", ".bmp",".heif",".heic" }; // Add other image formats as needed
if (!allowedExtensions.Contains(fileExtension))
{
throw new UserFriendlyException("Only image files (JPG, JPEG, PNG, BMP, heif, heic) are allowed.");
}
//Dennis: When assigning a new file we need to save the name of the old file to remove it from the store in the future.
if (fileName != FileName) {// updated, old code was: if (string.IsNullOrEmpty(tempFileName))
tempFileName = RealFileName;
}
FileName = fileName;
TempSourceStream = source;
Size = (int)TempSourceStream.Length;
OnChanged();//T582918
}
//Dennis: Fires when saving or opening a file.
void IFileData.SaveToStream(Stream destination) {
try {
if(!File.Exists(RealFileName)) {
return;
}
if (!string.IsNullOrEmpty(RealFileName)) {
if (destination == null)
FileSystemDataModule.OpenFileWithDefaultProgram(RealFileName);
else
FileSystemDataModule.CopyFileToStream(RealFileName, destination);
}
else if (TempSourceStream != null)
FileSystemDataModule.CopyStream(TempSourceStream, destination);
} catch (DirectoryNotFoundException exc) {
throw new UserFriendlyException(exc);
} catch (FileNotFoundException exc) {
throw new UserFriendlyException(exc);
}
}
[Persistent]
[RuleValueComparison("FileSizeValidation", DefaultContexts.Save, ValueComparisonType.LessThanOrEqual, 524288, // 512 KB
CustomMessageTemplate = "The file size must be less than or equal to 512 KB.")]
public int Size {
get { return GetPropertyValue<int>(nameof(Size)); }
private set { SetPropertyValue(nameof(Size), value); }
}
#endregion
#region IEmptyCheckable Members
public bool IsEmpty {
//T153149
get { return FileDataHelper.IsFileDataEmpty(this) || !(TempSourceStream!= null || File.Exists(RealFileName)); }
}
#endregion
}
}