《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