2
\$\begingroup\$

I am implementing the Factory pattern for creating my objects and am trying to compose the factories using the AssemblyCatelog from MEF.

The problem I have is that while the Import of the InspectionFactory works the Import of the InspectionPhotoFactory does not.

If I call the AddPhoto method on an InspectionFault object I can see that the PhotoFactory is null. I can see from looking at the container object after the composition completes ( _container.ComposeParts(Me)) that there is a IInspectionPhotoFactory part in the collection but it does not get assigned to the Import on the InspectionFault.PhotoFactory property.

Any ideas what I am missing? Should I really be using a single factory for both objects and not having a PhotoFactory in each instance of the InspectionFault collection?

Form 1

<Import(GetType(IInspectionFactory))>
Public Property InspectionFactory As IInspectionFactory

Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    _catelog = New AssemblyCatalog(Assembly.GetExecutingAssembly)
    _container = New CompositionContainer(_catelog)

    Try
        _container.ComposeParts(Me)
    Catch ex As CompositionException
        Stop
    Catch ex As Reflection.ReflectionTypeLoadException
        Stop
    Catch ex As Exception
        Stop
    End Try

End Sub

Private Sub GetInspectionObject()

    Dim ins As InspectionFault = InspectionFactory.CreateInspection

    Try
        Dim by(10) As Byte
        ins.AddPhoto(by)
    Catch ex As Exception
        Stop
    End Try


    Stop

End Sub

Private Sub SimpleButton1_Click(sender As System.Object, e As System.EventArgs) Handles SimpleButton1.Click
    GetInspectionObject()
End Sub

IInspectionFactory

Public Interface IInspectionFactory

    Function CreateInspection() As InspectionFault

End Interface

IInspectionPhotoFactory

Public Interface IInspectionPhotoFactory

    Function CreateInspectionPhoto() As IList(Of InspectonPhoto)

End Interface

InspectionFactory

Imports System.ComponentModel.Composition

<Export(GetType(IInspectionFactory))>
Public Class InspectionFactory
    Implements IInspectionFactory

    Public Function CreateInspection() As InspectionFault Implements IInspectionFactory.CreateInspection
        Return New InspectionFault
    End Function

End Class

InspectionFault

Imports System.ComponentModel.Composition

Public Class InspectionFault

    Public Property PartCentreID() As Int16
    Public Property PartNumberID() As Int32
    Public Property FaultCodeID() As Int16
    Public Property FaultCodeDetailID() As Int16
    Public Property SuplierID() As Int32
    Public Property CreatedByID() As Int32
    Public Property AdviceNumber() As String
    Public Property InspectionNotes() As String
    Public Property Quantity() As Int16
    Public Property InspectionPhotos() As IList(Of InspectonPhoto)

    <Import(GetType(IInspectionPhotoFactory))>
    Public Property PhotoFactory As IInspectionPhotoFactory

    Public Sub AddPhoto(img As Byte())

        If img Is Nothing Then Throw New ArgumentNullException("img", "Parameter Can Not Be Null")

        If InspectionPhotos Is Nothing Then InspectionPhotos = PhotoFactory.CreateInspectionPhoto
        InspectionPhotos.Add(New InspectonPhoto With {.Photo = img})

    End Sub

End Class

InspectionPhotoFactory

Imports System.ComponentModel.Composition

<Export(GetType(IInspectionPhotoFactory))>
Public Class InspectionPhotoFactory
    Implements IInspectionPhotoFactory

    Public Function CreateInspectionPhoto() As IList(Of InspectonPhoto) Implements IInspectionPhotoFactory.CreateInspectionPhoto
        Return New List(Of InspectonPhoto)
    End Function

End Class

InspectonPhoto

Public Class InspectonPhoto

    Public Property Photo() As Byte()

End Class

Possible Resolution

I can make the changes as shown below and it does work but I still don't understand why the above does not

InspectionFactory

Imports System.ComponentModel.Composition

<Export(GetType(IInspectionFactory))>
Public Class InspectionFactory
    Implements IInspectionFactory

    <Import(GetType(IInspectionPhotoFactory))>
    Public Property PhotoFactory As IInspectionPhotoFactory

    Public Function CreateInspection() As InspectionFault Implements IInspectionFactory.CreateInspection
        Return New InspectionFault With {.InspectionPhotos = PhotoFactory.CreateInspectionPhoto}
    End Function

End Class

InspectionFault

Public Class InspectionFault

    Public Property PartCentreID() As Int16
    Public Property PartNumberID() As Int32
    Public Property FaultCodeID() As Int16
    Public Property FaultCodeDetailID() As Int16
    Public Property SuplierID() As Int32
    Public Property CreatedByID() As Int32
    Public Property AdviceNumber() As String
    Public Property InspectionNotes() As String
    Public Property Quantity() As Int16
    Public Property InspectionPhotos() As IList(Of InspectonPhoto)

    Public Sub AddPhoto(img As Byte())

        If img Is Nothing Then Throw New ArgumentNullException("img", "Parameter Can Not Be Null")
        InspectionPhotos.Add(New InspectonPhoto With {.Photo = img})

    End Sub

End Class

Anyone have any opinions of this solution? It doesn't feel right having the PhotoFactory inside the InspectionFactory and calling the New InspectonPhoto in the InspectionFault class.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If I call the AddPhoto method on an InspectionFault object I can see that the PhotoFactory is null.

MEF will never silently fail to compose an object in this way. It will either create the object with all required imports, or fail with a CompositionException.

Therefore, if you see an object instance which has a missing import, it must mean that you did not construct it with MEF, but just called the constructor directly. And indeed, you don't have an export attribute on the InspectionFault class so it is not even possible to ask MEF to construct it.

\$\endgroup\$
1
  • \$\begingroup\$ Very good point Wim. No idea how I missed that :-) \$\endgroup\$ Commented May 21, 2012 at 8:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.