Mam problem w MEF kompozycji w moim usługa WindowsMEF importu nie powiedzie się w systemie Windows Służby
Poniższe klasy są częściowe klas, które dziedziczą z System.ServiceProcess.ServiceBase
Imports System.ServiceProcess
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class svc_EpmsOPCService_6Cylinder_Zone1
Inherits System.ServiceProcess.ServiceBase
'UserService overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
If _catelog IsNot Nothing Then _catelog.Dispose()
If _mefContainer IsNot Nothing Then _mefContainer.Dispose()
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
' The main entry point for the process
<MTAThread()> _
Shared Sub Main()
#If Not Debug Then
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New svc_EpmsOPCService_6Cylinder_Zone1}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
#Else
Dim service = New Worker
service.InitWork()
#End If
End Sub
'Required by the Component Designer
Private components As System.ComponentModel.IContainer
' NOTE: The following procedure is required by the Component Designer
' It can be modified using the Component Designer.
' Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.ServiceName = "JCB.EpmsOPCService_6Cylinder_Zone1"
End Sub
End Class
Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Imports Service.Common
Public Class svc_EpmsOPCService_6Cylinder_Zone1
Private _catelog As AssemblyCatalog
Private _mefContainer As CompositionContainer
<Import(GetType(IServiceWorker))>
Private Property ServiceWorker As IServiceWorker
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim catelog As AggregateCatalog = New AggregateCatalog(New DirectoryCatalog("."), New AssemblyCatalog(Reflection.Assembly.GetExecutingAssembly().CodeBase))
_mefContainer = New CompositionContainer(_catelog)
_mefContainer.ComposeParts(Me)
End Sub
Protected Overrides Sub OnStart(ByVal args() As String)
ServiceWorker.InitWork()
End Sub
Protected Overrides Sub OnStop()
ServiceWorker.StopWork()
_mefContainer.Dispose()
End Sub
End Class
Emisja Mam to jest, gdy MEF próbuje uruchomić kompozycję na właściwości IServiceWorker
, której nie powiedzie się. Początkowo pomyślałem, że IServiceWorker
był nie nadchodzi jako jeden z dostępnych części w AggregateCatalog
Dim catelog As AggregateCatalog = New AggregateCatalog(New DirectoryCatalog("."), New AssemblyCatalog(Reflection.Assembly.GetExecutingAssembly().CodeBase))
W celu potwierdzenia, że była to ważna część I wyprowadzany wtedy zbiór części do pliku tekstowego za pomocą poniższego kodu.
For Each p As System.ComponentModel.Composition.Primitives.ComposablePartDefinition In catelog.Parts
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, p.ToString, vbCrLf), Text.Encoding.Unicode)
For Each meta As KeyValuePair(Of String, Object) In p.Metadata
System.IO.File.AppendAllText(compositionErrorLog, String.Concat("Meta Data Key : ", meta.Key, vbCrLf), Text.Encoding.Unicode)
System.IO.File.AppendAllText(compositionErrorLog, String.Concat("Meta Data Val : ", meta.Value.ToString, vbCrLf), Text.Encoding.Unicode)
Next
For Each exp As Primitives.ExportDefinition In p.ExportDefinitions
System.IO.File.AppendAllText(compositionErrorLog, String.Concat("Export Definition Contract Name : ", exp.ContractName, vbCrLf), Text.Encoding.Unicode)
Next
For Each imp As Primitives.ImportDefinition In p.ImportDefinitions
System.IO.File.AppendAllText(compositionErrorLog, String.Concat("Import Definition Contract Name : ", imp.ContractName, vbCrLf), Text.Encoding.Unicode)
Next
System.IO.File.AppendAllText(compositionErrorLog, vbCrLf, Text.Encoding.Unicode)
Next
Widać z ekstraktu poniżej że Service_EPMS_OPC_6Cylinder_Zone1.Worker
część implementuje IServiceWorker
w jego ExportDefinitions
Service.Common.DataAccess.AuditLogger
Export Definition Contract Name : Service.Common.DataAccess.IAuditLogger
Import Definition Contract Name : Service.Common.DataAccess.IDatabaseHelperFactory
Service.Common.DataAccess.DataHelper
Export Definition Contract Name : Service.Common.DataAccess.IDataHelper
Import Definition Contract Name : Service.Common.DataAccess.IDatabaseHelperFactory
Service.Common.DataAccess.SqlDatabaseHelperFactory
Export Definition Contract Name : Service.Common.DataAccess.IDatabaseHelperFactory
Service.Common.Logging.ErrorLogger
Export Definition Contract Name : Service.Common.Logging.ILogger
Import Definition Contract Name : Service.Common.DataAccess.IDataHelper
Service.Common.Network.NetworkAvailability
Export Definition Contract Name : Service.Common.Network.INetworkAvailability
Import Definition Contract Name : Service.Common.DataAccess.IDataHelper
Import Definition Contract Name : Service.Common.Network.IRemoteServiceHost
Service.Common.Network.RemoteServiceHost
Export Definition Contract Name : Service.Common.Network.IRemoteServiceHost
Service.Common.ObjectCreation.EngineBuilder
Export Definition Contract Name : Service.Common.ObjectCreation.IEngineBuilder
Import Definition Contract Name : Service.Common.DataAccess.IDataHelper
Service.Common.Opc.OpcHelper
Export Definition Contract Name : Service.Common.Opc.IOpcHelper
Service_EPMS_OPC_6Cylinder_Zone1.Worker
Export Definition Contract Name : Service.Common.IServiceWorker
Service_EPMS_OPC_6Cylinder_Zone1.ZoneProcess
Export Definition Contract Name : Service.Common.IZoneProcess
Import Definition Contract Name : Service.Common.Logging.ILogger
Import Definition Contract Name : Service.Common.DataAccess.IDataHelper
Import Definition Contract Name : Service.Common.Network.INetworkAvailability
Import Definition Contract Name : Service.Common.ObjectCreation.IEngineBuilder
Import Definition Contract Name : Service.Common.Opc.IOpcHelper
Import Definition Contract Name : Service.Common.DataAccess.IAuditLogger
To jest to, co spodziewałem się jako klasa Worker
robi Eksportuj typu IServiceWorker
. Skomentowałem dwa dodatkowe produkty importowane w tej klasie, aby upewnić się, że nie powodują problemu.
Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Imports System.Threading
Imports Service.Common
Imports Service.Common.Enums
Imports Service.Common.Logging
<Export(GetType(IServiceWorker))>
Public Class Worker
Implements IServiceWorker
Private _thread As Thread
'<Import(GetType(IZoneProcess))>
'Private Property Processor() As IZoneProcess
'<Import(GetType(ILogger))>
'Private Property Logger() As ILogger
#Region " Service Methods"
''' <summary>
''' Tear down the service
''' </summary>
''' <remarks></remarks>
Public Sub StopWork() Implements IServiceWorker.StopWork
'Tear down the worker thread
If Not _thread Is Nothing Then
If Not _thread.Join(100) Then
_thread.Abort()
End If
End If
End Sub
''' <summary>
''' Initialise the worker thread
''' </summary>
''' <remarks></remarks>
Public Sub InitWork() Implements IServiceWorker.InitWork
Dim objThreadStart As New ThreadStart(AddressOf Me.StartWork)
_thread = New Thread(objThreadStart)
_thread.Start()
End Sub
''' <summary>
''' Start the worker thread functionality
''' </summary>
''' <remarks></remarks>
Private Sub StartWork()
Try
If Not Initialise() Then
Me.StopWork()
End If
Catch ex As Exception
' If Logger IsNot Nothing Then Logger.LogError(My.Settings.ApplicationID, "StartWork", ex.Message, IssueSeverity.Critical)
Me.StopWork()
End Try
End Sub
#End Region
Private Function Initialise() As Boolean
#If DEBUG Then
RunDebugModeComposition()
#End If
'Return Processor.InitialiseApplication()
End Function
Private Sub RunDebugModeComposition()
Try
Dim catelog As AggregateCatalog = New AggregateCatalog(New DirectoryCatalog("."), New AssemblyCatalog(Reflection.Assembly.GetExecutingAssembly().CodeBase))
Dim container As CompositionContainer = New CompositionContainer(catelog)
container.ComposeParts(Me)
Catch ex As CompositionException
Throw New ApplicationException("The composition of the application failed. Pleae check the underlying exception", ex)
End Try
End Sub
End Class
I dalej queryed kwestię składu z kodem poniżej
Try
_mefContainer.ComposeParts(Me)
Catch ex As CompositionException
For Each e As CompositionError In ex.Errors
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, "Description : ", e.Description, vbCrLf), Text.Encoding.Unicode)
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, "Message : ", e.Exception.Message, vbCrLf), Text.Encoding.Unicode)
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, "Stack Trace : ", e.Exception.StackTrace, vbCrLf), Text.Encoding.Unicode)
If e.Exception.InnerException IsNot Nothing Then
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, "Message : ", e.Exception.InnerException.Message, vbCrLf), Text.Encoding.Unicode)
System.IO.File.AppendAllText(compositionErrorLog, String.Concat(vbCrLf, "Stack Trace : ", e.Exception.InnerException.StackTrace, vbCrLf), Text.Encoding.Unicode)
End If
Next
End Try
Ta gra mi następujących wyjście w pliku tekstowym
Description : Cannot set import 'Service_EPMS_OPC_6Cylinder_Zone1.svc_EpmsOPCService_6Cylinder_Zone1.ServiceWorker (ContractName="Service.Common.IServiceWorker")' on part 'Service_EPMS_OPC_6Cylinder_Zone1.svc_EpmsOPCService_6Cylinder_Zone1'.
Message : The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No exports were found that match the constraint:
ContractName Service.Common.IServiceWorker
RequiredTypeIdentity Service.Common.IServiceWorker
Stack Trace :
co teraz jestem pewny dlatego IServiceWorker
Eksport, który znajduje się w kolekcji Części Catelog MEF, nie jest odbierany przez ComposeParts
. O ile widzę, atrybut Export w klasie Worker powinien pasować do właściwości Importuj w obiekcie ServiceWorker
w svc_EpmsOPCService_6Cylinder_Zone1
Jaki jest pomysł, dlaczego ten import nie działa?
EDYTOWANIE: Ja refaktoryzowałem kod tak, że klasa "Pracownik" jest nazywana konkretną implementacją, a kompozycja ma wtedy miejsce w klasie "Pracownik" i wszystko działa. Czy istnieje ograniczenie, że nie można skomponować części MEF z komponentu usługi systemu Windows, który dziedziczy po "System.ServiceProcess.ServiceBase"?
dlaczego wciąż używasz bazy serwisowej? PM> Install-Package TopShelf Po prostu przejście do górnej półki prawdopodobnie wyeliminuje ten błąd. –
Dlaczego używam ServiceBase? To standardowy sposób na wdrożenie usługi Windows. Nie wszyscy jesteśmy w stanie korzystać z technologii Open Source lub innych niż Microsoft. To cuda pracy w dużym przedsiębiorstwie. –