Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I'm using a web service with this request format:
{
"type":"LogonReq",
"id":"b43b301c-5216-4254-b3fc-cc863d4d6652",
"date":"Wed, 16 Aug 2017 17:35:34 UTC",
"parameters":[
{
"userName":"user",
"password":"password"
}
]
}
Even though every message in the API requires only 1 set of parameters, the API still requires "parameters" to be an array.
Is it better practice to have the caller create the list or to create the list in the MessageBase constructor, or something altogether different ?
Which way would satisfy an OOP purist code reviewer?
public class MessageBase<T>
{
public MessageBase() { this.parameters = new List<T>(); }
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
};
logon.parameters.Add(new LogonMessage() { userName = "user", password = "password" });
or
public class MessageBase<T>
{
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
parameters = new List<LogonMessage>() { new LogonMessage() { userName = "user", password = "password" } }
};
You will probably find many interesting opinions and answers to this. I can only give you mine based on my experience.
I myself would probably initialize the list within the constructor
However, since you are trying to get a good idea around the phylosophy of coding, here are some things to consider :
1) Does the MessageBase object make sense or is it useful with a NULL list? Is there any scenario where I want this list as null?
2) Actually, I would expect an OOP purist to say that you should not expose the "parameters" as a List. By exposing the object as a property, someone can do this:
login.parameters.Add()
Or this
logon.parameters = anotherListOfMine
In a way it does break encapsulation. You could make the list property read only (ie, with a protected/private setter) but "clients" of this class will still be able to access all properties and methods of the List and modify/handle them.
Now, you have to expose this in some way as you will be serializing/deserializing into JSON, so that poses a problem! Maybe you can have a private/protected List field and expose the values through a readonly property that exposes an IEnumerable and behind the scenes, you are doing:
get { return myPrivateList.ToArray(); }
3) But again, do you really win that much? Your next question should be "Who is my client?" If you are exposing this class to other developers, or is part of a framework, you might want to apply something like my point number 2, and limit the exposure. If this is internal to your application and your team maybe you should be pragmatic and simply expose the List as you are doing right now.
4) Alternatively, while still making it open, you could instead have a property of type IEnumerable so you can pass in any type.
5) Another option is to expose your list because you need to serialize it, but make it readonly. Have instead different methods, or non-serializable properties, of username and password. If these parameters are always the same that is. I am thinking this might not be your case.
I think I could go on and on this. I will stop here before you hit the downvote button :).
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to read a JSON string in C# (in fact, it is much longer, but just to show the structure...) This is the string that I receive.
42["cti-agentes","{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
\"6197\":{
\"id_agents_interface\":\"5743\",
\"agent\":\"6197\",
\"interface\":\"contact1\",
\"logintime\":\"2020-01-16 10:16:17\",
\"pausetime\":null,
\"paused\":\"no\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact2\",
\"textoterminal\":\"contact2\"
}
}"]
The String is supposed to be an array of 'agents'. 6139 is one agent, with all its properties, and 6197 is another agent. In this example there are only two agents, but in the real string there are many of them.
I am not very familiar with the JSON format, but I tried to validate it in this web https://jsonformatter.curiousconcept.com/ and I can't make it work, so maybe I have to "clean" the string a little bit before parsing it? Hope you can help.
The aplication should be able to read the JSON string and parse it to a .NET object, I tried the JsonConvert.DeserializeObject() and JArray.Parse() functions but neither of them have worked for me.
Any help?
The first part seems to be an int, you have multiple way to remove it:
var withoutNumberPrefix = new string(input.SkipWhile(c=> Char.IsDigit(c)).ToArray());
var fixedSize = input.Substring(2, input.Length - 2);
var always42 = input.TrimStart(new[] { '4', '2' });
Once you have done that you have a List<string>, where the first value is the type and the second the "array" of that type.
var listResults = JsonConvert.DeserializeObject<string[]>(fixedSize);
You can deserialize the second part:
var result = JsonConvert.DeserializeObject<Dictionary<int,CtiAgentes>>(listResults[1]);
Into the matching type, created with a simple copy past using those tool
How to auto-generate a C# class file from a JSON string
:
public partial class CtiAgentes
{
[JsonProperty("id_agents_interface")]
public int IdAgentsInterface { get; set; }
[JsonProperty("agent")]
public int Agent { get; set; }
[JsonProperty("interface")]
public string Interface { get; set; }
[JsonProperty("logintime")]
public DateTimeOffset Logintime { get; set; }
[JsonProperty("pausetime")]
public DateTimeOffset? Pausetime { get; set; }
[JsonProperty("paused")]
public string Paused { get; set; }
[JsonProperty("id_pausa")]
public object IdPausa { get; set; }
[JsonProperty("invalid")]
public string Invalid { get; set; }
[JsonProperty("invalidtime")]
public object Invalidtime { get; set; }
[JsonProperty("fullcontact")]
public string Fullcontact { get; set; }
[JsonProperty("textoterminal")]
public string Textoterminal { get; set; }
}
In this Live demo, you will notice that there is no string manipulation except "remove the 42". Not backslash not quote were modify. It's a json hardcoded in a string Store Hardcoded JSON string to variable
Nota bene:
I used DateTimeOffset for Pausetime and Logintime, because there where no timezone in that input. You can use Datetime but it will be nice to know if it's gmt or localized data.
For all the null value I choosed object. because I don't know the type. And that will go boom sooner or later with data. One can assume that id is a int and invalid time a DateTimeOffSet, but I can't make that decision.
There are multiple issues with your text. I will try to elabroate on them in the following parts...
42 prepended to the string
Quite obvious to all of us - this just should not be there
Your json object is a list
Since your json object starts with [ it's actually a string list, that has to be separated by ,, e.g. ["a", "b", "c"], which is probably the reason for the next point...
Your json value objects are strings
First of all the following is kind of a mixture of a string list and a json object
"cti-agentes","{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
But also if you wanted to have json objects, you may not have surrounding "'s around your objects.
symbol because it makes it a string instead of a json object, e.g.
"employee_1": { "name": "dominik" } instead of
"employee_1": "{ "name": "dominik" }" like it is in your example.
Conclusion
The system providing you a "json" does not provide a json and instead some string that is kind of similar to a json. Why? I don't know - probably "42" lol :)
The best advice is probably to talk to the guy who made the api and fix it
What can I do now?
Maybe you can try to extract the value for cti-agentes, since the following is actually a valid json you should be able to parse.
{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
\"6197\":{
\"id_agents_interface\":\"5743\",
\"agent\":\"6197\",
\"interface\":\"contact1\",
\"logintime\":\"2020-01-16 10:16:17\",
\"pausetime\":null,
\"paused\":\"no\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact2\",
\"textoterminal\":\"contact2\"
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
When Domain Model property Name gets data from the database it's a string "David,James", but I have created another View Model to convert that string into an array ["David","James"]. I have used my ViewModel in the read method now, now the ViewModel should read the Name property as ["David","James"]. I am not sure how to make it happen.
I would appreciate if anybody has any suggestion on how to make it happen.
Domain Model:
public class FullName
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Address {get; set;}
}
View Model:
public class NameViewModel
{
public Int32 Id { get; set; }
public List<string> Name { get; set; }
public String Address { get; set;}
}
Read Method:
public ActionResult Name_Read([DataSourceRequest]DataSourceRequest request)
{
try
{
DataSourceResult result = Identity.ToDataSourceResult(request, NameViewModel => new
{
Id = NameViewModel.Id,
Name = NameViewModel.Name ,
Address = NameViewModel.Address,
});
return Json(result);
}
I think you're looking for something like this:
DataSourceResult result = Identity.ToDataSourceResult(request, dataModel => new NameViewModel
{
Id = dataModel.Id,
Name = dataModel.Name.Split(","),
Address = dataModel.Address,
});
// typical delimiter characters
char[] delimiterChars = { ' ' };
// verify the name exists
if (!String.IsNullOrEmpty(name))
{
// Get the list of strings
string[] strings = name.Split(delimiterChars);
if (strings != null)
{
if (strings.Length == 1)
{
firstName = strings[0];
}
else if (strings.Length == 2)
{
firstName = strings[0];
lastName = strings[1];
}
else if (strings.Length == 3)
{
firstName = strings[0];
middleName = strings[1];
lastName = strings[2];
}
}
}
I am not at Visual Studio, but I think that is right.
When Domain Model property Name gets data from the database it's a string "David,James"
That is a terrible mistake in database Design. The ideal solution would be to fix the Backend Database to actually have two fields for those distinct values.
Failing that, the next step would be to try and split on the DB side. Many modern DBMS support Views, wich can have columns computed from actuall rows. That way you could avoid issues, like different code splitting the same input differently. And you could even henceforth treat it like it was always two Columns.
If you really want or need to it in code and given this exact input format, String.Split() can deal with this. Of coruse you can get fancier, and use stuff like Regular Expressions instead. But for this example, Split seems perfectly suiteable for the case.
I have been agonizing over this problem for a few days now and have no hope left. I'm still in the early stages of learning C#, so excuse me if my explanations or understanding are lacking.
My scenario is that I have a need to access an API and download the data as JSON then deserialize it into a class. At the moment, things work as they should, however every variable is defined as String which means I need to convert and manipulate data that should be int/double on the fly constantly as the API can give "N/A" for these data. The impression I get is relying on everything being string is bad practice.
So how should I implement it? I need to be able to store the data as the correct type while keeping in mind that it could be wrong.
Example of properties with wrong type
public string Title { get; set; }
public string Year { get; set; } // Wanted int. Often has an end year "2010-2014"
public string Metascore { get; set; } // Wanted double. Could be "N/A"
The only way I can imagine solving this is by having two classes: the first one being the original string-only class, then having the second being an almost identical class with the desired properties that uses the data from the original then converts it.
My problem with that is that the class already has a few dozen properties, so duplicating it seems nearly as wasteful as the original problem. Regardless, I would like to know an alternative for future use anyway.
EDIT:
Found a similar question here, though unfortunately it didn't help.
you can deserialize the json to JObject and than load it your self
public class RootObject
{
public RootObject(JObject obj)
{
Title = obj["Title"].ToString();
var year = obj["year"].ToString();
Year = year == "N/A" ? 0 : int.Parse(year);
var metascore = obj["Metascore"].ToString();
Metascore = metascore == "N/A" ? 0 : int.Parse(metascore);
}
public string Title { get; set; }
public int Year { get; set; }
public double Metascore { get; set; }
}
static void Main(string[] args)
{
string json = "{\"Title\":\"test\",\"year\":\"2012\",\"Metascore\":\"N/A\"}";
RootObject root = new RootObject(JObject.Parse(json));
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am new to both SPA and Entity Framework and I have a question about the right/preferred way to do this.
I've got a web page to search customers by some filters (like name, surname, birthday date, phone number).
With ajax I pass from View to Controller a ViewModel object like this:
public class CustomerSearch
{
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? Birthday{ get; set; }
public string Phone{ get; set; }
}
Into controller I've got this search method:
public List<CustomerList> GetCustomersList(CustomerSearch cs)
{ ..... }
In my application there are also DataAccess objects.
Now, the question is: how I can to do the query to database in smart mode?
I've thinked some scenario but i don't know which is the best about the layer separation.
I can ask to model an IQueryable object and perform the Where condition into controller
I can create a DataAccess method with the filters like parameters
I can create a Customer object (model object) filled with the filters value and pass this to model that perform the query
Which is the best method?
Thanks in advance.
Daniele
I would suggest the first option you present for the following reasons:
Your second option would possibly require a lot of parameters if the number of possible search queries grows. It is generally not recommended to have a very large number of parameters since it leads to readability issues. (e.g. calling a method with 30 parameters)
Your third option would make it impossible to create a query like 'BirthDate in 1998' or 'Surname starts with Q'.
By creating a class specifically for the purposes of querying you can do something like the following:
public class CustomerQuery
{
public string Name { get; set; }
public DateTime? BirthDay { get; set; }
internal IQueryable<Customer> Apply(IQueryable<Customer> query)
{
var result = query;
if (!string.IsNullOrWhiteSpace(Name))
{
result = result.Where(c => c.Name == Name);
}
if (BirthDay.HasValue)
{
result = result.Where(c => c.BirthDay == BirthDay.Value);
}
return result;
}
}
Pay specific attention to the internal visibility of the Apply method. If you define this class in your Data Access Layer and this is defined in a separate C# project, the Apply method will only be visible to this Data Access Layer and not to the GUI project.
Calling it would be:
public List<Customer> GetCustomersList(CustomerQuery customerQuery)
{
using (var context = new MyDbContext())
{
var customers = context.Customers;
return customerQuery.Apply(customers).ToList();
}
}
This can be further extended to support e.g. different types of string search (Contains, StartsWith etc):
public enum TextFilterType
{
StartsWith,
EndsWith,
Contains,
ExactMatch
}
public class StringQuery
{
private readonly string _value;
private readonly TextFilterType _filterType;
public StringQuery(string value, TextFilterType filterType)
{
_value = value;
_filterType = filterType;
}
public string Value
{
get { return _value; }
}
public TextFilterType FilterType
{
get { return _filterType; }
}
}
If we would apply this to the CustomerQuery type:
public class CustomerQuery
{
public StringQuery Name { get; set; }
}
Then you look at the FilterType property of the StringQuery to find out if you need to do Contains, StartsWith etc.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
EDIT:
For clarity, this question is related to DDD, which has a concept called Value Objects, these are not Value Types, they are a way of building objects in such a way that the contents make up the identity, I was trying to understand how far these concepts should apply (From Comments it seems they should not seep outside domain). This question may look odd for people not familiar with DDD but to be clear it is about a very specific mechanism for creating objects NOT creating value types.
Consider the following sample code, which has two Value Objects:
public class SqlServerConnectionSettings
{
public string DatabaseName { get; set; }
public string ServerName { get; set; }
public SqlServerCredentials Credentials { get; private set; }
public SqlServerConnectionSettings(SqlServerCredentials credentials)
{
Credentials = credentials;
}
public string AsConnectionString()
{
//Snip
}
}
public class SqlServerCredentials
{
public string Username { get; private set; }
public string Password { get; private set; }
public bool UseIntegratedSecurity { get; private set; }
public SqlServerCredentials(string username = "", string password = "", bool useIntegratedSecurity = true)
{
Username = username;
Password = password;
UseIntegratedSecurity = useIntegratedSecurity;
}
public string AsConnectionStringCredentials()
{
//Snip
}
}
Rather than have distinct params for Username, Password, UseIntegratedSecurity I have created a value object to hold them. My question is, Is this taking the concept too far, have I misunderstood the point value objects have been designed for?
Looks good to me. You group items which belong together into cohesive units, what could be wrong about that?
It depends on your context.
If you define SqlServerCredentials as an Entity, yes, you're going too far :
"An entity is an object that is not defined by its attributes, but rather by a thread of continuity and its identity."
If you define SqlServerCredentials as a Value Object, you're right (don't forget that it should be immutable !):
"A value object is an object that contains attributes but has no conceptual identity. They should be treated as immutable."
If you define SqlServerCredentials as an Aggregate, you're right, too :
A n aggregate is a collection of objects that are bound together by a root entity, otherwise known as an aggregate root. The aggregate root guarantees the consistency of changes being made within the aggregate by forbidding external objects from holding references to its members.
In conclusion, in a DDD way, if you're not considering SqlServerCredentials as an entity, it's ok. But it's all about context.