c# Generic property - c#

I am trying to make a class in C# that can be used to return data of any types.
public class ResponseObject
{
public <T> data { get;set }
public Boolean Success { get; set; }
public string Message { get; set; }
}
The Object will be a wrapper for the response object when my application sends a request to the API.
i have tried researching this but cannot find any tutorials which are relevant to what i am trying to do.
Is this possible in C#? the Response Object will be converted to a JSON string and then sent as a response.
I will not be doing any processing of this object as that will already by done. I just want to place the data inside the ResponseObject and send it
I want to do something along the lines of:
var customers = repository.GetCustomers();
var orders = repository.GetOrders();
if(customers)
{
success = true;
message = "";
}
else{
success = false;
message = "failed to get customers";
}
if(orders)
{
orderssuccess = true;
ordersmessage = "";
}
else{
orderssuccess = false;
ordersmessage = "failed to get orders";
}
ResponseObject customerResponse = new ResponseObject{
data = customers,
success = success,
message = message
};
ResponseObject orderResponse = new ResponseObject{
data = orders,
success = orderssuccess,
message = ordersmessage
};

You need to add <T> to the class and use T as the type of your property.
public class ResponseObject<T>
{
public T data { get; set; }
public Boolean Success { get; set; }
public string Message { get; set; }
}

You have almost done it already! Just change your <T> to T.
public class ResponseObject<T> where T : class
{
public T data { get; set; }
public Boolean Success { get; set; }
public string Message { get; set; }
}
Here where T : class ensure that the generic type parameter is a reference type. From your question it seems you are going to pass in an object there.

You have two options here:
Make the class generic, or
Use generic methods for accessing the property
Here are the examples of both approaches:
// Make the class generic
public class ResponseObject<T> {
public T Data { get; set }
public Boolean Success { get; set; }
public string Message { get; set; }
}
// Use generic methods to access the property
public class ResponseObject {
private object data;
public T GetData<T>() {
return (T)data;
}
public void SetData<T>(T newData) {
data = newData;
}
public Boolean Success { get; set; }
public string Message { get; set; }
}
Second approach is less robust than the first one - basically, it's a glorified unrestricted cast. First approach, however, does not let you build a container of ResponseObjects with different Ts. You can address this problem by adding an interface on top of ResponseObject:
interface IResponseObject {
object DataObj { get; set }
Type ObjType { get; }
bool Success { get; set; }
string Message { get; set; }
}
public class ResponseObject<T> {
public T Data { get; set }
public ObjType => typeof(T);
public DataObj {
get => Data;
set => Data = value; // C# 7 syntax
}
public Boolean Success { get; set; }
public string Message { get; set; }
}

Related

JsonConvert.DeserializeObject defaults to first Enum item

I have the following data object.
public class Response<T> where T : MyBaseDTO
{
public bool result
{
get; set;
}
public List<Message> messages
{
get; set;
}
public List<T> data
{
get; set;
}
}
public class Message
{
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
public string type
{
get
{
return typeEnum.ToString();
}
}
public MessageTypeEnum typeEnum
{
get; set;
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public string message
{
get; set;
}
public string messageValue
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
When I use RestSharp to call the API, the deserialized Data is null with following error(Content contains correct response in string):
" ErrorMessage "Each parameter in the deserialization constructor on type 'Response.Message' must bind to an object property or field on deserialization."
I found the following post and added empty constructor to my object.
Error: Each parameter in constructor must bind to an object property or field on deserialization
public class Message
{
public Message()
{
}
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
public string type
{
get
{
return typeEnum.ToString();
}
}
public MessageTypeEnum typeEnum
{
get; set;
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public string message
{
get; set;
}
public string messageValue
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
Added empty constructor resolved my issue with RestSharp. However I just noticed it failed some unit tests in my other project that uses Message Object.
Here is the code
using var reader = new StreamReader(result.ResponseMessage.Content.ReadAsStream());
body = reader.ReadToEnd();
Response<Test> responseObject = JsonConvert.DeserializeObject<Response<Test>>(body);
"body" looks like something below which is expected.
body "{\"result\":true,\"messages\":[{\"type\":\"ERROR\",\"index\":0,\"field\":\"ID\",\"code\":\"MISSING-ID\",\"message\":\"The entry is incomplete.",\"messageValue\":null}],\"data\":[{\"....
However, after the deserialization, "Type" became WARNING instead ERROR and hence it failed the unit test.
Looks like it defaults to first one of the Enum.
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
Does anyone knows what's going on here and how to fix the issue?
since you have type as string too, you have to fix your Message costructor by adding attribute
[JsonConstructor]
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
after this everything is working properly
Your code is not complete and your JSON example is malformed, so I am unable to provide an example with your exact code. That said, you should be able to suss out the details you need to fix your particular issue.
First, when you are deserializing to a class you must have an empty constructor as required by the deserializer. The deserializer will not be passing any parameters to your constructor, so you can't depend on them.
Second, to read/write a class property it must have both a get and set. The deserializer will not be able to fully work with properties that do not have both get and set.
One possible solution, is to create a string property that contains both get and set, and then create an additional property with only the get that is typed to the Enum.
The root object is basically your Response object, but as you didn't provide that code I made the RootObject.
public class RootObject
{
public bool result { get; set; }
public Message[] messages { get; set; }
}
public class Message
{
// string property to allow deserialization
public string type
{
get; set;
}
// read only property typed to the enum that will
// refer to the 'type' property for conversion to the enum
public MessageTypeEnum typeEnum
{
get
{
switch (type.ToUpper())
{
case nameof(MessageTypeEnum.WARNING):
return MessageTypeEnum.WARNING;
case nameof(MessageTypeEnum.INFO):
return MessageTypeEnum.INFO;
case nameof(MessageTypeEnum.ERROR):
return MessageTypeEnum.ERROR;
default:
return MessageTypeEnum.UNKNOWN;
// return UNKNOWN or throw an out of range exception?
}
}
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
}

dynamic to specific class object conversion

how to convert dynamic variable to specific class.
dynamic variable has the same properties as my specific class.
public class PracovnikHmotZodpovednostDropDownListItem
{
[Column("ZAZNAM_ID")]
public int? ZaznamId { get; set; }
[Column("TEXT")]
public string Text { get; set; }
[Column("VALL")]
public int Value { get; set; }
public bool Disabled { get; set; } = false;
public UpdateStatusEnum UpdateStatus { get; set; }
}
void someMethod(dynamic dtos){
List<PracovnikHmotZodpovednostDropDownListItem> dto =
(List<PracovnikHmotZodpovednostDropDownListItem>)dtos;
}
If all you know is that the properties have the same names, you're in duck typing territory, casting won't help you.
Good news is, it's trivial to do, just tedious:
var dtoList = new List<PracovnikHmotZodpovednostDropDownListItem>();
foreach(var dto in dtos)
dtoList.Add(new()
{
ZaznamId = dto.ZaznamId,
Text = dto.Text,
// etc..
});

Need help using generic type APIResponse class

My manager told me to use the following class while sending response back from Web pi controller in Asp.net core project, now I am new to programming and confuse how to make instance of it, i can convert it to JSON after. Only the usage of APIResponse class is out of my knowledge.
public class APIResponse<T>
{
public APIResponse()
: this(default(T))
{
}
public APIResponse(T data)
: this(ResponseCodes.RESPONSE_OK, ResponseMessages.RESPONSE_OK, data)
{
}
public APIResponse(int _code, string _msg, T _data)
{
this.code = _code;
this.msg = _msg;
this.data = _data;
}
public int code
{
get;
set;
}
public string msg
{
get;
set;
}
public T data
{
get;
set;
}
public int pageCount { get; set; }
public int pageSize { get; set; }
public int recordCount { get; set; }
}
I want to make object of it and add data in the fields.
Here is the response sample:
You could create a class called Data with the following fields:
public class Data
{
public string status;
public string statusMessage;
}
Then you would call the generic class and set the values like this,
APIResponse<Data> APIResponseData = new APIResponse<Data>();
APIResponseData.data.status = "Set Status";
APIResponseData.data.statusMessage = "Set Status Message";
APIResponseData.code = 1;
APIResponseData.msg = "message";
You can then use the APIResponseData object how you'd like.
Not sure if this is what you are asking for, but hope it helps you

Deserialize JSON with dynamic objects

I have a JSON object that comes with a long list of area codes. Unfortunately each area code is the object name on a list in the Data object. How do I create a class that will allow RestSharp to deserialize the content?
Here's how my class looks now:
public class phaxioResponse
{
public string success { get; set; }
public string message { get; set; }
public List<areaCode> data { get; set; }
public class areaCode
{
public string city { get; set; }
public string state { get; set; }
}
}
And here's the JSON content:
{
success: true
message: "277 area codes available."
data: {
201: {
city: "Bayonne, Jersey City, Union City"
state: "New Jersey"
}
202: {
city: "Washington"
state: "District Of Columbia"
} [...]
}
Since this JSON is not C# friendly, I had to do a little bit of hackery to make it come out properly. However, the result is quite nice.
var json = JsonConvert.DeserializeObject<dynamic>(sampleJson);
var data = ((JObject)json.data).Children();
var stuff = data.Select(x => new { AreaCode = x.Path.Split('.')[1], City = x.First()["city"], State = x.Last()["state"] });
This code will generate an anonymous type that best represents the data. However, the anonymous type could be easily replaced by a ctor for a more normal DTO class.
The output looks something like this:
your json is incorrect, but if you do correct it you can use a json-to-csharp tool like the one on http://json2csharp.com/ to generate your classes:
public class __invalid_type__201
{
public string city { get; set; }
public string state { get; set; }
}
public class Data
{
public __invalid_type__201 __invalid_name__201 { get; set; }
}
public class RootObject
{
public bool success { get; set; }
public string message { get; set; }
public Data data { get; set; }
}
I don't know anything about RestSharp, but if you're using Newtonsoft on the server side, then you can just pass a JObject to your method. Then you can interrogate the object to see what type of object it really is and use JObject.ToObject() to convert it.
I think using Dictionary<int,areaCode> is the easiest way.
public class phaxioResponse
{
public string success { get; set; }
public string message { get; set; }
public Dictionary<int,areaCode> data { get; set; }
public class areaCode
{
public string city { get; set; }
public string state { get; set; }
}
}
Then:
var res= JsonConvert.DeserializeObject<phaxioResponse>(json);
Console.WriteLine(string.Join(",", res.data));

Cannot implicitly convert type 'System.Collections.Generic.List

I have this application where I am trying to pass a list to another class. I keep getting the error
Cannot implicitly convert type 'System.Collections.Generic.List<eko_app.LoginForm.Business>' to 'System.Collections.Generic.List<eko_app.GlobalClass.Business>'
The list is generated from Json.
Login class
private void Connect()
{
try
{
serverUrl = "https://eko-app.com/Users/login/username:" + usernameEntered + "/password:" + passwordEntered + ".json";
var w = new WebClient();
var jsonData = string.Empty;
// make the login api call
jsonData = w.DownloadString(serverUrl);
if (!string.IsNullOrEmpty(jsonData))
{
// deserialize the json to c# .net
var response = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsonData);
// Get the sessionId
GlobalClass.SessionId = string.Empty;
GlobalClass.SessionId = response.response.SessionId;
if (GlobalClass.SessionId != null)
{
var businesses = response.response.Businesses;
GlobalClass.Username = "";
GlobalClass.Username = usernameEntered;
GlobalClass.Businesses = null;
GlobalClass.Businesses = businesses; **<-----error thrown here**
HomeForm homeForm = new HomeForm();
this.Hide();
homeForm.Show();
}
else
{
Console.WriteLine("Login failed");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private class Business
{
public string businessID { get; set; }
public string businessName { get; set; }
}
private class Response
{
[JsonProperty("sessionId")]
public string SessionId { get; set; }
[JsonProperty("businesses")]
public List<Business> Businesses { get; set; }
}
private class Messages
{
public string sessionId { get; set; }
public List<Business> businesses { get; set; }
}
private class RootObject
{
public Response response { get; set; }
public Messages messages { get; set; }
}
I have another class: Global Class
namespace eko_app
{
static class GlobalClass
{
...some code
public class Business
{
private string businessID { get; set; }
private string businessName { get; set; }
}
private static List<Business> businesses = null;
public static List<Business> Businesses
{
get { return businesses; }
set { businesses = value; }
}
}
}
What am I doing wrong? The error is thrown in the first class at GlobalClass.Businesses = businesses;
It appears that you have two identical classes called Business - one nested inside your GlobalClass, and the other nested inside your LoginForm.
Although both classes look the same, they are not assignable to each other. Moreover, collections based on these classes are not assignable to each other either.
Consider dropping one of these classes (e.g. the private one in the LoginForm) and replace all its uses with GlobalClass.Business, which is public.
You have two completely different classes, both of which happen to be named Business. One here:
static class GlobalClass
{
public class Business
{
private string businessID { get; set; }
private string businessName { get; set; }
}
}
and one here:
public class LoginForm
{
private class Business
{
public string businessID { get; set; }
public string businessName { get; set; }
}
}
Even though these two classes are mostly identical, they statically compile to two completely different things. No amount of similar naming will change that.
You could write methods to convert one to another, but that will probably just hide the problem instead of actually solve it. I imagine what you want to do is choose which one is your actual Business class and use only that. So you might deprecate the second one and change the Response property to something like:
public List<GlobalClass.Business> Businesses { get; set; }

Categories