2013-03-27 30 views
5

Mam problem w MEF kompozycji w moim usługa WindowsMEF importu nie powiedzie się w systemie Windows Służby

Poniższe klasy są częściowe klas, które dziedziczą z 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 

Emisja Mam to jest, gdy MEF próbuje uruchomić kompozycję na właściwości IServiceWorker, której nie powiedzie się. Początkowo pomyślałem, że IServiceWorker był nie nadchodzi jako jeden z dostępnych części w AggregateCatalog

Dim catelog As AggregateCatalog = New AggregateCatalog(New DirectoryCatalog("."), New AssemblyCatalog(Reflection.Assembly.GetExecutingAssembly().CodeBase)) 

W celu potwierdzenia, że ​​była to ważna część I wyprowadzany wtedy zbiór części do pliku tekstowego za pomocą poniższego kodu.

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 

Widać z ekstraktu poniżej że Service_EPMS_OPC_6Cylinder_Zone1.Worker część implementuje IServiceWorker w jego 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 

To jest to, co spodziewałem się jako klasa Worker robi Eksportuj typu IServiceWorker. Skomentowałem dwa dodatkowe produkty importowane w tej klasie, aby upewnić się, że nie powodują problemu.

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 

I dalej queryed kwestię składu z kodem poniżej

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 

Ta gra mi następujących wyjście w pliku tekstowym

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 : 

co teraz jestem pewny dlatego IServiceWorker Eksport, który znajduje się w kolekcji Części Catelog MEF, nie jest odbierany przez ComposeParts. O ile widzę, atrybut Export w klasie Worker powinien pasować do właściwości Importuj w obiekcie ServiceWorker w svc_EpmsOPCService_6Cylinder_Zone1

Jaki jest pomysł, dlaczego ten import nie działa?

EDYTOWANIE: Ja refaktoryzowałem kod tak, że klasa "Pracownik" jest nazywana konkretną implementacją, a kompozycja ma wtedy miejsce w klasie "Pracownik" i wszystko działa. Czy istnieje ograniczenie, że nie można skomponować części MEF z komponentu usługi systemu Windows, który dziedziczy po "System.ServiceProcess.ServiceBase"?

+0

dlaczego wciąż używasz bazy serwisowej? PM> Install-Package TopShelf Po prostu przejście do górnej półki prawdopodobnie wyeliminuje ten błąd. –

+1

Dlaczego używam ServiceBase? To standardowy sposób na wdrożenie usługi Windows. Nie wszyscy jesteśmy w stanie korzystać z technologii Open Source lub innych niż Microsoft. To cuda pracy w dużym przedsiębiorstwie. –

Odpowiedz

0

Spóźniam się na imprezę, ale zastanawiam się, czy problem jest bardziej związany z rejestrowaniem i utrzymywaniem usług przez system Windows. Uważam, że SCM lub inny składnik usługi zaplecza blokuje zasoby, gdy usługa jest zarejestrowana.

Nie sądzę, że jest to problem związany z samą klasą usługi, sam w sobie nie wydaje się zbyt dziwny, nie jest statyczny, po prostu rozciąga komponent itp. Raczej zakładam, że jest powiązany do samych usług i zarządzania zasobami.

Dla uśmiechów i chichotów używałeś programu ShadowCopy do katalogu katalogów MEF? Gdybyś nie był, zastanawiałbym się, czy to by pomogło ... niektóre z tego są spekulacjami, ponieważ nie miałem czasu, aby ustawić moje własne łóżko testowe, ale to wykształcone domysły z doświadczenia z zarówno MEF, jak i Usługami osobno.

Powiązane problemy