У меня есть надстройка для MS Excel, которой нужен единый пакет для обмена данными между модулями.В зависимости от версии Excel (2003, 2007, 2010) и от того, как Excel был запущен, он вызывает мой надстройку из разных непредсказуемых доменов приложений, что предотвращает классический одноэлементный подход.
Создание собственного AppDomainManager не будетработать, потому что Excel уже создал AppDomains до вызова надстройки.
Ссылка на mscoree для перечисления доменов нарушает процесс регистрации надстройки (и я действительно не хочу этого в любом случае);кажется, нет другого способа перечисления, так что это тоже не вариант.
Единственное решение, которое я нашел, это использовать удаленное взаимодействие.Вот мой тестовый стенд:
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
' Remeber to add reference to System.Runtime.Remoting DLL !
Public Class CrossAppDomainSingleton(Of T As {New})
Inherits MarshalByRefObject
Private Const _portnumber As Integer = 9999 ' adjust to suit taste
Private Shared _instance As T = Nothing
Private Shared _lock As Object = New Object
Private Shared _id As Guid = Nothing
Private Shared _myapp As String = System.Reflection.Assembly.GetExecutingAssembly().GetName.Name
Private Shared _myname As String = GetType(T).ToString
Private Shared _myfullname As String = _myapp & "/" & _myname
Protected Sub New()
_id = Guid.NewGuid
Console.WriteLine("New " & ID & " in " & AppDomain.CurrentDomain.FriendlyName)
End Sub
Public Function GetInstance() As T
If _instance Is Nothing Then
Console.WriteLine("GetInstance in " & AppDomain.CurrentDomain.FriendlyName)
_instance = New T
End If
Return _instance
End Function
Public ReadOnly Property ID As String
Get
Return _id.ToString
End Get
End Property
Public Overrides Function InitializeLifetimeService() As Object
Console.WriteLine("InitializeLifetimeService=infinite")
Return Nothing
End Function
Public Shared Function Instance() As T
Dim currentdomain As AppDomain
Dim uri As String
Dim registered As Boolean = False
Dim remotet As Object
Dim tcpchannel As Tcp.TcpChannel
Dim tcpprops As System.Collections.IDictionary
Dim sw As Stopwatch = New Stopwatch
Try
sw.Start()
SyncLock _lock
Console.WriteLine("Instance in " & AppDomain.CurrentDomain.FriendlyName)
If _instance Is Nothing Then
currentdomain = AppDomain.CurrentDomain
_instance = currentdomain.GetData(_myfullname)
If _instance Is Nothing Then
' Build connection string "tcp://localhost:[_portnumber]/[myapp]/[myname]".
uri = String.Format("tcp://localhost:{0}/{1}/{2}",
_portnumber.ToString,
_myapp,
_myname)
registered = False
Try
remotet = RemotingServices.Connect(GetType(T), uri)
_instance = remotet.GetInstance()
currentdomain.SetData(_myfullname, _instance)
registered = True
Catch ex As Exception
End Try
If registered Then
Console.WriteLine("... instanced with remoting")
Else
Try
Dim ichannel As IChannel = ChannelServices.GetChannel(_myfullname)
ChannelServices.UnregisterChannel(ichannel)
Catch ex As Exception
End Try
tcpprops = New System.Collections.Hashtable
tcpprops("port") = _portnumber.ToString
tcpprops("name") = _myfullname
tcpchannel = New Tcp.TcpChannel(tcpprops, Nothing, Nothing)
ChannelServices.RegisterChannel(tcpchannel, False)
RemotingConfiguration.ApplicationName = _myapp
RemotingConfiguration.RegisterWellKnownServiceType(GetType(T),
_myname,
WellKnownObjectMode.Singleton)
remotet = RemotingServices.Connect(GetType(T), uri)
_instance = remotet.GetInstance()
Console.WriteLine("... singleton instance created")
End If
Else
Console.WriteLine("... instanced from AppDomain")
End If
Else
Console.WriteLine("... instanced statically")
End If
End SyncLock
Catch ex As Exception
Console.WriteLine(String.Format("Error in {0}.Instance: {1}", _myname, ex.Message))
End Try
Console.WriteLine("instance time=" & CLng(1000000 * sw.ElapsedTicks / Stopwatch.Frequency) & " µS")
sw.Stop()
Return _instance
End Function
End Class
(пожалуйста, не обращайте внимания на стиль и т. Д., Это просто макет).
Я тренирую его с помощью:
Module Main
Public Class Common
Inherits CrossAppDomainSingleton(Of Common)
' real application data goes here
End Class
Sub Main()
Dim common As Common
common = common.Instance
Dim defaultdomain As AppDomain = AppDomain.CurrentDomain
defaultdomain.DoCallBack(AddressOf ShowSingleton)
Dim domain1 As AppDomain = AppDomain.CreateDomain("One")
domain1.DoCallBack(AddressOf ShowSingleton)
Dim domain2 As AppDomain = AppDomain.CreateDomain("Two")
domain2.DoCallBack(AddressOf ShowSingleton)
defaultdomain.DoCallBack(AddressOf ShowSingleton)
domain1.DoCallBack(AddressOf ShowSingleton)
domain2.DoCallBack(AddressOf ShowSingleton)
Dim junk As Object = Console.ReadKey
End Sub
Private Sub ShowSingleton()
Console.WriteLine("ShowSingleton in " & AppDomain.CurrentDomain.FriendlyName)
Dim common As Common = common.Instance
Console.WriteLine("guid is " & common.ID)
End Sub
End Module
ЗдесьВот результаты:
Instance in CrossAppDomainSingletonDemo.vshost.exe
New 497696b6-71c7-4001-b232-39b379034385 in CrossAppDomainSingletonDemo.vshost.exe
InitializeLifetimeService=infinite
GetInstance in CrossAppDomainSingletonDemo.vshost.exe
New 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4 in CrossAppDomainSingletonDemo.vshost.exe
InitializeLifetimeService=infinite
... singleton instance created
instance time=2593865 µS ' AAAARRRRGGGGHHHHH !!!!!!!!!!!!!!
ShowSingleton in CrossAppDomainSingletonDemo.vshost.exe
Instance in CrossAppDomainSingletonDemo.vshost.exe
... instanced statically
instance time=38 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
ShowSingleton in One
Instance in One
... instanced with remoting
instance time=440087 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
ShowSingleton in Two
Instance in Two
... instanced with remoting
instance time=438821 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
ShowSingleton in CrossAppDomainSingletonDemo.vshost.exe
Instance in CrossAppDomainSingletonDemo.vshost.exe
... instanced statically
instance time=111 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
ShowSingleton in One
Instance in One
... instanced statically
instance time=106 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
ShowSingleton in Two
Instance in Two
... instanced statically
instance time=105 µS
guid is 3a3a7a9c-a4f7-46d4-9b16-35fdbfbdc6c4
Когда все работает, доступ к синглтону занимает ~ 100 мкс, что идеально.Я могу жить с ~ 400 мс при первой инициализации каждого домена приложений.Проблема при запуске, когда вызов удаленного взаимодействия занимает ~ 2,5 секунды.
Любые предложения будут приветствоваться, я неделями пытался найти достойное решение>; -)