I'm working on an ASP.NET MVC application and just getting to error handling. Help me solve the issue of getting the error message back to the user.
I have a controller:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Show(string callNumber)
{
ServiceCallService sc = new ServiceCallService();
return View(sc.GetServiceCallByCallNumber("", callNumber));
}
a Service:
public ServiceCall GetServiceCallByCallNumber(string custID, string callNumber)
{
ServiceCall sc = new ServiceCall();
sc = _serviceCallRepository.GetServiceCallByCallNumber(custID, callNumber);
return sc;
}
a Repository:
public ServiceCall GetServiceCallByCallNumber(string custID, string callNumber)
{
ServiceCall sc = new ServiceCall();
try
{
LoginToDB();
sc.CallNumber = "123";
}
catch (Exception e)
{
logger.error(Server.GetLastError());
}
finally
{
LogoutFromDB();
}
return sc;
}
Let's say there is a problem in the LoginToDB() method. I am logging the error but how do I get the error message back to the controller and then to the view.
Thanks.
The easiest way are:-
1) To use the build in model validation in ASP.NET MVC Release Canditate 1 (download from asp.net/mvc).
2) Re-throw the exception and catch it in your controller action then pass a nice customized error message to the View to render to the user - pass it using ViewData["error"] or something similar.
Related
According to Microsoft's recommendation, throwing and catching should not be used for the normal logic of the program.
Minimize exceptions
As part of a ASP.Net core clean architecture project (with 3 Layers Generic Repositories - BL Services - Controllers), how should the error handling and the results be designed and implemented?
Should a struct or a global result class be used for all Api Controllers and BL services?
Is it enough if the errors and the results are encapsulated in a struct?
Example of result class in the WebApi project:
public class ExampleResult<T>
{
public ExampleResult(T value, string message, bool success)
{
(...)
}
}
Controller:
public ActionResult<ExampleResult<NewResourceDto>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
if(!Validate(myNewResource))
return new ExampleResult(null, "some business logic validate failed", true);
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return result;
}
catch (Exception ex)
{
// Log the exception here...
return new ExampleResult(null, "some message" + ex, false);
}
}
The Angular Client then validates if the value is null and/or whether the success is true or false.
The message contains the error messages.
The http status will be 200 (no matter if success or not).
How are the exceptions minimized elegantly?
targeting the best practice in .Net Core or any other framework you need to return a common model of all of your apis that holds all the date returned from your api in case if it's a result or an error then in your angular service you should check on your returned object keys which is your base model.
public class ErrorModel
{
public ErrorModel()
{
ErrorMessages = new List<string>();
}
public List<string> ErrorMessages { get; set; }
public Exception Exception { get; set; }
}
public class BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public ErrorModel Error { get; set; }
}
public class BaseModel<T>: BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public bool HasError => Error.ErrorMessages.Count > 0 || Error.Exception != null;
public T Result { get; set; }
}
then your api should look like that
public ActionResult<BaseModel<dynamic>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return OK( new BaseModel<dynamic>()
{
Result=result
});
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, new BaseModel<dynamic>()
{
Error = new ErrorModel()
{
ErrorMessages = new List<string>()
{
ex.Message,
"your message 2",
"your message 3"
},
Exception = ex
}
});
}
}
then in your angluar service you shold check on your response.hasError and displays your data according to it.
I agree that throwing Exceptions should not be used as signaling in the system. Maybe I don't understand your question about the returning a struct or a global result class. Seems like a bad idea. Especially, don't return HTTP OK 200 if something goes south.
Keep your Web API controllers as thin and dumb as possible
Wrap your Web API controller method methods in a try-catch so you always return HTTP Internal Server Error 500 on an unexpected error
Example of a controller method:
public IActionResult Post([FromBody] NewResourceDto myNewResource)
{
try
{
_service.TrySaveMyNewResource(myNewResource);
return StatusCode(201);
}
catch (Exception ex)
{
// Log the exception here...
return StatusCode(500);
}
}
I am using React Js in my client-side and .Net Core 3.0 Web API on the server-side. I have one API method called CreateAccount and the return type is IActionResult. Now if I do validate with any one of the model property then I have to send or return the validation message along with empty model data. I am new to API and tried like below but could not send the string as a result type.
API method,
[AllowAnonymous]
[HttpPost("createaccount")]
public async Task<IActionResult> CreateAccount([FromBody]Users user)
{
try
{
if (ModelState.IsValid)
{
if (user == null)
return BadRequest(new { message = "Data is empty" });
if(user.UserType!="Admin")
{
return new ValidationResult("Only Admin can create new account");
}
return Ok(await _userService.CreateAnUserAccount(user));
}
}
catch(Exception e)
{
throw new ArgumentException(e.Message);
}
return ValidationProblem();
}
I do not know the proper .Net Core API coding part, could anyone please help me to resolve this issue?
You could return an ObjectResult with a StatusCode other than StatusCodes.Status200OK and a serialized object that contains whatever information you want to return to the client, e.g.:
return new ObjectResult(new YourApiError() { Message = "message.." })
{
StatusCode = StatusCodes.Status405MethodNotAllowed
};
When I catch an exception in a controller, the client side still receives an InternalServerError, how can I resolve this?
I have my own 'Result' class, which I can set to failed, and populate with a user friendly error message, I want to catch exceptions in specific controller methods, and send back my failed 'Result' class instead of the code 500 InternalServerError.
Thanks for the help!
[HttpGet]
[Route(Server_DevTestApiEndpoints.INTERNAL_SERVER_EXCEPTION_RESULT_TEST)]
public Result GetInternalServerExceptionTest()
{
try
{
throw new Exception();
return new Result();
}
catch (Exception e)
{
return new Result(e);
}
}
It will be better from architectural standpoint to use an ExceptionFilterAttribute, that will be responsible for catching all errors in your controller actions:
public class LogExceptionFilterAttribute : ExceptionFilterAttribute
{
public override async Task OnExceptionAsync(ExceptionContext context)
{
//log your exception;
context.Result = new ObjectResult("your custom message")
{
StatusCode = StatusCodes.Status200OK
};
}
}
and just decorate your action or entire controller:
[HttpGet]
[LogExceptionFilter]
[Route(Server_DevTestApiEndpoints.INTERNAL_SERVER_EXCEPTION_RESULT_TEST)]
public Result GetInternalServerExceptionTest()
{
//your action logic
}
Developing a C#, MVC5 web app....
In one of my class methods, when I receive a network error (ie can't connect to database) I want to redirect to an HTML error page. What's the best way to handle this?
Here's what I tried so far....
public static class MyClass
{
public static string MyMethod(SettingKey key)
{
try
{
using (var cnn = new dbContext())
{
return cnn.MySettings.Where(s => s.Key == key.ToString()).AsNoTracking().Select(s => s.Value)
.FirstOrDefault();
}
}
catch (Exception e)
{
if (e.InnerException != null && e.InnerException.Message.Contains("A network-related or instance-specific error occurred"))
{
return Redirect("error_network_related.html");
}
return "";
}
return "";
}
}
As you can see, I'm specifically trying to navigate to error_network_related.html in the root of my application whenever the network is down and the db cannot be accessed.
So, my question has to do with (1) the best way to catch this specific network-related error (db down) and (2) best way to redirect to the error page.
Other suggestions are welcomed!
Create an Action / Controller to handle the Error message/UI you need to show. Then use MVC Controller OnException to Customize Responses and then Return the specific action using RedirectToAction().
OnException is similar to HandleErrorAttribute but provides more flexibility. It works with all HTTP status codes, and not just 500 level responses. It also gives you the ability to log the errors!
public class UserMvcController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
//Redirect or return a view, but not both.
filterContext.Result = RedirectToAction("Index", "ErrorHandler");
// OR
filterContext.Result = new ViewResult
{
ViewName = "~/Views/ErrorHandler/Index.cshtml"
};
}
}
This is a suggested approach :)
I'm wonder how can I build full path to the action within my signalR hub. I have code in my hub:
public string GetUpdateUrl(string identifier)
{
var helper = new System.Web.Mvc.UrlHelper(HttpContext.Current.Request.RequestContext);
var result = String.Empty;
try
{
result = helper.Action("Download", "Agent", identifier);
}
catch (Exception e)
{
var t = e;
}
return result;
}
What I want is just to return full url (like example.com/Conteroller/Action?identifier=some_code) to the action.
And here Download action
public ActionResult Download(string identifier)
{
//return download
}
But I'm getting error.
Response is not available in this context.
Since your SignalR service is self hosted by owin (isn't it?), you shall try to check this and this answers.