I just happaned to have some troubles.
I have a model with a function
public class Profile
{
public void PrintResult()
{
if(1 == 1)
{
Console.WriteLine("equals 1");
if(2 == 2)
{
Console.WriteLine("equals 2");
}
}
else
{
Console.WriteLine("error");
}
}
}
this is the controller:
public ActionResult Index()
{
Profile p = new Profile();
p.PrintResult();
return View();
}
Well, I know that console.writeline or response.write.
So, my question is: how could I make those console.writeline to things like
string s = "Equals 2";
instead of console.writelines which does not working obviously and then call it somehow both equals 1 and equals 2 show in the view.
Been googling for quite long and couldn't find an answer.
If you need more info to help me, tell me #_ #
Instead of console.writeline, you have to return comma seperated string Or list of string
public List<string> PrintResult()
{
var listItems = new List<string>();
if (1 == 1)
{
listItems.Add("equal 1");
if (2 == 2)
{
listItems.Add("equal 2");
}
}
else
{
listItems.Add("error");
}
return listItems;
}
Return a comma separated list from your model in this case(Though i do not support coding such kind of models.Think this is for your practise).
public class Profile
{
public string PrintResult()
{
string strSample="";
if(1 == 1)
{
if(strSample=="")
{
strSample="equals 1";
}
else
{
strSample+=","+"equals1";
}
if(2 == 2){
if(strSample=="")
{
strSample="equals 2";
}
else
{
strSample+=","+"equals2";
}
|
}else
{
if(strSample=="")
{
strSample="error";
}
else
{
strSample+=","+"error";
}
}
}
}
Now In your controller pass this string returned from the model to your view as follows
public ActionResult Index()
{
Profile p = new Profile();
string sample=p.PrintResult();
return View((object)sample);
}
Now in your Index View, make the view as strongly typed to a string like below
#model string
<h1>#Model</h1>
Related
This is my first question here so I'm really open for opinions, I searched a lot about ASP.NET Core MVC and still I don't have enough answers if I'm writing code in right way.
In many tutorials on Youtube I saw people create ASP.NET Core MVC applications with CRUD operations but there were just simple without any logic and all code was in controllers.
What if I want add some logic for example checking if my record already exists in the database? Where should I put this?
I have class Patient and I want add patient to database so I got in patient controller this :
public async Task<IActionResult> Create([Bind("PatientId,Name,Surname,Pesel")] Patient patient)
{
if (ModelState.IsValid)
{
String result = facade.Add_patient(patient);
if (result == "Patient added")
{
_context.Add(patient);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
else
{
ViewBag.Message = "Patient exists";
return View();
}
}
}
Facade is my class in model folder where I have this :
public class Facade
{
private Database_controller _context;
public Facade(Database_controller context)
{
_context = context;
}
private List<Patient> patients = new List<Patient>();
public List<Patient> Patients { get => patients; set => patients = value; }
public void updatedata()
{
patients = _context.Patients.ToList();
}
public string Add_patient(Patient patient)
{
Patient Patient = new Patient();
Patient.Name = patient.Name;
Patient.Surname = patient.Surname;
Patient.Pesel = patient.Pesel;
String if_is = addpacjent(Patient);
if (!"Is".Equals(if_is))
{
return "Patient added";
}
else
{
return "Patient exists";
}
}
public String addpacjent(Patient val)
{
bool if_is = patients.Contains(val);
if (if_is == true)
{
return ("Is");
}
else
{
patients.Add(val);
return null;
}
}
}
In Patient class is override method equals for checking
public override bool Equals(Object ob)
{
String Name = Surname;
String Name2 = ((Patient)ob).Surname;
String Pesel1 = Pesel;
String Pesel2 = ((Patient)ob).Pesel;
bool a = Name.Equals(Name2);
if (Pesel2 != "0")
{
bool b = Pesel1.Equals(Pesel2);
bool c = false;
if (a && b == true)
{
c = true;
}
return c;
}
else
return a;
}
Is it the right way? Should I have method _context.Add(patient) in Facade or controller? Where should I check existence in database?
I already have application which I want write in .NET Core in Winforms so I want use as many as possible code from Winforms classes so it's why I started coding like this in ASP.NET Core MVC
The easiest way is to use Any(),this is because Any() will return as soon as it finds a match.
Like my following:
public IActionResult Test()
{
//Simulation data:
var patient = new Patient
{
Name="AA",
SumName="AA-aa",
Pesel="23"
};
//Here you can add your conditions.
if (!_context.Patients.Any(o => o.Name == patient.Name&&o.SumName==patient.SumName&&o.Pesel==patient.Pesel))
{
_context.Add(patient);
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
else
{
ViewBag.Message = "Patient exists";
return View();
};
}
Below is the demo data in my database:
Sample effect display:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Crystal_Message
{
class Message
{
private int messageID;
private string message;
private ConcurrentBag <Employee> messageFor;
private Person messageFrom;
private string calltype;
public Message(int iden,string message, Person messageFrom, string calltype, string telephone)
{
this.messageID = iden;
this.messageFor = new ConcurrentBag<Employee>();
this.Note = message;
this.MessageFrom = messageFrom;
this.CallType = calltype;
}
public ConcurrentBag<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
public int MessageIdentification
{
get { return this.messageID; }
private set
{
if(value == 0)
{
throw new ArgumentNullException("Must have Message ID");
}
this.messageID = value;
}
}
public string Note
{
get { return message; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Must Have a Message");
}
this.message = value;
}
}
public Person MessageFrom
{
get { return messageFrom; }
private set
{
this.messageFrom = value;
}
}
public string CallType
{
get { return this.calltype; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentNullException("Please specify call type");
}
this.calltype = value;
}
}
public void addEmployee(Employee add)
{
messageFor.Add(add);
}
public override string ToString()
{
return "Message: " + this.message + " From: " + this.messageFrom + " Call Type: " + this.calltype + " For: " + this.returnMessagefor();
}
private string returnMessagefor()
{
string generate="";
foreach(Employee view in messageFor)
{
generate += view.ToString() + " ";
}
return generate;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
Message testEquals = obj as Message;
if((System.Object)testEquals == null)
{
return false;
}
return (this.messageID == testEquals.messageID) && (this.message == testEquals.message) && (this.messageFor == testEquals.messageFor) && (this.messageFrom == testEquals.messageFrom) && (this.calltype == testEquals.calltype);
}
public bool Equals(Message p)
{
if ((Object)p == null)
{
return false;
}
return (this.messageID == p.messageID) && (this.message == p.message) && (this.messageFor == p.messageFor) && (this.messageFrom == p.messageFrom) && (this.calltype == p.calltype);
}
public override int GetHashCode()
{
unchecked
{
return this.messageID.GetHashCode() * 33 ^ this.message.GetHashCode() * 33 ^ this.messageFor.GetHashCode() * 33 ^ this.messageFrom.GetHashCode() * 33 ^ this.calltype.GetHashCode();
}
}
}
}
I have a Message class where a user could leave a message for more than one person. I have a getter for it, however, is returning a ConcurrentBag<> the way I've done proper practice? If not, how do i return the ConcurrentBag<> so I can loop through it and display it?
ConcurrentBag<T> is an IEnumerable<T>. You can loop through it as usual. However, as this is a thread safe collection, there are performance concerns to using it.
If you want to get rid of the performance impact while looping, call ToArray on it and return the new array instead.
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
It's not clear to me what you are trying to accomplish.
Are you trying to externalize the Bag for all operations? Because that's what you did...
If you want to externalize something you can iterate over you should either return the Bag as IEnumerable or return an array or a list copied from the Bag.
Either way it's safe to iterate over. Might not be the best in terms of performance, but that's another question.
// Option 1
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
// Option 2
public Employee[] ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
Notes:
You might want to make messageFor readonly (in the code you posted it is readonly).
Remember that a ConcurrentBag allows you to safely iterate over a snapshot of the collection in a thread safe manner, but it does not lock the items in the collection.
How do you write an if/else statement for this method if there is no result?
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
return View("_RestaurantSearchResults", restaurants);
}
Helpers class contains:
public class Helpers
{
FoodReviewContext _db = new FoodReviewContext();
public static IQueryable<Restaurant> getRestaurant(string q)
{
var restaurents = _db.Restaurants
.Where(r => r.Name.StartsWith(q) || String.IsNullOrEmpty(q))
.Take(2);
return restaurents;
}
}
If I understand your question correctly:
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
if (restaurants.Count() == 0) {
// do something
} else {
// do something else
}
return View("_RestaurantSearchResults", restaurants);
}
Take a look here: http://msdn.microsoft.com/en-us/library/bb351562%28v=vs.110%29.aspx. This goes over all the methods in the IQueryable<T> interface.
Oftentimes when you are looking for how to work with a certain part of the .NET Framework, C#, or others' code, the documentation is the best first place to go to.
simply check your result count for it.
public ActionResult Search(string q)
{
Helpers Helpers = new Helpers();
var restaurants = Helpers.getRestaurant(q);
if(restaurants.Count()>0)
{
return View("_RestaurantSearchResults", restaurants);
}
else
{
ViewBag.Message="No result found";
return View("_RestaurantSearchResults");
}
}
And just check if ViewBag.Message is available or not in View.
Try this
if (restaurants.Count() != 0)
{
//non-zero thing
}
else
{
//zero thing
}
If possible I need to use some code where an 'if' follows after an 'else' as follows:
if (Car1.isEmpty)
{
Do stuff
}
else
{
Car1.EmptyOut();
}
else if (Car2.isEmpty)
{
Do stuff
}
else
{
Car2.EmptyOut()
}
Etcetera. This needs to be done multiple times. Basically if Car1 isn't available (because it's not empty), Car2 needs to be used and Car1 needs to be send home to get emptied.
I'm wondering if it will get to the next 'else-if' statement though.
Maybe you are looking for "when first car is not free use second one"?
if (Car1.isEmpty)
{
Do stuff
}
else
{
Car1.EmptyOut();
if (Car2.isEmpty)
{
Do stuff
}
else
{
Car2.EmptyOut()
}
}
Note that if you have multiple "cars" using list of some sort and LINQ queries could make more sense. I.e.
var firstEmpty = cars.Where(car => car.IsEmpty).FirstOrDefault();
if (firstEmpty != null)
{
// use empty car
}
else
{
// no empty cars - recover and maybe retry...
}
No, this is not possible. If you need to perform an action like this then it would be a good idea to use a loop
var carList = new List<car>();
for(var car in carList ) {
if(car.isEmpty){
//Do stuff
} else {
car.emptyOut();
}
}
if you don't want to use a loop, for whatever reason, you can simply put a lot of if statements together
if(car1.isEmpty) {
//Do stuff
} else {
car1.emptyOut();
}
if(car2.isEmpty) {
//Do stuff
} else {
car2.emptyOut();
}
Do you mean this?
if (Car1.isEmpty)
{
//Do stuff
}
else
{
Car1.EmptyOut();
if (Car2.isEmpty)
{
//Do stuff
}
else
{
Car2.EmptyOut()
}
}
No. This is not allowed. Do this instead:
if (Car1.isEmpty)
{
// Do stuff.
}
else
{
Car1.EmptyOut();
if (Car2.isEmpty)
{
// Do stuff.
}
else
{
Car2.EmptyOut();
}
}
Since you have lots of cars, if you can enumerate their variable names, then you can use reflection. For example:
using System;
class Car
{
public Car(string name)
{
Name = name;
}
public bool isEmpty { get; set; }
public string Name { get; set; }
public void EmptyOut() { }
}
static class Program
{
public static Car Car0 = new Car("Car0");
public static Car Car1 = new Car("Car1");
public static Car Car2 = new Car("Car2");
public static Car Car3 = new Car("Car3");
public static Car Car4 = new Car("Car4");
public static Car Car5 = new Car("Car5");
public static Car Car6 = new Car("Car6");
public static Car Car7 = new Car("Car7");
public static Car Car8 = new Car("Car8");
public static Car Car9 = new Car("Car9");
static void Main()
{
var type = typeof(Program);
for (int i = 0; i <= 9; i++)
{
var field = type.GetField("Car" + i);
var temp = (Car)field.GetValue(null);
if (temp.isEmpty)
{
// Do stuff.
break;
}
else
{
temp.EmptyOut();
}
}
}
}
10 cars? If you've got more than a couple of cars, something like this should do you:
public bool Process( IEnumerable<Car> cars , Action<Car> process )
{
bool success = false ;
foreach( Car car in cars )
{
if ( car.IsEmpty )
{
process(car) ;
success = true ;
break ;
}
car.EmptyOut() ;
}
return success ;
}
That s not possible in C# syntax, manage to use a Switch statement, or nested If Else statements
This is really a generic (and probably a more subjective too) question. I have some classes where I use an interface to define a standard approach to validating the object state. When I did this, I got to scratching my head... is it best to
1.) allow the constructor (or initializing method) to silently filter out the errant information automatically or...
2.) allow the client to instantiate the object however and let the client also call the interface's IsValid property or Validate() method before moving forward?
Basically one approach is silent but could be misleading in that the client may not be aware that certain pieces of information were filtered away due to it not meeting the validation criteria. The other approach then would be more straight forward, but also adds a step or two? What's typical here?
Okay, after a long day of trying to keep up with some other things, I finally did come up with an example. Please for me for it as it's not ideal and by no means something wonderful, but hopefully should serve well enough to get the point across. My current project is just too complicated to put something simple out for this, so I made something up... and trust me... totally made up.
Alright, the objects in the example are this:
Client: representing client-side code (Console App btw)
IValidationInfo: This is the actual interface I'm using in my current project. It allows me to create a validation framework for the "back-end" objects not necessarily intended for the Client to use since the business logic could be complicated enough. This also allowed me to separate validation code and call as-needed for the business logic.
OrderManager: This is an object the client-side code can use to manage their orders. It's client-friendly so-to-speak.
OrderSpecification: This is an object the client-side code can use to request an order. But if the business logic doesn't work out, an exception can be raised (or if necessary the order not added and exceptions ignored...) In my real-world example I actually have an object that's not quite so black-and-white as to which side of this fence it goes... thus my original question when I realized I could push validation request (calling IsValid or Validate()) to the cilent.
CustomerDescription: represents customers to which I've classified (pretending to have been read from a DB.
Product: Represents a particular product which is classified also.
OrderDescription: Represents the official order request.The business rule is that the Customer cannot order anything to which they've not been classified (I know.. that's not very real-world, but it gave me something to work with...)
Ok... I just realized I can't attach a file here, so here's the code. I apologize for it's lengthy appearance. That was the best I could do to create a client-friendly front-end and business logic back-end using my Validation interface:
public class Client
{
static OrderManager orderMgr = new OrderManager();
static void Main(string[] args)
{
//Request a new order
//Note: Only the OrderManager and OrderSpecification are used by the Client as to keep the
// Client from having to know and understand the framework beyond that point.
OrderSpecification orderSpec = new OrderSpecification("Customer1", new Product(IndustryCategory.FoodServices, "Vending Items"));
orderMgr.SubmitOrderRequest(orderSpec);
Console.WriteLine("The OrderManager has {0} items for {1} customers.", orderMgr.ProductCount, orderMgr.CustomerCount);
//Now add a second item proving that the business logic to add for an existing customer works
Console.WriteLine("Adding another valid item for the same customer.");
orderSpec = new OrderSpecification("Customer1", new Product(IndustryCategory.FoodServices, "Sodas"));
orderMgr.SubmitOrderRequest(orderSpec);
Console.WriteLine("The OrderManager now has {0} items for {1} customers.", orderMgr.ProductCount, orderMgr.CustomerCount);
Console.WriteLine("Adding a new valid order for a new customer.");
orderSpec = new OrderSpecification("Customer2", new Product(IndustryCategory.Residential, "Magazines"));
orderMgr.SubmitOrderRequest(orderSpec);
Console.WriteLine("The OrderManager now has {0} items for {1} customers.", orderMgr.ProductCount, orderMgr.CustomerCount);
Console.WriteLine("Adding a invalid one will not work because the customer is not set up to receive these kinds of items. Should get an exception with message...");
try
{
orderSpec = new OrderSpecification("Customer3", new Product(IndustryCategory.Residential, "Magazines"));
orderMgr.SubmitOrderRequest(orderSpec);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
public interface IValidationInfo
{
string[] ValidationItems { get; }
bool IsValid { get; }
void Validate();
List<string> GetValidationErrors();
string GetValidationError(string itemName);
}
public class OrderManager
{
private List<OrderDescription> _orders = new List<OrderDescription>();
public List<OrderDescription> Orders
{
get { return new List<OrderDescription>(_orders); }
private set { _orders = value; }
}
public int ProductCount
{
get
{
int itemCount = 0;
this.Orders.ForEach(o => itemCount += o.Products.Count);
return itemCount;
}
}
public int CustomerCount
{
get
{
//since there's only one customer per order, just return the number of orders
return this.Orders.Count;
}
}
public void SubmitOrderRequest(OrderSpecification orderSpec)
{
if (orderSpec.IsValid)
{
List<OrderDescription> orders = this.Orders;
//Since the particular customer may already have an order, we might as well add to an existing
OrderDescription existingOrder = orders.FirstOrDefault(o => string.Compare(orderSpec.Order.Customer.Name, o.Customer.Name, true) == 0) as OrderDescription;
if (existingOrder != null)
{
List<Product> existingProducts = orderSpec.Order.Products;
orderSpec.Order.Products.ForEach(p => existingOrder.AddProduct(p));
}
else
{
orders.Add(orderSpec.Order);
}
this.Orders = orders;
}
else
orderSpec.Validate(); //Let the OrderSpecification pass the business logic validation down the chain
}
}
public enum IndustryCategory
{
Residential,
Textile,
FoodServices,
Something
}
public class OrderSpecification : IValidationInfo
{
public OrderDescription Order { get; private set; }
public OrderSpecification(string customerName, Product product)
{
//Should use a method in the class to search and retrieve Customer... pretending here
CustomerDescription customer = null;
switch (customerName)
{
case "Customer1":
customer = new CustomerDescription() { Name = customerName, Category = IndustryCategory.FoodServices };
break;
case "Customer2":
customer = new CustomerDescription() { Name = customerName, Category = IndustryCategory.Residential };
break;
case "Customer3":
customer = new CustomerDescription() { Name = customerName, Category = IndustryCategory.Textile };
break;
}
//Create an OrderDescription to potentially represent the order... valid or not since this is
//a specification being used to request the order
this.Order = new OrderDescription(new List<Product>() { product }, customer);
}
#region IValidationInfo Members
private readonly string[] _validationItems =
{
"OrderDescription"
};
public string[] ValidationItems
{
get { return _validationItems; }
}
public bool IsValid
{
get
{
List<string> validationErrors = GetValidationErrors();
if (validationErrors != null && validationErrors.Count > 0)
return false;
else
return true;
}
}
public void Validate()
{
List<string> errorMessages = GetValidationErrors();
if (errorMessages != null && errorMessages.Count > 0)
{
StringBuilder errorMessageReported = new StringBuilder();
errorMessages.ForEach(em => errorMessageReported.AppendLine(em));
throw new Exception(errorMessageReported.ToString());
}
}
public List<string> GetValidationErrors()
{
List<string> errorMessages = new List<string>();
foreach (string item in this.ValidationItems)
{
string errorMessage = GetValidationError(item);
if (!string.IsNullOrEmpty(errorMessage))
errorMessages.Add(errorMessage);
}
return errorMessages;
}
public string GetValidationError(string itemName)
{
switch (itemName)
{
case "OrderDescription":
return ValidateOrderDescription();
default:
return "Invalid item name.";
}
}
#endregion
private string ValidateOrderDescription()
{
string errorMessage = string.Empty;
if (this.Order == null)
errorMessage = "Order was not instantiated.";
else
{
if (!this.Order.IsValid)
{
List<string> orderErrors = this.Order.GetValidationErrors();
orderErrors.ForEach(ce => errorMessage += "\n" + ce);
}
}
return errorMessage;
}
}
public class CustomerDescription : IValidationInfo
{
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public int ZipCode { get; set; }
public IndustryCategory Category { get; set; }
#region IValidationInfo Members
private readonly string[] _validationItems =
{
"Name",
"Street",
"City",
"State",
"ZipCode",
"Category"
};
public string[] ValidationItems
{
get { return _validationItems; }
}
public bool IsValid
{
get
{
List<string> validationErrors = GetValidationErrors();
if (validationErrors != null && validationErrors.Count > 0)
return false;
else
return true;
}
}
public void Validate()
{
List<string> errorMessages = GetValidationErrors();
if (errorMessages != null && errorMessages.Count > 0)
{
StringBuilder errorMessageReported = new StringBuilder();
errorMessages.ForEach(em => errorMessageReported.AppendLine(em));
throw new Exception(errorMessageReported.ToString());
}
}
public List<string> GetValidationErrors()
{
List<string> errorMessages = new List<string>();
foreach (string item in this.ValidationItems)
{
string errorMessage = GetValidationError(item);
if (!string.IsNullOrEmpty(errorMessage))
errorMessages.Add(errorMessage);
}
return errorMessages;
}
public string GetValidationError(string itemName)
{
//Validation methods should be called here... pretending nothings wrong for sake of discussion & simplicity
switch (itemName)
{
case "Name":
return string.Empty;
case "Street":
return string.Empty;
case "City":
return string.Empty;
case "State":
return string.Empty;
case "ZipCode":
return string.Empty;
case "Category":
return string.Empty;
default:
return "Invalid item name.";
}
}
#endregion
}
public class Product
{
public IndustryCategory Category { get; private set; }
public string Description { get; private set; }
public Product(IndustryCategory category, string description)
{
this.Category = category;
this.Description = description;
}
}
public class OrderDescription : IValidationInfo
{
public CustomerDescription Customer { get; private set; }
private List<Product> _products = new List<Product>();
public List<Product> Products
{
get { return new List<Product>(_products); }
private set { _products = value; }
}
public OrderDescription(List<Product> products, CustomerDescription customer)
{
this.Products = products;
this.Customer = customer;
}
public void PlaceOrder()
{
//If order valid, place
if (this.IsValid)
{
//Do stuff to place order
}
else
Validate(); //cause the exceptions to be raised with the validate because business rules were broken
}
public void AddProduct(Product product)
{
List<Product> productsToEvaluate = this.Products;
//some special read, validation, quantity check, pre-existing, etc here
// doing other stuff...
productsToEvaluate.Add(product);
this.Products = productsToEvaluate;
}
#region IValidationInfo Members
private readonly string[] _validationItems =
{
"Customer",
"Products"
};
public string[] ValidationItems
{
get { return _validationItems; }
}
public bool IsValid
{
get
{
List<string> validationErrors = GetValidationErrors();
if (validationErrors != null && validationErrors.Count > 0)
return false;
else
return true;
}
}
public void Validate()
{
List<string> errorMessages = GetValidationErrors();
if (errorMessages != null && errorMessages.Count > 0)
{
StringBuilder errorMessageReported = new StringBuilder();
errorMessages.ForEach(em => errorMessageReported.AppendLine(em));
throw new Exception(errorMessageReported.ToString());
}
}
public List<string> GetValidationErrors()
{
List<string> errorMessages = new List<string>();
foreach (string item in this.ValidationItems)
{
string errorMessage = GetValidationError(item);
if (!string.IsNullOrEmpty(errorMessage))
errorMessages.Add(errorMessage);
}
return errorMessages;
}
public string GetValidationError(string itemName)
{
switch (itemName)
{
case "Customer":
return ValidateCustomer();
case "Products":
return ValidateProducts();
default:
return "Invalid item name.";
}
}
#endregion
#region Validation Methods
private string ValidateCustomer()
{
string errorMessage = string.Empty;
if (this.Customer == null)
errorMessage = "CustomerDescription is missing a valid value.";
else
{
if (!this.Customer.IsValid)
{
List<string> customerErrors = this.Customer.GetValidationErrors();
customerErrors.ForEach(ce => errorMessage += "\n" + ce);
}
}
return errorMessage;
}
private string ValidateProducts()
{
string errorMessage = string.Empty;
if (this.Products == null || this.Products.Count <= 0)
errorMessage = "Invalid Order. Missing Products.";
else
{
foreach (Product product in this.Products)
{
if (product.Category != Customer.Category)
{
errorMessage += string.Format("\nThe Product, {0}, category does not match the required Customer category for {1}", product.Description, Customer.Name);
}
}
}
return errorMessage;
}
#endregion
}
Any reason you wouldn't want the constructor to noisily throw an exception if the information is valid? It's best to avoid ever creating an object in an invalid state, in my experience.
It's completely depends on the client. There's a trade-off as you already mentioned. By default approach number 1 is my favorite. Creating smart classes with good encapsulation and hiding details from client. The level of smartness depends who is going to use the object. If client is business aware you can reveal details according to the level of this awareness. This is a dichotomy and should not be treated as black or white.
Well if I correctly understood, there are basically two question - whether you should fail right away or later and whether you should omit/assume certain information.
1) I always prefer failing as soon as possible - good example is failing at compile time vs failing at run time - you always want to fail at compile time. So if something is wrong with the state of some object, as Jon said - throw exception right away as loudly as you can and deal with it - do not introduce additional complexity down the road as you'll be heading for if/elseif/elseif/elseif/else mumbo jumbo.
2) When it comes to user input, if you are in position to simply filter out errors automatically - just do it. For example, I almost never ask users for country - if I really need it, I automatically detect it from IP and display it in the form. It's way easier if user just needs to confirm/change the data - and I don't need to deal with null situation.
Now, in case we are talking about the data generated by code during some processing - for me situation is drastically different - I always want to know an much as possible (for easier debugging down the road) and ideally you never should destroy any piece of information.
To wrap up, in your case I would recommend that you keep IsValid as simple yes/no (not yes/no/maybe/kindaok/etc). If you can fix some problems automatically - do it, but consider that they keep object in IsValid yes. For everything else, you throw exception and go to IsValid=no.