我在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
类在类型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
我使用以下代码进一步查询了Composition问题
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集合中的ComposeParts
导出。据我所知,Worker类的Export属性应与ServiceWorker
svc_EpmsOPCService_6Cylinder_Zone1
属性的Import相匹配
知道为什么导入不起作用?
编辑: 我已经重构了代码,以便&#39;工作者&#39; class被称为具体实现,然后组合在“工作人员”中进行。上课,一切正常。 是否存在限制,您无法从继承自System.ServiceProcess.ServiceBase&#39; System.ServiceProcess.ServiceBase&#39;的Windows服务组件组成MEF部分。 ?
答案 0 :(得分:0)
关于这一方的晚会,但我想知道这个问题是否与Windows如何注册和维护服务有关。我相信SCM或其他一些后端服务组件在注册服务时会锁定资源。
我不相信它本身就是Service基类的一个问题,它看起来并不太奇怪,它不是静态的,它只是扩展Component等。相反,我敢打赌它与服务本身和资源管理。
对于笑脸和咯咯笑声,你是否在你的MEF DirectoryCatalog中使用ShadowCopy?如果你不是我不知道它是否会有所帮助...其中一些是猜测因为我没有时间设置我自己的试验台,但这是对MEF和服务分开经验的有根据的猜测。