C#实战:如何用后台服务定时将SolidWorks图纸批量转成Web可预览格式(附完整代码)
·
C#实战:构建高可靠SolidWorks图纸批量转换后台服务
在制造业数字化转型浪潮中,PLM与MES系统的深度集成已成为提升生产效率的关键。作为核心资产的三维设计图纸,如何在Web环境中实现安全、高效的共享查看,是每个工程团队必须解决的痛点。本文将手把手带您构建一个基于C#的Windows服务,实现SolidWorks图纸的自动化批量转换,解决实际部署中的命名映射、错误处理和性能优化等难题。
1. 服务架构设计与环境准备
1.1 技术选型与依赖配置
构建稳定运行的转换服务需要以下基础环境:
- SolidWorks 2020+ :确保安装时勾选API SDK组件
- .NET 6.0 :推荐使用LTS版本以获得长期支持
- Windows服务项目模板 :Visual Studio 2022中的Worker Service模板
关键NuGet包依赖:
<PackageReference Include="SolidWorks.Interop.sldworks" Version="2023.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
1.2 服务生命周期设计
采用IHostedService接口构建服务主体框架:
public class ConversionService : IHostedService, IDisposable
{
private Timer _timer;
private readonly ILogger<ConversionService> _logger;
public ConversionService(ILogger<ConversionService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting conversion service...");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromMinutes(Config.ScanInterval));
return Task.CompletedTask;
}
}
2. 核心转换逻辑实现
2.1 文件系统监控策略
采用混合监控模式提升效率:
- 定时全量扫描 :每日凌晨执行完整目录遍历
- FileSystemWatcher监听 :实时捕获新增/修改文件
- 内存缓存去重 :避免重复处理相同文件
文件过滤实现示例:
private IEnumerable<FileInfo> FilterSolidWorksFiles(DirectoryInfo dir)
{
var extensions = new[] { ".sldprt", ".sldasm", ".slddrw" };
return dir.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(f => extensions.Contains(f.Extension.ToLower()))
.Where(f => f.LastWriteTime > LastScanTime);
}
2.2 SolidWorks API调用封装
安全调用SolidWorks COM API的最佳实践:
public class SwApplication : IDisposable
{
private SldWorks _swApp;
public SwApplication()
{
_swApp = Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application")) as SldWorks;
_swApp.Visible = false;
}
public void ExportToScs(string inputPath, string outputPath)
{
try
{
var doc = _swApp.OpenDoc6(inputPath, (int)swDocumentTypes_e.swDocPART,
(int)swOpenDocOptions_e.swOpenDocOptions_Silent, "", 0, 0);
if (doc != null)
{
doc.ExportToWebPage(outputPath);
_swApp.CloseDoc(doc.GetPathName());
}
}
finally
{
Marshal.FinalReleaseComObject(_swApp);
}
}
}
3. 生产环境关键问题解决
3.1 文件名映射解决方案
针对PLM系统散列存储与原始命名不一致问题,设计多级查找策略:
| 查找方式 | 实现方法 | 适用场景 |
|---|---|---|
| XML元数据 | 解析配套index.xml文件 | 标准PLM导出 |
| 数据库查询 | 调用PLM API获取映射关系 | 定制化系统 |
| 正则匹配 | 提取图纸特征编码 | 遗留系统迁移 |
典型XML解析实现:
public string GetOriginalName(FileInfo sldFile)
{
var xmlFile = new FileInfo(Path.Combine(
sldFile.DirectoryName,
"metadata.xml"));
if (xmlFile.Exists)
{
var doc = XDocument.Load(xmlFile.FullName);
return doc.Descendants("OriginalName").FirstOrDefault()?.Value;
}
return Path.GetFileNameWithoutExtension(sldFile.Name);
}
3.2 转换任务队列管理
使用Channel实现生产者-消费者模式:
private readonly Channel<ConversionTask> _queue =
Channel.CreateBounded<ConversionTask>(new BoundedChannelOptions(1000)
{
FullMode = BoundedChannelFullMode.Wait,
SingleReader = true
});
// 生产者
async Task EnqueueTaskAsync(ConversionTask task)
{
await _queue.Writer.WriteAsync(task);
}
// 消费者
async Task ProcessQueueAsync()
{
await foreach (var task in _queue.Reader.ReadAllAsync())
{
await ProcessSingleFile(task);
}
}
4. 运维监控与性能优化
4.1 分布式日志收集方案
配置Serilog实现结构化日志:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File(new CompactJsonFormatter(),
"logs/conversion-.json",
rollingInterval: RollingInterval.Day)
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://elk:9200"))
{
AutoRegisterTemplate = true,
IndexFormat = "sw-conversion-{0:yyyy.MM}"
})
.CreateLogger();
关键监控指标:
- 转换成功率 :成功数/总数 × 100%
- 平均处理时间 :从开始到完成的耗时
- 资源占用率 :CPU/内存使用峰值
4.2 性能调优技巧
-
实例池优化 :
public class SwInstancePool : IDisposable { private readonly ConcurrentBag<SldWorks> _instances = new(); private readonly int _maxInstances = 4; public SldWorks GetInstance() { if (_instances.TryTake(out var instance)) return instance; return Activator.CreateInstance( Type.GetTypeFromProgID("SldWorks.Application")) as SldWorks; } } -
并行处理控制 :
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 }; Parallel.ForEach(files, options, file => { ProcessFile(file); }); -
内存泄漏预防 :
- 使用Marshal.ReleaseComObject释放COM对象
- 定期重启服务(每日凌晨)
- 监控SolidWorks进程资源占用
5. 异常处理与容错机制
5.1 错误分类处理策略
| 错误类型 | 处理方式 | 重试策略 |
|---|---|---|
| 文件锁定 | 延迟重试 | 指数退避 |
| API超时 | 实例重启 | 最大3次 |
| 内存不足 | 暂停处理 | 人工介入 |
| 权限不足 | 终止任务 | 立即告警 |
典型错误处理实现:
public async Task SafeConvertAsync(string inputPath, string outputPath)
{
int retryCount = 0;
while (retryCount < 3)
{
try
{
using var swApp = new SwApplication();
swApp.ExportToScs(inputPath, outputPath);
return;
}
catch (COMException ex) when (ex.HResult == -2147221164)
{
retryCount++;
await Task.Delay(1000 * retryCount);
}
}
throw new ConversionException($"Failed after {retryCount} attempts");
}
5.2 死信队列设计
对于持续失败的任务,转入死信队列供后续分析:
public class DeadLetterService
{
private readonly string _storePath = "deadletters";
public void StoreFailedTask(ConversionTask task, Exception ex)
{
var record = new
{
Timestamp = DateTime.UtcNow,
Task = task,
Error = ex.ToString()
};
var fileName = $"{DateTime.Now:yyyyMMddHHmmss}-{Guid.NewGuid()}.json";
File.WriteAllText(Path.Combine(_storePath, fileName),
JsonSerializer.Serialize(record));
}
}
6. 部署与持续集成
6.1 Windows服务安装脚本
使用SC命令创建服务:
$serviceName = "SolidWorksConverter"
$displayName = "SolidWorks图纸转换服务"
$binPath = "C:\Services\SWConverter\SolidWorksConverter.exe"
sc.exe create $serviceName binPath= `"$binPath`" start= auto DisplayName= `"$displayName`"
sc.exe description $serviceName "自动将SolidWorks图纸转换为Web可预览格式"
sc.exe start $serviceName
6.2 CI/CD管道配置
示例Azure Pipelines配置:
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'publish'
publishWebProjects: false
arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: true
- task: WindowsMachineFileCopy@2
inputs:
sourceFolder: '$(Build.ArtifactStagingDirectory)'
targetFolder: '\\prod-server\SWConverter'
machineNames: 'sw-converter-01'
adminUserName: '$(deployUser)'
adminPassword: '$(deployPassword)'
7. 浏览器端集成方案
7.1 Web查看器选型对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| SolidWorks Web Viewer | 官方支持,功能完整 | 需要授权许可 | 企业内网 |
| Three.js自定义渲染 | 高度定制化 | 开发成本高 | 互联网产品 |
| Autodesk Forge | 云服务支持 | 按量计费 | 混合云部署 |
7.2 安全访问控制
JWT令牌验证示例:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
8. 实战经验分享
在多个制造业客户现场部署时,我们发现几个关键点:
-
SolidWorks版本兼容性 :不同年份版本的API存在细微差异,建议在服务启动时检查版本:
var version = _swApp.RevisionNumber(); if (version < 20200000) throw new NotSupportedException("Requires SolidWorks 2020+"); -
大文件处理 :超过500MB的装配体需要特殊处理:
- 增加超时时间至30分钟
- 单独分配SolidWorks实例
- 优先安排在非高峰期处理
-
临时文件清理 :定期清理SolidWorks生成的临时文件:
Get-ChildItem -Path $env:TEMP -Filter "swx*" | Remove-Item -Force -Recurse
更多推荐
所有评论(0)