如何在Matlab启动时程序化加载.NET程序集绑定重定向配置?
程序化配置.NET绑定重定向替代手动编辑Matlab配置文件
背景
我们在Matlab环境中开发时,需加载第三方.NET程序集实现设备通信,示例代码如下:
function [] = foo() %[ NET.addAssembly('.\resources\motors.dll'); %] end
该程序集引用的子模块版本与部署版本不同,需配置绑定重定向。目前通过手动编辑matlab.exe.config实现重定向(配置代码如下):
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> <supportedRuntime version="v2.0.50727"/> </startup> <runtime> <!-- !!! MANUAL EDITION FOR REQUIRED BINDING REDIRECTIONS !!! --> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" /> </dependentAssembly> </assemblyBinding> <loadFromRemoteSources enabled="true"/> </runtime> </configuration>
编译foo.m(命令:mcc -m foo.m -a .\resources\**.*)后,还需部署修改后的matlab.exe.config并重命名为foo.exe.config。
我们使用Git仓库中共用的startup.m在多台机器上开发,手动维护每台机器的matlab.exe.config繁琐且易出错,希望通过程序化方式加载/合并绑定重定向配置,实现:
- 无需手动维护每台机器的
matlab.exe.config,配置自动保持最新; - 编译后
mcc自动部署并执行启动逻辑,无需额外部署配置文件,只需通过-a参数添加资源。
可行实现方案
核心思路
Matlab没有内置的System.Configuration.ConfigurationManager.PostMerge方法,但可以通过动态注册.NET程序集解析事件实现绑定重定向,同时针对开发环境和编译部署环境分别处理:
1. 开发环境:动态绑定重定向(startup.m实现)
在共享的startup.m中添加以下代码,读取共享配置文件并拦截程序集加载请求,自动重定向到指定版本:
function startup() % 加载共享的绑定重定向配置文件 configPath = fullfile('..', 'Common', 'startup.config'); if exist(configPath, 'file') setupBindingRedirects(configPath); end % 其他启动项 % ... end function setupBindingRedirects(configPath) % 解析XML配置文件 xmlDoc = xmlread(configPath); ns = 'urn:schemas-microsoft-com:asm.v1'; assemblyBindingNode = xmlDoc.getElementsByTagNameNS(ns, 'assemblyBinding').item(0); if isempty(assemblyBindingNode) return; end % 注册.NET程序集解析事件,拦截加载请求 domain = System.AppDomain.CurrentDomain; addlistener(domain, 'AssemblyResolve', @onAssemblyResolve); % 存储重定向规则到持久化变量 persistent redirectRules; redirectRules = struct(); % 遍历所有绑定重定向规则 dependentAssemblies = assemblyBindingNode.getElementsByTagName('dependentAssembly'); for i = 0:dependentAssemblies.getLength()-1 depNode = dependentAssemblies.item(i); % 读取程序集标识 idNode = depNode.getElementsByTagName('assemblyIdentity').item(0); asmName = char(idNode.getAttribute('name')); asmPublicKeyToken = char(idNode.getAttribute('publicKeyToken')); % 读取重定向版本规则 redirectNode = depNode.getElementsByTagName('bindingRedirect').item(0); newVersion = char(redirectNode.getAttribute('newVersion')); % 保存规则 redirectRules(asmName) = struct(... 'publicKeyToken', upper(asmPublicKeyToken), ... 'newVersion', newVersion); end end function resolvedAssembly = onAssemblyResolve(sender, args) persistent redirectRules; if isempty(redirectRules) resolvedAssembly = []; return; end % 获取请求加载的程序集信息 reqAsm = args.RequestingAssembly; if isempty(reqAsm) resolvedAssembly = []; return; end reqName = char(reqAsm.GetName().Name); reqPublicKeyToken = upper(char(reqAsm.GetName().GetPublicKeyToken())); % 匹配重定向规则并加载指定版本 if isfield(redirectRules, reqName) rule = redirectRules(reqName); if strcmp(rule.publicKeyToken, reqPublicKeyToken) try resolvedAssembly = System.Reflection.Assembly.Load(... sprintf('%s, Version=%s, Culture=neutral, PublicKeyToken=%s', ... reqName, rule.newVersion, lower(rule.publicKeyToken))); catch ME warning('加载重定向程序集失败:%s v%s,错误信息:%s', reqName, rule.newVersion, ME.message); resolvedAssembly = []; end return; end end resolvedAssembly = []; end
2. 编译部署环境:自动生成exe.config
编译时,除了通过-a参数包含共享配置文件,还可以添加一个简单的编译脚本,自动将共享配置复制并重命名为对应exe的config文件:
批处理脚本示例(compile.bat)
@echo off set MCC_COMMAND=mcc -m foo.m -a .\resources\**.* -a ..\Common\startup.config %MCC_COMMAND% :: 复制共享配置为程序对应的config文件 copy "..\Common\startup.config" "foo.exe.config"
如果需要合并Matlab默认的matlab.exe.config中的基础配置(如startup节点),可以编写一个简单的XML合并脚本(比如用PowerShell),将共享配置的runtime节点合并到默认配置中。
方案优势
- 开发环境:所有机器共享同一配置文件,无需手动修改
matlab.exe.config,配置更新自动同步 - 编译部署:通过脚本自动生成对应exe的config文件,或在程序启动时动态处理重定向,完全避免手动配置操作
内容的提问来源于stack exchange,提问作者CitizenInsane
相关产品推荐
相关产品推荐

