2
votes

I've got this interface, from a WCF service:

[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]
public interface IQuerySageService
{

    [OperationContract]
    CustomerLedger GetBillingContact(string crmAccountNumber);

    [OperationContract]
    ImportCrmInvoicesResponse ImportCrmInvoices(List<New.Xrm.Entities.Invoice> invoices);


}

And the method refered above is from this class:

internal static class KnownTypesProvider
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        List<Type> types = new List<Type>();

        types.Add(typeof(New.Xrm.Entities.InvoiceDetail));

        return types;
    }
}

But when invoking ImportCrmInvoices (Invoice has InvoiceDetail children) from the client (a CRM workflow), I get the following error:

There was an error while trying to serialize parameter http://tempuri.org/:invoices. The InnerException message was 'Type 'New.Xrm.Entities.InvoiceDetail' with data contract name 'InvoiceDetail:http://schemas.datacontract.org/2004/07/New.Xrm.Entities' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details."

I thought this ServiceKnownType decoration would do the trick from what I've read, but apparently not.

The types (Invoice, InvoiceDetail) are contained within an assembly, refered by both the client and the server (namespace New.Xrm.Entities)

Now, the physical CS file that holds those types is huge (7MB), and barely editable. So maybe I'm missing a DataContract decoration somewhere, but I don't want to go in this file to add it.

Any other ways to achieve this ?

2
Serializing/Deserializing early bound entities is a pain and also will increase dependency and not to mention the 1001 unnecessary members that it holds. Try to flatten it out by using a poco with just the members you need, it is much cleaner and leaner this way.dynamicallyCRM
@dynamicallyCRM I think that's what it'll come to... Thanks.Francis Ducharme

2 Answers

1
votes

Another way to achieve this is to use the KnownTypes attribute on your parent DataContract class from which your child classes derive.

The KnownTypeAttribute class allows you to specify, in advance, the types that should be included for consideration during deserialization.

(https://msdn.microsoft.com/en-us/library/ms730167(v=vs.110).aspx)

The KnownTypes attribute can either take a type parameter, or you can provide the name of a method in that class that returns an array of valid types.

For example:

[DataContract]
[KnownTypes(typeof(InvoiceDetail)]
public class Invoice
{
    [DataMember]
    public string SomeProperty {get; set; }
}

[DataContract]
public class InvoiceDetail : Invoice
{
}
0
votes

I ended up have having the WCF service doing it's own look ups in CRM. The ImportCrmInvoices method accepts a list of GUIDS and fetches the data about them itself.