Best way to control unicity of an attribute using EF Code First - c#

I've got a class User which has an attribute Name that must be unique.
So far I've investigated 3 ways of checking this:
Annotations
[StringLength(100)]
[Index(IsUnique = true)]
public string Name { get; set; }
Problem is, by trying to insert a user with a repeated name it throws this ex:
as you can see, I would have to navigate into the inner exceptions (which I don´t know if it is possible, but I assume it is) and the last inner exception´s message is not user friendly at all.
Fluent Api
https://stackoverflow.com/a/23155759/5750078
I haven´t tried it but I believe it is has the same problem that Annotations.
Check by hand
controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Name,Password,Profile")] User user)
{
if (ModelState.IsValid)
{
lock (locker)
{
validateNameUnicity();
db.Users.Add(user);
db.SaveChanges();
}
return RedirectToAction("Index");
}
return View(user);
}
Problem: the check depends on my code, which may not be as accurate as date base checkings. Besides I will need to program more logic than the other two options. And last but no least if somehow I access the database directly there will be no checks at all.
I need to know which is the best practice to do this, because I'm trying to learn on my own, and I would like to do things as best as possible.

You should actually do both, a check in code and a uniqueness index as a final guard when concurrent users manage to insert identical records after all. (Because of the latency between the check and the actual insert).
This means that you always have to catch exceptions when you call SaveChanges, but that's not a bad idea anyway.
For the uniqueness check you could use the mechanism I described here, just change email into Name and you're good to go.
You could dig up the last exception message from a chain of inner exceptions by this extension method:
public static string GetDeepestExceptionMessage(this Exception exception)
{
string msg = string.Empty;
while (exception != null)
{
msg = exception.Message;
exception = exception.InnerException;
}
return msg;
}

Related

When to Throw an Exception? When to Handle an Exception (Service Layer, Controller) where?

I rewritten my question as I think it was too wordy and maybe what I am trying to achieve was lost.
I written this code in notepad so it may have mistakes and some stuff maybe not well thoughout but it is to illustrate what I see my options are.
// I wrap all code send back from service layer to controller in this class.
public class ResponseResult
{
public ResponseResult()
{
Errors = new Dictionary<string, string>();
Status = new ResponseBase();
}
public void AddError(string key, string errorMessage)
{
if (!Errors.ContainsKey(key))
{
Errors.Add(key, errorMessage);
}
}
public bool IsValid()
{
if (Errors.Count > 0)
{
return false;
}
return true;
}
public Dictionary<string, string> Errors { get; private set; }
public ResponseBase Status { get; set; }
}
public class ResponseResult<T> : ResponseResult
{
public T Response { get; set; }
}
public class ResponseBase
{
public HttpStatusCode Code { get; set; }
public string Message { get; set; }
}
Option 1 (what I am using now)
//controller
public HttpResponseMessage GetVenue(int venueId)
{
if (venueId == 0)
{
ModelState.AddModelError("badVenueId", "venue id must be greater than 0");
if (ModelState.IsValid)
{
var venue = venueService.FindVenue(venueId);
return Request.CreateResponse<ResponseResult<Venue>>(venue.Status.Code, venue);
}
// a wrapper that I made to extract the model state and try to make all my request have same layout.
var responseResult = new ResponseResultWrapper();
responseResult.Status.Code = HttpStatusCode.BadRequest;
responseResult.Status.Message = GenericErrors.InvalidRequest;
responseResult.ModelStateToResponseResult(ModelState);
return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
}
// service layer
public ResponseResult<Venue> FindVenue(int venueId)
{
ResponseResult<Venue> responseResult = new ResponseResult<Venue>();
try
{
// I know this check was done in the controller but pretend this is some more advanced business logic validation.
if(venueId == 0)
{
// this is like Model State Error in MVC and mostly likely would with some sort of field.
responseResult.Errors.Add("badVenueId", "venue id must be greater than 0");
responseResult.Status.Code = HttpStatusCode.BadRequest;
}
var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();
if(venue == null)
{
var foundVenue = thirdPartyService.GetVenue(venueId);
if(foundVenue == null)
{
responseResult.Status.Code = HttpStatusCode.NotFound;
responseResult.Status.Message = "Oops could not find Venue";
return responseResult;
}
else
{
var city = cityService.FindCity(foundVenue.CityName);
if(city == null)
{
city = cityService.CreateCity(foundVenue.CityName);
if(city.Response == null)
{
responseResult.Status.Code = city.Status.Code;
responseResult.Status.Message = city.Status.Message;
return responseResult;
}
CreateVenue(VenueId, city.Response, foundVenue.Name);
responseResult.Status.Code = HttpStatusCode.Ok;
// I don't think I would return a success message here as the venue being displayed back to the user should be good enough.
responseResult.Status.Message = "";
reponseResult.Response = foundVenue;
}
}
return responseResult;
}
}
catch (SqlException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
// maybe roll back statement here depending on the method and what it is doing.
}
// should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
catch (InvalidOperationException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
}
// should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
}
return responseResult;
}
// another service layer.
// it is ResponseResult<City> and not city because I could have a controller method that directly calls this method.
// but I also have a case where my other method in another service needs this as well.
public ResponseResult<City> CreateCity(string CityName)
{
ResponseResult<City> responseResult = new ResponseResult<City>();
try
{
City newCity = new City { Name = "N" };
context.Cities.Add(newCity);
context.SaveChanges();
responseResult.Status.Code = HttpStatusCode.Ok;
responseResult.Status.Message = "City was succesfully added";
}
// same catch statmens like above
catch (SqlException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
responseResult.Status.Code = HttpStatusCode.InternalServerError;
responseResult.Status.Message = GenericErrors.InternalError;
// maybe roll back statement here depending on the method and what it is doing.
}
return responseResult;
}
As you can see the methods are all wrapped in the status codes as they could be directly called by the controller being public. FindCity() and CreateVenue() could also have this wrapping.
Option 2
public HttpResponseMessage GetVenue(int venueId)
{
try
{
if (venueId == 0)
{
ModelState.AddModelError("badVenueId", "venue id must be greater than 0");
if (ModelState.IsValid)
{
var venue = venueService.FindVenue(venueId);
return Request.CreateResponse<ResponseResult<Venue>>(HttpSatusCode.Ok, venue);
}
// a wrapper that I made to extract the model state and try to make all my request have same layout.
var responseResult = new ResponseResultWrapper();
responseResult.Status.Code = HttpStatusCode.BadRequest;
responseResult.Status.Message = GenericErrors.InvalidRequest;
responseResult.ModelStateToResponseResult(ModelState);
return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
}
catchcatch (SqlException ex)
{
// can't remember how write this and too tried to look up.
return Request.CreateResponse(HttpStatusCode.InternalServerError;, "something here");
}
}
public Venue FindVenue(int venueId)
{
try
{
// how to pass back business logic error now without my wrapper?
if(venueId == 0)
{
// what here?
}
var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();
if(venue == null)
{
var foundVenue = thirdPartyService.GetVenue(venueId);
if(foundVenue == null)
{
// what here?
}
else
{
var city = cityService.FindCity(foundVenue.CityName);
if(city == null)
{
city = cityService.CreateCity(foundVenue.CityName);
if(city == null)
{
// what here?
}
CreateVenue(VenueId, city.Response, foundVenue.Name);
}
}
return venue;
}
}
catch (SqlException ex)
{
// should there be a try catch here now?
// I am guessing I am going to need to have this here if I need to do a rollback and can't do it in the controller
// throw exception here. Maybe this won't exist if no rollback is needed.
}
return null;
}
public City CreateCity(string CityName)
{
// if it crashes something I guess will catch it. Don't think I need to rollback here as only one statement being sent to database.
City newCity = new City { Name = "N" };
context.Cities.Add(newCity);
context.SaveChanges();
return newCity;
}
As you see with option 2, I might still need to wrap it in try catches for rollbacks and I am not sure how to handle advanced business validation.
Also with catching everything in the controller and sending back vanilla objects(without my wrapper) I am unsure how to do fine grain HttpStatus codes(say like notFound,Create and such)
Sorry for the brief response, but here is my general rule - if an exception occurs which you expect might happen, deal with it - either by retrying or telling the user something went wrong and giving them options to fix it.
If an unexpected exception occurs, if it's something you can deal with (e.g a timeout which you can retry) try to deal with it, otherwise get out - just think what any MS app does - e.g. office - you get an apology that something went wrong and the app ends. It's better to end gracefully than to potentially corrupt data and leave things in a real mess.
This is an article with Java-specific concepts and examples, but the broad principles here are the way to go.
Distinguish between fault exceptions, which are catastrophic and unrecoverable, and contingency exceptions, which are very much recoverable. Let the faults "bubble" to the fault barrier, where you handle appropriately. For example, you might log the error, E-mail someone or send a message to a message queue, and present the user with a nice, informative error page.
Whatever you do, be sure to preserve all the exception information from the source.
Hope that helps.
Throw an exception wherever your code determines that something has gone wrong.
You always need to handle exceptions in methods which are called directly by the end-user. This is to cater for unexpected errors which your code doesn't have specific handling for. Your generic handling code would typically log the error and may or may not include letting the user know that an unexpected error has occurred.
But if there are errors which you can expect ahead of time, you'll often want to handle these lower down in the code, nearer to the point at which they occur, so that your application can "recover" from the error and continue.
I think exceptions are useful any time you need to return details of a failure from a method, whilst being able to use the ideal return type for the method you're calling.
You said in your question:
Now for me I try to return error messages back to the the controller
and try not to really catch anything in the controller.
If the service method is supposed to ideally return a Venue object, how do you return this potential error message back to the controller? an out parameter? change the return type to something which has an error message property on it?
If you're doing either of those options, I think you're reinventing the wheel... i.e. creating a way to return exception information when one already exists.
Finally, Exceptions are strongly typed representations of what went wrong. If you return an error message, then that is fine to send back to the user, but if you need to programatically do different things based on the details of the error, then you don't want to be switching on magic string.
For example, wouldn't it be handy to differentiate between authorization errors and not found errors so you can return the most appropriate http status code to the user?
Don't forget that the Exception class has a Message property you can simply return to the user if you want to use it that way
To make sure I understand the question, your are creating a web service and want to know when to handle and when to throw exceptions.
In this situation I would strongly recommend that you catch all exceptions. "Unhandled" exceptions are very bad form. On web sites they result in displays that range from meaningless to dangerous by exposing internal information that you do no want the public to see.
If this is a good sized program I suggest that you create your own MyException class which derives from System.Exception. The purpose of this is provide a place for you to add additional information specific to your application. Here are some typical things I like to add to my MyException classes:
An ID number that will help me find the location in the code where the problem occurred.
A "LogMessage" method that logs the exception, sometimes to the Windows Event Log. Whether or not you log and to which log you write depends on what you want recorded, and the severity of the situation.
An indicator that shows the exception has been logged so the above method will not log twice even if it gets called more than once.
Anything else that might be useful given the circumstance.
I also like to put the text of the messages in an external resource file, like an XML document, and key them to the error number that you assign. This allows you to change the error text to improve clarity without having to redeploy the application.
Catch all exceptions and create a new instance of your MyException type and put the original exception into inner exception property. Below the first level of my application, I always throw one of my MyException instances rather than the original exception.
At the top level (application level), NEVER let an exception go unhandled and never throw your own exception. A better way is to return an error code and message in your data contract. That way the client application will only get what you want them to see. The only exceptions they'll need to worry about are the ones outside your scope, i.e. configuration errors or communication failures. In other words if they are able to invoke your service and the network stays connected you should give them a response they can interpret.
Hope this helps.
PS I didn't include a sample exception as I am sure a little searching will find many. Post if you want me to put up a simple sample.
Use try catch at all levels and bubble it up. Optionally, log the error in a file or database. I use text file - tab delimited. Capture at each level
1. Module Name (Use C# supplied methods to get this)
2. Method Name
3. Code Being Executed (User created - "Connecting to database")
4. Error Number
5. Error Description
6. Code Being Executed (User created - "Accessing database")
7. Error Number for the end user
8. Error Description for the end user
Additionally, I also pass a unique identifier like - Session Id in case of Web, Logged in User Id, User Name (if available)
I always have the Exception catch block. In here I set the error number as -0 and the message from the exception object as the error description. If it is SQL Server related - I capture SQL Exception. This generates an error number - I use that.
I want to extend this some more though.

Error from class

I'm a IT student, second year. We just learned to program with 3 layers, one for getting data with a class, one for manipulating stuff with requests (all of the methods go in here) and one for the working of the program itself. Seeing as the first two go into classes instead of a form I dont know how to show errors.
Example:
We need to make a login system with a webbrowser and some other stuff behind it. So I make the login in a class, but how to check back for errors? I don't think it's normal or even possible to do MessageBox.Show(error); from a class, I can only return stuff, but I want the username/id to be returned if possible.
So in short, what is the best/most accepted way to report errors that are caused by data, so from a class?
Your framework level API's (eg. your layers) should use Exceptions for real errors, and return values to report non-critical errors.
public class Login
{
public bool AccountExists(string name) {
bool exists;
// do checking
return exists;
}
public LoginResult Login(string name, string password) {
// Try login
// If successful
return LoginResult.Success;
// What if the user does not exist?
return LoginResult.AccountNotFound;
// What about an error?
return LoginResult.Error;
}
}
public enum LoginResult
{
None,
AccountNotFound,
Error,
Success
}
In the example above, you can report the status of operations through return values. For LoginResult this could even be a value type (struct) that contains more information about the result (eg. a string message or something). Because these types of operations on non-critical, there is no necessity for exceptions here. Exceptions are costly and not always necessary to report errors.
Now let's talk about a different type of error. Logical developer errors. These should be handled by throwing exceptions. Take this example (assume we have some type Account that has a Role property).
public class Foo
{
public bool IsAdmin(Account account) {
if (account == null) {
throw new System.ArgumentNullException("You cannot pass a null account!");
}
return account.Role == "Admin";
}
}
We know as a developer that the account should not be null, so we should check for it and throw an exception if it is. If this exception is ever thrown, its a bug in the calling code and should be fixed not to pass in a null value.
Now that I've given two rough scenarios, how does this apply to your question? These are API's. Whatever your UI layer is, whether it be a WinForm, WPF Window, WebForm, or some other UI, the UI only has to use the API. The API is responsible for reporting information that can be usable by the UI, and the UI is responsible for displaying info in whatever way is best suited for that UI.
The framework API layers should never be responsible for reporting an error to the user with a UI. They should only be responsible for reporting errors to the developer who can take the result, and wire it up to the UI layer in some fashion. You would never display a message box or write to a console from a framework API for example. You would return some result that the UI can use to display its own message.
I highly recommend that you read Framework Design Guidelines. It covers a lot of this material and is an extremely great read.
You should have a class which validates the data object and returns error information. Then your front-end code can ask this class to validate the data and show any error messages that get returned.
var username = GetUserName();
var password = GetPassword();
var validationResult = new Validator().ValidateLogin(username, password);
if(validationResult.ErrorMessage != null) {
MessageBox.Show(validationResult.ErrorMessage);
} else {
// Do what you would have done.
}
If any errors occur that are outside of the expected logic flow, they should throw an exception.
Well you can use Exceptions. You Just throw the exception, it is up to the caller on what to do with the exception.
class Login
{
public Login()
{
}
public bool CheckLogin(string userName, string password)
{
// Do your validation here.
If every thing goes fine
return True.
else
throw Exception("custom message.");
}
}
class Input //class which takes input.
{
Login login = new Login();
public void TakeInput(string username, string password)
{
try
{
login.CheckLogin(username, password);
}
catch(Exception ex)
{
MessageBox.show(ex.message);
}
}
}

Deleting a chlid object from a collection with MVC3 Entity Framework 4.3 Code First

I have found numerous posts with very similar problems as mine, but they all seem to use a DeleteObject() method that doesnt appear to exist in the version of EF i am using! (although its more than likely i am looking in the wrong places)
Anyway, my problem. I have two classes, User and Email where a user can have many emails. I have an edit form that will quite happily allow me to edit all email addresses attached to each user. I would like to allow each email address to be deleted simply by clearing the text box in the edit form (to be done using JavaScript function triggered by a remove button associated with each box later on). To this end, when the data is posted back, I loop through all the email addresses and test if the address property is null, at which point i want to delete that Email object completely. Below is my edit controller that is (not) doing the business:
[HttpPost]
public ActionResult Edit(int id, User User)
{
try
{
foreach (Email Email in User.Emails)
{
if (Email.Address == null)
{
User.Emails.Remove(Email);
}
else
{
db.Entry(Email).State = EntityState.Modified;
}
}
db.Entry(User).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return RedirectToAction("Index");
}
}
This works to a point, using the debugger i can see that it is quite happily removing the Email object from the User, but as soon as it has done that once it will throw an exception when it tries to go through the loop again:
Message=Collection was modified; enumeration operation may not execute.
my question: what is the correct method of deleting the Email object, not only from the User, but from my db too?
Thanks in advance ;-)
EDIT:
I have modified my controller to create two lists, one for Emails with and address and one for those where the address is null, and loop through those instead:
[HttpPost]
public ActionResult Edit(int id, User User)
{
try
{
var notNullEmails = User.Emails.Where(e => e.Address != null).ToList();
foreach (Email Email in notNullEmails)
{
db.Entry(Email).State = EntityState.Modified;
}
var isNullEmails = User.Emails.Where(e => e.Address == null).ToList();
foreach (Email Email in isNullEmails)
{
db.Emails.Remove(Email);
}
db.Entry(User).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return RedirectToAction("Index");
}
}
But that resulted in this exception:
Message=The object cannot be deleted because it was not found in the ObjectStateManager.
So i adapted the foreach used for the null addresses to explicitly pull the email to be deleted into the context like so:
var isNullEmails = User.Emails.Where(e => e.Address == null).ToList();
foreach (Email Email in isNullEmails)
{
Email EmailToDelete = db.Emails.Find(Email.Id);
db.Emails.Remove(EmailToDelete);
}
But that results in this exception:
Message=Value cannot be null.
I think i am getting there thanks to you guys, but i could use a little more help please :-)
You have two different problems:
One is, you can't remove items from a collection as you iterate the collection. Iterate through a List copy uoi make with .ToList() instead.
The other is, calling the Remove() method you are calling is only removing the relationship to the User - not actually removing it from the database. This would generate a referential integrity error, if the db enforces it.
Instead, You want to call Remove on the Emails DbSet.
context.emails.Remove(email);
Remove() is the method used by the DbContext. DeleteObject and RemoveObject are older/alternative APIs
I know you said about not using DeleteObject, but I had the same problem and thought I should post the answer here for others searching about this issue:
int i = User.Emails.Count - 1;
while (true)
{
if (i<0)
{
break;
}
Db.Emails.DeleteObject(User.Emails.ElementAt<Email>(i));
i--;
}
I know this is really old, but i thought i should probably answer it with the method i have found to actually work:
foreach(Email email in User.Emails)
{
if(string.IsNullOrEmpty(email.Address))
{
db.Entry(email).State = System.Data.EntityState.Deleted;
}
}
db.SaveChanges();
I think this is the simplest of any solution that i have seen so far, but feel free to correct me if there is a better way.

Passing Errors (Exception Messages) from Repository to Controller Action in asp.net MVC2

I have been trying to develop an app using the repository pattern like in the Nerd Dinner application however I would like to handle exceptions in the repository and pass the exception messages back to the controller so that I can output the message in a nice page to the user.
How do I pass back this exception message, or even pass that an exception has occured in the repository.
http://www.asp.net/ajaxlibrary/jquery_errors.ashx
In the following example from the above url, "_repository.HasErrors" is used as a check but I want to know what the implementaion of this is in the repository in C# as I dont know how this is implemented and also if its possible to also get the error message as well.
01.// GET: /HandlejQueryErrors/Contact/Create
02.public ActionResult Create()
03.{
04. return View();
05.}
06.
07.// POST: /HandlejQueryErrors/Contact/Create
08.[HttpPost]
09.public ActionResult Create(ContactViewModel viewModel)
10.{
11. var response = new AjaxResponseViewModel();
12.
13. try
14. {
15. var contact = _repository.SaveOrUpdate(viewModel);
16. if (!_repository.HasErrors)
17. {
18. response.Success = true;
19. response.Message = "Your contact was successfully created!";
20. }
21. else
22. {
23. response.Message = "There was an error updating your contact!";
24. }
25. }
26. catch (Exception exception)
27. {
28. response.Success = false;
29. response.Messages exception.Message;
30. }
31.
32. return Json(response);
33.}
Thanks in advance.
You could allow your repository's exceptions to fall through, and override your controller's OnActionExecuted method to handle specific errors for you. Example:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception is RepositoryException)
{
filterContext.ExceptionHandled = true;
filterContext.Result = View("Exception", filterContext.Exception);
}
base.OnActionExecuted(filterContext);
}
So, in general in ASP.NET MVC you need to handle 2 kinds of errors: Validation errors, and System errors.
For System errors, those occurring because of some system rules violation (like foreign key constraint violation in database during insert), you should use try-catche operator and then pass them to the view in some way to show them to the user.
For validation errors, you should read about ASP.NET MVC Validation:
Validation with the Data Annotation Validators - here you can see how to validate simple validation rules using built-in annotation attributes.
Validating with a Service Layer - this is more advanced topic, where you can learn how to validate more complex validation rules (for example for inter-connected properties, etc.)
So, as a conclusion, think of separating the concerns about domain/business functionality from the concerns related to validation. The only common thing they should have (in the perfect scenario) is a view where you show the results of validation.
Personally I (taking 2-nd approach) even do a save in validation, so that Validation implementation knows about domain/business logic and manipulates it to validate all the rules. In the end of validation, if all rules were met, then it tries to save the data, and returns the validation error message in case of non-success. This is also a good start to go further and even localize your custom validation messages.
I hope this helps!
I personally still like the GetRuleViolations() approach started by ScottGu and would simply follow this through on the Repository.
In the controller I would do (pseudo here):
[HttpPost]
public ActionResult ControllerAction(MyViewModel viewModel)
{
ModelState.AddRuleViolations(viewModel.GetRuleViolations);
if (!ModelState.IsValid)
{
return View();
}
// Perform repository action (pseudo code to follow)
_repository.ClearErrorState();
_repository.DoSomething();
ModelState.AddRuleViolation(repository.GetRuleViolations());
if (!ModelState.IsValid)
{
return View();
}
return RedirectToAction("Foo","Bar");
}
class Repository
{
List<RuleViolation> _errors = new List<RuleViolation>();
public void ClearErrorState()
{
_errors.Clear();
}
public void DoSomething(...)
{
try
{
DoSomthingThatFails();
}
catch (Exception ex)
{
_errors.Add(new RuleViolation(null, "Error while saving customer");
_errors.Add(new RuleViolation("SSN", "SSN must be unique"); // This one I struggle with as bad design, tying UI element to data elements is bad, so generally I try to prevent everything when checking the viewmodel and only catch general (unforeseen) errors here.
}
}
public IEnumerable<RuleViolation> GetRuleViolations()
{
return _errors;
}
}

Error message vs. throwing exception C# ASP.Net

In many cases in web applications you would need to return an error message, rather than simple true/false result. One would use exceptions for that, but I consider exceptions to be an indication of, you know, exceptional behavior. Let's take a Register() function for a class User for instance. If it was successful we can simply return true, but if something went wrong we would like to know what exactly: "passwords don't match", "e-mail is in invalid format" and so on (could be an error code instead of a message, doesn't matter).
The question is what is the best practice for returning such error messages in C# and .Net? There might be a struct ready, something like:
public struct Result {
public bool OK;
public string Message;
}
Or perhaps I should just use a parameter in the function? Like Register(out string Message).
Update. This pretty much describes everything I need: http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx
If it's for validation purposes I would recommend you the excellent Fluent Validation library.
Quote from the site:
using FluentValidation;
public class CustomerValidator: AbstractValidator<Customer> {
public CustomerValidator() {
RuleFor(customer => customer.Surname).NotEmpty();
RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
RuleFor(customer => customer.Company).NotNull();
RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
RuleFor(customer => customer.Address).Length(20, 250);
RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
}
private bool BeAValidPostcode(string postcode) {
// custom postcode validating logic goes here
}
}
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);
bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;
I think exceptions can and should be used here.
You can put your Register() call in a try/catch block therefore preventing application execution stop. In the catch block you will analyze what exactly got wrong and return an appropriate message.
I think exception should be used when it comes to program mistakes and IO communication.
This means:
non-validated input
a bug in the software. (adding 2 equal keys to dictionaries)
disk access/network/cross application/ etc
For a Register method i should either use a boolean for result checking.
if(Register("someone", "password"))
{
// success
}
else
{
// failed
}
or if you like more details on the result, specify a result enum:
public enum RegisterResult
{
Success,
BadUsernamePassword,
PasswordTooShort
}
RegisterResult result = Register("someone", "password");
switch(result)
{
case(RegisterResult.Success):
// success
break;
case(RegisterResult.BadUsernamePassword):
// failed
break;
case(RegisterResult.PasswordTooShort):
// failed
break;
}
If you need more information like a userId, you should define it as a output parameter
int userId = 0;
RegisterResult result = Register("someone", "password", out userId);
etc...
So if an exception is thrown, this means 1 of 3 things.
Some of the input (by user) is not validated. ' (negligence of the programmer)
There is bug in it. (like accessing disposed objects or something serious. etc.)
There is an IO problem. (connecting lost from database.. etc)
I advice u to use exceptions only in exceptional situations. A bad login isn't an exception, it's a user fault.
Regards,
Jeroen
Throwing exceptions creates CPU utilization while adding all call stack and setting other fields of exception class.
I prefer not to throw Exceptions. If it is really casual error like say Argument is null,i would go for struct with an ExceptionMessage field with it.
But it is better to type-value check before calling a method and expecting primitive types to return from the method since you need a boolean value return to.

Categories

Resources