《Asp.Net Core3 + Vue3入坑教程》 此教程適合新手入門或者先後端分離嘗試者。能夠根據圖文一步一步進操做編碼也能夠選擇直接查看源碼。每一篇文章都有對應的源碼html
Asp.Net Core後端項目前端
Vue3 前端項目vue
本文爲《Asp.Net Core3 + Vue3入坑教程》系列教程的後端第六篇 - 異常處理與UserFriendlyException上文已經爲Simple項目升級了SDK而且應用了JWT,本文繼續爲Simple項目增長異常處理與使用友好異常(UserFriendlyException)。git
爲何須要使用友好異常的方式進行開發呢?github
在不少狀況下,咱們在一個方法中每每包含着校驗參數與返回結果兩個動做,這時候咱們的返回結果就須要考慮用對象來包裹校驗結果與返回結果。 若是咱們使用友好異常,默認方法能順利經過校驗並返回正確的結果,若是校驗出現失敗的狀況則將失敗緣由經過友好異常的方式返回給調用者,可讓方法的返回內容不須要考慮校驗的結果,代碼更簡潔明瞭!vue-router
用戶友好參照了開源項目ABP項目 https://docs.abp.io/zh-Hans/abp/latest/Exception-Handlingsql
代碼調整以下:vuex
using Simple_Asp.Net_Core.Models; using Simple_Asp.Net_Core.ServiceProvider; using System; using System.Collections.Generic; using System.Linq; namespace Simple_Asp.Net_Core.Data { public class SqlCommanderRepo : ICommanderRepo { private readonly CommanderContext _context; public SqlCommanderRepo(CommanderContext context) { _context = context; } public void CreateCommand(Command cmd) { if (cmd == null) { throw new ArgumentNullException(nameof(cmd)); } _context.Commands.Add(cmd); } public void DeleteCommand(Command cmd) { if (cmd == null) { throw new ArgumentNullException(nameof(cmd)); } _context.Commands.Remove(cmd); } public IEnumerable<Command> GetAllCommands() { return _context.Commands.ToList(); } public Command GetCommandById(int id) { if (id == 0) throw new Exception("id不能爲0!"); return _context.Commands.First(p => p.Id == id); } public bool SaveChanges() { return (_context.SaveChanges() >= 0); } public void UpdateCommand(Command cmd) { //Nothing } } }
當前的異常信息將程序內部內容都暴露出來,而且返回信息也不清晰,調用者難以處理。vue-cli
代碼以下:json
using System; namespace Simple_Asp.Net_Core.ServiceProvider { public class UserFriendlyException : Exception { public UserFriendlyException(string message) : base(message) { } public UserFriendlyException(string message, Exception inner) : base(message, inner) { } } }
在捕捉到程序異常的時候須要寫入日誌方便問題追蹤
代碼以下:
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using System.Text; using System.Threading.Tasks; namespace Simple_Asp.Net_Core.ServiceProvider { public class ExceptionHandler { public static Task ErrorEvent(HttpContext context) { var feature = context.Features.Get<IExceptionHandlerFeature>(); var error = feature?.Error; if (error.GetType() == typeof(UserFriendlyException)) { SetResponse(context); var content = GetApiResponse(error.Message); return context.Response.WriteAsync(JsonConvert.SerializeObject(content), Encoding.UTF8); } else { // 寫入日誌 // error.Message // error.StackTrace SetResponse(context); var content = GetApiResponse("程序發生錯誤,請聯繫客服!"); return context.Response.WriteAsync(JsonConvert.SerializeObject(content), Encoding.UTF8); } } /// <summary> /// 解決異常消息返回跨域問題 /// </summary> private static void SetResponse(HttpContext context) { context.Response.Clear(); context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET"); context.Response.ContentType = "application/json"; } /// <summary> /// 響應Response /// </summary> private static ErrorResponse GetApiResponse(string message) { return new ErrorResponse() { success = false, message = message }; } private class ErrorResponse { public bool success { get; set; } public bool Success { get { return success; } } public string message { get; set; } public string Message { get { return message; } } } } }
代碼以下:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Newtonsoft.Json.Serialization; using Simple_Asp.Net_Core.Data; using Simple_Asp.Net_Core.ServiceProvider; using System; namespace Simple_Asp.Net_Core { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddJWT(); services.AddDbContext<CommanderContext>(options => options.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=123456")); services.AddCORS(); services.AddMvc(); services.AddSwagger(); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddScoped<ICommanderRepo, SqlCommanderRepo>(); services.AddControllers().AddNewtonsoftJson(s => { s.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1"); }); } app.UseExceptionHandler(builder => builder.Run(async context => await ExceptionHandler.ErrorEvent(context))); app.UseCors("CorsTest"); app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute()); } } }
代碼調整以下:
using Simple_Asp.Net_Core.Models; using Simple_Asp.Net_Core.ServiceProvider; using System; using System.Collections.Generic; using System.Linq; namespace Simple_Asp.Net_Core.Data { public class SqlCommanderRepo : ICommanderRepo { private readonly CommanderContext _context; public SqlCommanderRepo(CommanderContext context) { _context = context; } public void CreateCommand(Command cmd) { if (cmd == null) { throw new ArgumentNullException(nameof(cmd)); } _context.Commands.Add(cmd); } public void DeleteCommand(Command cmd) { if (cmd == null) { throw new ArgumentNullException(nameof(cmd)); } _context.Commands.Remove(cmd); } public IEnumerable<Command> GetAllCommands() { return _context.Commands.ToList(); } public Command GetCommandById(int id) { if (id == 0) throw new Exception("id不能爲0!"); return _context.Commands.First(p => p.Id == id); } public bool SaveChanges() { return (_context.SaveChanges() >= 0); } public void UpdateCommand(Command cmd) { //Nothing } } }
本文爲Simple項目增長異常處理與使用友好異常(UserFriendlyException),在捕捉到程序異常的時候須要寫入日誌方便問題追蹤!
目前Simple項目還未使用日誌組件,後續會補上
異常捕捉爲了可以將異常內容進行收集,而且能以統一的方式返回給客戶端,保證服務器的安全、幫助咱們追蹤問題而且客戶端的體驗也能有所保證。
異常捕捉結合友好異常的方式可以爲咱們減小代碼量,而且讓代碼更直觀明瞭,推薦你們一試!
注意:源碼調試過程當中若是出現xml文件路徑錯誤,須要參照第一章(後端項目搭建與Swagger配置步驟)Swagger配置「配置XML 文檔文件」步驟,取消勾選而後再選中 ,將XML路徑設置成與你的電腦路徑匹配!
ABP開源項目異常處理 https://docs.abp.io/zh-Hans/abp/latest/Exception-Handling