Cannot Cast PipelineBuilder HostView to AddInView?

Sep 11, 2008 at 12:20 AM
I have a host contract which has a function which returns another contract as a return value. In passing a contract from host to add-in, I'm not able to cast the converted HostView implementation to my AddInView implementation. My views are generated with PipelineBuilder.

The following snippets are hand-reduced versions of what I'm working with. When the bolded line executes, it throws an exception:

Unable to cast object of type ‘MyContracts.AddInSideAdapters.IDataReferenceContractToViewAddInAdapter’ to type ‘AddInSample.DataReference’.


I can view the contents of the returned contract just fine, so I know the pipeline is working. I just can't figure out why I can't assign the returned contract object to the add-in side implementation. I can get around this by hand-copying each value from the return value to the implementation, but I wouldn't think I would have to since they're implementing the same contract.

Thanks in advance!
-Gary Geniesse

-------------------------Contracts -----------------------------------
<AddInContract()>
Public Interface IDataReferenceContract
    Inherits System.AddIn.Contract.IContract
    Property Thing() as String
End Interface

Public Interface IHostContract
    Inherits System.AddIn.Contract.IContract
    Function GetDataReference() as IDataReferenceContract
End Interface
-------------------------Host Code----------------------------------
Public Class HostDataReference
    Implements MyContracts.HostViews.IDataReference
    Private m_Thing as String
    Public Property Thing() as String Implements MyContracts.HostViews.IDataReference.Thing
        ...
    End Property
End Class
Public Class Hoster
    Implements MyContracts.HostViews.IHost
    ...
    Public Function GetDataReference() as MyContracts.HostViews.IDataReference Implements MyContracts.HostViews.IHost.GetDataReference
        GetDataReference = New HostDataReference
    End Function
End Class
-------------------------Add-in Code-------------------------------
Public Class AddInDataReference
    Implements MyContracts.AddInViews.IDataReference
    Private m_Thing as String
    Public Property Thing() as String Implements MyContracts.AddInViews.IDataReference.Thing
        ...
    End Property
End Class
Public Class AddInSample
    Implements IMyAddin
    Protected m_Host As MyContracts.AddInViews.IHost
    ...
    Public Function GetDataReference() As AddInDataReference
        GetDataReference = m_Host.GetDataReference()
    End Function
End Class
----------------------------------------------------------------------

Sep 11, 2008 at 3:54 PM
Here is the cleanest solution I can come up with. I think the issue is that something needs to create a local instance of the AddInDataReference class regardless of it implementing the same pipeline.

----------------------------------------------------------------------
GetDataReference = new AddInDataReference(m_Host.GetDataReference)

Public Class AddInDataReference
    ...
    Public Sub (byref copyRef as MyContracts.AddInViews.IDataReference)
       m_Thing = copyRef.m_Thing
    End Sub
    ...
End Class
----------------------------------------------------------------------
Sep 11, 2008 at 8:44 PM

Hi Gary,

Is there a reason you're copying the Thing value to an AddInDataReference object?

You can just return the host object from GetDataReference() directly:

Public Class AddInSample
    Implements IMyAddin
    Protected m_Host As MyContracts.AddInViews.IHost
    ...
    Public Function GetDataReference() As MyContracts.AddInViews.IDataReference
        GetDataReference = m_Host.GetDataReference()
    End Function
End Class

This way you don't even need the AddInDataReference class.

The way you have it currently, you're copying the Thing value to the add-in side, so if it changes on the host at some point, the add-in won't know about it. If you keep a reference to the MyContracts.AddInViews.IDataReference object, then every time you access Thing on it, it will call into the host and get an updated value.

Generally, if you want to copy data from the host to the add-in, we recommend using a Structure in the contract. And if you want to get a reference to a host object and later call into methods/properties in the host, we recommend creating a contract interface for it.

Sep 11, 2008 at 9:25 PM
Ok, I think I see my misunderstanding. Since the generated Views are Interfaces on both sides, I was thinking I was supposed implement the interfaces on both sides to access them.

My understanding now is that any contracts should only be implemented on one side, with the other side just accessing the interface directly.

Concerning Contracts versus Structures, I'd like to use the most efficient pipeline for static data. My understanding is as follows:
- Contracts maintain storage on one side, reference is passed across pipeline, each property access is through pipeline
- Structures create several copies of data, data is passed across pipeline, each property access is local

If this is correct, I'm weighing the cost of copying n data members versus the cost of traversing the pipeline n times. Does anyone have a good feel for how expensive it is to cross the pipeline boundary?

Thanks for the help!