Is that a good practice to throw exception from controller?
For instance we may throw IllegalStateException from some controller's method if Request hasn't some attribute.
Also for instance we may throw IllegalArgumentException from some controller's method if Request's parameter is not in appropriate format/range.
No, I don't think so. Who will handle it? The client. What does handling it mean? Exceptions won't tell them what to do. Better to change the UI to instruct them on what do to next. You see this in every decent web UI that you use: the text box is highlighted and you're told what the proper range is. What kind of experience would seeing a stack trace be?
So the controller should catch all exceptions and change the display accordingly.
I don't think it is a good idea to throw such exception to end user. Instead you may alert end user a meaningful error message which use can easily understand what is wrong.
Related
Business validations are implemented by throwing CustomeException(key) such that user will be displayed error messages when something goes wrong.
I have to forward to input jsp (like struts) when business exception raised, to correct the user actions then continue with application.
we have custom HandlerExceptionResolverImpl to handle the all exceptions at once place. when exception raised then we don't know the input page.
How to do this in spring4 like struts ?
Please suggest the way how to accomplish this?
Thanks
Dhorrairaajj
base requirement is explained in this
I have solved this, all controllers should extends CustomeWebReq Class, which has getter method to get the input page like String getInputPage(String path). Controllers are responsible to return the input page based on the servlet path argument. getInputPage(string path) method will be invoked from HandlerExceptionMapping where exceptions are handling.
Thanks
Dhorrairaajj
We have a WebForms Control which requires that the ID of another Control implementing ITextControl is provided.
What exception should we throw if there is no control with that ID or a control is found but it's not implementing the interface?
var text = Page.FindControl(TextProviderId) as ITextControl;
if (text == null) {
throw new WhatEverException(...);
...
Should we split it into two cases and throw one exception if there is no control with that ID, and another one if said control does not implement ITextControl? If so, which exceptions should we use then?
If the control should really be there, I would say that your web form is in an invalid state if it is missing, so I would probably go for InvalidOperationException:
The exception that is thrown when a method call is invalid for the object's current state.
This would be applicable to both scenarios; regardless of whether the control is missing or if it does not implement the expected interface, the containing object is in an invalid state.
If this is a scenario that is expected to happen for various reasons (let's say that you are making some tool that others will program against, and this is a situation that they might very well produce), perhaps you should instead create two custom exceptions that make it very clear what is happening and how to correct it (such as ControlNotFoundException and InterfaceNotFoundException or something similar).
ArgumentOutOfRangeException?
Whether or not you should split them up into different exceptions probably depends most on whether or not you think it is likely that anyone will ever want to distinguish the two exceptions in different catch blocks.
Not knowing exactly how this will be used, this seems like the kind of error that should be brought to the developer's attention, where rewriting code to point to the correct file or implement the correct interface is the proper action, rather than implementing a try-catch and give the user friendly error messages. As such, I'd just throw an ArgumentException.
I have a common base class from which all my ASMX webservice classes will inherit. In the constructor, I want to do some common authentication checks; if they fail, I would like to halt processing right away (subclass's code would not get executed) and return a 401-status-code response to the caller.
However, the common ASPX-like ways of doing this don't seem to work:
Context.Response.End(); always kicks back a ThreadAborted exception to the caller, within a 500-status-code response. Even if I explicitly set Context.Response.StatusCode = 401 before calling End(), it is ignored. The result is still a 500-response, and the message is always "thread-aborted-exception".
MSDN suggests I use HttpContext.Current.ApplicationInstance.CompleteRequest() instead. However, this does not stop downstream processing: my subclass's functions are still executed as if the constructor had done nothing. (Kind of defeats the purpose of checking authorization in the constructor.)
I can throw a new HttpException. This is a little better in that it does prevent downstream processing, and at least it gives me control over the exception Message returned to the caller. However, it isn't perfect in that the response is still always a 500.
I can define a DoProcessing instance var, and set it to true/false within the constructor. Then have every single WebMethod in every single subclass wrap its functionality within an if (DoProcessing) block... but let's face it, that's hideous!
Is there a better / more thorough way to implement this sort of functionality, so it is common to all my ASMX classes?
edit: Accepting John's answer, as it is probably the best approach. However, due to client reluctance to adopt additional 3rd-party code, and some degree of FUD with AOP, we didn't take that approach. We ended up going with option #3 above, as it seemed to strike the best balance between speed-of-implementation and flexibility, and still fulfill the requirements.
The best way to do it would be to switch to WCF, which has explicit support for such a scenario.
If you must still use ASMX, then your best bet is to call the base class methods from each web method. You might want to use something like PostSharp to "magically" cause all of your web methods to call the base class method.
Context.Response.Write("My custom response message from constructor");
Context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
Context.Response.End();
That code prevent to pass in web method after constructor.
I am using methods with the Attribute [WebMethod] in my aspx pages. I don't use any asp.net ajax but jQuery to call these methods and return objects in JSON. This all works fine.
Next I added an authorization check inside the webMethod, if the current user doesn't have access to the feature I need to let the calling JavaScript know.
So I am throwing an AccessViolationException exception which can then be parsed by the OnError callback function in JavaScript. This works too but the exception includes the full StackTrace and I don't want to make this available to the calling client.
What other ways I could use to return an "Access Denied" to the client when the WebMethod returns a business object?
I'm using ASP.Net 3.5SP1 and jQuery 1.32
You can also add a:
customErrors mode="On"/
in your web.config, this will cut away the stack trace and leave you only the exception message
Why propagate errors through the wire? why not use an error response ?
Just wrap your object in a response object wich can contain an error code for status and an error message to present to users.
As suggested by NunFur I changed my approach and rather than throwing an error, I return a 'richer' object.
There are at least two options, the first one would be to encapsulate my business object into a response object with some status properties. I tried this but it makes the JSON more complicated.
So rather than adding a new object I added two properties to my business object, something like ServiceStatus and ServiceMessage. By default these are 200 and '', but can be set by the WebMethod code if anything goes wrong (no access, proper error). In this case they business object will be 'empty' (no data). The JavaScript code then first checks for the ServiceStatus and reacts appropriately.
I add the two fields to all my objects that are returned by WebMethods, even a simple string. They have to implement an Interface with those two properties.
Now I have complete control over that goes over the wire in case something unexpected is happening.
Thanks for the input
I save exceptions for when things go really wrong. (e.g. can't connect to the database)
Either return nothing (null/nill/whatever), or return a false bool value.
Sorry that I don't have a better answer than that...I'll have to keep looking myself.
You could look at SoapException: http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapexception(VS.71).aspx
I'm just not sure, if it will work when it is called from JavaScript. Espeially if it's called with a get-request.
BTW AccessViolationException is to my best knowlegde ment to be thrown when the application is accessing memory it has no access to.
/Asger
What is a good error handling practice for an asp.net site? Examples? Thanks!
As with any .net project I find the best way is to only catch specific error types if they are may to happen on the given page.
For example you could catch Format Exceptions for a users given input (just incase JavaScript validation fails and you have not use tryparse) but always leave the catching of the top level Exception to the global error handler.
try
{
//Code that could error here
}
catch (FormatException ex)
{
//Code to tell user of their error
//all other errors will be handled
//by the global error handler
}
You can use the open source elmah (Error Logging Modules and Handlers) for ASP.Net to do this top level/global error catching for you if you want.
Using elmah it can create a log of errors that is viewable though a simple to configure web interface. You can also filter different types of errors and have custom error pages of your own for different error types.
One practice that I find to be especially useful is to create a generic error page, and then set your defaultRedirect on the customErrors node of the web.config to that error page.
Then setup your global.asax for logging all unhandled exceptions and then put them (the unhandled exceptions) in a static property on some class (I have a class called ErrorUtil with a static LastError property). Your error page can then look at this property to determine what to display to the user.
More details here: http://www.codeproject.com/KB/aspnet/JcGlobalErrorHandling.aspx
Well, that's pretty wide open, which is completely cool. I'll refer you to a word .doc you can download from Dot Net Spider, which is actually the basis for my small company's code standard. The standard includes some very useful error handling tips.
One such example for exceptions (I don't recall if this is original to the document or if we added it to the doc):
Never do a “catch exception and do nothing.” If you hide an exception, you will never know if the exception happened. You should always try to avoid exceptions by checking all the error conditions programmatically.
Example of what not to do:
try
{
...
}
catch{}
Very naughty unless you have a good reason for it.
You should make sure that you can catch most of the errors that are generated by your application and display a friendly message to the users. But of course you cannot catch all the errors for that you can use web.config and defaultRedirect by another user. Another very handy tool to log the errors is ELMAH. ELMAH will log all the errors generated by your application and show it to you in a very readable way. Plugging ELMAH in your application is as simple as adding few lines of code in web.config file and attaching the assembly. You should definitely give ELMAH a try it will literally save you hours and hours of pain.
http://code.google.com/p/elmah/
Code defensively within each page for exceptions that you expect could happen and deal with them appropriately, so not to disrupt the user every time an exception occurs.
Log all exceptions, with a reference.
Provide a generic error page, for any unhandled exceptions, which provides a reference to use for support (support can identify details from logs). Don't display the actual exception, as most users will not understand it but is a potential security risk as it exposes information about your system (potentially passwords etc).
Don't catch all exceptions and do nothing with them (as in the above answer). There is almost never a good reason to do this, occasionally you may want to catch a specific exception and not do any deliberately but this should be used wisely.
It is not always a good idea to redirect the user to a standard error page. If a user is working on a form, they may not want to be redirected away from the form they are working on. I put all code that could cause an exception inside a try/catch block, and inside the catch block I spit out an alert message alerting the user that an error has occurred as well as log the exception in a database including form input, query string, etc. I am developing an internal site, however, so most users just call me if they are having a problem. For a public site, you may wish to use something like elmah.
public string BookLesson(Customer_Info oCustomerInfo, CustLessonBook_Info oCustLessonBookInfo)
{
string authenticationID = string.Empty;
int customerID = 0;
string message = string.Empty;
DA_Customer oDACustomer = new DA_Customer();
using (TransactionScope scope = new TransactionScope())
{
if (oDACustomer.ValidateCustomerLoginName(oCustomerInfo.CustId, oCustomerInfo.CustLoginName) == "Y")
{
// if a new student
if (oCustomerInfo.CustId == 0)
{
oCustomerInfo.CustPassword = General.GeneratePassword(6, 8);
oCustomerInfo.CustPassword = new DA_InternalUser().GetPassword(oCustomerInfo.CustPassword, false);
authenticationID = oDACustomer.Register(oCustomerInfo, ref customerID);
oCustLessonBookInfo.CustId = customerID;
}
else // if existing student
{
oCustomerInfo.UpdatedByCustomer = "Y";
authenticationID = oDACustomer.CustomerUpdateProfile(oCustomerInfo);
}
message = authenticationID;
// insert lesson booking details
new DA_Lesson().BookLesson(oCustLessonBookInfo);
}
else
{
message = "login exists";
}
scope.Complete();
return message;
}
}