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
私が抱えている問題は、MEFIServiceWorker
が失敗したプロパティでコンポジションを実行しようとしたときです。当初、私はIServiceWorker
が入手可能なパーツの 1 つとして流通していないと思っていました。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
です。問題の原因ではないことを確認するために、このクラスの 2 つの追加のインポートをコメントアウトしました。
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 カタログ パーツ コレクションにあるエクスポートが によって取得されていない理由ComposeParts
です。私が見る限り、Worker クラスの Export 属性は、ServiceWorker
プロパティの Import と一致する必要があります。svc_EpmsOPCService_6Cylinder_Zone1
このインポートが機能しない理由は何ですか?
編集:コードをリファクタリングして、「Worker」クラスが具体的な実装として呼び出され、構成が「Worker」クラス内で行われ、すべてが機能するようにしました。「System.ServiceProcess.ServiceBase」から継承した Windows サービス コンポーネントから MEF パーツを構成できないという制限はありますか?