Intro
Sometimes I got errors when I had accessed to server with HttpClient.I had wanted to know what should I do, so I tried in some situations.
Returning errors sample (ASP.NET Core)
Because I had wanted to get some kinds of problems, I used Identity.Startup.cs
using Files;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Models;
using UpgradeSample.Models;
using UpgradeSample.Products;
using UpgradeSample.Users;
public class Startup
{
private IConfigurationRoot Configuration { get; }
public Startup(IHostEnvironment env)
{
...
}
public void ConfigureServices(IServiceCollection services)
{
// DB Connect
services.AddDbContext<UpgradeSampleContext>(options =>
options.UseNpgsql(Configuration["DbConnect"]));
// Identity
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddUserStore<ApplicationUserStore>()
.AddEntityFrameworkStores<UpgradeSampleContext>()
.AddDefaultTokenProviders();
// SPA
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "clients/dist";
});
// DI
services.AddSingleton<ILocalFileAccessor, LocalFileAccessor>();
services.AddScoped<IProductDao, ProductDao>();
services.AddScoped<IProductService, ProductService>();
services.AddScoped<IUserService, UserService>();
services.AddRazorPages();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
...
if (env.IsDevelopment() == false)
{
app.UseSpaStaticFiles();
}
app.UseStaticFiles();
app.UseCors(AllowedOrigins);
app.UseRouting();
// when I tried to redirect what was caused by unauthorized, I would uncomment.
// app.UseStatusCodePagesWithRedirects("/login");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "clients";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "s");
}
});
}
}
ThrowSampleController.cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Files;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using UpgradeSample.Models;
namespace Controllers
{
public class ThrowSampleController: Controller
{
private readonly SignInManager<ApplicationUser> _signInManager;
public ThrowSampleController(SignInManager<ApplicationUser> signInManager)
{
_signInManager = signInManager;
}
// Throw some results
/* For authentication */
[Route("/sample-signin")]
public async Task Signin()
{
await _signInManager.PasswordSignInAsync("hello", "world", false, false);
}
[Route("/sample-signin")]
public async Task SignOut()
{
await _signInManager.SignOutAsync();
}
// For redirection of unauthorized
[Route("/Account/Login")]
public IActionResult GetLoginPage()
{
return View("~/Views/LoginPage.cshtml");
}
// Generate dummy data
private List<Product> GenerateSampleData()
{
return new List<Product>
{
new Product { ProductId = 0, ProductName = "Hello", LastUpdateDate = DateTime.Now },
new Product { ProductId = 1, ProductName = "World", LastUpdateDate = DateTime.Now },
};
}
}
}
Get results with HttpClient
Default
If no any probrems were happened, I could get data like below.ThrowSampleController.cs
...
namespace Controllers
{
public class ThrowSampleController: Controller
{
...
[Route("/throw/ok")]
public List<Product> GetOk()
{
return GenerateSampleData();
}
}
}
throw-sample.service.ts
import { Injectable } from '@angular/core';
import {HttpClient, HttpErrorResponse} from "@angular/common/http";
import {Observable, throwError} from "rxjs";
import {catchError, map} from 'rxjs/operators';
import {Product} from "./models/product";
import {UploadResult} from "./file-upload/upload-result";
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
public getOk(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/ok`);
}
...
}
If I had subscribed this method, I could get the array of "Product".It was great simple:)
But unfortunately, some errors might happen.
404
ThrowSampleController.cs
...
namespace Controllers
{
public class ThrowSampleController: Controller
{
...
[Route("/throw/notfound")]
public IActionResult GetNotFound()
{
return NotFound();
}
...
}
}
throw-sample.service.ts
...
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
...
public getNotFound(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/notfound`);
}
...
}
This was the result.Object { headers: {…}, status: 404, statusText: "Not Found", url: "http://localhost:5000/throw/notfound", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:5000/throw/notfound: 404 Not Found", error: null }How to handling the errors?
I could write like this.
throw-sample.component.ts
import { Component, OnInit } from '@angular/core';
import {ThrowSampleService} from "../throw-sample.service";
@Component({
selector: 'app-throw-sample',
templateUrl: './throw-sample.component.html',
styleUrls: ['./throw-sample.component.css']
})
export class ThrowSampleComponent implements OnInit {
constructor(private throwSampleService: ThrowSampleService) { }
...
public getNotFound() {
this.throwSampleService.getNotFound()
.subscribe(result => console.log(result),
error => {
console.error(error);
// Do something.
},
() => console.log('getNotFound completed')*/);
}
...
}
But should I do like this?According to the documents, I had felt I shall handle the errors in the service.
Angular - HttpClient
throw-sample.service.ts
...
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
...
public getNotFound(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/notfound`)
.pipe(
catchError(ThrowSampleService.handleError)
);
}
...
private static handleError(error: HttpErrorResponse){
console.error(error);
// Do something
return throwError(error.message);
}
}
I could write common operations.For example, if I had got 401 error, I would move to login page.
And I hadn't had to return error in handleError.
So I also could delegate error handling to the class, and return default values.
throw-sample.service.ts
...
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
...
public getNotFound(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/notfound`)
.pipe(
catchError(error => ThrowSampleService.handleError(error, []))
);
}
...
private static handleError<T> (error: HttpErrorResponse, args: T) {
console.error(error);
// Do something
return args;
}
}
401
How about the other errors?I tried to handle the 401 error.
ThrowSampleController.cs
...
namespace Controllers
{
public class ThrowSampleController: Controller
{
...
[Route("/throw/unauthorized")]
public IActionResult GetUnauthorized()
{
return Unauthorized();
}
...
}
}
throw-sample.service.ts
...
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
...
public getUnauthorized(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/unauthorized`)
.pipe(
catchError(ThrowSampleService.handleError)
);
}
...
}
Off cource I could get 401 error.Object { headers: {…}, status: 401, statusText: "Unauthorized", url: "http://localhost:5000/throw/unauthorized", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:5000/throw/unauthorized: 401 Unauthorized", error: null }
404 with redirection
How about I had used redirection to the login page?Startup.cs
...
namespace UpgradeSample
{
public class Startup
{
...
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
...
app.UseStatusCodePagesWithRedirects("/login");
...
}
ThrowSampleController.cs
...
namespace Controllers
{
public class ThrowSampleController: Controller
{
...
[Route("/throw/unauthorized")]
public IActionResult GetUnauthorized()
{
return Unauthorized();
}
...
[Route("/login")]
[Route("/Account/Login")]
public IActionResult GetLoginPage()
{
return View("~/Views/LoginPage.cshtml");
}
}
}
The result was here.Object { headers: {…}, status: 200, statusText: "OK", url: "http://localhost:5000/login", ok: false, name: "HttpErrorResponse", message: "Http failure during parsing for http://localhost:5000/login", error: {…} }If the request had been redirected, the status code what I could get was 200.
So I couldn't think only about the status code of 401 in this case.
403
How about 403 error?I had removed the redirection again.
Startup.cs
...
namespace UpgradeSample
{
public class Startup
{
...
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
...
// app.UseStatusCodePagesWithRedirects("/login");
...
}
ThrowSampleController.cs
...
namespace Controllers
{
public class ThrowSampleController: Controller
{
...
[Route("/throw/forbidden")]
public IActionResult GetForbidden()
{
return Forbid();
}
...
}
}
throw-sample.service.ts
...
@Injectable({
providedIn: 'root'
})
export class ThrowSampleService {
constructor(private httpClient: HttpClient) { }
...
public getForbidden(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/throw/forbidden`)
.pipe(
catchError(ThrowSampleService.handleError)
);
}
...
This was the result.Object { headers: {…}, status: 404, statusText: "Not Found", url: "http://localhost:5000/Account/AccessDenied?ReturnUrl=%2Fthrow%2Fforbidden", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:5000/Account/AccessDenied?ReturnUrl=%2Fthrow%2Fforbidden: 404 Not Found", error: "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot GET /Account/AccessDenied</pre>\n</body>\n</html>\n" }Why redirected automatically?
Because I hadn't written the page what was routed "/Account/AccessDenied".
So I hadn't been surprised. But I didn't know the redirection.
I would read the document.
Resources
RxJS in ActionAngular-HttpClient
コメント
コメントを投稿