using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Routing.Template; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using Wood.Util; namespace Wood.Admin.WebApi { /// /// 自动扫描所有带service名称的程序集 /// 扫描程序集中所有带service后缀的类 /// 给类中所有public 方法注册路由 /// public class AutoRouteConvention : IApplicationModelConvention { private readonly string _baseRoutePrefix = "api"; /// /// 应用路由规则 /// get 开头为 get /// 其他为post /// /// public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { var controllerName = controller.ControllerName.ToLowerInvariant().Replace("service", ""); foreach (var action in controller.Actions) { var actionName = action.ActionName.ToLowerInvariant(); var httpMethod = "POST"; var isGetMethod = false; if (!action.Selectors.Any() || !action.Selectors[0].ActionConstraints.Any()) { if (actionName.StartsWith("get")) { httpMethod = "GET"; actionName = actionName.Substring(3); isGetMethod = true; } else if (actionName.StartsWith("post")) { httpMethod = "POST"; actionName = actionName.Substring(4); } // 构建路由模板 var routeTemplate = $"{_baseRoutePrefix}/{controllerName}/{actionName}"; if (action.Selectors.Any()) { //当前已经有了 Selectors 信息则直接设置 action.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }; action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); } else { //当前没有 Selectors 信息则直接新增 var selectorModel = new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }, }; selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); action.Selectors.Add(selectorModel); } } else { // 构建路由模板 var routeTemplate = $"{_baseRoutePrefix}/{controllerName}/{actionName}"; //重新指定路由路径 action.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }; //是否get请求 isGetMethod = action.Attributes.Any(it => it.GetType() == typeof(HttpGetAttribute)); } //查找所有没有绑定来源的参数 IEnumerable noBindModels = action.Parameters.Where(it => it.BindingInfo == null); if (noBindModels.Any()) { // 设置参数来源:GET 请求的参数来自 URL,POST 请求的参数来自请求体 // 只会设置没有明确指定来源的参数 // Get 会加上 FromQuery // Post 会加上 FromBody (只有第一个参数加上 Frombody 多个参数会报错!) if (isGetMethod) { foreach (var parameter in noBindModels) { var bindId = parameter.BindingInfo?.BindingSource?.Id; if (string.IsNullOrEmpty(bindId)) { // 对于 GET 请求,默认情况下参数应该来自于查询字符串或路径 parameter.BindingInfo = new BindingInfo() { BindingSource = BindingSource.Query }; // 对于 GET 请求,默认情况下参数应该来自于 URL //parameter.BindingInfo = new BindingInfo() { BindingSource = BindingSource.Path }; } } } else { if (noBindModels.Count() > 1) throw Oops.Oh($"系统不支持Post请求FromBody绑定多个参数,请改成一个。路径:Controller({controller.ControllerName})Action({action.ActionName})"); else { if (action.Parameters.Any(it => it.BindingInfo?.BindingSource?.Id == "Body")) throw Oops.Oh($"系统不支持Post请求FromBody绑定多个参数,请改成一个。路径:Controller({controller.ControllerName})Action({action.ActionName})"); noBindModels.First().BindingInfo = new BindingInfo() { BindingSource = BindingSource.Body }; } } } } } } } }