1、AbpFramework.WebApi》Scripting
service接口
using Abp; using Abp.Collections.Extensions; using Abp.Dependency; using Abp.Extensions; using Abp.Web.Api.ProxyScripting.Generators; using Abp.WebApi.Controllers.Dynamic; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Web; namespace AbpFramework.Api.Scripting { public class ScriptProxyVueManager : ISingletonDependency { private class ScriptInfo { public string Script { get; private set; } public ScriptInfo(string script) { Script = script; } } private readonly IDictionary<string, ScriptInfo> CachedScripts; private readonly DynamicApiControllerManager _dynamicApiControllerManager; public ScriptProxyVueManager(DynamicApiControllerManager dynamicApiControllerManager) { _dynamicApiControllerManager = dynamicApiControllerManager; CachedScripts = new Dictionary<string, ScriptInfo>(); } public string GetScript(string name) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("name is null or empty!", "name"); } string cacheKey = "Vue_" + name; lock (CachedScripts) { ScriptInfo cachedScript = CachedScripts.GetOrDefault(cacheKey); if (cachedScript == null) { DynamicApiControllerInfo dynamicController = _dynamicApiControllerManager.GetAll().FirstOrDefault((DynamicApiControllerInfo ci) => ci.ServiceName == name && ci.IsProxyScriptingEnabled); if (dynamicController == null) { throw new HttpException(404, "There is no such a service: " + cacheKey); } string script = CreateProxyGenerator(dynamicController, amdModule: true).Generate(); cachedScript = (CachedScripts[cacheKey] = new ScriptInfo(script)); } return cachedScript.Script; } } public string GetAllScript() { lock (CachedScripts) { string cacheKey = "Vue_all"; if (!CachedScripts.ContainsKey(cacheKey)) { StringBuilder script = new StringBuilder(); //script.AppendLine("import request from '@/utils/request'\r\n"); //script.AppendLine("import request from './utils/request'\r\n"); script.AppendLine("(function(){"); script.AppendLine(" var serviceAppNamespace = abp.utils.createNamespace(abp, 'services.app');"); foreach (DynamicApiControllerInfo dynamicController in from ci in _dynamicApiControllerManager.GetAll() where ci.IsProxyScriptingEnabled select ci) { IScriptProxyGenerator proxyGenerator = CreateProxyGenerator(dynamicController, amdModule: false); script.AppendLine(proxyGenerator.Generate()); script.AppendLine(); } //script.AppendLine("\r\n export default { app: abp.services.app }"); script.AppendLine("})();"); CachedScripts[cacheKey] = new ScriptInfo(script.ToString()); } return CachedScripts[cacheKey].Script; } } private static IScriptProxyGenerator CreateProxyGenerator(DynamicApiControllerInfo controllerInfo, bool amdModule) { return new VueProxyGenerator(controllerInfo, amdModule); //switch (type) //{ // case ProxyScriptType.JQuery: // return new VueProxyGenerator(controllerInfo, amdModule); // case ProxyScriptType.Angular: // return new AngularProxyGenerator(controllerInfo); // default: // throw new AbpException("Unknown ProxyScriptType: " + type.ToString()); //} } } internal class VueProxyGenerator : IScriptProxyGenerator { private readonly DynamicApiControllerInfo _controllerInfo; private readonly bool _defineAmdModule; public VueProxyGenerator(DynamicApiControllerInfo controllerInfo, bool defineAmdModule = true) { _controllerInfo = controllerInfo; _defineAmdModule = defineAmdModule; } public string Generate() { StringBuilder script = new StringBuilder(); script.AppendLine("(function(){"); script.AppendLine(); //script.AppendLine(" var serviceNamespace = abp.utils.createNamespace(abp, 'services." + _controllerInfo.ServiceName.Replace("/", ".") + "');"); //获取接口名称 string servicerName = Regex.Replace(_controllerInfo.ServiceInterfaceType.Name, "I(?<str>.*?)AppService", "${str}"); //接口名称首字母小写 var nameChars = servicerName.ToCharArray(); if (nameChars[0] >= 'A' && nameChars[0] <= 'Z') { nameChars[0] = Char.ToLower(nameChars[0]); } //script.AppendLine(" export const " + new string(nameChars) + " = {"); script.AppendLine(" serviceAppNamespace['" + new string(nameChars) + "']={"); script.AppendLine(); foreach (DynamicApiActionInfo methodInfo2 in _controllerInfo.Actions.Values) { AppendMethod(script, _controllerInfo, methodInfo2); script.AppendLine(); } if (_defineAmdModule) { script.AppendLine(" if(typeof define === 'function' && define.amd){"); script.AppendLine(" define(function (require, exports, module) {"); script.AppendLine(" return {"); int methodNo = 0; foreach (DynamicApiActionInfo methodInfo in _controllerInfo.Actions.Values) { script.AppendLine(" '" + methodInfo.ActionName.ToCamelCase() + "' : serviceNamespace" + ProxyScriptingJsFuncHelper.WrapWithBracketsOrWithDotPrefix(methodInfo.ActionName.ToCamelCase()) + ((methodNo++ < _controllerInfo.Actions.Count - 1) ? "," : "")); } script.AppendLine(" };"); script.AppendLine(" });"); script.AppendLine(" }"); } script.AppendLine(); script.AppendLine(" }"); script.AppendLine("})();"); return script.ToString(); } private static void AppendMethod(StringBuilder script, DynamicApiControllerInfo controllerInfo, DynamicApiActionInfo methodInfo) { VueActionScriptGenerator generator = new VueActionScriptGenerator(controllerInfo, methodInfo); script.AppendLine(generator.GenerateMethod()); } } internal class VueActionScriptGenerator { private readonly DynamicApiControllerInfo _controllerInfo; private readonly DynamicApiActionInfo _actionInfo; private const string JsMethodTemplate = " serviceNamespace{jsMethodName} = function({jsMethodParameterList}) {\r\n return axios.post($.extend({\r\n{ajaxCallParameters}\r\n }, ajaxParams));\r\n };"; public VueActionScriptGenerator(DynamicApiControllerInfo controllerInfo, DynamicApiActionInfo actionInfo) { _controllerInfo = controllerInfo; _actionInfo = actionInfo; } public virtual string GenerateMethod() { string jsMethodName = _actionInfo.ActionName.ToCamelCase(); //string jsMethodParameterList = ActionScriptingHelper.GenerateJsMethodParameterList(_actionInfo.Method, "ajaxParams"); //return " serviceNamespace{jsMethodName} = function({jsMethodParameterList}) {\r\n return axios.post($.extend({\r\n{ajaxCallParameters}\r\n }, ajaxParams));\r\n };" // .Replace("{jsMethodName}", ProxyScriptingJsFuncHelper.WrapWithBracketsOrWithDotPrefix(jsMethodName)) // .Replace("{jsMethodParameterList}", jsMethodParameterList) // .Replace("{ajaxCallParameters}", GenerateAjaxCallParameters()); string jsMethodParameterList = ActionScriptingHelper.GenerateJsMethodParameterList(_actionInfo.Method); return " {jsMethodName}:function({jsMethodParameterList}) {\r\n return request({\r\n url:{ajaxCallParameters}, \r\n method:'{verb}'\r\n {inputParams} \r\n})\r\n }," .Replace("{jsMethodName}", jsMethodName) .Replace("{jsMethodParameterList}", jsMethodParameterList) .Replace("{inputParams}", string.IsNullOrWhiteSpace(jsMethodParameterList) ? string.Empty : ", data: " + jsMethodParameterList) .Replace("{ajaxCallParameters}", GenerateAjaxCallParameters()) .Replace("{verb}", _actionInfo.Verb.ToString().ToLower()); } protected string GenerateAjaxCallParameters() { //StringBuilder script = new StringBuilder(); //script.AppendLine(" url: abp.appPath + '" + ActionScriptingHelper.GenerateUrlWithParameters(_controllerInfo, _actionInfo) + "',"); //script.AppendLine(" type: '" + _actionInfo.Verb.ToString().ToUpperInvariant() + "',"); //if (_actionInfo.Verb == HttpVerb.Get) //{ // script.Append(" data: " + ActionScriptingHelper.GenerateBody(_actionInfo)); //} //else //{ // script.Append(" data: JSON.stringify(" + ActionScriptingHelper.GenerateBody(_actionInfo) + ")"); //} //return script.ToString(); StringBuilder script = new StringBuilder(); script.AppendLine(" abp.appPath + '" + ActionScriptingHelper.GenerateUrlWithParameters(_controllerInfo, _actionInfo) + "'"); return script.ToString(); } } // localhost:6234/api/AbpServiceProxiesVue/GetAll?v=637230113351569822' // 最终要返回的脚本,每个 api 都是一个 export function getAll(data) 脚本块 //import request from '@/utils/request' //export user ={ // getAll: function (data) //{ // return request({ // url: '/vue-element-admin/article/create', // method: 'post', // data // }) //} //get: function (data) //{ // return request({ // url: '/vue-element-admin/article/create', // method: 'post', // data // }) //} //} internal static class ActionScriptingHelper { public static string GenerateUrlWithParameters(DynamicApiControllerInfo controllerInfo, DynamicApiActionInfo actionInfo) { string baseUrl = "api/services/" + controllerInfo.ServiceName + "/" + actionInfo.ActionName; ParameterInfo[] primitiveParameters = (from p in actionInfo.Method.GetParameters() where TypeHelper.IsPrimitiveExtendedIncludingNullable(p.ParameterType) select p).ToArray(); if (!primitiveParameters.Any()) { return baseUrl; } string qsBuilderParams = primitiveParameters.Select((ParameterInfo p) => "{ name: '" + p.Name.ToCamelCase() + "', value: " + p.Name.ToCamelCase() + " }").JoinAsString(", "); return baseUrl + "' + abp.utils.buildQueryString([" + qsBuilderParams + "]) + '"; } public static string GenerateJsMethodParameterList(MethodInfo methodInfo, string ajaxParametersName = "") { List<string> paramNames = (from prm in methodInfo.GetParameters() select prm.Name.ToCamelCase()).ToList(); if (!string.IsNullOrWhiteSpace(ajaxParametersName)) { paramNames.Add(ajaxParametersName); } return string.Join(", ", paramNames); } public static string GenerateBody(DynamicApiActionInfo actionInfo) { ParameterInfo[] parameters = (from p in actionInfo.Method.GetParameters() where !TypeHelper.IsPrimitiveExtendedIncludingNullable(p.ParameterType) select p).ToArray(); if (parameters.Length == 0) { return "{}"; } if (parameters.Length > 1) { throw new AbpException("Only one complex type allowed as argument to a web api controller action. But " + actionInfo.ActionName + " contains more than one!"); } return parameters[0].Name.ToCamelCase(); } } /// <summary> /// Some simple type-checking methods used internally. /// </summary> internal static class TypeHelper { public static bool IsFunc(object obj) { if (obj == null) { return false; } Type type = obj.GetType(); if (!type.GetTypeInfo().IsGenericType) { return false; } return type.GetGenericTypeDefinition() == typeof(Func<>); } public static bool IsFunc<TReturn>(object obj) { if (obj != null) { return obj.GetType() == typeof(Func<TReturn>); } return false; } public static bool IsPrimitiveExtendedIncludingNullable(Type type, bool includeEnums = false) { if (IsPrimitiveExtended(type, includeEnums)) { return true; } if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { return IsPrimitiveExtended(type.GenericTypeArguments[0], includeEnums); } return false; } private static bool IsPrimitiveExtended(Type type, bool includeEnums) { if (type.GetTypeInfo().IsPrimitive) { return true; } if (includeEnums && type.GetTypeInfo().IsEnum) { return true; } if (!(type == typeof(string)) && !(type == typeof(decimal)) && !(type == typeof(DateTime)) && !(type == typeof(DateTimeOffset)) && !(type == typeof(TimeSpan))) { return type == typeof(Guid); } return true; } } internal interface IScriptProxyGenerator { string Generate(); } }