mirror of https://github.com/abpframework/abp
Dynamic Javascript Client for API Services #98
parent
67fca93d0f
commit
5ac3369a7f
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Volo.Abp.Http.ProxyScripting;
|
||||
using Volo.Abp.Http.ProxyScripting.Generators.JQuery;
|
||||
|
||||
namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting
|
||||
{
|
||||
public class ServiceProxyGenerationModel //: TODO: IShouldNormalize
|
||||
{
|
||||
public string Type { get; set; }
|
||||
|
||||
public bool UseCache { get; set; }
|
||||
|
||||
public string Modules { get; set; }
|
||||
|
||||
public string Controllers { get; set; }
|
||||
|
||||
public string Actions { get; set; }
|
||||
|
||||
public ServiceProxyGenerationModel()
|
||||
{
|
||||
UseCache = true;
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = JQueryProxyScriptGenerator.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public ProxyScriptingModel CreateOptions()
|
||||
{
|
||||
var options = new ProxyScriptingModel(Type, UseCache);
|
||||
|
||||
if (!Modules.IsNullOrEmpty())
|
||||
{
|
||||
options.Modules = Modules.Split('|').Select(m => m.Trim()).ToArray();
|
||||
}
|
||||
|
||||
if (!Controllers.IsNullOrEmpty())
|
||||
{
|
||||
options.Controllers = Controllers.Split('|').Select(m => m.Trim()).ToArray();
|
||||
}
|
||||
|
||||
if (!Actions.IsNullOrEmpty())
|
||||
{
|
||||
options.Actions = Actions.Split('|').Select(m => m.Trim()).ToArray();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Volo.Abp.Http.Modeling;
|
||||
|
||||
namespace Volo.Abp.Http.ProxyScripting.Generators
|
||||
{
|
||||
public interface IProxyScriptGenerator
|
||||
{
|
||||
string CreateScript(ApplicationApiDescriptionModel model);
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Http.Modeling;
|
||||
|
||||
namespace Volo.Abp.Http.ProxyScripting.Generators.JQuery
|
||||
{
|
||||
public class JQueryProxyScriptGenerator : IProxyScriptGenerator, ITransientDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// "jquery".
|
||||
/// </summary>
|
||||
public const string Name = "jquery";
|
||||
|
||||
public string CreateScript(ApplicationApiDescriptionModel model)
|
||||
{
|
||||
var script = new StringBuilder();
|
||||
|
||||
script.AppendLine("/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */");
|
||||
script.AppendLine();
|
||||
script.AppendLine("var abp = abp || {};");
|
||||
script.AppendLine("abp.services = abp.services || {};");
|
||||
|
||||
foreach (var module in model.Modules.Values)
|
||||
{
|
||||
script.AppendLine();
|
||||
AddModuleScript(script, module);
|
||||
}
|
||||
|
||||
return script.ToString();
|
||||
}
|
||||
|
||||
private static void AddModuleScript(StringBuilder script, ModuleApiDescriptionModel module)
|
||||
{
|
||||
script.AppendLine($"// module '{module.Name.ToCamelCase()}'");
|
||||
script.AppendLine("(function(){");
|
||||
script.AppendLine();
|
||||
script.AppendLine($" abp.services.{module.Name.ToCamelCase()} = abp.services.{module.Name.ToCamelCase()} || {{}};");
|
||||
|
||||
foreach (var controller in module.Controllers.Values)
|
||||
{
|
||||
script.AppendLine();
|
||||
AddControllerScript(script, module, controller);
|
||||
}
|
||||
|
||||
script.AppendLine();
|
||||
script.AppendLine("})();");
|
||||
}
|
||||
|
||||
private static void AddControllerScript(StringBuilder script, ModuleApiDescriptionModel module, ControllerApiDescriptionModel controller)
|
||||
{
|
||||
script.AppendLine($" // controller '{controller.ControllerName.ToCamelCase()}'");
|
||||
script.AppendLine(" (function(){");
|
||||
script.AppendLine();
|
||||
|
||||
script.AppendLine($" abp.services.{module.Name.ToCamelCase()}.{controller.ControllerName.ToCamelCase()} = abp.services.{module.Name.ToCamelCase()}.{controller.ControllerName.ToCamelCase()} || {{}};");
|
||||
|
||||
foreach (var action in controller.Actions.Values)
|
||||
{
|
||||
script.AppendLine();
|
||||
AddActionScript(script, module, controller, action);
|
||||
}
|
||||
|
||||
script.AppendLine();
|
||||
script.AppendLine(" })();");
|
||||
}
|
||||
|
||||
private static void AddActionScript(StringBuilder script, ModuleApiDescriptionModel module, ControllerApiDescriptionModel controller, ActionApiDescriptionModel action)
|
||||
{
|
||||
var parameterList = ProxyScriptingJsFuncHelper.GenerateJsFuncParameterList(action, "ajaxParams");
|
||||
|
||||
script.AppendLine($" // action '{action.NameOnClass.ToCamelCase()}'");
|
||||
script.AppendLine($" abp.services.{module.Name.ToCamelCase()}.{controller.ControllerName.ToCamelCase()}{ProxyScriptingJsFuncHelper.WrapWithBracketsOrWithDotPrefix(action.NameOnClass.ToCamelCase())} = function({parameterList}) {{");
|
||||
script.AppendLine(" return abp.ajax($.extend(true, {");
|
||||
|
||||
AddAjaxCallParameters(script, controller, action);
|
||||
|
||||
script.AppendLine(" }, ajaxParams));;");
|
||||
script.AppendLine(" };");
|
||||
}
|
||||
|
||||
private static void AddAjaxCallParameters(StringBuilder script, ControllerApiDescriptionModel controller, ActionApiDescriptionModel action)
|
||||
{
|
||||
var httpMethod = action.HttpMethod?.ToUpperInvariant() ?? "POST";
|
||||
|
||||
script.AppendLine(" url: abp.appPath + '" + ProxyScriptingHelper.GenerateUrlWithParameters(action) + "',");
|
||||
script.Append(" type: '" + httpMethod + "'");
|
||||
|
||||
if (action.ReturnValue.Type == typeof(void))
|
||||
{
|
||||
script.AppendLine(",");
|
||||
script.Append(" dataType: null");
|
||||
}
|
||||
|
||||
var headers = ProxyScriptingHelper.GenerateHeaders(action, 8);
|
||||
if (headers != null)
|
||||
{
|
||||
script.AppendLine(",");
|
||||
script.Append(" headers: " + headers);
|
||||
}
|
||||
|
||||
var body = ProxyScriptingHelper.GenerateBody(action);
|
||||
if (!body.IsNullOrEmpty())
|
||||
{
|
||||
script.AppendLine(",");
|
||||
script.Append(" data: JSON.stringify(" + body + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
var formData = ProxyScriptingHelper.GenerateFormPostData(action, 8);
|
||||
if (!formData.IsNullOrEmpty())
|
||||
{
|
||||
script.AppendLine(",");
|
||||
script.Append(" data: " + formData);
|
||||
}
|
||||
}
|
||||
|
||||
script.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
namespace Volo.Abp.Http.ProxyScripting.Generators
|
||||
{
|
||||
public static class ParameterBindingSources
|
||||
{
|
||||
public const string ModelBinding = "ModelBinding";
|
||||
public const string Query = "Query";
|
||||
public const string Body = "Body";
|
||||
public const string Path = "Path";
|
||||
public const string Form = "Form";
|
||||
public const string Header = "Header";
|
||||
public const string Custom = "Custom";
|
||||
public const string Services = "Services";
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Volo.Abp.Http.Modeling;
|
||||
|
||||
namespace Volo.Abp.Http.ProxyScripting.Generators
|
||||
{
|
||||
internal static class ProxyScriptingJsFuncHelper
|
||||
{
|
||||
private const string ValidJsVariableNameChars = "abcdefghijklmnopqrstuxwvyzABCDEFGHIJKLMNOPQRSTUXWVYZ0123456789_";
|
||||
|
||||
private static readonly HashSet<string> ReservedWords = new HashSet<string> {
|
||||
"abstract",
|
||||
"else",
|
||||
"instanceof",
|
||||
"super",
|
||||
"boolean",
|
||||
"enum",
|
||||
"int",
|
||||
"switch",
|
||||
"break",
|
||||
"export",
|
||||
"interface",
|
||||
"synchronized",
|
||||
"byte",
|
||||
"extends",
|
||||
"let",
|
||||
"this",
|
||||
"case",
|
||||
"false",
|
||||
"long",
|
||||
"throw",
|
||||
"catch",
|
||||
"final",
|
||||
"native",
|
||||
"throws",
|
||||
"char",
|
||||
"finally",
|
||||
"new",
|
||||
"transient",
|
||||
"class",
|
||||
"float",
|
||||
"null",
|
||||
"true",
|
||||
"const",
|
||||
"for",
|
||||
"package",
|
||||
"try",
|
||||
"continue",
|
||||
"function",
|
||||
"private",
|
||||
"typeof",
|
||||
"debugger",
|
||||
"goto",
|
||||
"protected",
|
||||
"var",
|
||||
"default",
|
||||
"if",
|
||||
"public",
|
||||
"void",
|
||||
"delete",
|
||||
"implements",
|
||||
"return",
|
||||
"volatile",
|
||||
"do",
|
||||
"import",
|
||||
"short",
|
||||
"while",
|
||||
"double",
|
||||
"in",
|
||||
"static",
|
||||
"with"
|
||||
};
|
||||
|
||||
public static string NormalizeJsVariableName(string name, string additionalChars = "")
|
||||
{
|
||||
var validChars = ValidJsVariableNameChars + additionalChars;
|
||||
|
||||
var sb = new StringBuilder(name);
|
||||
|
||||
sb.Replace('-', '_');
|
||||
|
||||
//Delete invalid chars
|
||||
foreach (var c in name)
|
||||
{
|
||||
if (!validChars.Contains(c))
|
||||
{
|
||||
sb.Replace(c.ToString(), "");
|
||||
}
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
{
|
||||
return "_" + Guid.NewGuid().ToString("N").Left(8);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string WrapWithBracketsOrWithDotPrefix(string name)
|
||||
{
|
||||
if (!ReservedWords.Contains(name))
|
||||
{
|
||||
return "." + name;
|
||||
}
|
||||
|
||||
return "['" + name + "']";
|
||||
}
|
||||
|
||||
public static string GetParamNameInJsFunc(ParameterApiDescriptionModel parameterInfo)
|
||||
{
|
||||
return parameterInfo.Name == parameterInfo.NameOnMethod
|
||||
? NormalizeJsVariableName(parameterInfo.Name.ToCamelCase(), ".")
|
||||
: NormalizeJsVariableName(parameterInfo.NameOnMethod.ToCamelCase()) + "." + NormalizeJsVariableName(parameterInfo.Name.ToCamelCase(), ".");
|
||||
}
|
||||
|
||||
public static string CreateJsObjectLiteral(ParameterApiDescriptionModel[] parameters, int indent = 0)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("{");
|
||||
|
||||
foreach (var prm in parameters)
|
||||
{
|
||||
sb.AppendLine($"{new string(' ', indent)} '{prm.Name}': {GetParamNameInJsFunc(prm)}");
|
||||
}
|
||||
|
||||
sb.Append(new string(' ', indent) + "}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GenerateJsFuncParameterList(ActionApiDescriptionModel action, string ajaxParametersName)
|
||||
{
|
||||
var methodParamNames = action.Parameters.Select(p => p.NameOnMethod).Distinct().ToList();
|
||||
methodParamNames.Add(ajaxParametersName);
|
||||
return methodParamNames.Select(prmName => NormalizeJsVariableName(prmName.ToCamelCase())).JoinAsString(", ");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace Volo.Abp.Http.ProxyScripting
|
||||
{
|
||||
public interface IProxyScriptManager
|
||||
{
|
||||
string GetScript(ProxyScriptingModel scriptingModel);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Volo.Abp.Http.ProxyScripting
|
||||
{
|
||||
public class ProxyScriptingModel
|
||||
{
|
||||
public string GeneratorType { get; set; }
|
||||
|
||||
public bool UseCache { get; set; }
|
||||
|
||||
public string[] Modules { get; set; }
|
||||
|
||||
public string[] Controllers { get; set; }
|
||||
|
||||
public string[] Actions { get; set; }
|
||||
|
||||
public IDictionary<string, string> Properties { get; set; }
|
||||
|
||||
public ProxyScriptingModel(string generatorType, bool useCache = true)
|
||||
{
|
||||
GeneratorType = generatorType;
|
||||
UseCache = useCache;
|
||||
|
||||
Properties = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public bool IsPartialRequest()
|
||||
{
|
||||
return !(Modules.IsNullOrEmpty() && Controllers.IsNullOrEmpty() && Actions.IsNullOrEmpty());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue