hi i would like to return the group data back to the ui layer.
here is how i want to do a simplify the groupby "GenerationDate" and return the data in List<> back to UI gridview.
i find it very troublesome as i got to do the forloop. Also in the UI layer i got to do another forloop for this simple groupby. Could you help to simplify it?
public List<SalaryTracker> GetSalaryTrackerOrderByGenerationDate(int tutorId)
{
List<SalaryTracker> salary = new List<SalaryTracker>();
using (leDataContext db = new leDataContext())
{
try
{
var r =
from s in db.SalaryTrackers
where s.StaffId == 2 && s.PaymentDate == null
group s by s.GenerationDate into g
where g.Count() > 0
select new
{
date = g.Key, totalSalary = g.Sum(p => p.SalaryAmount)
};
foreach (var rr in r)
{
SalaryTracker m = new SalaryTracker();
m.GenerationDate = rr.date;
m.SalaryAmount = rr.totalSalary;
salary.Add(m);
}
return salary;
}
catch (Exception ex)
{
Logger.Error(typeof(SalaryTracker), ex.ToString());
throw;
}
}
}
--------------- GUI
totalCommissionsGroup = salary.GetSalaryTrackerOrderByGenerationDate(tutor.Id);
IList<SalaryTracker> rr = (
totalCommissionsGroup.GroupBy(x => x.GenerationDate)
.Select(g => new SalaryTracker
{
MonthId = g.Key.Month,
MonthToPay = common.GetMonthName(Convert.ToInt16(g.Key), true),
SalaryAmount = g.Sum(x => x.SalaryAmount)
})).ToList<SalaryTracker>();
gvSalaryPayment.DataSource = rr;
i do this so that i can get the MonthToPay in string
public List<SalaryTracker> GetSalaryTrackerOrderByGenerationDate(int tutorId)
{
using (var db = new leDataContext())
{
try
{
return (
from s in db.SalaryTrackers
where s.StaffId == 2 && s.PaymentDate == null
group s by s.GenerationDate into g
select new
{
MonthId = g.Key.Month,
// I don't know what "common" is in your UI code,
// I am just using GetMonthName here
MonthToPay = GetMonthName(Convert.ToInt16(g.Key), true),
SalaryAmount = g.Sum(p => p.SalaryAmount)
})
.AsEnumerable()
.Select(x => new SalaryTracker
{
MonthId = x.MonthId,
MonthToPay = x.MonthToPay,
SalaryAmount = x.SalaryAmount
})
.ToList();
}
catch (Exception ex)
{
Logger.Error(typeof(SalaryTracker), ex.ToString());
throw;
}
}
}
I agree with the refactoring of Mahesh Velaga (+1 for that) and I like to add that logging errors at that level of the application is unusual. Especially when you decide to rethrow the exception any way. Therefore, I suggest that you remove the complete try catch with error logging and log only in the root of your application (if you're not already doing that). That makes your code much more cleaner.
When you've done that, you'll see that what's left is a nice readable method with hardly anything else than business logic.
UPDATE
But if we do not put the 'try catch'
in the datamodel layer, how would the
main caller catch the error? i have
been using this pattern for years..
please correct me if i am wrong. Refer
to this link.
Catching the way you do in your question or is done as is shown in the referenced article you provide is almost always sub optimal, because of several reasons:
Catching, logging and rethrowing at the service layer is unfortunate, because you will end up with double entries of this error in your logging system, simply, because you need to log at the top layer of your application anyway, because otherwise you will miss logging errors that do not originate from the service layer. Ignoring the error (by not rethrowing it) is also a bad idea, because the client should hardly ever continue when an error occurs.
Catching at the presentation layer as shown in the referenced article is also unfortunate, because this way you don't log the errors, but more importantly, you present the user with possibly technical and obscure error messages (perhaps even in a foreign language) that they don't understand and it will frustrate them. Even worse, it could lead to information leakage that allows hackers to see what going on under the surface when attacking your application (in case of a publicly exposed web application).
This doesn't mean that you can't display any error information to the users, but only do that for exceptions that you thrown explicitly to present error information for the users. For instance:
try
{
// Call into service layer
}
catch (BusinessLayerException ex)
{
this.ValidationSummary1.Add(new CustomValidator
{
ErrorMessage = ex.Message, IsValid = false
});
}
In this example, the BusinessLayerException is a special exception that is thrown from the business layer that contains error messages that are understandable for the user (possibly with a localized error message if your application is used by users of multiple languages).
For all other exceptions, most of the time you don't want to show the user that exact error message, because you have no idea what went wrong and how severe the error is and what information the exception contains. The best thing to do is to have as less error handling logic as possible in your presentation layer, and handle this at one place in the top layer of the application. Here you ensure that an error page is displayed to the user in that case and you ensure that the error is logged to the logging system.
You can configure ASP.NET to show a custom error page in case of an error. Here's an example:
<customErrors mode="RemoteOnly"
defaultRedirect="~/ErrorPage.htm">
</customErrors>
The ErrorPage.htm can display general information like the general "it's our fault" error page here at Stackoverflow. Perhaps some contact information of support, your home phone number, so they can call you at night ;-)
By implementing the Application_Error method in the global.asax, you can at a single place in the application log unhandled exceptions:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
// Log the exception here.
}
Make sure you log al the information about the error you need, such as stack trace, error message, exception type, and all the inner exceptions that can occur.
I hope this helps.
Related
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.
Is there a way to check if exception is handled on a higher application level to skip logging and re-throw? Like this, for example:
try
{
// Execute some code
}
catch (Exception e)
{
if(!ExceptionIsHandled())
LogError(e);
throw e;
}
Nothing that I'm aware of. If you're committed to this design (see note at end), you could write a wrapper for an Exception that's some sort of HandledException and just make its InnerException be the one that was thrown. Then you could make your code look like:
try
{
// Execute some code
}
catch (HandledException e)
{
LogError(e.InnerException);
// Do something else
}
catch (Exception e)
{
throw ;
}
Here comes the stereotypical Stackoverflow "you're doin it wrong" part of the answer...
However, if you've truly "handled" the exception, it doesn't make a lot of sense to be re-throwing it. Maybe your method should just return a failure result, possibly including the Exception as a detail item for what went wrong.
This is old, but I do have some input here. There is a design pattern I've used before that does this very well, but does add a little bit of overhead to everything.
Basically, all methods would return a response object (e.g., Response<T>). Any exceptions that occur should be wrapped in the response object and returned instead of thrown.
public class Response<T>
{
public T Payload { get; set; }
public bool IsSuccessful { get; set; } = false;
public string Message { get; set; }
public Exception Error { get; set; }
}
public class MyService
{
public Response<IEnumerable<Customer>> GetCustomers()
{
var response = new Response<IEnumerable<Customer>>();
try
{
var customers = new List<Customer>()
{
new Customer() { CompanyName = "ABC Co." },
new Customer() { CompanyName = "ACME" }
};
response.Payload = customers;
response.IsSuccessful = true;
}
catch (Exception e)
{
response.IsSuccessful = false;
response.Error = e;
// A friendly message, safe to show to users.
response.Message = "An error occurred while attempting to retrieve customers.";
}
return response;
}
}
You can bubble up the exception without rethrowing it, and handle appropriately. You can then add exception catches for more custom user-friendly messages.
I also use a custom base Exception type for any errors that are safe to show the client. This way I can add a generic catch at the controller level to propagate those prepared error messages.
Well no, hasn't got there yet has it. Exceptions bubble up through handlers.
Usual way to go about this.
Is define your own exceptions, then only catch the ones you are going to handle where you are.
If you could be certain that code was wrapped within a specially-designed try-catch block which was written in a language that supports exception filters, it would be possible to determine before or during stack unwinding whether the exception was likely to be caught by that outer block or by an inner one. The usefulness of this is rather limited, however, especially given the extremely common anti-pattern of code catching and rethrowing exceptions that it knows it's not going to resolve, simply for the purpose of finding out that they occurred.
If your goal is simply to avoid redundant logging, I'd suggest that you should use a logging facility which can deal efficiently with redundancy. While some people might argue that it's better to have exceptions logged just once at the outer layers, there are advantages to having more logging opportunities. If an exception occurs within the inner layer and a middle layer swallows it, logging code within the outer layer will never find out about it. By contrast, if the inner layer starts out by capturing the exception and arranging for it to get logged, then even if the middle layer swallows the exception the fact that it occurred could still get recorded.
I have an MVC EF5 setup, with classes:
Program - this is the controller
UserInterface - this is the view, responsible for displaying and prompting for data.
DataAccess - Model, this Creates, Reads, Updates, and Deletes data in my EF model classes
When the DataAccess class tries to do a CRUD operation on my database, if it catches an error, it needs to be handled, my UserInterface class needs to print messages to the user, reporting any errors if neccessary. So, when an error happens, it needs to go through the program class first, then to the UserInterface class, because data layer shouldn't directly communicate to the presentation layer.
It was suggested to me that I don't pass or return the exception to a calling function, but that I should "throw a new simpler exception to the layers above". All this talk about exceptions is confusing to me because My experience with exceptions is limited to this format:
try
{
// stuff
}
catch (exception ex)
{
console.writeline(ex.ToString());
}
I've done some of my own research to try and find the answer to this problem, and I've learned a few things but don't know how to put it all together:
I learned:
throw; rethrows an exception and preserves the stack trace
throw ex throws an existing exception, such as one caught in a catch block. and resets the stack trace.
There is a property called Exception.StackTrace. I understand that each time an exception is thrown, the frames in the call stack are recorded to the Exception.StackTrace property.
However, I don't know where to place my try/catch blocks to utilize rethrowing
Is it something like the following code? Or am I missing the point on how this works?
EDITED: (added a little more to make sense of this guesswork to others)
void MethodA()
{
try
{
MethodB();
}
catch (MyExceptionType ex)
{
// Do stuff appropriate for MyExceptionType
throw;
}
}
void MethodB()
{
try
{
MethodC();
}
catch (AnotherExceptionType ex)
{
// Do stuff appropriate for AnotherExceptionType
throw;
}
}
void MethodC()
{
try
{
// Do Stuff
}
catch (YetAnotherExceptionType ex)
{
// Do stuff appropriate for YetAnotherExceptionType
throw;
}
}
There is more than how you use different type of exception handling. Functionally you should define what layers has to do what with a exception.
Like data layer => dont throw anything other than DataException or SQLException. Log them and throw back a generic database exception back to UI.
Business layer => log and rethrow simple bussiness exception
UI layer => catch only business exception and alert it in a message inside business exception
Once all this is defined, you can use what you have learned and summarized in question to build this.
What (I think) was suggested you do by throw a new simpler exception is that you translate the exceptions from the lower layers into new, higher level exceptions for consuming in the outer layers. The lower level exceptions are not suitable for consumption at the upper levels of the program.
For example, in LINQ to Entities, the method Single() will throw an InvalidOperationException when the sequence has no elements. However, this exception type is very common, so catching it in the user interface levels is hard to do: how would you differentiate between different possibilities of this exception being thrown (for example, modifying a read-only collection)? The solution is to translate the exception into another (new, user-defined) type that the application can easily handle.
Here is a simple example of the idea:
public class MyUserService {
public User GetById(int id) {
try {
using(var ctx = new ModelContainer()) {
return ctx.Where(u => u.Id == id).Single();
}
}
catch(InvalidOperationException) {
// OOPs, there is no user with the given id!
throw new UserNotFoundException(id);
}
}
}
Then the Program layer can catch the UserNotFoundException and know instantly what happened, and thus find the best way to explain the error to the user.
The details will depend on the exact structure of your program, but something like this would work in an ASP.NET MVC app:
public class MyUserController : Controller {
private MyUserService Service = new MyUserService();
public ActionResult Details(int id) {
User user;
try {
user = Service.GetById(id);
}
catch(UserNotFoundException) {
// Oops, there is no such user. Return a 404 error
// Note that we do not care about the InvalidOperationException
// that was thrown inside GetById
return HttpNotFound("The user does not exist!");
}
// If we reach here we have a valid user
return View(user);
}
}
I have a process that is parsing an XML file.
This is occuring in the PAckage Class.
The Package class has a Delegate that sets the object to an invalid state and captures the detailed info on error that occured the Package Class
For simplicity I am showing the filitem being passed to the package..
i.e `
foreach( var package in Packages)
{
try
{
package.ProcessXml(fileitem.nextfile);
}
catch (CustomeErrorException ex)
{
Logger.LogError(ex)
}
}
Inside The Package my validations look something like this
var Album = xml.Descendants()
.Select(albumShards => new Album {
Label = (string)albumShards.Descendants(TempAlbum.LabelLoc).FirstOrDefault() == "" ?
FailPackage("Error on label Load",Componets.Package,SubComp.BuildAlbum ) : (string)albumShards.Descendants(TempAlbum.LabelLoc).FirstOrDefault()
On this validation I check to see if "" is returned for label... if so Call Failpackage with error info and create exception
protected override void FailPackage(string msg, LogItem logItem)
{
Valid = ProcessState.Bad;
Logger.LogError(msg,logItem);
throw CustomErrorException(msg, Logitem);
}
that is captured via the containing try catch block
My concern is that I am using Exceptions for Program flow ... how else should I look at approaching this problem or is this a valid Pattern.
ProcessXml fails to do what its name implies in certain cases; these are error cases. Exceptions are for error handling, despite what the name implies.
One of the biggest misconceptions about exceptions is that they are
for “exceptional conditions.” The reality is that they are for
communicating error conditions.
Krzysztof Cwalina, Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
In other words, you're in the right. :)
Read the chapter on exceptions in the above book for some excellent guidelines.
You can put the error along with the ProcessState:
foreach( var package in Packages)
{
package.ProcessXml(fileitem.nextfile);
if(!package.Valid)
Logger.LogError(package.Error)
}
var albumShards = xml.Descendants().FirstOrDefault();
if((string)albumShards.Descendants(TempAlbum.LabelLoc).FirstOrDefault() == "")
return FailPackage("Error on label Load",Componets.Package,SubComp.BuildAlbum );
album = (string)albumShards.Descendants(TempAlbum.LabelLoc);
protected override void FailPackage(string msg, LogItem logItem)
{
Valid = ProcessState.Bad;
Logger.LogError(msg,logItem);
Error = msg;
}
i have this application structure:
1. Presentation Layer which calls
2. Business Logic Layer which in turn calls
3. Data Access Layer to do the dealing with the database.
Now i have a Contacts page from where i can add a new contact to the database.
So to add a New Contact i fill in all the required details and then call a Add Method (residing in the BLL) from the page, which in turn call a Add Method residing in the DAL.
this method in the DAL returns the Current Identity of the record which is then return back to the BLL method and finally delivered on the page.
this is fine. but what if a get an exception how do i handle it properly because the method in DAL has a return type of int and i dont want to throw another error!! coz other wise i will have to write try catch in almost all the methods.
//something like this
public int AddMethod(ContactClass contactObj)
{
int result = 0;
try
{
result = ExecuteSomeSP("SPName", SP_Parameters);
}
catch(SQLException se)
{
throw new SQLException
}
return result;
}
rather i want to show the user a user-friendly message which they can easily understand and in the mean while i will send a mail to myself documenting the Error that just occurred.
Also kindly tell me how can i implement my custom exception classes.
Please tell me how do i do this!!
thank you.
You shouldn't need a try/catch in every method. But you usually need a try/catch in every Layer (for a certain action).
And that is proper, each layer has to deal with its own broken contracts, cleanup etc.
The conversion from Exception to "friendly message" is something for the GUI, not a lower layer.
And when you catch and re-throw an exception, make sure you don't loose information, forward it in the InnerException property:
try
{
// DAL
}
catch (DALException de)
{
// Log, ....
throw new BLLException(message, de);
}
Do not try catch in every method or layer, only were it is reasonable. A try catch should never act like a conditional. The presentation layer should never have logic in it.
Since your using a DAL interface I would create a custom DalException and throw that over the SQLException
public int addMethod(ContactClass contactObj) throws DalException {
try {
return ExecuteSomeSP("SPName", SP_Parameters);
}
catch(SQLException e) {
throw new DalException(e);
}
}
In your business logic layer catch the exception and produce the popup using the presentation layer
public void addMethod(ContactClass contactObj) {
try {
dal.addMethod(contactObj);
}
catch(DalException e) {
// notify user
view.alert(e.getMessage());
}
}