How to save more values in XML - c#

I have a textfield where user can fill in strings under each other. But how to save now the different strings. Because now it is one long string. And not seperated strings
This is the class for Serialize and Deserialize:
public class PreConditionSettings
{
[Display(Name = "PreConditionResidentsOnly", ResourceType = typeof(Resources.Entity.Product))]
public bool ResidentsOnly { get; set; }
[Display(Name = "PreConditionMinimumAge", ResourceType = typeof(Resources.Entity.Product))]
public int MinimumAge { get; set; }
[SfsHelpers.PreConditionRedirectValidation(ErrorMessageResourceType = typeof(Resources.Entity.Product), ErrorMessageResourceName="PreConditionRedirectUrlValidation")]
[Display(Name = "PreConditionRedirectUrl", ResourceType = typeof(Resources.Entity.Product))]
public string RedirectUrl { get; set; }
[Display(Name = "PreConditionIpAddress", ResourceType = typeof(Resources.Entity.Product))]
public string IpAddress { get; set; }
public PreConditionSettings() {
this.ResidentsOnly = false;
this.MinimumAge = 0;
this.RedirectUrl = null;
this.IpAddress = null;
}
internal string Serialize(EditProductModel model) {
if (this.ResidentsOnly == false && this.MinimumAge == 0)
return model.Product.AuthenticationSettings;
XElement settings = XElement.Parse(model.Product.AuthenticationSettings ?? "<settings/>");
if (settings == null || settings.Attribute("authenticationrequired") == null || settings.Attribute("authenticationrequired").Value != "true")
return model.Product.AuthenticationSettings;
settings.Add(
new XElement("preconditions",
new XElement("residentsonly", this.ResidentsOnly ? "1" : "0"),
new XElement("minimumage", this.MinimumAge),
new XElement("redirecturl", this.RedirectUrl),
new XElement("ipaddress", this.IpAddress)
)
);
return settings.ToString();
}
internal void Deserialize(EditProductModel model) {
Deserialize(model.Product);
}
internal void Deserialize(Product product) {
XElement settings = XElement.Parse(product.AuthenticationSettings ?? "<settings/>");
if (settings == null || settings.Attribute("authenticationrequired") == null || settings.Attribute("authenticationrequired").Value != "true")
return;
XElement conditions = settings.Element("preconditions");
if (conditions == null)
return;
XElement condition = conditions.Element("residentsonly");
if (condition!= null)
this.ResidentsOnly = (condition.Value == "1");
condition = conditions.Element("minimumage");
if (condition != null) {
int age = 0;
if (Int32.TryParse(condition.Value, out age))
this.MinimumAge = age;
}
condition = conditions.Element("redirecturl");
if (condition != null) {
this.RedirectUrl = condition.Value;
}
condition = conditions.Element("ipaddress");
if (condition != null) {
this.IpAddress = condition.Value;
}
}
And it is about the propertie: IpAddress. The output of this is:
<settings authenticationrequired="true">
<accesslevel>level10</accesslevel>
<profile>test</profile>
<preconditions>
<residentsonly>1</residentsonly>
<minimumage>55</minimumage>
<redirecturl>/page/newpage</redirecturl>
<ipaddress>88888888
999999999</ipaddress>
</preconditions>
</settings>
But you see that it is one string, and not two strings: 88888888 and 999999999.
Thank you
I try it like this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
this.IpAddress = condition.Value;
}
I try it something like this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
string lines = string.Join("\n",condition.Value);
//this.IpAddress = condition.Value;
}
If I try this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; i++) {
lines[i] = condition.Value.ToString();
//lines = string.Join("\n", condition.Value.ToArray());
}
//lines = string.Join("\n",condition.Value);
//this.IpAddress = condition.Value;
}
I get this error:
Object reference not set to an instance of an object.
on this line:
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);

You should split your string IpAddress by \n or Environment.NewLine and save as array of strings.
After your edits :
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = condition.Value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
this.IpAddress = new XElement("ipaddresses", lines.Select(o=> new XElement("item", o))).ToString();
}

I would recommend you to either change the property to an ICollection or create a custom type IpAddresses, implementing ICollection and custom serialization/business logic.
This would bring the following change to your xml file:
<ipaddresses>
<item>88888888</item>
<item>99999999</item>
</ipaddresses>

Related

C# is there any better way to check if more than 2 properties in an object is not null

I am trying to check if more than 2 properties in a object has value and return invalid string if so
Example :
Class Student
{
string Name
string Code
string SNumber
}
Considering above code example , below scenarios can be written
if(studentObj.Name != null && studentObj.Code != null)
return "invalid";
if(studentObj.Name != null && studentObj.SNumber != null)
return "invalid";
if(studentObj.Code != null && studentObj.SNumber != null)
return "invalid";
Is there a way this can be simplified?
Thanks
typeof(Student).GetFields() // use GetProperties() if you have them, and not fields
.Select(field => field.GetValue(studentObj) as string)
.Count(value => !string.IsNullOrEmpty(value))
You could actually count:
class Student
{
public string Name {get; set;}
public string Code {get; set;}
public string SNumber {get; set;}
}
class StudentValidator
{
public string Validate(Student student)
{
int nonZeroCount = 0;
if( student.Name is object ) nonZeroCount++;
// in C# 9: if( student.Name is not null )
if( student.Code is object ) nonZeroCount++;
if( student.SNumber is object ) nonZeroCount++;
return (nonZeroCount > 2)? "invalid" : "valid";
}
}
Mind that you might prefer to check either with
string.IsNullOrEmtpty(string) or
string.IsNullOrWhitespace(string)
Here you can optionally optimize the select statement, but as an example, I offer this option for discussion:
class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "Mary", Code = "1", SNumber = "001" },
new Student{Name = "Sarah", Code = "", SNumber = "002" },
new Student{Name = "", Code = "3", SNumber = "003" },
new Student{Name = "Katherine", Code = "4", SNumber = "004" },
new Student{Name = "Eva", Code = "", SNumber = "" }
};
var listedProperty = from student in students
select new List<string> { student.Name, student.Code, student.SNumber };
listedProperty
.ToList()
.ForEach(l =>
{
var nullPropertyCount = l.Count(i => string.IsNullOrWhiteSpace(i));
if (nullPropertyCount <= 1)
{
Console.WriteLine(string.Join(", ", l.ToArray()));
}
});
Console.ReadLine();
}
}
Output result to the console:

Own class object attribute get overridden

I have created an object with the attributes String, and the other is a List<String>.
I have also created a static List<MyObject> where i add then all my Objects.
Now my Problem is the second attribute is getting overridden.
For example I have 3 Objects:
Object1: "Name"; List with 3 Strings
Object2: "Name2"; List with 2 Strings
Object3: "Name3"; List with 5 Strings
If i add them now to my Object List, it looks like so
Name; List with 5 Strings
Name2; List with 5 Strings
Name3; List with 5 Strings
It override the second attributes to all the other Objects in the List.
Code:
for (int i = 0; i < 100; i++)
{
if (elo.ReadObjMask(i) > 0)
{
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
else
{
// Do nothing
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
eigenschaften.Clear();
}
}
Here is my object class:
public class EloMask
{
public string name;
public List<String> eigenschaften;
public EloMask(string iname, List<String> ieigenschaften)
{
name = iname;
eigenschaften = ieigenschaften;
}
}
The List<string> always points to the same instance because you are passing a reference to the list, not a copy. As a result, the list is cleared and filled again for each EloMask that you pass that list into.
To fix your issue, create a new list instead:
if (elo.ReadObjMask(i) > 0)
{
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
// create a new list here!!!
var eigenschaften = new List<string>();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
// clearing the list is no longer needed
}
Here is an example how you can do what you want:
public static List<Person> PersonsList = new List<Person>();
public static Random rd = new Random();
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
List<string> tmpAbilities = new List<string>() {((char)rd.Next(255)).ToString(), ((char)rd.Next(255)).ToString() , ((char)rd.Next(255)).ToString() };
Person tmpPerson = new Person("TmpName_"+i,tmpAbilities);
PersonsList.Add(tmpPerson);
}
foreach (var persona in PersonsList)
{
Console.WriteLine(persona);
}
}
public class Person
{
public string Name { get; set; }
public List<string> Abilities;
public Person(string name,List<string> abilities)
{
Name = name;
Abilities = abilities;
}
public override string ToString()
{
string retVal = $"Name: {Name}\n";
foreach (var ability in Abilities)
{
retVal += $"Ability : {ability}\n";
}
return retVal;
}
}
for (int i = 0; i < 100; i++)
{
if (elo.ReadObjMask(i) > 0)
{
// Create a new listin here
eigenschaften = new List<string>();
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
else
{
// Do nothing
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
}
}

Split string to list of object

I have inputs like following:
"10+18+12+13"
"10+18-12+13"
"2-5"
e.g. number followed by a "+" or "-"
I created class MathOper
public class MathOper
{
public int Num { get; set; }
public string Oper { get; set; } //this display the number will be operated.
}
I want to return list of MathOper as following
"10+18-12+13" will return
new MathOper(){Num=10,"+"}
new MathOper(){Num=18,"+"}
new MathOper(){Num=12,"-"}
new MathOper(){Num=13,"+"}
I tried to code that by this way:
public class MathOperCreator
{
private readonly string _mathString;//8+2-3
public MathOperCreator(string mathString)
{
this._mathString = mathString.Trim();
}
public List<MathOper> Create()
{
var lMo = new List<MathOper>();
int l = this._mathString.Length;//5
for (int i = 0; i < l; i = i + 2)
{
char n = _mathString[i];
int n1 = int.Parse(n.ToString(CultureInfo.InvariantCulture));
string o1 = "+";
if (i > 0)
{
o1 = _mathString[i - 1].ToString(CultureInfo.InvariantCulture);
}
var mo = new MathOper { Num = n1, Oper = o1 };
lMo.Add(mo);
}
return lMo;
}
}
I found that it is only for number with one char, if the number is two char ,such as 18 , it doesn't work.
Please advice how implement described functionality?
This is a tested Solution
//Model class
public class MathOperation
{
public Int32 Num { get; set; }
public String Operation { get; set; }
}
String testData = "10+18+12-13";
String[] GetNumbers = testData.Split(new Char[] { '+', '-' });
String[] GetOperators = Regex.Split(testData, "[0-9]+");
//remove empty entries in operator
GetOperators = GetOperators.Where(x => !string.IsNullOrEmpty(x)).ToArray();
List<MathOperation> list = new List<MathOperation>();
MathOperation mathOperation = new MathOperation();
for (int i = 0; i < GetNumbers.Count(); i++)
{
mathOperation.Num = Convert.ToInt32(GetNumbers[i]);
mathOperation.Operation = (i>GetOperators.Length)? GetOperators[i] : null;
list.Add(mathOperation);
}
This will give a list like
{Num=10,"+"}
{Num=18,"+"}
{Num=12,"-"}
{Num=13,"null"} //as in my test string there is no char after 13
if you dont want a null always a + then
mathOperation.Operation = (i>GetOperators.Length)? GetOperators[i] : "+";
then This will give a list like
{Num=10,"+"}
{Num=18,"+"}
{Num=12,"-"}
{Num=13,"+"} //as in my test string there is no char after 13
This works for me.
//you can change in to MathOper
List<Tuple<int, char>> result = new List<Tuple<int, char>>();
string _mathString = "2-2+10-13"; //Test
char sign = '-';
if (_mathString[0] != '-') //checking the first sign
{
sign = '+';
}
while (_mathString.Length > 0)
{
int nextPl = _mathString.IndexOf('+');
int nextMn = _mathString.IndexOf('-');
if (nextPl == -1 && nextMn == -1) //condition when _mathString contains only number
{
result.Add(new Tuple<int, char>(int.Parse(_mathString), sign));
break;
}
else
{
//getting the end position of first number
int end = nextPl == -1 ? nextMn : (nextMn == -1 ? nextPl : (Math.Min(nextPl, nextMn)));
//retrieving first number
result.Add(new Tuple<int, char>(int.Parse(_mathString.Substring(0, end)), sign));
_mathString = _mathString.Remove(0, end);
//retrieving next sign
sign = _mathString[0];
_mathString = _mathString.Remove(0, 1);
}
}
Try this, I think it works the way you wanted: (Easy to understand solution but not optimal)
public class MathOper
{
public int Num { get; set; }
public string Oper { get; set; } //this display the number will be operated.
}
public class MathOperCreator
{
public readonly string _mathString;//8+2-3
public MathOperCreator(string mathString)
{
this._mathString = mathString.Trim();
}
public List<MathOper> Create()
{
var lMo = new List<MathOper>();
int l = this._mathString.Length;//5
string _mathStringTemp;
char[] charArr = _mathString.ToCharArray();
if (charArr[0] != '+' || charArr[0] != '-')
{
_mathStringTemp = "+"+_mathString;
} else
{
_mathStringTemp = _mathString;
}
char[] delimitersNumb = new char[] { '+', '-' };
string[] numbers = _mathStringTemp.Split(delimitersNumb,
StringSplitOptions.RemoveEmptyEntries);
string[] operators = new string[numbers.Length];
int count = 0;
foreach (char c in _mathStringTemp)
{
if (c == '+' || c == '-')
{
operators[count] = c.ToString();
count++;
}
}
for(int i=0; i < numbers.Length; i++)
{
lMo.Add(new MathOper(){Num = int.Parse(numbers[i]), Oper = operators[i]});
Console.WriteLine(operators[i]+" "+numbers[i]);
}
return lMo;
}
}

I need to remove items from a list

I am making a program that takes user input and populates that into a list. That part is working great. However the user needs the ability to edit or delete his/her input. I cannot figure out how to remove an item from the list. Here is the code for populating the list:
[Serializable]
class Recipient
{
public string Fname { get; set; }
public string MInit { get; set; }
public string Lname { get; set; }
public string Suffix { get; set; }
public string Amount { get; set; }
public string Message { get; set; }
public string Custom { get; set; }
public string CardType { get; set; }
} protected void btnToCart_Click(object sender, EventArgs e)
{
if (ValidateInput("Card Information"))
{ SetUI("Your Shopping Cart"); }
else
{
return;
}
Recipient recipients = new Recipient();
List<string> FName = (List<string>)ViewState["recipientList"];
List<string> MInit = (List<string>)ViewState["recipientList"];
List<string> LName = (List<string>)ViewState["recipientList"];
List<string> Suffix = (List<string>)ViewState["recipientList"];
List<string> Amount = (List<string>)ViewState["recipientList"];
List<string> Message = (List<string>)ViewState["recipientList"];
List<string> Custom = (List<string>)ViewState["recipientList"];
List<string> CardType = (List<string>)ViewState["recipientList"];
if (FName == null && MInit == null && LName == null && Suffix == null && Amount == null &&
Message == null && Custom == null && CardType == null)
{
FName = new List<string>();
MInit = new List<string>();
LName = new List<string>();
Suffix = new List<string>();
Amount = new List<string>();
Message = new List<string>();
Custom = new List<string>();
CardType = new List<string>();
}
recipients.Fname = txtFName.Text;
recipients.MInit = txtMInit.Text;
recipients.Lname = txtLName.Text;
recipients.Suffix = ddlSuffix1.SelectedItem.ToString();
recipients.Amount = txtAmount.Text;
recipients.Message = ddlMessage.SelectedItem.ToString();
recipients.Custom = txtCustom.Text;
recipients.CardType = lblImage.Text;
FName.Add(recipients.Fname);
MInit.Add(recipients.MInit);
LName.Add(recipients.Lname);
Suffix.Add(recipients.Suffix);
Amount.Add(recipients.Amount);
Message.Add(recipients.Message);
Custom.Add(recipients.Custom);
CardType.Add(recipients.CardType);
ViewState["recipientList"] = FName;
ViewState["recipientList"] = MInit;
ViewState["recipientList"] = LName;
ViewState["recipientList"] = Suffix;
ViewState["recipientList"] = Amount;
ViewState["recipientList"] = Message;
ViewState["recipientList"] = Custom;
ViewState["recipientList"] = CardType;
if (FName.Count == 1 && MInit.Count == 1 && LName.Count == 1 && Suffix.Count == 1)
{
lblCartName.Text = FName[0] + " " + MInit[0] + " " + LName[0] + " " + Suffix[0];
lnkEdit1.Visible = true;
}
if (Amount.Count == 1 && Message.Count == 1 && Custom.Count == 1)
{
lblCartAmount.Text = "$" + Amount[0] + ".00";
if (txtCustom.Text == string.Empty)
{
lblCartMessage.Text = Message[0];
}
else
{
lblCartMessage.Text = Custom[0];
}
}
Yes there is more to it but anyways, once the user clicks the next button then a summary is displayed to the user with all input information. There is also two linkbuttons on the form that gives the user the choice of editing or deleting. I have tried variations of:
FName.Remove(recipients.fname); and FName.RemoveAt(0);for example and none of these have worked. So that is my problem, any help would be greatly appreciated. Thanks
Like #rich.okelly wrote you overwrite your ViewState:
Use something like this:
List<string> FName = (List<string>)ViewState["recipientListFName"];
List<string> MInit = (List<string>)ViewState["recipientListMInit"];
List<string> LName = (List<string>)ViewState["recipientListLName"];
List<string> Suffix = (List<string>)ViewState["recipientListSuffix"];
List<string> Amount = (List<string>)ViewState["recipientListAmount"];
List<string> Message = (List<string>)ViewState["recipientListMessage"];
List<string> Custom = (List<string>)ViewState["recipientListCustom"];
List<string> CardType = (List<string>)ViewState["recipientListCardType"];

How do you get a user's country name in C#?

I am currently using geolocation to get the user's country name. Here is my code:
navigator.geolocation.getCurrentPosition(function (pos) {
var latlng = pos.coords.latitude + "," + pos.coords.longitude;
var apiurl = 'http://maps.google.com/maps/geo?output=json&sensor=false&q=' + latlng;
var yqlqry = encodeURIComponent('select * from json where url="' + apiurl + '"');
var yqlurl = 'http://query.yahooapis.com/v1/public/yql?q=' + yqlqry + '&format=json&callback=?';
$.getJSON(yqlurl, function (data) {
var countryName = data.query.results.json.Placemark.AddressDetails.Country.CountryName;
var newCountryName = countryName.toLowerCase();
if (newCountryName == "united states")
newCountryName = "us";
else if (newCountryName == "england" || newCountryName == "ireland" || newCountryName == "scotland" || newCountryName == "wales" || newCountryName == "northern ireland")
newCountryName = "uk";
else if (newCountryName == "australia")
newCountryName = "au";
else if (newCountryName == "canada")
newCountryName = "ca";
else
newCountryName = "world";
$('a[title = "' + newCountryName + '"]').trigger('click');
});
});
I would rather use something on the server side. Does anyone know if you can get the user's country name in C#?
On the server side, the only thing you can reply upon is the IP address, which you can use to perform a location lookup. There are free databases out there of IP address-to-location mappings, or you can use HostIP.info.
Look at https://stackoverflow.com/questions/372591/how-to-get-city-country-and-country-code-for-a-particular-ip-address-in-asp-ne for more info.
I did this for WP7, but code is almost the same in standard.net framework: http://www.felicepollano.com/2012/01/11/AnImplementationOfICivicAddressResolverForWP7.aspx
the class doing the job is below. Just remove ICivicAddressResolver that is a WP7 dependency and create your own interface.
public class AddressResolver:ICivicAddressResolver
{
string language = "en-GB";
public AddressResolver()
{
}
public AddressResolver(string language)
{
this.language = language;
}
[DataContract]
public class AddressInfo
{
[DataMember(Name = "formatted_address")]
public string FormattedAddress { get; set; }
}
[DataContract]
public class ResultInfo
{
[DataMember(Name = "results")]
public AddressInfo[] Info { get; set; }
}
readonly string URITemplate = "http://maps.googleapis.com/maps/api/geocode/json?latlng={0},{1}&sensor=true&language={2}";
#region ICivicAddressResolver Members
public CivicAddress ResolveAddress(GeoCoordinate coordinate)
{
throw new NotImplementedException("Use async version instead");
}
public void ResolveAddressAsync(GeoCoordinate coordinate)
{
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
var ainfo = ReadToObject<ResultInfo>(e.Result);
ResolveAddressCompleted(this, new ResolveAddressCompletedEventArgs(ToCivic(ainfo),e.Error,false,null));
}
else
{
ResolveAddressCompleted(this, new ResolveAddressCompletedEventArgs(new CivicAddress(), e.Error, false, null));
}
};
client.DownloadStringAsync(new Uri(GetFormattedUri(coordinate)));
}
private CivicAddress ToCivic(ResultInfo ainfo)
{
List<string> res = new List<string>();
foreach (var single in ainfo.Info)
{
res.Add(single.FormattedAddress);
}
if (res.Count > 0)
return new CivicAddress() { AddressLine1 = res[0] };
else
return new CivicAddress() { AddressLine1 = "#UNKNOWN#" };
}
public event EventHandler<ResolveAddressCompletedEventArgs> ResolveAddressCompleted = delegate { };
#endregion
private string GetFormattedUri(GeoCoordinate coord)
{
return string.Format(CultureInfo.InvariantCulture, URITemplate, coord.Latitude, coord.Longitude,language);
}
public static T ReadToObject<T>(string json) where T : class
{
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
T res = ser.ReadObject(ms) as T;
ms.Close();
return res;
}
}
Why don't you try IP2Location's API ?
You could just pass your ipaddress like this.
http://api.ip2location.com/?ip=145.228.219.221&key=demo
More info at
http://www.ip2location.com/ip-country-web-service.aspx
Don't know if this will help but in local this
CultureInfo.CurrentCulture.Name
return something like "en-GB" or "fr-FR" depending of your current locale

Categories

Resources