feat: enhance error handling and backup functionality in ShellOptimizer

This commit is contained in:
sladro 2026-03-02 18:16:49 +08:00
parent a0c89cac52
commit 80051f3759
2 changed files with 106 additions and 13 deletions

View File

@ -288,8 +288,26 @@ namespace RevitHttpControl.Controllers
}
catch (InvalidOperationException ex)
{
if (ex.Message.Contains(ErrorMessages.NO_DOCUMENT_OPEN_MSG))
{
return this.CreateErrorResponse(
ErrorCodes.NO_DOCUMENT_OPEN,
ex.Message,
HttpStatusCode.BadRequest
);
}
if (ex.Message.Contains("创建备份失败"))
{
return this.CreateErrorResponse(
ErrorCodes.FILE_WRITE_PERMISSION_DENIED,
ex.Message,
HttpStatusCode.Forbidden
);
}
return this.CreateErrorResponse(
ErrorCodes.NO_DOCUMENT_OPEN,
ErrorCodes.REVIT_COMMAND_FAILED,
ex.Message,
HttpStatusCode.BadRequest
);

View File

@ -274,10 +274,22 @@ namespace RevitHttpControl.Services
if (worksetId != WorksetId.InvalidWorksetId)
{
var doc = element.Document;
var worksetTable = doc.GetWorksetTable();
var workset = worksetTable.GetWorkset(worksetId);
if (workset.IsOpen && workset.Owner != doc.Application.Username)
return false;
// 仅对工作共享文档执行“他人占用”校验,避免本地/样例文件误判。
if (doc.IsWorkshared)
{
var worksetTable = doc.GetWorksetTable();
var workset = worksetTable.GetWorkset(worksetId);
var owner = workset?.Owner;
var currentUser = doc.Application?.Username;
if (workset != null &&
workset.IsOpen &&
!string.IsNullOrWhiteSpace(owner) &&
!string.Equals(owner, currentUser, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
}
// 检查是否有依赖关系(如主体构件)
@ -341,18 +353,38 @@ namespace RevitHttpControl.Services
throw new InvalidOperationException("文档必须先保存才能创建备份");
}
var directory = Path.GetDirectoryName(originalPath);
var fileName = Path.GetFileNameWithoutExtension(originalPath);
var extension = Path.GetExtension(originalPath);
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupFileName = $"{fileName}_backup_{timestamp}{extension}";
var backupPath = Path.Combine(directory, backupFileName);
// 复制文件
File.Copy(originalPath, backupPath, false);
return backupPath;
// 先尝试写入原目录;若无权限则回退到用户本地目录。
var sourceDirectory = Path.GetDirectoryName(originalPath);
if (!string.IsNullOrWhiteSpace(sourceDirectory))
{
var backupPathInSource = Path.Combine(sourceDirectory, backupFileName);
try
{
File.Copy(originalPath, backupPathInSource, false);
return backupPathInSource;
}
catch (UnauthorizedAccessException)
{
// Ignore and fallback.
}
catch (IOException ex) when (File.Exists(backupPathInSource))
{
throw new InvalidOperationException($"备份文件已存在: {backupPathInSource}", ex);
}
}
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var fallbackDirectory = Path.Combine(localAppData, "RevitHttpControl", "Backups");
Directory.CreateDirectory(fallbackDirectory);
var backupPathInFallback = Path.Combine(fallbackDirectory, backupFileName);
File.Copy(originalPath, backupPathInFallback, false);
return backupPathInFallback;
}
catch (Exception ex)
{
@ -367,9 +399,20 @@ namespace RevitHttpControl.Services
{
try
{
if (doc.IsModified)
if (!doc.IsModified)
{
return;
}
try
{
doc.Save();
return;
}
catch (Exception ex) when (IsReadOnlySaveError(ex))
{
SaveDocumentAsWritableCopy(doc);
return;
}
}
catch (Exception ex)
@ -378,6 +421,38 @@ namespace RevitHttpControl.Services
}
}
private bool IsReadOnlySaveError(Exception ex)
{
if (ex == null) return false;
var message = ex.Message ?? string.Empty;
return message.IndexOf("read-only", StringComparison.OrdinalIgnoreCase) >= 0 ||
message.IndexOf("只读", StringComparison.OrdinalIgnoreCase) >= 0;
}
private void SaveDocumentAsWritableCopy(Document doc)
{
var originalPath = doc.PathName;
if (string.IsNullOrWhiteSpace(originalPath))
throw new InvalidOperationException("文档为只读且无法获取原始路径,不能自动另存为");
var fileName = Path.GetFileNameWithoutExtension(originalPath);
var extension = Path.GetExtension(originalPath);
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var outputDirectory = Path.Combine(localAppData, "RevitHttpControl", "Optimized");
Directory.CreateDirectory(outputDirectory);
var outputPath = Path.Combine(outputDirectory, $"{fileName}_optimized_{timestamp}{extension}");
var saveAsOptions = new SaveAsOptions
{
OverwriteExistingFile = false,
Compact = true
};
doc.SaveAs(outputPath, saveAsOptions);
}
/// <summary>
/// 获取文档文件大小
/// </summary>