繁体   English   中英

MEF导入在Windows服务中失败

[英]MEF Import fails in Windows Service

我在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部件在其ExportDefinitions实现IServiceWorker

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零件集合了由ComposeParts 据我所知,Worker类的Export属性应与svc_EpmsOPCService_6Cylinder_Zone1ServiceWorker属性上的Import相匹配

知道为什么这个导入不起作用?

编辑:我重构了代码,以便'Worker'类被称为具体实现,然后组合在'Worker'类中进行,一切正常。 是否有限制,你不能从继承自'System.ServiceProcess.ServiceBase'的Windows服务组件组成MEF部分?

这个问题迟到了,但我想知道这个问题是否与Windows如何注册和维护服务有关。 我相信SCM或其他一些后端服务组件在注册服务时会锁定资源。

我不相信它本身就是Service基类的一个问题,它看起来并不太奇怪,它不是静态的,它只是扩展Component等等。相反,我敢打赌它与服务本身和资源管理。

对于笑脸和咯咯笑声,您是否使用ShadowCopy作为MEF DirectoryCatalog? 如果你不是我不知道它是否会有所帮助...其中一些是猜测,因为我没有时间设置我自己的测试床,但这是一个有教育的猜测来自MEF和服务分开的经验。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM