Fixed. The answer was to add the ServiceKnownType, using the helper method form, to the service interface, not the service implementation, and to add a helper class that reflects the types I need instead of adding them by referring to the concrete types in code. (Recall, I couldn't do that because I can't add a reference to that assembly.)
[ServiceContract]
[ServiceKnownType("GetDataContractTypes", typeof(MyServiceHelper))]
public interface IMyService
{ ... }
And I added a new MyServiceHelper class to Nightingale.Interface, but it's not public so I'm not concerned about unnecessarily exposing a class from an assembly that I want to be "pure" interface only.
// Not public outside of this assembly.
static class MyServiceHelper
{
public static IEnumerable<Type> GetDataContractTypes(ICustomAttributeProvider paramIgnored)
{
// Get the assembly with the concrete DataContracts.
Assembly ass = Assembly.Load("MyService"); // MyService.dll
// Get all of the types in the MyService assembly.
var assTypes = ass.GetTypes();
// Create a blank list of Types.
IList<Type> types = new List<Type>();
// Get the base class for all MyService data contracts
Type myDataContractBase = ass.GetType("MyDataContractBase", true, true);
// Add MyService's data contract Types.
types.Add(assTypes.Where(t => t.IsSubclassOf(myDataContractBase)));
// Add all the MyService data contracts to the service's known types so they can be serialized.
return types;
}
}
This particular solution works for me because all of my DataContract classes extend a common base class. It could be reworked to load all Types from the assembly that have the DataContract attribute which would result in the same set, in my case.