我的 Windows 服务中的 MEF 组合存在问题
下面的类是继承自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
我遇到的问题是,当 MEF 尝试在IServiceWorker
它失败的属性上运行组合时。最初我虽然IServiceWorker
没有作为可用部分之一通过AggregateCatalog
Dim catelog As AggregateCatalog = New AggregateCatalog(New DirectoryCatalog("."), New AssemblyCatalog(Reflection.Assembly.GetExecutingAssembly().CodeBase))
为了确认这是一个有效的零件,我使用以下代码将零件集合输出到一个文本文件。
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
您可以从下面的摘录中看到该Service_EPMS_OPC_6Cylinder_Zone1.Worker
部件IServiceWorker
在其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
这是我所期望的,因为Worker
该类在 type 上执行 Export IServiceWorker
。我已经在这个类上注释掉了两个额外的 Imports,以确保它们不会导致问题。
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
我用下面的代码进一步查询了组合问题
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
这个游戏我在文本文件中的以下输出
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 :
现在我不确定的是为什么IServiceWorker
MEF Catelog Parts 集合中的 Export 没有被ComposeParts
. 据我所见, Worker 类上的 Export 属性应该与ServiceWorker
属性中的 Import 匹配svc_EpmsOPCService_6Cylinder_Zone1
知道为什么此导入不起作用吗?
编辑:我已经重构了代码,以便将“Worker”类称为具体实现,然后组合发生在“Worker”类中,一切正常。是否存在不能从继承自 'System.ServiceProcess.ServiceBase' 的 Windows 服务组件中组合 MEF 部件的限制?