I use DataAnnotations in my GUI layer to show error messages in forms, but I have some questions about how to handle exceptions from my service layer and what to show the user if they occur.
To communicate with my service layer I use a request and response class. For example:
public class RegisterUserRequest
{
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
Should I check for nulls in my request class inside the setter methods? Or should I do this in my service? I think it makes sense to do this on both the request and response setter methods and throw an ArgumentNullException if a parameter is null.
In my service class I throw an InvalidOperationException when for example the username or password is invalid. Is this the right exception to throw?
Another question I have is if I should catch all exceptions, and if so, what do I tell the user about the exception? If for example some property is null, it should throw an ArgumentNullException. But should I let the user know about this?
When an username is invalid I throw an InvalidOperationException. This one I do want to show to the user because it tells the user that it should use at least 3 characters or something.
I think I should use the error message from the InvalidOperationException to show to users and redirect to a standard error view when other exceptions occur like: "Oops, something went wrong".
I think a more relevant exception to throw when the username or password is invalid is an ArgumentException. In the description of that exception type it specifically covers the case where an argument is invalid.
As for passing the exception to the user, you should try to inform the user of the error without exposing any of the inner workings of your service, so having a response message containing the error "Invalid username - must be at least 3 characters" will give them useful feedback.
For errors that you don't want to pass on in detail I would suggest logging an error message yourself and then passing the error ID to the user. e.g. "An unhandled error has occured. Please contact support, quoting error ID xxx". This should only be used as a last resort however - it is better to inform the user how to fix it but this would be a suitable way to catch all errors without passing too much information to the client.
I would simply use DataAnnotations again because no-one wants to be redirected an error page if they don't put the correct formatting in for their username or password.
Related
I have written a webservice that basically inserts data into the central database and is expected to be consumed by multiple clients from multiple systems.
It works but the problem is that it can be accessed by anyone hence making it vulnerable to be used by anybody i.e. anybody can spam by entering data or anything.
One way is to check for the Session variable but how would I know the name of the session variable of the client consuming the system or may be he's not authenticating that way?
So what should I do to make it secure?
[WebMethod(EnableSession= true)]
public int InsertEngineeringData(string FunctionalLocation, string EqptType, string WINFileNo, string ComponentTagNo)
{
try
{
if (Session["User"] != null)
{
}
int EngineeringDataID = 0;
EngineeringDataDAL EngineeringDataDAL = new Vail_PlantWebApi.EngineeringDataDAL();
EngineeringDataID = EngineeringDataDAL.InsertEngineeringData(FunctionalLocation, EqptType, WINFileNo, ComponentTagNo);
return EngineeringDataID;
}
catch (Exception ex)
{
throw ex;
}
}
If it is an asmx webservice, then use the link Crocoder posted or another quick way if it works is you can try the [Authorize] attribute although I'm not sure if that will work with an inline webmethod you're using, I've only seen it used in WebAPI. Authorize attribute in ASP.NET MVC
A more robust way that would definitely work is you add a column to the Users table called 'CurrentSessionID' and another one that says 'LastLoginDateStamp' For each login request if you have a valid user you update their session there and a datestamp. Then when the user hits the api, you compare the session and make sure it hasn't exceeded what you decide is a valid threshold for the last login, maybe 24 hours for example.
There would be a lot more work to do after that, but that's the basic idea.
I have created a custom object that i use to generate a json error response for all error. The issue i am having is there are some errors that i cant catch. For example, if i try to call an action that does not support GET the default response is
{"Message":"The requested resource does not support http method
'GET'."}
This is fine, but i want to control the format. I want to control every single automated error like this so i can make sure that nothing gets output that i dont want to be output. I need to be able to gracefully let the client know if a code exception occurs.
I found this and this seems to be what i am looking for, but it doesnt seem to be catching the errors as there are no matching actions for these . How to override all standard error pages in WebAPI
I tried to implement this, but i still get the same error message from above even when i have this in the main controller.
[AllowAnonymous]
[ActionName("405")]
[HttpGet]
public string Status405()
{
return "error";
}
I was hoping there would be an onerror event or something that would act as a catch all so i could override everything. I tried to work based off the HttpResponseEx
public class ErrorFilter : System.Web.Http.HttpResponseException
{
public override string Message
{
get
{
return "My custom response based on whatever params are in this error";
}
}
}
This doesnt work either and i can see why as it doesnt tap into any events that get triggered.
Surely there is a way to do this. How is it normally done?
In the web.config, you need to turn on custom errors. By default it's set to remote, which allows the developer to see the stack trace and the end user to see a nice error page. You want to set this to on. See here for more details https://msdn.microsoft.com/en-us/library/h0hfz6fc(v=vs.85).aspx
I want to implement custom exception handling in web API.
I am able to implement some initial implementation, However I want to pass class object to exception to display all attributes. like
class error
{
int error_code
string error_message
string API
}
When some error occur it should show json like
{
"error_code": 0,
"error_message":"Either Your are not authorized or you don't have any project yet.",
"API": "save data"
}
This code only show the message
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
Any suggestion,
Thanks
You just need to give your object as input for the CreateResponse method. Generate the error response as follows,
return Request.CreateResponse(HttpStatusCode.BadRequest, error,
new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
The web API will automatically json-fies the error object you passed.
Make sure you set the necessary values in the error object before you do this.
Hope this helps.
EDIT
Set your HttpStatusCode as BadRequest instead of NotFound since you are generating the exception. It's more appropriate.
I have a very simple WCF4 Restful web service which uses WcfRestContrib to allow custom Basic Authentication. It works great when the client preemptively supplies a username and password but if they don't it returns a 400 Bad Request response rather than challenging the client to supply credentials (through a 401 response).
The service is using the declarative approach to implementing WcfRestContrib by decorating the necessary classes with Attributes. Here is my ServiceContract declaration:
// Standard attributes here
[WebAuthenticationConfiguration(typeof(WebBasicAuthenticationHandler),
typeof(SecurityValidator),
false,
"SearchService")
]
public class SearchService
Which only has one very simple operation:
// Standard attributes here
[OperationAuthentication]
SearchResponse Fetch(SearchRequest request)
And my UserNamePasswordValidator looks like (though it probably doesn't matter since it only gets called when credentials are passed):
public override void Validate(string userName, string password)
{
// TODO: Insert login validation logic here.
// To indicate login failure, throw a FaultException
// throw new FaultException("Unknown Username or Incorrect Password");
// Just return to indicate that the username and password are valid
return;
}
I tried to debug WcfRestContrib and found that the WebBasicAuthenticationHandler class is throwing a BasicAuthorizationException (which is only caught in framework code), however, for some reason it isn't transforming the exception into a 401.
Based on what I've read on the WcfRestContrib github site, there is an issue posted by its author (Mike O'Brian) saying that he'd like to see it return anything other than a 401 which I read as it currently returns the 401 challenge.
If this functionality is there then what am I missing, or am I doing something else wrong?
UPDATE
If there is not a way to do this with WcfRestContrib, is there an alternative way to achieve this (beyond using the standard Windows-based Basic Authentication in IIS)? I'm open to any (other) alternative solution.
I figured it out. I needed to decorate my ServiceContract with the ErrorHandlerAttribute:
// Standard attributes here
[WebAuthenticationConfiguration(typeof(WebBasicAuthenticationHandler),
typeof(SecurityValidator),
false,
"SearchService"),
ErrorHandler(typeof(WebErrorHandler))]
public class SearchService
Just by adding the [ErrorHandler(typeof(WebErrorHandler))] attribute to the service makes all of the magic happen. I knew it had to be something simple, just wish I would have seen it before flattening my forehead on my desk.
As I ask this question, I'm mainly thinking about bad parameters. Parameters where:
int <= 0
string is empty or whitespace
model bound object is missing key properties
"id not found errors" (a "valid" integer id is passed to the action, but there is no corresponding database record)
Here are the two error handling scenarios I'm talking about:
public ActionResult GoToError(int value, string name)
{
if (value <= 0 || string.IsNullOrWhiteSpace(name))
{
// Parameter(s) not meeting basic conditions
TempData["ErrorMessage"] = "Invalid parameters";
return RedirectToAction("Index", "Error");
}
return View();
}
public ActionResult ReturnView(int value, string name)
{
if (value <= 0 || string.IsNullOrWhiteSpace(name))
{
// Parameter(s) not meeting basic conditions
ViewData["ErrorMessage"] = "Invalid parameters";
return View("Error");
}
return View();
}
There are different scenarios, that need to be handled differently:
For totally unexpected errors you don't anticipate, I suggest letting the exception bubble up and handling it in the Controller.OnException(...) method and/or the asp.net custom error pages
For common errors that are anticipated, such as a user providing bad input, its proper to return a view and display errors passed through ModelState.Errors
If the action is intended to be called via AJAX / Javascript / As a service, you need to coordinate what you send back. It may be a custom JSON object or a specific view.
Based on what you've posted, I can't classify weather they're 'anticipated' or 'unanticipated.' The main question is, how does the client of these calls expect them to be handled?
In a RESTFul application you should return the view and set the corresponding HTTP status code (401, 403, 404, 500, ...). When you redirect this means status code 200 and returning status code 200 for an error page doesn't make sense. Here's a technique that I use to handle errors. This works also very nicely with AJAX when you can subscribe for different status codes. For example let's suppose that you have an authenticated site where logged in users can perform AJAX requests. After certain inactivity their session could expire and when they need to perform some AJAX request if your server doesn't return proper status code (401 in this case) the client script will have hard time understanding and handling the scenario.
Doing errors properly in ASP.NET is just short of nightmare-ishly hard.
If you follow what the web is meant to do:
You should return an error result for any impossible to recover from error, like 400 bad request, 404 resource not found, etc. This includes most of the errors in the 4xx range.
For application errors that are unhandled exception that will result in a 500 error, the correct solution is to issue a 302 redirect to an error page that properly returns the 500 status code.
As #Darin Dimitrov said, in RESTful applications, you should never issue a redirect for anything it should always return the result definitively.