Serializing Object as JSON String Instead of JSON Object - c#

I am working on writing a client library for reading from an MQTT API (that I have no control over).
For making requests I have a helper Request class that has all the default request parameters that always need to be provided. Each request has a payload property. I implemented this by making the Request class a generic class like: public class Request<T> where T : IRequestPayload and that has worked great, with one exception, when the request payload is only a string. Since string doesn't implement IRequestPayload, I cant make a Request with a payload of type string.
While looking into ways to handle this I wondered if it would be possible to flatten a derived Request class's Value property and save it to Payload. An example of what I mean is below:
Classes:
public interface IPayload { }
public interface IRequestPayload : IPayload { }
public abstract class Request<T> where T : IRequestPayload {
public T? Payload { get; set; } = null;
}
public class MyAPIRequestPayload : IRequestPayload {
public string Value { get; set; }
}
public class MyAPIRequest : Request<MyAPIRequestPayload> {
}
Desired JSON Input/Output:
{
"Payload":"MyValue"
}
Desired object values:
MyAPIRequest.Payload = instanceof(MyAPIRequestPayload)
MyAPIRequestPayload.Value = "MyValue"
Edit:
Added in the payload marker interfaces.

Related

Using generics in interfaces and property

I am trying to create a bunch of classes/interfaces for use in defining HTTP requests.
The Request class is defined as below
internal class Request : IRequest
{
public Request(Uri uri, Method method, Headers headers)
{
Uri = uri;
Method = method;
Headers = Headers;
}
public IRequestBody Body { get; set; }
}
For IRequestBody I want to be able to define a Type, based on what the request is. For example, a request might contain JSON data, or Form Data.
I tried to define IRequestBody as
public interface IRequestBody<T>
{
RequestBodyType Type { get; }
T Payload { get; }
}
With the hope that I could then define classes such as:
public class FormDataRequestBody : IRequestBody<NameValueCollection>
{
public RequestBodyType Type => RequestBodyType.FormData;
public NameValueCollection Payload => new NameValueCollection();
}
However, on the Request class I must define the Type in the Body property definition. How can I make Body on the Request class generic so I can pass any instance of IRequestBody without knowing the Type upfront?

Exception when serializing polymorphic c# class with method hiding to json, ASP.NET core API

To get deep into the problem, here is a console app :
class Program
{
static void Main()
{
Console.WriteLine(JsonSerializer.Serialize(
new PolyMorphicClass { Data = new SomeData { N = 2} }));
}
class BaseClass
{
public virtual object Data { get; set; }
}
class PolyMorphicClass : BaseClass
{
public new SomeData Data { get; set; }
}
class SomeData
{
public int N { get; set; }
}
}
This code throw an invalid operation exception with this message :
The JSON property name for 'ConsoleApp_for_test.Program+PolyMorphicClass.Data' collides with another property.
I found that if I initializing BaseClass instead, like below, it works
static void Main()
{
Console.WriteLine(JsonSerializer.Serialize(
new BaseClass { Data = new SomeData { N = 2} }));
}
My actual problem is: in a WebAPI where PolymorphicClass is the response type of a controller action that is being serialized to json, and this same exception happens.
extra note: In the API I use this polymorphic behavior to make the response consistent across endpoints i.e. similar data type.
My questions are : is it ok to use the BaseClass instead of the polymorphicClass like I said above in the context of initializing API response? Is there other solutions to serialize this? Can someone explain why the exception is happening?
You can't change the return type with the new keyword, all it does is hide it and requires the use of the same signature.
You could fix this in a couple of ways.
Using Generics
Replacing object with a generic type would allow for you to define PolyMorphicClass with a specific type for Data, which I believe is similar to what you're trying to do here.
class BaseClass<T>
{
public virtual T Data { get; set; }
}
class PolyMorphicClass : BaseClass<SomeData>
{
}
Provide implementations for the property
Properties are essentially 2 methods (a getter and a setter) and you use some default ones with { get; set; }. These defaults get and set, respectively, a private member underneath the hood.
virtual properties are basically saying "You should override my getter and setter". Just specify an underlying member with the type SomeData to get and set. Here's a basic example.
class BaseClass
{
public virtual object Data { get; set; }
}
class PolyMorphicClass : BaseClass
{
private SomeData data { get; set; }
public override object Data
{
get
{
return data;
}
set
{
data = (SomeData) value;
}
}
}
Note that if you deserialize some JSON that can't be casted to SomeData you'll run into a runtime exception of System.InvalidCastException, so you may want to add some additional type checking in your setter.

C# how to make constructor for class

I have a class Response with generic parameter:
public class Response<T> where T : class {
public bool Result;
public T Data;
}
Also, I have a class Instance with simple parameters
public sealed class Instance {
public long Rank { get; set; }
public int ID_Member { get; set; }
}
And then I have a class where I use last ones
public sealed class InstanceResponse : Response<IList<Instance>> { }
And I try to add a constructor to last class and don't understand how to do it
I've tried like there, but it's doesn't work, JsonString contains serialized class InstanceResponse
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
this = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
}
}
I've got an error Cannot assign to 'this' because it is read-only
How it possible?
It's not possible to deserialize json to the object and assign it directly in ctor to the object itself using this keyword.
Provided that
Json contains serialized class InstanceResponse
You can do something like this:
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
var response = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
this.Data = response.Data;
this.Result = response.Result;
}
}
Another possible solution is to deserialize json in a code that creates instance of InstanceResponse (call's ctor) somewhere.
Instead of:
var response = new InstanceResponse(json);
You could deserialize json right there:
var response = JsonConvert.DeserializeObject<InstanceResponse>(json);
P.S.
With that being said, an interesting point was raised by #Lasse Vågsæther Karlsen regarding the subject. It is actually possible to assign something to this however it is only working inside of a structs ctor and use cases for it are very limited...(thanks Lasse)

C# Hiding fields from model where xml deserialization points to

sI have one controller class, which is having private field of another class which is a model, model which gets data from xml deserialization. Because of this deserialization process I had to create public, parameterless constructor and some public fields-helpers which are simply processing data formats to another types. This processing is so simple that I don't want to re-write and XmlSerialization class using it's interface.
What I want to achieve is to have access to the fields from the model from the interface it inherits from only, but the model has to have public fields - how to hide some of them? They are in the same project. (Whole application is so tiny that dividing it to smaller pieces not always makes sense).
There is an example:
public class Program
{
public static void RequestHandler
{
public RequestHandler(string xmlRequest){
IRequest request = DataModel.ParseXml(xmlRequest);
//now user can use request from IRequest only
//but when he doesn't know that he has to use IRequest he can easily access and change
//values in DataModel properties, I want to prevent such possibility
}
}
}
public interface IRequest{
int test_id { get; }
DateTime description { get; }
IRequest ParseXml(string request);
bool Validate(IRequest request);
}
public class DataModel : IRequest {
[XmlElement("testId")]
int test_id { get; set; }
[XmlElement("testId")]
DateTime description { get; set; }
public DataModel() {} //this has to be specified to be allowed to use Serialization
//I don't want users to be able to use this constructor, however it has to be public
IRequest static ParseXml(string request){
// Xml Parsing process
}
bool Validate(IRequest request) {
//Process of checking if all data are available
}
}
Can you make your model as 'Internal' and expose all fields only via multiple interfaces and write another class which will expose your model objects via interface. e.g.
internal class DataModel : Interface1, Interface2 {
internal DataModel(_xml)
{
this.xml = _xml;
}
private xml {get; set;}
public Interface1.Property1 {get; set;}
public Interface2.Property2 {get; set;}
}
//expose DataModel only via below Helper class
public class DataModelHelper {
public Interface1 GetModel_1(string xml)
{
Interface1 i1 = new DataModel(xml);
return i1;
}
public Interface2 GetModel_2(xml)
{
Interface2 i2 = new DataModel(xml);
return i2;
}
}

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 ...

Categories

Resources