SAP NCo多连接(不同主机)注册配置异常问题咨询
问题分析与解决方案
为啥会出现这个报错呢?其实是因为RfcDestinationManager.RegisterDestinationConfiguration这个方法全局只能注册一次配置实例!你现在的代码逻辑是,每次找不到对应连接池的连接,就新建一个DestinationConfig去注册,第二次注册时系统发现已经有全局配置了,自然就抛出异常说之前的配置已经初始化,不能再注册新的了。
怎么修复?我给你分步骤说:
1. 让你的DestinationConfig能管理多连接池
原来的DestinationConfig应该是只能处理单个站点的配置,现在得改成能维护多个连接池和站点的映射关系,比如用一个字典来存,键是连接池名称,值是对应的站点信息。
2. 全局只注册一次配置
别每次找不到连接就去注册新配置,应该在应用启动或者第一次使用的时候,注册一次全局的DestinationConfig实例,之后就复用它,别再重复注册了。
3. 调整SAPConnection方法的逻辑
修改代码,确保只注册一次配置,并且从同一个全局配置实例里获取不同连接池的目标。
给你改好的示例代码
// 全局维护唯一的DestinationConfig实例,确保只注册一次 private static readonly DestinationConfig _globalSAPConfig = new DestinationConfig(); private static bool _isConfigRegistered = false; function() { if (SAPDestination == null) { SAPDestination = SAPConnection(ApplicationSite); RfcSessionManager.BeginContext(SAPDestination); } rfcTravelfunc = SAPDestination.Repository.CreateFunction("FunctionName"); } private RfcDestination SAPConnection(SPSite ApplicationSite) { RfcDestination SAPConnect = null; try { // 确保全局只注册一次配置 if (!_isConfigRegistered) { RfcDestinationManager.RegisterDestinationConfiguration(_globalSAPConfig); _isConfigRegistered = true; } // 先尝试获取对应连接池的目标 SAPConnect = RfcDestinationManager.GetDestination(ConnectionPoolName); // 如果目标不存在,就把当前站点的配置添加到全局配置里,再获取 if (SAPConnect == null) { _globalSAPConfig.AddPoolSiteMapping(ConnectionPoolName, ApplicationSite); SAPConnect = RfcDestinationManager.GetDestination(ConnectionPoolName); } } catch(Exception ex) { // 这里建议加个日志记录,方便后续排查问题,别空着catch // Log.Error($"创建SAP连接失败,连接池名称:{ConnectionPoolName}", ex); } return SAPConnect; } // 修改后的DestinationConfig类,支持多连接池配置 public class DestinationConfig : IDestinationConfiguration { // 用字典存连接池名称和对应站点的映射,线程安全起见加个锁对象 private readonly Dictionary<string, SPSite> _poolToSiteMap = new Dictionary<string, SPSite>(); private readonly object _mapLock = new object(); public void AddPoolSiteMapping(string poolName, SPSite site) { lock (_mapLock) { if (!_poolToSiteMap.ContainsKey(poolName)) { _poolToSiteMap.Add(poolName, site); } } } public RfcConfigurationParameters GetParameters(string destinationName) { // 根据连接池名称(也就是这里的destinationName)返回对应的SAP配置参数 if (_poolToSiteMap.TryGetValue(destinationName, out var targetSite)) { var sapParams = new RfcConfigurationParameters(); // 这里替换成你从站点获取SAP服务器参数的逻辑 sapParams.Add(RfcConfigParameters.AppServerHost, targetSite.RootWeb.Properties["SAPAppServer"].ToString()); sapParams.Add(RfcConfigParameters.SystemNumber, targetSite.RootWeb.Properties["SAPSystemNum"].ToString()); sapParams.Add(RfcConfigParameters.Client, targetSite.RootWeb.Properties["SAPClient"].ToString()); // 其他必要参数比如用户名、密码,建议用安全的方式存储和获取,别硬编码 // sapParams.Add(RfcConfigParameters.User, "your-user"); // sapParams.Add(RfcConfigParameters.Password, "your-password"); return sapParams; } return null; } public bool ChangeEventsSupported() { return false; // 如果不需要动态修改配置,返回false就行 } public event EventHandler<DestinationConfigurationChangedEventArgs> ConfigurationChanged; }
几个关键要点要注意:
- 全局单例配置:
RfcDestinationManager的配置是全局生效的,只能注册一次,所以用静态字段维护唯一的配置实例,避免重复注册。 - 多连接池映射:通过字典把不同的连接池名称和对应的站点配置绑定,这样每次获取目标时,就能返回对应站点的SAP服务器参数。
- 线程安全:操作字典的时候加个锁,防止多线程环境下出现冲突。
内容的提问来源于stack exchange,提问作者Priya
相关产品推荐
相关产品推荐

