Serializing an IEnumerable in protobuf-net - c#

I have a library of fairly heavy-weight DTOs that is currently being used by some WCF services. We are attempting to bring it into protobuf-net world, with as little modification as possible. One particular set of items is giving me trouble in serialization. I'm going to simply them here because it gets a little complicated, but the gist of the problem is:
public class Key
{
public string Id {get; set;}
}
public class KeyCollection : IEnumerable<Key>
{
private readonly List<Key> list;
#region IEnumerable
// etc...
#endregion
}
public class Item
{
public long Id { get; set; }
}
public abstract class ContainerBase
{ }
public abstract class ContainerBase<T> : ContainerBase
where T : Item
{ }
public abstract class ContainerType1Base : ContainerBase<Item>
{
public KeyCollection Keys { get; set; }
}
public class ContainerType1 : ContainerType1Base
{ }
I've left out the decorators because I don't they're the problem, mostly because if I add void Add(Key item) { } to KeyCollection the whole thing seems to work. Otherwise, I run into problems attempting to serialize an instance of ContainerType1.
Actually, changing the signature of KeyCollection is kind of prohibitive, so I'm attempting to follow this answer to try to do it programatically. Specifically, setting itemType and defaultType to null on the "Keys" ValueMember of ContainerType1, ContainerType1Base and ContainerBase<Item>. I also set IgnoreListHandling to true on KeyCollection... which totally doesn't work. I get a generic "failed to deserialize" exception on the client, which I can post here if it would help. On the server side, I serialize it out using Serializer.Serialize(), and I spit out Serializer.GetProto<>() as well as JSON of the object, and they all seem to be work okay.
How can I turn off the list handling? Related to that, is there a way to turn on extra debugging while serializing to try to get some more information of the problem?

Fundamentally, the code shown looks fine. Unfortunately, there's currently a "feature" in gRPC that means that it discards the original exception when a marshaller (serializer) fails for some reason, so gRPC does not currently expose the actual problem. I have submitted a fix for this - it may or may not be accepted.
In the interim, I suggest that you simply remove gRPC from the equation, and simulate just the marshaller workload; to do this, on the server: generate the data you are trying to send, and do:
var ms = new MemoryStream();
Serializer.Serialize(ms, yourDataHere);
var payload = Convert.ToBase64String(ms.ToArray());
and obtain the value of payload (which is just a string). Now at the client, reverse this:
var ms = new MemoryStream(Convert.FromBase64String(thatStringValue));
Serialize.Deserialize<YourTypeHere>(ms);
My expectation here is that this should throw an exception that will tell you what the actual problem is.
If the gRPC change gets merged, then the fault should be available via:
catch (RpcException fault)
{
var originalFault = fault.Status.DebugException;
// ^^^
}

Related

Can I use reflection to detect potential attack gadget vulnerabilities?

I use a package that contains code for a tcp server and client that is really easy to use, problem is it uses Newtonsoft Json serialization and deserialization with TypeNameHandling.All to send an receive messages, and client or servers could be untrusted sources.
public static JsonSerializerSettings JsonSettings = new()
{
TypeNameHandling = TypeNameHandling.All,
};
[...]
[...]
return JsonConvert.DeserializeObject<INetMessage>(message.Substring(8), JsonSettings);
It also contains such a class:
public class NetMessage<T> : INetMessage where T: ISafeNetSerialization
{
public ulong snowflake { get; set; }
public T Content { get; set; }
public NetMessage(T content)
{
this.Content = content;
}
public override string ToString()
{
return Content.ToString();
}
}
Can I use a code snippet using reflection, to go through all types inheriting INetMessage and ISafeNetSerialization interfaces and check if they can possibly contain something (or contain something that contains... etc) like an object, a dynamic or an Exception, a CollectionBase and other untyped objects and collections, including any Generic types inheriting those two that could be added in another library ?
I know that I should especially look for TempFileCollection and ObjectDataProvider.
Code snippet would then be used inside an unit test or at runtime before the initialization of the first server / and / or tcp client.

Deserializing XML when the root type is the same but the inner XML can represent different types

I have to work on a application when sends XML back. Because the root is always the "Reply", but the property's differ, deserializing can't be based on 1 object type.
I've now written code which loads the Xml first in a new XmlDocument, reads a Name attribute and based on the attribute, I try to deserialize it. Are there
better ways?
Example xml I can expect:
<Reply Name="GetModulesList" Result="yes"><ModuleName="xxxxxx.exe" Path="\Debug\xxxxxxx.exe" Order="1"/></Reply>
<Reply Name="OpenRecipe" Result="yes"/>
How whould you solve this?
XmlDocument doc = new XmlDocument();
doc.LoadXml(trimmedPart);
if (doc.DocumentElement?.Attributes != null)
{
XmlAttribute name = doc.DocumentElement.Attributes.Cast<XmlAttribute>().SingleOrDefault(a => String.Compare(a.Name, "name", StringComparison.OrdinalIgnoreCase) == 0);
replyName = name?.Value;
}
if (!string.IsNullOrEmpty(replyName))
{
XmlSerializer serializer = new XmlSerializer(GetSerializerObjectType(replyName));
using (StringReader reader = new StringReader(trimmedPart))
{
object obj = serializer.Deserialize(reader);
if (obj != null) returnList.Add(obj);
}
}
I recently dealt with a similar scenario. Here's a very rough outline, adapted from what I was working with to your case as specifically as I can.
My assumption is that you're going to do different things with different types. If it's an OpenRecipe you're going to do one thing, if it's GetModuleList you're going to do something else.
The biggest difference is that each "handler" I worked with for different types might handle completely different types of data - XML, JSON, even Excel, so the handlers received content in the form of a byte array and were responsible for deserializing it. (It wasn't my idea to write an in-house version of Biztalk.)
In this case, if it's always XML, you can
Determine the type of the inner XML from the Name attribute
Deserialize the inner XML to that type
Pass it off to a strongly-typed class
This class is concerned with deserializing the Reply (except for the unknown inner content) and passing it to something that will handle that inner content in a more strongly typed way:
public class XmlReplyRouter
{
private readonly IReplyTypeMapper _replyTypeMapper;
private readonly IHandlerFactory _handlerFactory;
private readonly XmlSerializer _serializer = new XmlSerializer(typeof(Reply));
public XmlReplyRouter(
IReplyTypeMapper replyTypeMapper,
IHandlerFactory handlerFactory)
{
_replyTypeMapper = replyTypeMapper;
_handlerFactory = handlerFactory;
}
public void RouteReply(string replyXml)
{
using (var reader = new StringReader(replyXml))
{
var reply = (Reply)_serializer.Deserialize(reader);
var replyType = _replyTypeMapper.GetReplyType(reply.Name);
var handler = _handlerFactory.GetHandler(replyType);
handler.HandleReply(reply);
}
}
}
public class Reply
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Result { get; set; }
[XmlAnyElement]
public XmlNode InnerXml { get; set; }
public string XmlContent => InnerXml?.OuterXml;
}
That's where all the ugliness goes.
The XmlAnyElement attribute allows us to deserialize without knowing what to make of that inner content. Once we know what type to use we can separately deserialize that.
The implementations of IReplyTypeMapper and IHandlerFactory could be anything. In my case I couldn't use a DI container so it contained a Dictionary<string, IReplyHandler> and selected the correct one based on the name. (The terminology I worked with was different, but same concept.)
The first determines the type (from the "name" attribute) and the second returns a handler for that type.
public interface IReplyTypeMapper
{
Type GetReplyType(string replyName);
}
public interface IHandlerFactory
{
IReplyHandler GetHandler(Type contentType);
}
Finally, here's the interface and a base class for the reply handlers.
As you can see, the base class doesn't really do anything. It just bridges the gap between object and generic types so that we can write strongly-typed handlers.
public interface IReplyHandler
{
void HandleReply(object content);
}
public abstract class BaseHandler<T> : IReplyHandler
{
private readonly XmlSerializer _serializer = new XmlSerializer(typeof(T));
public void HandleReply(object content)
{
HandleReplyContent((T)content);
}
protected abstract void HandleReplyContent(T content);
}
As you can see it's very similar to what you're doing. The objective, though, is that once I've gotten this minimal amount of initial code out of the way, everything else is a strongly-typed class like this:
public class SomeSpecificReplyHandler : BaseHandler<SomeSpecificReply>
{
// Maybe these have dependencies of their own. That's easiest if
// everything gets resolved from an IoC container.
protected override void HandleReplyContent(SomeSpecificReply content)
{
// do whatever
}
}
I don't know if this might be overkill for your needs. My intent was to start from an entry point where my data could be just about anything and quickly get out of there to a place where all of my code was strongly-typed and easy to test. All of these classes are testable (I wrote a few while typing this up) the individual handlers would also be easy to test.
This post contains some other details about implementing the factories without an IoC container. In my case I couldn't work with an IoC container, so I had to "manually" compose all of my classes. The inner implementation of the factory was just a dictionary. That way if I had the option of switching to an IoC container later I could replace the whole thing with DI registrations.

How to use Json.NET with standard (like) OData service

I try to use Json.NET for consuming an OData (like) service. My data structures have collection properties.
However all those properties are wrapped in a property called 'results' by my service. Even the main query which returns with a collection of the entities are wrapped into a root property called results.
Although I am not an OData expert I think this is pretty much a standard because if I try to send an object graph for update, and omit this 'results' wrapper around say a int collection type property then I got an error message from the server "A collection was found without the 'results' property. In OData, each collection must be represented as a JSON object with a property 'results'"
So I understand the server error message, and I also know how to workaround this. Of course I can mimic this object graph in my C# object model, but after writing the 101st wrapper in my object model it tends to be boring, and I do not want to reinvent the wheel.
My question is there an out of the box solution how to deal with this result property, and make it transparent? If this is a 'standard' I suppose not I am the first who are facing this task.
Thanks in advance
you can just write one and use it everywhere
public class OData<T> where T : IEnumerable
{
public T results { get; set; }
}
public class X
{
public string Prop { get; set; }
public OData<List<int>> List { get; set; }
}
class Program
{
static void Main(string[] args)
{
var x = new X()
{
Prop = "test",
List = new OData<List<int>> {results = new List<int>() {1, 2, 3}}
};
Console.WriteLine(JsonConvert.SerializeObject(x));
}
}

How can I deserialize xml with 2 different types of the same xml element and property name?

In the database, we have an xml field that contains 2 validation schemas; the old one does not have a namespace, the new one does. The reason for this is that we had to version one of the properties. Here is an example of the differences:
Version 1
<PropertyA>
<PropertyA1>false</PropertyA1>
<PropertyA2>3.23</PropertyA2>
</PropertyA>
Version 2
<ts:PropertyA xmlns:ts="http://www.example.com/v2">
<ts:PropertyA1>false</ts:PropertyA2>
<ts:PropertyA2>
<ts:PropertyA2a>
<ts:PropertyA2a1>City 1</ts:PropertyA2a1>
<ts:PropertyA2a2>3.23</ts:PropertyA2a2>
</ts:PropertyA2a>
<ts:PropertyA2b>
<ts:PropertyA2b1>City 2</ts:PropertyA2b1>
<ts:PropertyA2b2>1.21</ts:PropertyA2b2>
</ts:PropertyA2b>
</ts:PropertyA2>
</ts:PropertyA>
Basically, we just create multiple options for PropertyA2...
So now the isue is deserialization. This object needs to be deserialized into the same data object in the app code and the problem is that the element name is the same so the serializer is obviously having trouble figuring out which object to deserialize into since sometimes the database will return Version 1 and sometimes it will return Version 2.
Here is an example of the data class being used for serialization and my current approach that isn't quite working:
[Serializable]
public class MyDataClass
{
// ... other stuff
[XmlElement(Name = "PropertyA", typeof(V1.PropertyA), Namespace = "")]
public V1.PropertyA PropertyAV1 { get ;set; }
[XmlElement(Name = "PropertyA", typeof(V2.PropertyA), Namespace = "http://www.example.com/v2")]
public V2.PropertyA PropertyAV2 { get; set; }
}
[Serializable]
public class V1.PropertyA
{
public bool PropertyA1 { get; set; }
public decimal PropertyA2 { get; set; }
}
[Serializable]
public class V2.PropertyA
{
public bool PropertyA1 { get; set; }
public List<SomeOtherThing> PropertyA2 { get; set; }
}
When I go to deserialize V1, it works fine. When I go to deserialize V2, i get an error Did not expect <ts:PropertyA xmlns:ts="http://www.example.com/v2"> so I'm thinking there's a parameter I'm missing in the deserialize method:
public MyDataClass Deserialize(string xml)
{
var s = new XmlSerializer(typeof (MyDataClass));
MyDataClass info = null;
using (var r = new StringReader(xml))
{
info = (MyDataClass) s.Deserialize(r);
}
return info;
}
I believe you can set the expected namespace in the serializer, but since I don't know what the namespace is going to be until I actually inspect the xml document, I'm not sure how to proceed.
So my question is this: Is what I'm trying to do even possible? Am I on the right track? Is there a better solution that is maybe less contrived? How can I have the serializer deal with the new namespace and deserialize to the correct properties?
You can't.
The problem here is that you have to hardcode MyDataClass according to a single XMLSchema. If the XMLSchema alters, MyDataClass is no longer a valid target for the XMLSerializer's deserialize method, which is why you're getting the 'Did not expect ...' error message. In this case, when reading the V2 xml data stream, the deserialize method tries to fill MyDataClass#PropertyAV1 with the content of <ts:PropertyA2> and there is no way of telling it to instead fill MyDataClass#PropertyAV2. Even if there was a way to achieve this, you'd be stuck with an undefined value for MyDataClass#PropertyAV1 in the object of type MyDataClass.
So there are two solutions to the problem at hand :
a) Stick with XMLSerializer and define class MyDataClass like so
public class MyDataClass
{
// only one Property here, as there's only one root element in the xml
// and this single Property is not bound to a specific XML element
[XmlAnyElement]
public PropertyA PropertyA { get ;set; }
}
You then have to analyze the contents of PropertyA yourself and build some logic around it, see here for more details :
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlanyelementattribute.aspx
b) Dispense the XMLSerializer, read the XML data stream with XMLReader and do the all the parsing of the xml yourself, also add logic to create the according C# objects, depending on the the type of xml you've read.
Obviously, both solutions require more coding on the C# side, but with solution b) you'll have the chance of gaining a performance benefit, as XMLSerializer#deserialize most probably builds a DOM tree to create the C# object from, which the XMLReader doesn't do.
It seems that what I was trying to do was either unachievable or no one with the right level of xml fu saw this thread :(.
So anyway, what I ended up doing was adding an extra column to the database with the version number of the xml contract. Since everything in there was the same, I just called it V1.
I then read that info out into app code and used the version number to drive a factory. Basically, if v1, then deserialize to this, if v2, deserialize to this other thing.
And of course, to support that, I simply created a new data object that had the appropriate structure to support v2. I'm not happy with it, but it works and is flexible enough :/

C# return a variable as read only from get; set;

I swear I have seen an example of this but have been googling for a bit and can not find it.
I have a class that has a reference to an object and need to have a GET; method for it. My problem is that I do not want anyone to be able to fiddle with it, i.e. I want them to get a read only version of it, (note I need to be able to alter it from within my class).
Thanks
No, there's no way of doing this. For instance, if you return a List<string> (and it's not immutable) then callers will be able to add entries.
The normal way round this is to return an immutable wrapper, e.g. ReadOnlyCollection<T>.
For other mutable types, you may need to clone the value before returning it.
Note that just returning an immutable interface view (e.g. returning IEnumerable<T> instead of List<T>) won't stop a caller from casting back to the mutable type and mutating.
EDIT: Note that apart from anything else, this kind of concern is one of the reasons why immutable types make it easier to reason about code :)
Return a reference to a stripped-down interface:
interface IFoo
string Bar { get; }
class ClassWithGet
public IFoo GetFoo(...);
If the object isn't too complicated/extensive then write an wrapper around it.
for example:
class A {
public string strField = 'string';
public int intField = 10;
}
class AWrapper {
private A _aObj;
public AWrapper(A aobj) {
_aObj = A;
}
public string strField {
get {
return _aObj.strField;
}
}
public int intField {
get {
return _aObj.intField;
}
}
}
So now all you do is give your client code an instance of the AWrapper class so that they may only use what you allow them to see.
this may get a bit complicated and may not scale well if your base class is not set in stone, but for most simple situation it may just do the trick. I think this is called a facade pattern(but don't quote me on that =) )
This isn't possible. Get and set accessors to reference types get and set the reference to the object. You can prevent changes to the reference by using a private (or internal) setter, but you cannot prevent changes to the object itself if it's exposed by a getter.
Your question reads like you're looking for:
public PropertyName { get; private set; }
But then, given the answers so far I'm not sure I'm interpreting your question correctly. Besides, who am I to question Jon Skeet? :)
i agree with ReadOnlyCollection
See my simple code:
private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices
{
get
{
return (_devices.AsReadOnly());
}
}
ReadOnlyCollection dosen't has Add method so user cant add properties to it.BUT ther is no warranty that if user can modify objects by calling their methods....
I have faced this problem in a certain way.
I have a CategoryViewModel class, which have a property Category that I want private read-only :
public CategoryViewModel
{
private Category { get; }
}
In fact, I want it to be exported as read-only to other class. However I can't do such thing.
In my case (maybe it will help some other guys), I want to add it to a repository. The only way that I've found is to have a function with the repository as param 1, and an Action as param 2 :
public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
action(repo, Category);
}
Like that, from elsewhere, I can do such thing :
categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));
This can help other to expose there property only for certains cases and can manage them.

Categories