Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular on top of ASP.NET MVC, displaying Errors

We are putting an angular front end on an existing asp.net c# MVC applicaiton. In our server code, we extensilvely use custom exceptions to return buisness rule errors.

Is there a best practice or slickest way to handle an exception on an mvc controller or an webApi controller (actually bullbing up from the buisness layer) and getting it across to angular and displaying it in a "user error" popup? How are folks solving this problem?

like image 462
Eric Brown - Cal Avatar asked Apr 24 '15 15:04

Eric Brown - Cal


People also ask

Can we use Angular with ASP.NET MVC?

To load Angular in ASP.NET MVC, include the script references of Angular core modules and Syncfusion JavaScript asset files in _Layout file , and load the component in index. cshtml like the following code snippets.

Can you use Angular with ASP NET?

The updated Angular project template provides a convenient starting point for ASP.NET Core apps using Angular and the Angular CLI to implement a rich, client-side user interface (UI). The template is equivalent to creating an ASP.NET Core project to act as an API backend and an Angular CLI project to act as a UI.

Is Angular better than asp net?

Growing libraries and extensions. Single-page applications, and Angular in particular, are constantly being updated with more and more presentation libraries and extensions compared to ASP.NET MVC. Angular provides robust extensibility and customization and has deep community support that is continually growing.

Is Angular the view in MVC?

A View, in the context of a Model View Controller (MVC) architecture, is a software class that contains a template and data form and produces a response for the browser. It receives data from the Controller of the MVC and packages it and presents it to the browser for display.


2 Answers

Other guys already gave great answers, but I want to elaborate my approach since I guess it will be covering both ends (frontend and server) with more details.

Here's my complete approach to error and exception handling in WebAPI + AngularJS applications.

Step 1. WebApi controllers in Server side

I have a specific DTO for communicating Validation Errors to the client, since I believe they are different from Exceptions. An exception will result in a 500 error, where a validation result should result in 400 (Bad Request) error.

So, here's my ApiValidationResult class:

public class ApiValidationResult
{
    public List<ApiValidationError> Errors { get; set; }

    public static ApiValidationResult Failure(string errorKey)
    {
        return new ApiValidationResult {Errors = new List<ApiValidationError> {new ApiValidationError(errorKey)}};
    }

    // You can add a bunch of utility methods here
}

public class ApiValidationError
{
    public ApiValidationError()
    {
    }

    public ApiValidationError(string errorKey)
    {
        ErrorKey = errorKey;
    }

    // More utility constructors here

    public string PropertyPath { get; set; }
    public string ErrorKey { get; set; }
    public List<string> ErrorParameters { get; set; }
}

I always use my own base class for WebApi (and MVC) controllers, so I can use them to add handy result method, such as this:

public abstract class ExtendedApiController : ApiController
{
    protected IHttpActionResult ValidationError(string error)
    {
        return new ValidationErrorResult(ApiValidationResult.Failure(error), this);
    }

    // More utility methods can go here
}

It uses a custom IHttpActionResult that I've created specifically for this purpose:

public class ValidationErrorResult : NegotiatedContentResult<ApiValidationResult>
{
    public ValidationErrorResult(ApiValidationResult content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) 
        : base(HttpStatusCode.BadRequest, content, contentNegotiator, request, formatters)
    {
    }

    public ValidationErrorResult(ApiValidationResult content, ApiController controller)
        : base(HttpStatusCode.BadRequest, content, controller)
    {
    }
}

As a result, I can cleanly use codes such as this in my controller actions:

    [HttpPost]
    public IHttpActionResult SomeAction(SomeInput input)
    {
        // Do whatever...
        if (resultIsValid)
        {
            return Ok(outputObject);
        }

        return ValidationResult(errorMessage);
    }

Step 2. Handling unexpected exceptions

As I said, I believe that only real unhandled Exceptions should result in a 500 (Internal server error) responses.

Such unhandled exceptions are automatically converted to a 500 result by WebApi. The only thing I need to do about them, is to log them. So, I create an implementation of IExceptionLogger interface and register it like this:

GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new UnhandledExceptionLogger());

Step 3. Intercepting and showing errors in Client side

AngularJS allows intercepting all HTTP calls sent from $http service. I use this to centralize all message popups. Here's my interceptor code:

appModule.factory("errorsHttpInterceptor", [
    "$q", "$rootScope", "$injector",
    ($q: ng.IQService, $rootScope: IAppRootScopeService, $injector) => {
        return {
            'responseError': rejection => {
                // Maybe put the error in $rootScope and show it in UI
                // Maybe use a popup
                // Maybe use a 'toast'
                var toastr = $injector.get('toastr');
                toastr.error(...);

                return $q.reject(rejection);
            }
        };
    }
]);

You can do all sorts of things in the interceptor, such as logging debug messages, or applying key to display-string translation of error codes. You can also distinguish between 500 and 400 errors, and display different types of error messages.

I use toastr library which I think shows a nice UI and is very handy in API level.

Finally, I register the interceptor like this:

appModule.config([
    '$httpProvider',
    ($httpProvider: ng.IHttpProvider) => {
        $httpProvider.interceptors.push('errorsHttpInterceptor');
    }
]);

The syntax is in TypeScript, which is very similar to JavaScript and I'm sure you can figure out what it means.

like image 123
Iravanchi Avatar answered Oct 26 '22 18:10

Iravanchi


Typically, I Have been doing this kind of thing within our WEB API, returning the correct status code is key with this, this is of course completely agnostic as to which of the many front end frameworks you want to use.

public IHttpActionResult Get(DateTime? updatesAfter = null)
        {
            try
            {
                // Do something here.
                return this.Ok(result);
            }
            catch (Exception ex) // Be more specific if you like...
            {
                return this.InternalServerError(ex);
                throw;
            }
        }

The helper methods that are now shipped with Web Api v2 ApiControllers are excellent...

this.BadRequest()
this.InternalServerError()
this.Ok()
this.Unauthorized()
this.StatusCode()
this.NotFound()

Some of them (such as InternalServerError) allow you to pass an exception or message (or simply an object) as a param.

Typically as with any front end framework or library there will be a fail or error callback that you can provide when initialising the ajax call to your API method, this will be called in scenarios where error status codes are returned.

like image 28
BenjaminPaul Avatar answered Oct 26 '22 18:10

BenjaminPaul