Protobuf-net not serializing base class members - c#

We have the following classes and WCF service (using protobuf-net for serialization):
[DataContract]
[KnownType(typeof(NamedViewModel))]
public class NamedViewModel<TKey> : IViewModel
{
[DataMember]
public virtual TKey Id { get; set; }
[DataMember]
public virtual string Name { get; set; }
}
[DataContract]
[KnownType(typeof(ScheduleTemplateViewModel))]
public class NamedViewModel : NamedViewModel<int>
{
}
[DataContract]
public class ScheduleTemplateViewModel : NamedViewModel
{
[DataMember]
public string Comment { get; set; }
}
[DataContract]
public class Container
{
[DataMember]
public IEnumerable<ScheduleTemplateViewModel> Templates { get; set; }
}
[ServiceContract]
public interface IService
{
[OperationContract]
Container Get();
}
public class Service : IService
{
public IEnumerable<Container> Get()
{
return new Container { Templates = Enumerable.Range(1, 10)
.Select(i => CreateTemplate()).ToArray() };
}
private void ScheduleTemplateViewModel CreateTemplate()
{
var instance = WindsorContainer.Resolve<ScheduleTemplateViewModel>();
// populate instance
return instance;
}
}
We have two problems:
We get an exception during serialization that the Castle DynamicProxy type for ScheduleTemplateViewModel is unexpected. We noticed that there is custom code in protobuf-net to handle NHibernate and EntityFramework proxies...but not Castle DynamicProxies. We worked around this by adding an additional case statement in the protobuf-net source code to check for Castle's IProxyTargetAccessor type...but it would be nice if there were a way of handling this without modifying the protobuf-net source code...
Members on ScheduleTemplateViewModel (namely Comment) are serialized correctly...but base class Members are not. We already have the InferTagFromNameDefault set to true on RuntimeTypeModel.Default.

I can add that; can you tell me the full name (including namespace) of that interface?
From the example you give, none of those values should serialize, as none of them include the necessary numeric field-number information. Since you say some do serialize, I'm going to assume that this is an omission in the copy/paste. Protobuf-net will try to use the Order=n information from [DataMember(...)] if nothing better is available. However, if must be emphasized that protobuf-net cannot use [KnownType(...)], and inheritance again needs some explicit numeric field-number information. This is most easily added via [ProtoInclude(...)], but can also be provided at runtime

Related

C# Redis Interface Collection Deserialization - Could not create an instance of type

I am using C# StackExchange.Redis cache, and am attempting to cache an object that has a collection of interface objects. Cache works fine, but deserialization throws the error:
Could not create an instance of type IMyInterface. Type is an interface or abstract class and cannot be instantiated.
If I were handling the deserialization myself, I understand I could create custom deserialization rules via this SO post:
var obj = JsonConvert.DeserializeObject <MyParentClass>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = binder // write some custom deserialization rules
});
However, I don't have access to the deserialization process because it handled by Redis / Newtonsoft.Json. Btw, I am using StackExchange.Redis 1.1.0.0 and Newtonsoft.Json 9.0.0.0
I also found this SO post, about specifying a serialVersionUID, however this is explicitly for Java as outlined in this SO post.
So what am I missing or what are my options? Thanks in advance!
Here is sample code to work with:
public interface IMyInterface
{
string Name { get; set; }
}
public class MyChildClassA : IMyInterface
{
public string Name { get; set; }
}
public class MyChildClassB : IMyInterface
{
public string Name { get; set; }
}
public class MyParentClass
{
public IList<IMyInterface> Children { get; set; }
// Assume proper init of list in constructor
}
public void DoStuff()
{
var parentValue = new MyParentClass();
// Assume parentValue.Children contains objects of both MyChildClassA and MyChildClassB
// Works!
MyCacheImplementation.Add<MyParentClass>(someKey, parentValue);
// Does NOT work!
MyCacheImplementation.Get<MyParentClass>(someKey);
}

ServiceStack: Property in request DTO becomes null if type is abstract

I have a ServiceStack 3-based client-server architecture. I'm trying to create a service whose request DTO contains a property with an abstract type, with two different concrete classes implementing it. The abstract type could be either an abstract class or an interface; however, in either case, the server receives a null object in the property.
There's three assemblies and corresponding namespaces: TestClient, Server, and CommonLib referenced by both client and server.
That is, spread across the three assemblies:
namespace CommonLib.Services
{
public class GetThing : IReturn<GetThingResponse> // request DTO
{
public IThisOrThat Context { get; set; }
}
public class GetThingResponse
{
public Dictionary<int, string> Result { get; private set; }
public GetThingResponse(Dictionary<int, string> result) // response DTO
{
Result = result;
}
}
}
namespace CommonLib
{
public interface IThisOrThat { }
public class This : IThisOrThat { } // and so forth
}
namespace Server.Services
{
public class GetThing Service : IService
{
public object Get(GetThing request)
{
var foo = request.Context; // this is null
}
}
}
namespace TestClient
{
class Program
{
public const string WSURL = "http://localhost:61435/";
static void Main(string[] args)
{
using (var client = new JsonServiceClient(WSURL))
{
var result = client.Get(new GetThing
{
Context = new CommonLib.This("context info")
});
}
}
If I change the Context property in GetThing to be of type This instead of IThisOrThat, this works. Leaving it as the interface, or changing IThisOrThat to be an abstract class, results in the data being transmitted as null.
I'm assuming this is a serialization problem. I've tried changing the interface to an abstract class and decorating that with appropriate KnownType attributes, but ServiceStack's serializer doesn't appear to benefit from this. Is there any trick to get this done?
You would need to enable JsConfig.IncludeTypeInfo = true; on the client side, so the serializer includes the type information with the request. This will add an extra property (__type) with the type definition so the service knows what to type it as.
It fails currently because requests by default don't provide type information to deserialize the object into the class that implements the interface. This was an issue that was previously raised.
The problem is the when the JSON client makes the request, it will serialize up the a class that implements IThisOrThat such as your This class. But when it gets to the other end ServiceStack.Text doesn't know what to deserialize the object into. The type information is lost so it doesn't know what kind of IThisOrThat it is. So without the additional __type information property in the request this is happening:
Scenario:
interface ISomething
{
string Name;
}
class MySomething : ISomething
{
public string Name { get; set; }
public int Age { get; set; }
}
class MySomethingElse : ISomething
{
public string Name { get; set; }
public int Size { get; set; }
}
Then you make the call from your JsonServiceClient using a typed object
client.Get(new MySomething { Name: "Duck", Age: 20 });
The JSON that is sent would be { "Name":"Duck", "Age":20 } what type does the deserialiser choose now? It could be an MySomething or a MySomethingElse, or even another ISomething that it just doesn't know about yet. So because it can't decide the result is simply null.
Generally interfaces and DTOs don't mix, see here.
I had a similar problem, and realized i didn't have { get; set; } applied to the response DTO, so the result of my object was always null...
Thought this information could also help anyone searching for this ...

How To Use Interface as DataContract in WCF

I need invoke webservice operations using standard wsdl, but data objects must be different in client and in the server.
Using interfaces for data objects in a common library, making proxy classes for it in client and in server.
Then, I'm declaring operation contract using the interface, but WCF don't recognize it.
I yet tried use DataContractSerializerBehavior and set knownTypes, no success yet.
Someone can help-me? I've attached a complete solution with more details.
public interface Thing
{
Guid Id {get;set;}
String name {get;set;}
Thing anotherThing {get;set;}
}
[DataContract]
public class ThingAtServer: BsonDocument, Thing // MongoDB persistence
{
[DataMember]
Guid Id {get;set;}
//...
}
[DataContract]
public class ThingAtClient: Thing, INotifyPropertyChanged // WPF bindings
{
[DataMember]
Guid Id {get;set;}
//...
}
[ServiceContract]
public interface MyService
{
[OperationContract]
Thing doSomething(Thing input);
}
Click here do see a Sample project on GitHub with TestCases
I've created WCF Service with contract:
[OperationContract]
CompositeTypeServer GetDataUsingDataContract( CompositeTypeServer composite );
My CompositeTypeServer looks like this:
[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeServer
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then I've created client project with type CompositeTypeClient:
[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeClient
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then I've added the reference to my service and selected to reuse types. Everything worked like charm. I was able to use CompositeTypeClient on client side.
So the trick was to specify Namespace for DataContract so they would match on both client and service.
[DataContract( Namespace = "http://enes.com/" )]
PS. I can provide full working VS solution on request.
Based on ServiceKnownTypeAttribute (MSDN documentation), I changed what types expected depending on the situation. The main idea is implemented in the class XHelper, responsible to return the correct Type[] according to the situation:
public static class XHelper
{
public static Boolean? IsClient = null;
public static Type[] ClientTypes;
public static Type[] ServerTypes;
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider pProvider)
{
if (!IsClient.HasValue)
throw new Exception("Invalid value");
if (IsClient.Value)
return ClientTypes;
return ServerTypes;
}
}
You must include the ServiceKnownType tag in the interface that has the ServiceContract to know XHelper class.
[ServiceContract(Namespace = MyProxyProvider.MyNamespace)]
[ServiceKnownType("GetKnownTypes", typeof(XHelper))]
public interface MyService
{
[OperationContract]
Thing2 CopyThing(Thing1 input);
}
At the beginning of the test unit, which was informed of the right Type[] for every situation:
[AssemblyInitialize]
public static void TestInitialize(TestContext pContext)
{
XHelper.ClientTypes = new Type[] { typeof(Thing1ProxyAtClient), typeof(Thing2ProxyAtClient), typeof(Thing2ProxyAtClient) };
XHelper.ServerTypes = new Type[] { typeof(Thing1ProxyAtServer), typeof(Thing2ProxyAtServer), typeof(ThingNProxyAtServer) };
}
Click here do see the final code Sample project on GitHub with TestCases

WCF Generic Class

How can this work as a WCF Service?
public class BusinessObject<T> where T : IEntity
{
public T Entity { get; set; }
public BusinessObject(T entity)
{
this.Entity = entity;
}
}
public interface IEntity { }
public class Student : IEntity
{
public int StudentID { get; set; }
public string Name { get; set; }
}
I want to expose the BusinessObject <T> class and the all the class that inherits the IEntity interface in the WCF Service.
My code is in C#, .NET Framework 4.0, build in Visual Studio 2010 Pro.
While exposing BusinessObject to the clients via WCF, you must do that by using closed generic type.
[DataContract]
public class BusinessObject<T> where T : IEntity
{
[DataMember]
public T Entity { get; set; }
public BusinessObject(T entity)
{
this.Entity = entity;
}
}
[ServiceContract]
interface IMyContract {
[OperationContract]
BusinessObject<Student> GetStudent(...) // must be closed generic
}
KnownType attribute is a way to ensure that the type data for the contract is added to the wsdl metadata. This only works for classes it will not work for an interface. An interface cant store data and is not univerally understood by all languages out there so its not really exposable over wcf. See this here- http://social.msdn.microsoft.com/forums/en-US/wcf/thread/7e0dd196-263c-4304-a4e7-111e1d5cb480
You need to register a DataContractResolver behavior with your host so WCF can (de)serialize as yet unknown types dynamically. See more information here:
http://msdn.microsoft.com/en-us/library/ee358759.aspx
That said, the type still needs to be closed generic type, albeit a common base class AFAIK.

Honouring of AttributeUsage on derived attribute types

Given the following, I would not expect the compiler to allow multiple attributes that are derived from the base attribute, given that is set to AllowMultiple=false. In fact it compiles without a problem - what am I missing here?
using System;
[AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=true)]
abstract class BaseAttribute : Attribute { }
sealed class DerivedAttributeA : BaseAttribute { }
sealed class DerivedAttributeB : BaseAttribute { }
class Sample1
{
[DerivedAttributeA()]
[DerivedAttributeB()]
public string PropertyA{ get; set; } // allowed, concrete classes differ
[DerivedAttributeA()]
[DerivedAttributeA()]
public string PropertyB { get; set; } // not allowed, concrete classes the same, honours AllowMultiple=false on BaseAttribute
}
The problem is simply that the AllowMultiple check only compares attributes of the same actual type (i.e. the concrete type instantiated) - and is perhaps best used with sealed attributes for this reason.
It will, for example, enforce the following (as an illegal duplicate), inheriting this from BaseAttribute:
[DerivedAttributeB()]
[DerivedAttributeB()]
public string Name { get; set; }
In short, I don't think you can do what you want here... (enforce no more than one instance including subclasses of BaseAttribute per property).
A similar example of this problem would be:
[Description("abc")]
[I18NDescriptionAttribute("abc")]
public string Name { get; set; }
class I18NDescriptionAttribute : DescriptionAttribute {
public I18NDescriptionAttribute(string resxKey) : base(resxKey) { }
}
The intent above is to provide a [Description] from resx at runtime (fully supported by ComponentModel etc) - but it can't stop you also adding a [Description].

Categories

Resources