简述 对 Abp的动态web api的改革过程 注册
1. 首先通过反射将《处事类型》通过ApiControllerBuilder 构建成成 DynamicApiControllerInfo
2. 在DynamicApiControllerInfo中同时构建DynamicApiActionInfo
3. Ioc注入DynamicApiController<TService> Tservice就是最开始的《处事类型》
3. 最后将DynamicApiControllerInfo添加到DynamicApiControllerManager,通过ServiceName缓存
1. AbpHttpControllerSelector 通过路由获取出“service” 这个参数即ServiceName
2. 通过ServiceName从DynamicApiControllerManager中获取DynamicApiControllerInfo 的信息
3. 将DynamicApiControllerInfo 放入HttpControllerDescriptor.Properties中,返回DynamicHttpControllerDescriptor给MVC措置惩罚惩罚流程
4. AbpControllerActivator 通过DynamicApiControllerInfor中的ControllerType激活Controller
5. AbpApiControllerActionSelector 获取HttpControllerDescriptor.Properties中的将DynamicApiControllerInfo 信息
6. AbpApiControllerActionSelector 通过 路由的{action}参数获取 要领名
7. AbpApiControllerActionSelector 在 DynamicApiControllerInfor通过要领名获取DynamicApiActionInfo 的信息
8. 最后返回DyanamicHttpActionDescriptor 给MVC措置惩罚惩罚流程
实际在Abp中 DyanamicHttpActionDescriptor 的 ExecuteAsync 中实际是通过AOP拦截实现的.这里我做了改削
首先将DynamicController改为组合的方法注入IService来作为代办代理东西如下图
然后执行的时候给与获取IDynamicApiController 的ProxyObject 来使用反射执行
此中由于MVC并没有放出ReflectedHttpActionDescriptor.ActionExecutor 这个类型,所以用了点技巧。
撑庄重载1. 首先在 DynamicApiControllerInfo 中增加属性 FullNameActions 类型和Actions 一致
2. 然后再初始化的时候同时初始化FullNameActions ,Action的key是Name,FullNameActions 是Method.ToString()[这种包罗的信息更多,可作为独一标识]
3. 最后在客户端挪用的时候放到Header即可区分,,实现函数重载
在ParameterBindingRules 中添加法则
//增加处事中多个参数的情况 ApiGlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, descriptor => { if (descriptor.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Get) || descriptor.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Delete)) return null; if (descriptor.ActionDescriptor.GetParameters().Count(item => !item.ParameterType.IsSimpleUnderlyingType()) < 2) return null; if (descriptor.ParameterType.IsSimpleUnderlyingType()) return null; if (descriptor.ParameterType.GetCustomAttribute(typeof(ParameterBindingAttribute)) != null) return null; var config = descriptor.Configuration; IEnumerable<MediaTypeFormatter> formatters = config.Formatters; var validators = config.Services.GetBodyModelValidator(); return new MultiPostParameterBinding(descriptor, formatters, validators); });
2. 在MultiPostParameterBinding 代码如下
public class MultiPostParameterBinding : FormatterParameterBinding { // Magic key to pass cancellation token through the request property bag to maintain backward compat. private const string CancellationTokenKey = "MS_FormatterParameterBinding_CancellationToken"; public MultiPostParameterBinding(HttpParameterDescriptor descriptor, IEnumerable<MediaTypeFormatter> formatters, IBodyModelValidator bodyModelValidator) : base(descriptor, formatters, bodyModelValidator) { } public override bool WillReadBody => false; public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { var paramFromBody = Descriptor; var type = paramFromBody.ParameterType; var request = actionContext.ControllerContext.Request; IFormatterLogger formatterLogger = new ModelStateFormatterLogger(actionContext.ModelState, paramFromBody.ParameterName); var task = ExecuteBindingAsyncCore(metadataProvider, actionContext, paramFromBody, type, request, formatterLogger, cancellationToken); return task; } // Perf-sensitive - keeping the async method as small as possible private async Task ExecuteBindingAsyncCore(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, HttpParameterDescriptor paramFromBody, Type type, HttpRequestMessage request, IFormatterLogger formatterLogger, CancellationToken cancellationToken) { // pass the cancellation token through the request as we cannot call the ReadContentAsync overload that takes // CancellationToken for backword compatibility reasons. request.Properties[CancellationTokenKey] = cancellationToken; //todo 这里如果只是处事端使用需要要结构一个匿名东西去接受数据 Dictionary<string, object> allModels; if (actionContext.ActionArguments.ContainsKey("MultiDictionary")) { allModels = actionContext.ActionArguments["MultiDictionary"] as Dictionary<string, object>; } else { allModels = await ReadContentAsync(request, typeof(Dictionary<string, object>), Formatters, formatterLogger, cancellationToken) as Dictionary<string, object>; actionContext.ActionArguments["MultiDictionary"] = allModels; } if (allModels != null) { var model = JsonConvert.DeserializeObject(allModels[paramFromBody.ParameterName].ToString(), type); actionContext.ActionArguments[paramFromBody.ParameterName] = model; // validate the object graph. // null indicates we want no body parameter validation if (BodyModelValidator != null) BodyModelValidator.Validate(model, type, metadataProvider, actionContext, paramFromBody.ParameterName); } } }
道理实际是如果有两个庞大类型User user和Company company,那么客户端需要传入的是一个字典有两个key,user和company,分袂对应两个参数即可
客户端代办代理