How to combine the common code to create a generic method? - c#

I have below classes with which I generate a request object and serialize the response to get a JSON string. The definition of classes are as follows
PortfolioResponse & StocksInfo classes are for mentioning purpose as they contain a lot many fields which I would not be able to write here.
[DataContract]
public class BaseInfoRequest
{
[DataMember]
public string Token { get; set; }
}
[DataContract]
public class StocksInfoRequest : BaseInfoRequest
{
[DataMember]
public string SomeKey { get; set; }
}
[DataContract]
public class PortfolioInfoRequest : BaseInfoRequest
{
[DataMember]
public string PortfolioId { get; set; }
[DataMember]
public string SomeKey { get; set; }
}
[DataContract]
public class StocksInfoResponse
{
[DataMember(Name = "success")]
public bool Success { get; set; }
[DataMember(Name = "message")]
public string Message { get; set; }
[DataMember(Name = "stocks")]
public StocksInfo StocksInfo { get; set; }
[DataMember(Name = "pfolio")]
public PortfolioResponse PortfolioInfo { get; set; }
}
public class PortfolioResponse
{
}
public class StocksInfo
{
}
Now, to get the data from different other classes and services in project I use below two methods in let's say class Sample
private string GetsStocksInformation(StocksInfoRequest request)
{
var response = new StocksInfoResponse();
if (ValidateRequestToken(request) || string.IsNullOrWhiteSpace(request.SomeKey))
{
response.Message =
GetsResponse().ErrorMessage;
return JsonConvert.SerializeObject(response);
}
response.StocksInfo = GetsStocksInfo(request);
response.Success = true;
return JsonConvert.SerializeObject(response);
}
private string GetsPortfolioInformation(PortfolioInfoRequest request)
{
var response = new StocksInfoResponse();
if (!ValidateRequestToken(request) || string.IsNullOrWhiteSpace(request.SomeKey) ||
string.IsNullOrWhiteSpace(request.PortfolioId))
{
response.Message =
GetsResponse().ErrorMessage;
return JsonConvert.SerializeObject(response);
}
response.PortfolioInfo = GetsPortfolioInfo(request.SomeKey, request.PortfolioId);
response.Success = true;
return JsonConvert.SerializeObject(response);
}
Now, if you look closely enough both the methods are almost same except condition
if (ValidateRequestToken(request) || string.IsNullOrWhiteSpace(request.SomeKey)) &&
response.StocksInfo = GetsStocksInfo(request);
Apart from above two, both the methods do more or less same things. The definition of ValidateRequestToken is below
private bool ValidateRequestToken(BaseInfoRequest request)
{
return true;
}
How do I combine both methods to create a generic method ?

Related

Deserialization without duplicates

I'm deserializing JSON into class objects and I would like to avoid duplicate ones. I've tried to implement IEqualityComparer, but it does not seem to work, because Equals() or GetHashCode() methods are never fired and resulting HashSet contains duplicates too. What's I'm doing wrong?
[DataContract]
public class Release : IEqualityComparer<Media>
{
public bool Equals(Media m1, Media m2)
{
if (m1.mediaFormat == m2.mediaFormat && m1.getTrackPosition() == m2.getTrackPosition()) { Console.WriteLine("Duplicate!"); return true; }
else return false;
}
public int GetHashCode(Media m) { Console.WriteLine("DDD!"); return m.ToString().GetHashCode(); }
[DataMember(Name = "title")]
public string releaseTitle { get; set; }
[DataMember(Name = "date")]
public string releaseDate { get; set; }
[DataMember(Name = "id")]
public string releaseMBID; //required for fetching artwork
[DataMember(Name = "media")]
public HashSet<Media> releaseMedia { get; set; }
public List<Media> getReleaseMedia() { return releaseMedia.ToList<Media>(); }
}
[DataContract]
public class Media
{
[DataMember(Name = "format")]
public string mediaFormat { get; set; }
[DataMember(Name = "track-offset")]
public string mediaTrackOffset { get; set; }
[DataMember(Name = "track-count")]
public string mediaTrackCount { get; set; }
public string getTrackPosition() { return (Convert.ToInt32(mediaTrackOffset) + 1).ToString() + "/" + mediaTrackCount; }
}
Yes you will need to pass the IEqualityComparer to the constructor like :
public class HFoo{
public string Name {get;set;}
public HashSet<Pet> Pets {get;set;} = new HashSet<Pet>(new CustomComparer());
}
public class Pet{
}
public class CustomComparer : IEqualityComparer<Pet>{
public int GetHashCode(Pet obj) {
return 1;
}
public bool Equals(Pet obj1, Pet obj2) {
return true;
}
}
Or the default object conparer will be used.
As you can see in the following demo: https://dotnetfiddle.net/Y9Afem.
The IEquatable will not be call.

response class with generic <T>

Sorry if this has been asked before, but I can't find it and I'm not exactly sure what to search on.
I've got a generic response class like this:
public class ResponseModel<T>
{
public T Data { get; set; }
public Exception Ex { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
}
I'd like to do something like the code below so that I can simply pass the errors up the stack by doing a return retVal.Set<T>(responseModelObject);
public ResponseModel<T> Set<T>(ResponseModel<T> rm)
{
Ex = rm.Ex;
Message = rm.Message;
return this;
}
This works fine if the T class is identical between retVal and responseModelObject, but won't compile if they don't match.
Is there a way to do this or am I just sol?
You may create an interface
public interface IResponseModel
{
Exception Ex { get; set; }
string Message { get; set; }
bool Success { get; set; }
}
public class ResponseModel<T> : IResponseModel
{
public T Data { get; set; }
public Exception Ex { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
}
Then the method will look like
public ResponseModel<T> Set(IResponseModel rm)
{
Ex = rm.Ex;
Message = rm.Message;
return this;
}
Also interface will allow you to create collections of IResponseModel which may conrain generics of different types. It maybe also useful with async operations like Task<IResponseModel>, etc.
You could try to declare method as:
public ResponseModel<T> Set<TOther>(ResponseModel<TOther> rm)
{
Ex = rm.Ex;
Message = rm.Message;
return this;
}
Sample usage:
ResponseModel<int> a = new ResponseModel<int>();
ResponseModel<string> b = new ResponseModel<string>();
b.Set(a); // It compiles
Is this working ?
public ResponseModel<T,S> Set<S>(ResponseModel<T> rm)
{
Ex = rm.Ex;
Message = rm.Message;
return this;
}

How to design different structures with common parts using inheritance

I've searched a lot about this problem without finding any appreciable result (maybe because i don't have a clear idea of what to ask), then here we are...
I have to design two structures derived from two different JSON which they have common parts:
{
"data":
{
"success": true,
"updated_ids": [0],
"not_updated_ids": [0]
}
}
{
"data":
{
"success": true,
"branch_ids":["0"]
}
}
My idea is to create something like this:
class Response
{
Data data { get; set; }
}
class Data
{
bool success { get; set; }
}
class UserResponse : Data
{
List<int> updatedIds { get; set; }
List<int> notUpdatedIds { get; set; }
}
class BranchResponse : Data
{
List<string> branchIds { get; set; }
}
Now my question is: How can i instantiate my two different classes?
If I do new Response() i don't get the UserReponse or BranchResponse part and if i do new UserResponse() i don't get the Response part.
Basically i would like to instantiate a variable for each structure, populate it with all the values and then Serialize to create the Json.
Thanks in advance!
Alright so what you need is an interface and a factory to accomplish what you are trying to create here.
public interface IData
{
bool Success { get; set; }
}
public class Response
{
public IData Data { get; set; }
}
public class UserData : IData
{
public bool Success { get; set; }
public List<int> UpdatedIds { get; set; }
public List<int> NotUpdatedIds { get; set; }
}
public class BranchData : IData
{
public bool Success { get; set; }
public List<string> BranchIds { get; set; }
}
public class HowToUseIt
{
public Response CreateResponse()
{
Response myReponse = new Response
{
Data = new UserData
{
Success = true,
UpdatedIds = new List<int>(),
NotUpdatedIds = new List<int>()
}
};
return myReponse;
}
public void WhatKindOfDataDoIHave(Response response)
{
if (typeof(UserData) == response.Data.GetType())
{
//You have user data
}
else if (typeof(BranchData) == response.Data.GetType())
{
//You have branch data
}
else
{
//You have a problem!
}
}
}
Using a part of the suggestion from Andrew i've finally found a solution whihc works for me. Posting it to anyone who maybe is going crazy with it:
class Response
{
Data data { get; set; }
}
public abstract class Data
{
bool Success { get; set; }
public abstract Response CreateDeserializationModelSchema();
}
public class UserData : Data
{
public bool Success { get; set; }
public List<int> UpdatedIds { get; set; }
public List<int> NotUpdatedIds { get; set; }
public override Response CreateDeserializationModelSchema()
{
return new Response
{
Data = new UserData()
};
}
public static UsersData GetContent(Response response)
{
if (response.Data.GetType() == typeof(UsersData))
return (UsersData)response.Data;
else
throw new FormatException("Response not in the correct format to parse into UpdateUsersStatusResponse");
}
}
class UsersDataConverter : CustomCreationConverter<Response>
{
public override Response Create(Type objectType)
{
return new UsersData().CreateDeserializationModelSchema();
}
}
public class HowToUseIt
{
public void Use()
{
Response resp = JsonConvert.DeserializeObject<Response>(jsonResponse.ToString(), new UserDataConverter());
UserData u = UserData.GetContent(resp)
}
}

Retrieving generic data without knowing the List<Type> to be returned, is that possible?

I dont know if the question is correct but what I need to do is to received the correct entity from the messagetoprocess repository method with the corresponding data, how can I do that in this scenario? (code below)
Im using AutoMapper.
I know that I can create a MessageEntity and eliminate the Interface and put all properties together in it but that is exactly what Im trying not to do.
Here is what I've got:
Interface:
public interface IMessage
{
string MessageFrom { get; set; }
string MessageTo { get; set; }
{
Implementer Entities
public class EmailMessageEntity : IMessage
{
public bool IsMessageBodyHtml { get; set; }
}
public class SmsMessageEntity : IMessage
{
public bool IsMmsMessage { get; set; }
}
Models:
public class EmailMessage
{
public string MessageFrom { get; set; }
public string MessageTo { get; set; }
public bool IsMessageBodyHtml { get; set; }
}
public class SMSMessage
{
public string MessageFrom { get; set; }
public string MessageTo { get; set; }
public bool IsMmsMessage { get; set; }
}
Repositry:
public static List<*****Entity problem*****> RetrieveMessageToProcess()
{
var commandSettings = new CommandSettings
{
CommandText = #"[Schema].[RetrieveMessageToProcess]",
CommandType = CommandType.StoredProcedure
};
return new MsSqlProviderBase(DbConnectionString, commandSettings).ExecuteQuery<*****Entity problem*****>();
}
Using it:
//code excerpt
var messagesToProcess = Db.RetrieveMessageToProcess(); //repository
if (messagesToProcess == null) return;
// Process Message(s)
foreach (var messageEntity in messagesToProcess)
{
if (Email) // this is just the verification example not the actual statement and not a variable
{
Mapper.CreateMap<EmailMessageEntity, EmailMessage>();
var emailMessage = Mapper.Map<EmailMessage>(messageEntity);
}
else if (SMS)
{
Mapper.CreateMap<SMSMessageEntity, SMSMessage>();
var smsMessage = Mapper.Map<SmsMessage>(messageEntity);
}
}
Could you consider having a MessageType member on your IMessage interface instead of the two IsXXX properties ?
You could return an enum, or whatever other value you deem appropriate, and use that in your if(EMAIL) statement.

using JSON response from REST api with nonstandard names

{"balances-and-info":{"on_hold":[],"available": {"USD":0.93033384},"usd_volume":"243.18","fee_bracket": {"maker":"0.00","taker":"0.60"},"global_usd_volume":"0.09942900"}}
I have this JSON response, and I'm trying to store it in an object, however as you can see "balances-and-info" cannot be used as a variable name. The method I have been using is:
RestClient client = new RestClient("http://currency-api.appspot.com/api/");
RestRequest request = new RestRequest(url);
var response = client.Execute<Currency>(request);
Currency obj = response.Data;
Where obviously the class is a lot easier
public class Currency
{
public string rate { get; set; }
}
So how can I handle this?
String.replace() balances-and-info with balances_and_info
in your code
YourObject deserialized = parseResponse(obj.replace("balances-and-info", "balances_and_info"));
YourObject parseResponse(string response) {
try
{
// https://www.nuget.org/packages/Newtonsoft.Json/
// Json.NET
YourObject ret = JsonConvert.DeserializeObject<YourObject>(response);
return ret;
}
catch (JsonSerializationException)
{
// do something
}
return null;
}
YourObject
Use http://json2csharp.com/ and generate your object (copy response string, replace balances-and-info with balances_and_info and generate)
public class Available
{
public double USD { get; set; }
}
public class FeeBracket
{
public string maker { get; set; }
public string taker { get; set; }
}
public class BalancesAndInfo
{
public List<object> on_hold { get; set; }
public Available available { get; set; }
public string usd_volume { get; set; }
public FeeBracket fee_bracket { get; set; }
public string global_usd_volume { get; set; }
}
public class YourObject
{
public BalancesAndInfo balances_and_info { get; set; }
}

Categories

Resources