加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

.net – Windows服务中的MEF导入失败

发布时间:2020-12-14 02:17:03 所属栏目:Windows 来源:网络整理
导读:我在 Windows服务中的MEF组合中遇到了问题 以下类是从System.ServiceProcess.ServiceBase继承的部分类 Imports System.ServiceProcessGlobal.Microsoft.VisualBasic.CompilerServices.DesignerGenerated() _Partial Class svc_EpmsOPCService_6Cylinder_Zone
我在 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,Text.Encoding.Unicode)
        System.IO.File.AppendAllText(compositionErrorLog,String.Concat("Meta Data Val : ",meta.Value.ToString,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,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,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,"Description : ",e.Description,"Message : ",e.Exception.Message,"Stack Trace : ",e.Exception.StackTrace,Text.Encoding.Unicode)

        If e.Exception.InnerException IsNot Nothing Then
            System.IO.File.AppendAllText(compositionErrorLog,e.Exception.InnerException.Message,Text.Encoding.Unicode)
            System.IO.File.AppendAllText(compositionErrorLog,e.Exception.InnerException.StackTrace,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 :

现在我不确定的是为什么ComposeParts没有选择MEF Catelog Parts集合中的IServiceWorker Export.据我所知,Worker类的Export属性应与svc_EpmsOPCService_6Cylinder_Zone1中的ServiceWorker属性上的Import相匹配

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

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

解决方法

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

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读