Generic argument property causes error on WebService - c#

Service:
Error:
The error is with a type that has ChainedListNode<T>. Thing is, when I remove the DataMemberAttribute from Value, the service works.
[DataContract]
public class ChainedListNode<T>
{
[DataMember]
public T Value { get; set; }
}
Any ideas to what's causing it and/or how to solve it?

The problem is that the type parameter in the open type ChainedListNode<T> means that ChainedListNode<T>.Value could contain anything at all. WCF can't create a contract which describes all the possible values which could be placed in the Value property, so it rejects the whole type. When there is no Value property, the type parameter T is irrelevant and is ignored, and everything works OK.
In similar situations I've created a closed type derived from my generic type and used that type as my data contract:
[DataContract]
public class ChainedListNodeOfString : ChainedListNode<string>
{
[DataMember]
public string Value { get; set; }
}
If you need to, you can create a derived type (and a related OperationContract) for each different kind of value you need to return. This makes your API more verbose, but it works.

I do no think that generic is a good idea to use in the WCF, because I do not see a good serialization going in this case, even if you can achive it, although I am not sure it possible, I would think that you may still get error eventually.
The reason why it work when you remove DataMember is because it not getting serialized theoretically not used in the service only on the backed end.

Related

ServiceRemoting V2_1 still throwing serialization exception when working with interface return types

over the last few days, I tried to equip my application with the service remoting IPC stack. I initially implemented the V2 version, but just noticed thanks to this post (https://github.com/Azure/service-fabric-issues/issues/735) that that does not support returning interfaces.
So, I just now made the switch to V2_1.
However, I still face this problem:
One or more errors occurred. (Type 'MooMed.Core.DataTypes.Session.SessionContext' with data contract name 'SessionContext:http://schemas.datacontract.org/2004/07/MooMed.Core.DataTypes.Session' is not expected. 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.)'
This is the service method that is being called on the endpoint:
[CanBeNull]
public Task<ISessionContext> GetSessionContext(int accountId):
The involved classes/intefaces look like this:
public interface ISessionContext
{
Account Account { get; set; }
}
[DataContract]
public class SessionContext : ISessionContext
{
[DataMember]
public Account Account { get; set; }
}
Also, as I mentioned, I changed my remoting version from V2 to V2_1 just now, so this is added to the Service class which contains the GetSessionContext method:
[assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2_1, RemotingClientVersion = RemotingClientVersion.V2_1)]
So, according to the docs (https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting#use-the-remoting-v2-interface-compatible-stack) I should now be fully equipped to have everything working properly.
The only thing I see myself doing differently than the tutorial is how I declare the endpoint listeners. I'm doing this via FabricTransportServiceRemotingListener like this:
public static ServiceReplicaListener CreateTypedListener([NotNull] IService service)
{
return new ServiceReplicaListener(context => new FabricTransportServiceRemotingListener(context, service),
$"I{service.GetType().Name}");
}
However, I don't see how this could be the culprit, as the request comes in properly and I don't think declaring endpoints does necessarily interfere with how responses are serialized.
So, what am I doing wrong here?
The DataContractSerializer can't serialize an interface. (see how to mark an interface as DataContract in WCF).
However, you can write your own custom serializer to achieve this. From that article you posted at the bottom are instructions on how to do this. You can also look at my example of implementing protobuf-net here:
https://github.com/mikeruhl/Frenetik.Fabric.Remoting.Protobuf
My example should not be used in production. It's a work in progress and there are zero tests written for it at the moment.

Using value of propertie in his own custom attribute

We use some DTOs in your business logic. I also use these DTOs for printing. So there is a custom attribute printable which will be used in the print-framework to recognize which properties to print. In some cases it is necessary to preformat the value for the printengine.
My idea was to use a construct like this:
[Printable(formatedValue = DoFormatingXY(MyProperty))]
public int MyProperty{ get; set; }
But unfortunatly this will not work (apart from the fact that it is unpleasant to have to use the propertie-name again):
Error An object reference is required for
the non-static field, method, or property '...MyPropertie.get'
So I understand what the problem is, but how can handle it? One idea was to use delegates, but there are a lot of formatting-methods with different method signatures.
Attributes are just metadata, not code. So change it to something like:
[Printable(FormatStyle = FormatStyles.XY)]
public int MyProperty{ get; set; }
Then the printer code can check for a FormatStyle parameter to the attribute and apply the requested format to the property.

KnownType Exception with WCF

I have following Service Interface
[ServiceContract]
public interface ICacheService
{
[OperationContract]
IEnumerable<CacheResponse> GetCache(IEnumerable<CacheRequest> requests);
}
[DataContract]
[KnownType(typeof(CacheItem))]
[KnownType(typeof(TreeItem))]
[KnownType(typeof(TreeTopGroup))]
[KnownType(typeof(TreeGroup))]
[KnownType(typeof(TreeView))]
[KnownType(typeof(ITreeItem))]
public class CacheResponse
{
[DataMember]
public IDictionary<string, CacheItem> CacheItems { get; set; }
[DataMember]
public IEnumerable<KCSLuceneDocument> LuceneDocuments { get; set; }
}
The request works so i won't post it. The Response only contains a DateTime, a String and a List of TreeItem.
Important part of the TreeItem Class
public class TreeItem : ITreeItem
{
public ITreeItem Parent { get; set; }
.
. more stuff
}
As soon as the parent Property is set to something other then null, the client gets a System.ServiceModel.Dispatcher.NetDispatcherFaultException.
Stating that the elment
\"http://schemas.datacontract.org/2004/07/Core.Base:_x003C_Parent_x003E_k__BackingField\" contains Data of the Type \"http://schemas.datacontract.org/2004/07/Core.Base:TreeItem\" and that the deserializere doesn't know any Type with that name.
I tried using the KnownType Attribute as well as the ServiceKnownType Attribute.
Both didn't help.
The only thing that worked is changing the type of Parent to TreeItem which i really don't want to do. Especially as it can contain ITreeItems in some other Locations which most likely also break the Service.
Any idea how to solve the problem?
Do you have the [DataContract] attribute on TreeItem? That would be required. if the TreeItem does have a [DataContract] attribute set, I have a few other ideas, but it may require a bit more of the code to be posted. So give it a try and let me know if I can be of more help.
A hint as to what the other issues may be can be found on the MSDN for Data Contract Known Type.
The KnownType is needed when the class marked with the Data Contract attribute meets one of the following:
The sent data contract is derived from the expected data contract. For more information, see the section about inheritance in Data Contract Equivalence). In that case, the transmitted data does not have the same data contract as expected by the receiving endpoint.
The declared type for the information to be transmitted is an interface, as opposed to a class, structure, or enumeration. Therefore, it cannot be known in advance which type that implements the interface is actually sent and therefore, the receiving endpoint cannot determine in advance the data contract for the transmitted data.
The declared type for the information to be transmitted is Object. Because every type inherits from Object, and it cannot be known in advance which type is actually sent, the receiving endpoint cannot determine in advance the data contract for the transmitted data. This is a special case of the first item: Every data contract derives from the default, a blank data contract that is generated for Object.
Some types, which include .NET Framework types, have members that are in one of the preceding three categories. For example, Hashtable uses Object to store the actual objects in the hash table. When serializing these types, the receiving side cannot determine in advance the data contract for these members.
source
If it is marked with [DataContract] you will likely need to add a [ServiceKnownType] attribute on the TreeItem class itself to show possibilities for the TreeItem.Parent property. That is just a conjecture, I would need to see a bit more code first.

using attributes vs conventional getting properties

I need to find all properties of a specific object which are not readonly and based on their type do something
I mean if the type of property is int i need to do sth and if it is string i should do something else
using reflection and get this type and conventionally i can create an object which can do what I want
for example if the property type is Int , I can create an instance of IntType:IType class
but I have another option: set an attribute for each property and based on these attributes,find suitable IType
I just cant decide which one is better?
If all the information you need is already contained in the type of the property, I can't see how introducing a new attribute is a good idea. Aside from anything else, you can easily forget to update the attribute when the data type changes. You start off with:
[Int32Type]
int Foo { get; set; }
then find you actually need it to be a long, but forget to change the attribute:
[Int32Type]
long Foo { get; set; }
Now you're probably going to be acting incorrectly on it.
If you're really adding information - e.g. if not all int properties need to be treated the same way - that's a different matter.

Design issue in C#: Generics or polymorphism or both?

I need some help with a design issue I'm having. What I try to achieve is this:
I have a main class called Document. This Class has a list of Attribute classes. These Attribute classes have some common properties such as Identity and Name, but they differ in one property I call Value. The Value type is different for each different Attribute class and be of type string, integer, List, DateTime, float, List and also classes that consists of several properties. One example would be a class I would call PairAttribute that have 2 properties: Title and Description.
What I try to achieve is type safety for Value property of the Attribute child classes and that these child classes should be able to be added to the Attribute list in the Document class. I could have made only one Attribute class that have a Value property of type object and be done with it, but that is exactly what I try to avoid here.
The common properties (Identity and Name) should be placed in a base class I guess, lets call that AttributeBase class. But I want to have a child class, say StringAttribute, where the Value property is of type string, a IntegerAttribute class where the Value property is of type Integer, a StringListAttribute where the Value property is of type List, a PairAttribute class where the Value is a class with several properties, etc
Do you know how I can implement this? Is this a solution I should go for at all or is it a better ways of solving this type safety issue? I would appreciate code examples for clarification:)
You don't specify a language, but the feature described by the term "generics" (as used by Java and C#) is often called "parametric polymorphism" in other languages (like ML and Haskell). Conversely, the common meaning of "polymorphism" in Java and C# is actually more precisely called "subtype polymorphism".
The point is, whether you are using subtype polymorphism or parametric polymorphism, either way your problem calls for polymorphism, so I think you're on the right track.
The question really boils down to: when is parametric polymorphism better than subtype polymorphism? The answer is actually quite simple: when it requires you to write less code.
So, I'd suggest you prototype both approaches, and then see which one leads to simpler, easier to understand code. Then do it that way.
You may pass with a generic Attribute instead of inheritance/method polymorphism, but you will need to store them in some list and for that you will need an interface, because datastores in .Net cannot be a collections of undefined generic types, and if you would define them you would not be able to mix types inside:
public interface IAttribute {
string Identity { get; set; }
string Name { get; set; }
T GetValue<T>();
}
public class Attribute<T> : IAttribute
{
public string Identity { get; set; }
public string Name { get; set; }
public T Value { get; set; }
public Tret GetValue<Tret>() {
return (Tret)(Object)Value;
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
List<IAttribute> lst = new List<IAttribute>();
Attribute<string> attr1 = new Attribute<string>();
attr1.Value = "test";
Attribute<int> attr2 = new Attribute<int>();
attr2.Value = 2;
lst.Add(attr1);
lst.Add(attr2);
string attr1val = lst[0].GetValue<string>();
int attr2val = lst[1].GetValue<int>();
}
}
The (Tret)(Object) actually does not change type, it only boxes T and the (Tret) unboxes the value without using middle variables. This will of course fail if you miss the right type when calling GetValue<type>(). Even if compatible types are sent like Value is integer and you do GetValue<double>() -> because unboxing an integer into a double is not allowed.
Boxing/Unboxing is not as fast as casting but it ensures type safety is preserved, and there is at my knowledge no way to use generics with an compile time known interface in some other way.
So this should be type safe... and without a lot of code.

Categories