You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

127 lines
4.4 KiB

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
{
/// <summary>
/// 自动扫描所有带service名称的程序集
/// 扫描程序集中所有带service后缀的类
/// 给类中所有public 方法注册路由
/// </summary>
public class AutoRouteConvention : IApplicationModelConvention
{
private readonly string _baseRoutePrefix = "api";
/// <summary>
/// 应用路由规则
/// get 开头为 get
/// 其他为post
/// </summary>
/// <param name="application"></param>
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<ParameterModel> 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 };
}
}
}
}
}
}
}
}