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();
    }
}
View Code

相关文章: