Write an Observable Collection to Csv file - c#

I have a datagridview that is bound to an observable collection in a mvvm fashion.
I'm trying to figure out how to write the collection to a csv file.
I can format the headers and get that put in, but not sure how one would iterate over a collection pulling out the values and putting them to a file with comma delimiting.
Here is my class
public class ResultsModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Phone { get; set; }
public string Username { get; set; }
public bool Sucess { get; set; }
public string MessageType { get; set; }
public string SenderMessageSent { get; set; }
public string SenderMessageReceived { get; set; }
}
which gets loaded into an observable collection

Here's a generic helper method which utilizes reflection to get values of all properties in the collection of objects and serializes to comma separated values string. (1 line = 1 object from collection)
public static IEnumerable<string> ToCsv<T>(IEnumerable<T> list)
{
var fields = typeof(T).GetFields();
var properties = typeof(T).GetProperties();
foreach (var #object in list)
{
yield return string.Join(",",
fields.Select(x => (x.GetValue(#object) ?? string.Empty).ToString())
.Concat(properties.Select(p => (p.GetValue(#object, null) ?? string.Empty).ToString()))
.ToArray());
}
}
And the examplary usage:
var oemResultsModels = new List<OemResultsModel>
{
new OemResultsModel
{
FirstName = "Fname1",
LastName = "LName1",
MessageType = "Type1",
Phone = 1234567,
SenderMessageReceived = "something1",
SenderMessageSent = "somethingelse1",
Sucess = true,
Username = "username1"
},
new OemResultsModel
{
FirstName = "Fname2",
LastName = "LName2",
MessageType = "Type2",
Phone = 123456789,
SenderMessageReceived = "something2",
SenderMessageSent = "somethingelse2",
Sucess = false,
Username = "username2"
}
};
using (var textWriter = File.CreateText(#"C:\destinationfile.csv"))
{
foreach (var line in ToCsv(oemResultsModels))
{
textWriter.WriteLine(line);
}
}

Related

custom response object for model validation in asp.net core

I want custom object in response of API having [required] data annotation on model properties like this:
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "fatal",
"code": "required",
"location": [
"/f:AllergyIntolerance/f:status"
]
}
]
}
Is it possible to do it or I would have to code it.
Because model validation happens before action is called, is there any way I can do it?
To create custom request and respond samples for your api, you can use Swashbuckle.AspNetCore.Swagger and to improve validations on your models you can use FluentValidations Sample. Good Luck!
first for simplify define your models like these :
public class ResponseModel
{
public string resourceType { get; set; }
public List<ResponseIssueModel> issue { get; set; } = new List<ResponseIssueModel>();
}
public class ResponseIssueModel
{
public string severity { get; set; }
public string code { get; set; }
public List<string> locations { get; set; } = new List<string>();
}
Then on your actions you can return this :
var response = new ResponseModel();
response.resourceType = "OperationOutcome";
response.issue.Add(new ResponseIssueModel
{
severity = "fatal",
code = "required",
locations = { "/f:AllergyIntolerance/f:status" }
});
return Ok(response);
you can use Builder Pattern for easy create response object
If you want to validate your model in controller,you could try with TryValidateModel method as mentioned in the document:
I tried as below:
in controller:
var model = new TestModel() { Id=1,nestedModels=new List<NestedModel>() { new NestedModel() { Prop1="P11"} } };
var isvalid=TryValidateModel(model);
var errorfiledlist = new List<string>();
if (!isvalid)
{
foreach (var value in ModelState.Values)
{
foreach (var error in value.Errors)
{
errorfiledlist.Add(MidStrEx(error.ErrorMessage,"The "," field"));
}
}
}
var jsonstring = JsonSerializer.Serialize(model);
foreach (var field in errorfiledlist)
{
var oldstr = String.Format("\"{0}\":null", field);
var newstr = String.Format("\"{0}\":\"required\"", field);
jsonstring = jsonstring.Replace(oldstr, newstr);
};
var obj = JsonSerializer.Deserialize<Object>(jsonstring);
return Ok(obj);
MidStrEx method:
public static string MidStrEx(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
try
{
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
}
catch (Exception ex)
{
}
return result;
}
Models:
public class TestModel
{
public int Id { get; set; }
[Required]
public string Prop { get; set; }
public List<NestedModel> nestedModels { get; set; }=new List<NestedModel>();
}
public class NestedModel
{
public string Prop1 { get; set; }
[Required]
public string Prop2 { get; set; }
}
The result:

How do I sort the csv file alphabetically and how to not show the "hidden" ones in the console with my code

I need to sort my csv file alphabetically and not show the ones that it says "hidden" for (aka. client 4 and client 5) this is the code:
static void Main(string[] args)
{
ReadCSFVFile();
Console.WriteLine();
}
static void ReadCSFVFile()
{
var lines = File.ReadAllLines("Navigation.txt");
var list = new List<Company>();
foreach (var line in lines)
{
var values = line.Split(';' );
var company = new Company() { ID = values[0], MenuName = values[1], ParentID = values[2], IsHidden = values[3], LinkURL = values[4] };
list.Add(company);
}
list.ForEach(x => Console.WriteLine($"{x.ID}\t {x.MenuName}\t {x.ParentID}\t {x.IsHidden}\t {x.LinkURL}"));
}
public class Company
{
public string ID { get; set; }
public string MenuName { get; set; }
public string ParentID { get; set; }
public string IsHidden { get; set; }
public string LinkURL { get; set; }
}
and this is the csv file:
ID;MenuName;ParentID;isHidden;LinkURL
1;Company;NULL;False; /company
2;About Us;1;False; /company/aboutus
3;Mission;1;False; /company/mission
4;Team;2;False; /company/aboutus/team
5;Client 2;10;False; /references/client2
6;Client 1;10;False; /references/client1
7;Client 4;10;True; /references/client4
8;Client 5;10;True; /references/client5
10;References;NULL;False; /references
The below should achieve this for you. I've commented the parts I've added to help out.
list.OrderBy(x => x.MenuName) // Order alphabetically based on MenuName
.Where(x => x.IsHidden != "True") // Filter only for non-hidden items
.ToList().ForEach(
x => Console.WriteLine($"{x.ID}\t {x.MenuName}\t {x.ParentID}\t{x.IsHidden}\t {x.LinkURL}"));

Cannot initialize type 'PeopleModel' with a collection initializer because it does not implement 'System.Collections.IEnumerable'

I have a method that aims to fill a PersonModel from OleDB;
public IEnumerable<PeopleModel> GetPeopleDetails()
{
var constr = ConfigurationManager.ConnectionStrings["dbfString"].ConnectionString;
using (var dbfCon = new OleDbConnection(constr))
{
dbfCon.Open();
using (var dbfCmd = dbfCon.CreateCommand())
{
dbfCmd.CommandText = "SELECT pp_firstname, pp_surname, pp_title, pp_compnm, pp_hmaddr1, pp_hmaddr2, pp_hmtown, pp_hmcounty, pp_hmpcode, pp_spouse, pp_children FROM people ORDERBY pp_surname";
using (var myReader = dbfCmd.ExecuteReader())
{
var peopleList = new List<PeopleModel>();
while (myReader.Read())
{
var details = new PeopleModel
{
details.Firstname = myReader[0].ToString(),
details.Lastname = myReader[1].ToString(),
details.Title = myReader[2].ToString(),
details.Company = myReader[3].ToString(),
details.Addr1 = myReader[4].ToString(),
details.Addr2 = myReader[5].ToString(),
details.Town = myReader[6].ToString(),
details.County = myReader[7].ToString(),
details.Spouse = myReader[8].ToString(),
details.Children = myReader[9].ToString(),
};
peopleList.Add(details);
}
return peopleList;
}
}
}
}
This code is pretty much identical to the method I am using to fill a companies details, which works no problem. Here is the PeopleModel I am using to build a person.
namespace SdcDatabase.Model
{
public class PeopleModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Title { get; set; }
public string Company { get; set; }
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Spouse { get; set; }
public string Children { get; set; }
}
}
Although the companies method has worked fine previously, I am now getting the following error when I try to build my project after implementing the People code: Cannot initialize type 'PeopleModel' with a collection initializer because it does not implement 'System.Collections.IEnumerable'
I really am at a lost cause with this as it is working in an almost identical method for a Company.
Correct syntax, without details. in the assignments in the initializer:
var details = new PeopleModel
{
Firstname = myReader[0].ToString(),
Lastname = myReader[1].ToString(),
Title = myReader[2].ToString(),
Company = myReader[3].ToString(),
Addr1 = myReader[4].ToString(),
Addr2 = myReader[5].ToString(),
Town = myReader[6].ToString(),
County = myReader[7].ToString(),
Spouse = myReader[8].ToString(),
Children = myReader[9].ToString(),
};

how to get Json nested properties to primary one

I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.

How do I create and insert one-to-many object with entity framework c#

I'm trying to create an object and insert to the database but keep getting the same error no matter what I try.
The row that I get the error on is ColumnGroupTest.ValidValues.Add(memberComment1); the error is
error message
NullReferenceException was unhandled by user code
my models
public class StoreColumnName
{
public int Id { get; set; }
public string StoreColumnGroupName { get; set; }
public string ColumnName { get; set; }
public string ColumnType { get; set; }
public List<StoreValidValue> ValidValues { get; set; }
}
public class StoreValidValue
{
public int Id { get; set; }
public string ValidValue { get; set; }
public StoreColumnName StoreColumnName { get; set; }
}
my controller
public ActionResult Index()
{
XDocument document = XDocument.Load(#"C:\Users\Physical.xml");
var result = document.Descendants("ColumnGroup");
foreach(var item in result){
var ColumnGroupName = item.Attribute("name").Value;
var Columns = item.Descendants("Column");
foreach (var itemColumn in Columns)
{
StoreColumnName ColumnGroup = new StoreColumnName();
var ColumnGroupTest = new StoreColumnName
{
StoreColumnGroupName = ColumnGroupName,
ColumnName = itemColumn.Attribute("name").Value,
ColumnType = itemColumn.Attribute("type").Value,
Id = 11
};
var ValidValues = itemColumn.Descendants("ValidValues");
var Values = ValidValues.Descendants("Value");
foreach (var Value in Values)
{
var memberComment1 = new StoreValidValue
{
StoreColumnName = ColumnGroupTest,
ValidValue = Value.Value,
Id = 101
};
ColumnGroupTest.ValidValues.Add(memberComment1);
}
}
}
return View();
}
(I gladly take tips on what I can improve when asking for help/guiding here).
Can anyone help ?
The issue that you're having is that you don't initialize your ValidValues property to a list. By default, those types of properties initialize to null unless you specify differently.
The best approach is to add that initialization to your constructor of that object.
public StoreColumnName() {
this.ValidValues = new List<StoreValidValue>();
}

Categories