How to handle exceptions in a nice way? [closed] - c#

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 2 years ago.
Improve this question
I am trying to write a simple Console App, where I have a User class that looks like this:
class User
{
public string Name { get; set; }
public int Age { get; set; }
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
My goals is to get an input from the user for every property, but I want to check whether the user input
meets specific criterias. For example: when to user tries to enter a value for the Name property, I want to check whether or not the entered value starts with an uppercase letter, contains digits, is less than fifty characters, etc. and if the entered value is not valid, then I throw an exception and ask the user to try again, if it is valid, then we move onto the next property and so on.
My problem is that I can not figure out how to simplify this process, because what happens if I have a property that has to meet a hundred criterias.
Is there a simple way to check if the user input meets a lot of criteria and if not, I throw an exception, show a random error message and after that the user can try again.

One very simple way would be to create a dictionary of ValidationCriterias and corresponding Error Messages for any given class. Since its user input validation checks, I would just throw a valid friendly error message, instead of exception, since such errors were already anticipated.
The following code runs all the validation criterias, even though if any single fails and at the end outputs all the error messages in a pipe separated string.
If at least a single criteria fails , the function will return false.
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class ValidateProps<T> where T: class
{
public static bool RunRules(Dictionary<Expression<Func<T, bool>>, string> lst,
T myObj,
out string errorMessages)
{
errorMessages = "";
bool isSuccess = true;
foreach (var l in lst)
{
if (l.Key.Compile()(myObj) == false) isSuccess = false;
errorMessages += l.Key.Compile()(myObj) == true ? "" : "|" +l.Value;
}
errorMessages = errorMessages.Trim('|');
return isSuccess;
}
}
// Example Usage
User u = new User() { Name = "dd23dd", Age = 100 };
Dictionary<Expression<Func<User, bool>>, string> dict1 =
new Dictionary<Expression<Func<User, bool>>, string>()
{ {x => Char.IsUpper(x.Name.ToCharArray().ElementAt(0)), "Error Message 1" },
{x => !(x.Name.Any(char.IsDigit)), "Error Message 2"},
};
string errorMsgs = "";
bool n1 = ValidateProps<User>.RunRules(dict1, u, out errorMsgs);

Related

Create Dictionary with custom class for value [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 days ago.
Improve this question
I'm using a dictionary in C# and want to make the value a custom class. I have the following code.
public class myMovies
{
public string Name { get; set; }
public string Year { get; set; }
}
Dictionary<string, myMovies> file_dict = new Dictionary<string, myMovies>();
foreach (string file in Directory.GetFiles(path1, "*.mkv", SearchOption.AllDirectories))
{
file_dict.Add(file, new myMovies("x", "x");
}
I'm doing something wrong, I just have no idea at this point. As a side note, this code does work when I just use a <string,string> dictionary and just store a text value in the value pair.
Edit
Required a constructor in my class definition. Thanks for help.
Either provide an appropriate constructor in the class definition:
public class myMovies
{
public string Name { get; set; }
public string Year { get; set; }
public myMovies(string name, string year)
{
Name = name;
Year = year;
}
}
Or use object initializer syntax to assign the property values when instantiating the object:
file_dict.Add(file, new myMovies { Name = "x", Year = "x" });
It's telling you it expects a Constructor, so give it what it expects:
public class myMovies
{
public myMovies(string name, string year)
{
Name = name;
Year = year;
}
public string Name { get; set; }
public string Year { get; set; }
}

How to create an object in a class by passing a token to a constructor? [closed]

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 2 years ago.
Improve this question
What I am attempting to do is to take a .txt file that has multiple lines of people's information (Last name, First name, phone number, email) and display the information into a listbox so that a user could select a name in the listbox and display all of the selected person's information in a second form. The instructions for my assignment say that the next thing I should do is Create your object by passing these tokens to your constructor. (Don’t pass the array but rather each element individually.) I have created a class called PersonEntry that constructs 4 strings containing the 4 pieces of information that's included in the .txt file. Here is where I'm at(the first one is my form1.cs code and the second is my PersonEntry.cs class code) and I don't know what to do next. Any help would be much appreciated!
namespace ChalabiMichaelProgram10
{
public partial class chalabiMichaelProgram10 : Form
{
List<PersonEntry> personsList = new List<PersonEntry>;
public chalabiMichaelProgram10()
{
InitializeComponent();
}
private void chalabiMichaelProgram10_Load(object sender, EventArgs e)
{
try
{
StreamReader inputfile;
string line;
int count;
inputfile = File.OpenText("contacts.txt");
while (!inputfile.EndOfStream)
{
line = inputfile.ReadLine();
char[] delimiters = { ',' };
string[] tokens;
tokens = line.Split(delimiters);
for( count = 0; count < 4; count++)
{
tokens[count] = tokens[count].Trim();
}
}
}
}
}
}
namespace ChalabiMichaelProgram10
{
class PersonEntry
{
//Constructor.
public PersonEntry()
{
lastName = "";
firstName = "";
phoneNumber = "";
email = "";
}
public string lastName { get; set; }
public string firstName { get; set; }
public string phoneNumber { get; set; }
public string email { get; set; }
}
}

select from list using LINQ's Where [closed]

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 4 years ago.
Improve this question
I need to get the vehicle type according to vehicle number. I need to select specific column from a list according to another column.
Here is my code:
protected void ddVehicleNo_SelectedIndexChanged(object sender, EventArgs e)
{
List<Exp_VehicleDTO> odata = (List<Exp_VehicleDTO>)Session["VehicleDTO"];
var vehityeps=odata.Select(x=>x.VehicleNo.Contains(x.VehicleType.Equals(Convert.ToInt32(ddVehicleNo.SelectedValue))))
}
This code causes error "the best overload method match for "string.contains(string)" has some invalid arguments".
Exp_vehicleDTO class
public class Exp_VehicleDTO
{
public int CompanyId { get; set; }
public int VehicleId { get; set; }
public int VehicleType { get; set; }
public string VehicleNo { get; set; }
public int Status { get; set; }
public DateTime CreatedDateTime { get; set; }
public string CreatedBy { get; set; }
public string CreatedMachine { get; set; }
}
You can get the vehicle type like so:
int vehicleType = odata.Single(x => x.VehicleNo.Equals(ddVehicleNo.SelectedValue)).VehicleType;
Single will take the first item that matches the condition. Note that it will throw an exception if the item isn't found, or if there are multiple matching items.
If you want to handle the case that the item isn't found, you can do something like this:
var vehicle = odata.SingleOrDefault(x => x.VehicleNo.Equals(ddVehicleNo.SelectedValue));
if (vehicle != null)
{
var vehicleType = vehicle.VehicleType;
}
else
{
// set combobox's SelectedIndex to -1
}
Difficult to help without knowing what error you are receiving but try changing your code to this:
protected void ddVehicleNo_SelectedIndexChanged(object sender, EventArgs e)
{
List<Exp_VehicleDTO> odata = (List<Exp_VehicleDTO>)Session["VehicleDTO"];
var vehityeps = odata
.Where(v => v.VehicleNo.ToString() == ddVehicleNo.SelectedValue)
.Select(v => v.VehicleType);
}
That should populate vehityeps with all VehicleType's where VehicleNo equals what the user has selected in the ddVehicleNo drop down.
UPDATED
I'm not sure what types are used Exp_VehicleDTO but my guess is VehicleNo is an int. To be safe with my solution this compares the values as strings.

Populating list property in ctor based on other property

My application is basically just a survey with questions and multiple choice answers. Questions have Answers, but a specific Answer may lead to a specific Question being asked which might otherwise not be asked at all. e.g. "Do you like chocolate?" (if yes ask...) "Do you prefer German or Dutch chocolate?"
In the Answer class, I am trying to populate a list property "DependentQuestions" which is meant to contain id numbers for the Quesiton(s) that will be asked next if this Answer is chosen. The problem is, I am always getting nothing and I'm not sure why. I confirmed the Answer.id is zero at the time the constructor runs by populating DependentQuestions with the commented code you'll see below.
Each Question has an icollection of Answers.
Question class:
public class Question
{
[Key]
public int id { get; set; }
public string question { get; set; }
public int? DependentAnswer { get; set; }
public virtual ICollection<Answer> answers { get; set; }
}
Answer class:
public class Answer
{
[Key]
public int id { get; set; }
public string answer { get; set; }
[Required]
public int questionId { get; set; }
public List<int> DependentQuestions { get; set; }
public Answer()
{
DependentQuestions = new List<int>();
using (dbSurvey db = new dbSurvey())
{
var _list = db.Questions.Where(q => q.DependentAnswer == id).Select(q => q.id).ToList();
if (_list.Any())
{
DependentQuestions.AddRange(_list);
}
//else
//{
// DependentQuestions.Add(id);
//}
}
}
}
The "answers" collection of the Question class is being filled with the Answers to the given Question and that works just fine, but the DependentQuestions list in the Answer class is always coming up empty since Answer.id is always zero at that point. So why is Answer.id always 0, and what can I do about it?
Constructor code is run before any property values are set, so at the point of executing the constructor all properties just contain their default values. That is why it is always 0.
I am not sure what are you using as a data access framework, but generally you can do few things:
Create Answer entity with id, so you always have it in constructor:
public Answer(int id)
If that's not an option, you could also have a lazy property loading questions as needed:
class Answer
{
private List<int> _dependentQuestions;
public List<int> DependentQuestions
{
get
{
if (_dependentQuestions == null)
// load questions here
return _dependentQuestions;
}
}
}
Note that this assumes id is already set, you probably should validate that too.

How do I fix the error: Argument 1: cannot convert from 'string' to 'Name.Entity.Models.MakeModelInfo

I'm trying to validate several user input fields that use type-ahead. I want to reject any input that's not contained in the type-ahead list.
But I'm getting a build error on the 'var isValid' line of code when I try to run my application:
My ViewModel
[Required]
[StringLength(100)]
[AllowedModelMake(ErrorMessage = "Please enter a Make from the list.")] //JosephW
public string Make { get; set; }
public string MakePlaceholder { get; set; }
[Required]
[StringLength(100)]
[AllowedModelMake(ErrorMessage = "Please enter a Model from the list.")] //JosephW
public string Model { get; set; }
public string ModelPlaceholder { get; set; }
My Controller
public class AllowedModelMakeAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// Validate that user input is in the list of allowed values
var allowedList = MakeModelHelpers.GetActiveMakeModelInfo();
var userInput = value as string;
var isValid = allowedList.Contains(userInput); //<- ERROR IS HERE
return isValid;
}
}
The return type for GetActiveMakeModelInfo() is here:
public static List<MakeModelInfo> GetActiveMakeModelInfo() {
return makeModelRepository.GetActiveInfo();
The string representation of MakeModelInfo is:
namespace Name.Entity.Models {
public class MakeModelInfo {
public int Id { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
}
According to the Microsoft documentation at https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/introduction/adding-validation this should work.
I'm pretty new at .Net and I'm not sure how to fix this problem. Can anyone offer a suggestion?
I'm guessing what you're really trying to check is if the user input (a string) exists in the "Allowed" list of MakeModelInfo. You already know you can't compare an object to a string, so the Contains method won't work. What you can do is something like this:
public override bool IsValid(object value)
{
// Validate that user input is in the list of allowed values
var allowedList = MakeModelHelpers.GetActiveMakeModelInfo();
var userInput = value as string;
var isValid = allowedList.Any(i -> i.Make == userInput || i.Model == userInput);
return isValid;
}
You can modify this if you're only interested in checking one of the properties and not both. Alternatively, what you might want to do is use one drop down containing the Makes of vehicle that is in your list and another containing the Models for the selected Make. Here is an example.
on this line:
var isValid = allowedList.Contains(userInput); //<- ERROR IS HERE
You are missing the point here. Contains() method has different overloading functions. You are using ICollection<T>.Contains(T), which means the type of list and the type of argument is the same. So, in above code, compiler thinks userInput has the same type i.e. MakeModelInfo.
You should use ICollection<T>.Contains(Predicate(T)), it takes lambda expression and in that you can check for the property value. e.g.
var isValid = allowedList.Contains(x=> x.Make.Equals(userInput));
//OR
var isValid = allowedList.Contains(x=> x.Model.Equals(userInput));
If the allowedList contains any item having property Make or Model equal to userInput, it will return true or false

Categories