Browse Source

Merge pull request #9905 from abpframework/liangshiwei/services-proxy

Add C# and JavaScript Static Client Proxy Generation
pull/10041/head
Halil İbrahim Kalkan 5 years ago
committed by GitHub
parent
commit
b65122a3cd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      common.props
  2. 25
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  3. 13
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs
  4. 6
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestProxyHttpClientFactory.cs
  5. 15
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  6. 10
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
  7. 29
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs
  8. 163
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs
  9. 31
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs
  10. 15
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/AbpCliServiceProxyOptions.cs
  11. 115
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/Angular/AngularServiceProxyGenerator.cs
  12. 404
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs
  13. 55
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/GenerateProxyArgs.cs
  14. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/IServiceProxyGenerator.cs
  15. 90
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/JavaScript/JavaScriptServiceProxyGenerator.cs
  16. 56
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/ServiceProxyGeneratorBase.cs
  17. 46
      framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs
  18. 5
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs
  19. 107
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs
  20. 52
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs
  21. 11
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs
  22. 283
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  23. 4
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/ApiVersionInfo.cs
  24. 12
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/DefaultProxyHttpClientFactory.cs
  25. 2
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs
  26. 8
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpClientProxyConfig.cs
  27. 267
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpProxyExecuter.cs
  28. 30
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpProxyExecuterContext.cs
  29. 12
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/IHttpProxyExecuter.cs
  30. 6
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/IProxyHttpClientFactory.cs
  31. 3
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/RequestPayloadBuilder.cs
  32. 3
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/UrlBuilder.cs
  33. 7
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs
  34. 5
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs
  35. 4
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs
  36. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs
  37. 1
      framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj
  38. 42
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleModule.cs
  39. 13
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyControllerFeatureProvider.cs
  40. 16
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyHelper.cs
  41. 12
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyOptions.cs
  42. 249
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyServiceConvention.cs
  43. 30
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs
  44. 14
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.cs
  45. 231
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json
  46. 10
      modules/account/src/Volo.Abp.Account.HttpApi.Client/Volo/Abp/Account/AbpAccountHttpApiClientModule.cs
  47. 2
      modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs
  48. 6
      modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj
  49. 76
      modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js
  50. 45
      modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/BlogManagementClientProxy.Generated.cs
  51. 14
      modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/BlogManagementClientProxy.cs
  52. 243
      modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/bloggingAdmin-generate-proxy.json
  53. 8
      modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/Volo/Blogging/Admin/BloggingAdminHttpApiClientModule.cs
  54. 2
      modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminWebModule.cs
  55. 7
      modules/blogging/src/Volo.Blogging.Admin.Web/Pages/Blogging/Admin/Blogs/Index.cshtml
  56. 6
      modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.csproj
  57. 64
      modules/blogging/src/Volo.Blogging.Admin.Web/wwwroot/client-proxies/bloggingAdmin-proxy.js
  58. 24
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.Generated.cs
  59. 14
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.cs
  60. 30
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogsClientProxy.Generated.cs
  61. 14
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogsClientProxy.cs
  62. 36
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/CommentsClientProxy.Generated.cs
  63. 14
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/CommentsClientProxy.cs
  64. 49
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/PostsClientProxy.Generated.cs
  65. 14
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/PostsClientProxy.cs
  66. 21
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/TagsClientProxy.Generated.cs
  67. 14
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/TagsClientProxy.cs
  68. 856
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/blogging-generate-proxy.json
  69. 8
      modules/blogging/src/Volo.Blogging.HttpApi.Client/Volo/Blogging/BloggingHttpApiClientModule.cs
  70. 2
      modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs
  71. 5
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml
  72. 5
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml
  73. 1
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml
  74. 5
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml
  75. 6
      modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj
  76. 190
      modules/blogging/src/Volo.Blogging.Web/wwwroot/client-proxies/blogging-proxy.js
  77. 4
      modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/Properties/launchSettings.json
  78. 39
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogAdminClientProxy.Generated.cs
  79. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogAdminClientProxy.cs
  80. 26
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogFeatureAdminClientProxy.Generated.cs
  81. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogFeatureAdminClientProxy.cs
  82. 39
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.Generated.cs
  83. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.cs
  84. 29
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/CommentAdminClientProxy.Generated.cs
  85. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/CommentAdminClientProxy.cs
  86. 29
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/EntityTagAdminClientProxy.Generated.cs
  87. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/EntityTagAdminClientProxy.cs
  88. 24
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MediaDescriptorAdminClientProxy.Generated.cs
  89. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MediaDescriptorAdminClientProxy.cs
  90. 50
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MenuItemAdminClientProxy.Generated.cs
  91. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MenuItemAdminClientProxy.cs
  92. 39
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/PageAdminClientProxy.Generated.cs
  93. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/PageAdminClientProxy.cs
  94. 46
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/TagAdminClientProxy.Generated.cs
  95. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/TagAdminClientProxy.cs
  96. 1967
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json
  97. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/Volo/CmsKit/Admin/CmsKitAdminHttpApiClientModule.cs
  98. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs
  99. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml
  100. 10
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml

5
common.props

@ -28,4 +28,9 @@
</None>
</ItemGroup>
<ItemGroup Condition="$(AssemblyName.EndsWith('HttpApi.Client'))">
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
</Project>

25
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -86,6 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc
var controllerModel = moduleModel.GetOrAddController(
_options.ControllerNameGenerator(controllerType, setting),
FindGroupName(controllerType) ?? apiDescription.GroupName,
controllerType,
_modelOptions.IgnoredInterfaces
);
@ -113,6 +114,14 @@ namespace Volo.Abp.AspNetCore.Mvc
allowAnonymous = false;
}
var implementFrom = controllerType.FullName;
var interfaceType = controllerType.GetInterfaces().FirstOrDefault(i => i.GetMethods().Any(x => x.ToString() == method.ToString()));
if (interfaceType != null)
{
implementFrom = TypeHelper.GetFullNameHandlingNullableAndGenerics(interfaceType);
}
var actionModel = controllerModel.AddAction(
uniqueMethodName,
ActionApiDescriptionModel.Create(
@ -121,7 +130,8 @@ namespace Volo.Abp.AspNetCore.Mvc
apiDescription.RelativePath,
apiDescription.HttpMethod,
GetSupportedVersions(controllerType, method, setting),
allowAnonymous
allowAnonymous,
implementFrom
)
);
@ -351,6 +361,19 @@ namespace Volo.Abp.AspNetCore.Mvc
return ModuleApiDescriptionModel.DefaultRemoteServiceName;
}
private string FindGroupName(Type controllerType)
{
var controllerNameAttribute =
controllerType.GetCustomAttributes().OfType<ControllerNameAttribute>().FirstOrDefault();
if (controllerNameAttribute?.Name != null)
{
return controllerNameAttribute.Name;
}
return null;
}
[CanBeNull]
private ConventionalControllerSetting FindSetting(Type controllerType)
{

13
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs

@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
{
RemoveDuplicateControllers(application);
foreach (var controller in application.Controllers)
foreach (var controller in GetControllers(application))
{
var controllerType = controller.ControllerType.AsType();
@ -71,11 +71,16 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
}
}
protected virtual IList<ControllerModel> GetControllers(ApplicationModel application)
{
return application.Controllers;
}
protected virtual void RemoveDuplicateControllers(ApplicationModel application)
{
var controllerModelsToRemove = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers)
foreach (var controllerModel in GetControllers(application))
{
if (!controllerModel.ControllerType.IsDefined(typeof(ExposeServicesAttribute), false))
{
@ -90,7 +95,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var exposedControllerModels = application.Controllers
var exposedControllerModels = GetControllers(application)
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
@ -109,7 +114,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
continue;
}
var baseControllerModels = application.Controllers
var baseControllerModels = GetControllers(application)
.Where(cm => baseControllerTypes.Contains(cm.ControllerType))
.ToArray();

6
framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs → framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestProxyHttpClientFactory.cs

@ -1,15 +1,17 @@
using System.Net.Http;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Client.Proxying;
namespace Volo.Abp.AspNetCore.TestBase.DynamicProxying
{
[Dependency(ReplaceServices = true)]
public class AspNetCoreTestDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency
public class AspNetCoreTestProxyHttpClientFactory : IProxyHttpClientFactory, ITransientDependency
{
private readonly ITestServerAccessor _testServerAccessor;
public AspNetCoreTestDynamicProxyHttpClientFactory(
public AspNetCoreTestProxyHttpClientFactory(
ITestServerAccessor testServerAccessor)
{
_testServerAccessor = testServerAccessor;

15
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs

@ -3,7 +3,12 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.LIbs;
using Volo.Abp.Cli.ServiceProxying;
using Volo.Abp.Cli.ServiceProxying.Angular;
using Volo.Abp.Cli.ServiceProxying.CSharp;
using Volo.Abp.Cli.ServiceProxying.JavaScript;
using Volo.Abp.Domain;
using Volo.Abp.Http;
using Volo.Abp.IdentityModel;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
@ -16,7 +21,8 @@ namespace Volo.Abp.Cli
typeof(AbpDddDomainModule),
typeof(AbpJsonModule),
typeof(AbpIdentityModelModule),
typeof(AbpMinifyModule)
typeof(AbpMinifyModule),
typeof(AbpHttpModule)
)]
public class AbpCliCoreModule : AbpModule
{
@ -58,6 +64,13 @@ namespace Volo.Abp.Cli
options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigratorCommand);
options.Commands["install-libs"] = typeof(InstallLibsCommand);
});
Configure<AbpCliServiceProxyOptions>(options =>
{
options.Generators[JavaScriptServiceProxyGenerator.Name] = typeof(JavaScriptServiceProxyGenerator);
options.Generators[AngularServiceProxyGenerator.Name] = typeof(AngularServiceProxyGenerator);
options.Generators[CSharpServiceProxyGenerator.Name] = typeof(CSharpServiceProxyGenerator);
});
}
}
}

10
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs

@ -1,4 +1,6 @@
namespace Volo.Abp.Cli
using System;
namespace Volo.Abp.Cli
{
public static class CliUrls
{
@ -33,5 +35,11 @@
{
return $"{NuGetRootPath}{apiKey}/v3/package/{packageId}/index.json";
}
public static string GetApiDefinitionUrl(string url)
{
url = url.EnsureEndsWith('/');
return $"{url}api/abp/api-definition";
}
}
}

29
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs

@ -1,21 +1,40 @@
using System.Text;
using Microsoft.Extensions.Options;
using Volo.Abp.Cli.ServiceProxying;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class GenerateProxyCommand : ProxyCommandBase
public class GenerateProxyCommand : ProxyCommandBase<GenerateProxyCommand>
{
public const string Name = "generate-proxy";
protected override string CommandName => Name;
protected override string SchematicsCommandName => "proxy-add";
public GenerateProxyCommand(
IOptions<AbpCliServiceProxyOptions> serviceProxyOptions,
IHybridServiceScopeFactory serviceScopeFactory)
: base(serviceProxyOptions, serviceScopeFactory)
{
}
public GenerateProxyCommand(CliService cliService)
: base(cliService)
public override string GetUsageInfo()
{
var sb = new StringBuilder(base.GetUsageInfo());
sb.AppendLine("");
sb.AppendLine("Examples:");
sb.AppendLine("");
sb.AppendLine(" abp generate-proxy -t ng");
sb.AppendLine(" abp generate-proxy -t js -m identity -o Pages/Identity/client-proxies.js -url https://localhost:44302/");
sb.AppendLine(" abp generate-proxy -t csharp --folder MyProxies/InnerFolder -url https://localhost:44302/");
return sb.ToString();
}
public override string GetShortDescription()
{
return "Generates Angular service proxies and DTOs to consume HTTP APIs.";
return "Generates client service proxies and DTOs to consume HTTP APIs.";
}
}
}

163
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs

@ -4,121 +4,74 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json.Linq;
using NuGet.Versioning;
using Microsoft.Extensions.Options;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Utils;
using Volo.Abp.Cli.ServiceProxying;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public abstract class ProxyCommandBase : IConsoleCommand, ITransientDependency
public abstract class ProxyCommandBase<T> : IConsoleCommand, ITransientDependency where T: IConsoleCommand
{
public CliService CliService { get; }
public ILogger<HelpCommand> Logger { get; set; }
public ILogger<T> Logger { get; set; }
protected abstract string CommandName { get; }
protected abstract string SchematicsCommandName { get; }
protected AbpCliServiceProxyOptions ServiceProxyOptions { get; }
public ProxyCommandBase(CliService cliService)
{
CliService = cliService;
Logger = NullLogger<HelpCommand>.Instance;
}
protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
public ProxyCommandBase(
IOptions<AbpCliServiceProxyOptions> serviceProxyOptions,
IHybridServiceScopeFactory serviceScopeFactory)
{
CheckAngularJsonFile();
await CheckNgSchematicsAsync();
var prompt = commandLineArgs.Options.ContainsKey("p") || commandLineArgs.Options.ContainsKey("prompt");
var defaultValue = prompt ? null : "__default";
var module = commandLineArgs.Options.GetOrNull(Options.Module.Short, Options.Module.Long) ?? defaultValue;
var apiName = commandLineArgs.Options.GetOrNull(Options.ApiName.Short, Options.ApiName.Long) ?? defaultValue;
var source = commandLineArgs.Options.GetOrNull(Options.Source.Short, Options.Source.Long) ?? defaultValue;
var target = commandLineArgs.Options.GetOrNull(Options.Target.Short, Options.Target.Long) ?? defaultValue;
var commandBuilder = new StringBuilder("npx ng g @abp/ng.schematics:" + SchematicsCommandName);
if (module != null)
{
commandBuilder.Append($" --module {module}");
}
if (apiName != null)
{
commandBuilder.Append($" --api-name {apiName}");
}
if (source != null)
{
commandBuilder.Append($" --source {source}");
}
if (target != null)
{
commandBuilder.Append($" --target {target}");
}
CmdHelper.RunCmd(commandBuilder.ToString());
ServiceScopeFactory = serviceScopeFactory;
ServiceProxyOptions = serviceProxyOptions.Value;
Logger = NullLogger<T>.Instance;
}
private async Task CheckNgSchematicsAsync()
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
var packageJsonPath = $"package.json";
var generateType = commandLineArgs.Options.GetOrNull(Options.GenerateType.Short, Options.GenerateType.Long)?.ToUpper();
if (!File.Exists(packageJsonPath))
if (string.IsNullOrWhiteSpace(generateType))
{
throw new CliUsageException(
"package.json file not found" +
throw new CliUsageException("Option Type is required" +
Environment.NewLine +
GetUsageInfo()
);
GetUsageInfo());
}
var schematicsVersion =
(string) JObject.Parse(File.ReadAllText(packageJsonPath))["devDependencies"]?["@abp/ng.schematics"];
if (schematicsVersion == null)
if (!ServiceProxyOptions.Generators.ContainsKey(generateType))
{
throw new CliUsageException(
"\"@abp/ng.schematics\" NPM package should be installed to the devDependencies before running this command!" +
throw new CliUsageException("Option Type value is invalid" +
Environment.NewLine +
GetUsageInfo()
);
GetUsageInfo());
}
var parseError = SemanticVersion.TryParse(schematicsVersion.TrimStart('~', '^', 'v'), out var semanticSchematicsVersion);
if (parseError)
using (var scope = ServiceScopeFactory.CreateScope())
{
Logger.LogWarning("Couldn't determinate version of \"@abp/ng.schematics\" package.");
return;
}
var generatorType = ServiceProxyOptions.Generators[generateType];
var serviceProxyGenerator = scope.ServiceProvider.GetService(generatorType).As<IServiceProxyGenerator>();
var cliVersion = await CliService.GetCurrentCliVersionAsync(typeof(CliService).Assembly);
if (semanticSchematicsVersion < cliVersion)
{
Logger.LogWarning("\"@abp/ng.schematics\" version is lower than ABP Cli version.");
return;
await serviceProxyGenerator.GenerateProxyAsync(BuildArgs(commandLineArgs));
}
}
private void CheckAngularJsonFile()
private GenerateProxyArgs BuildArgs(CommandLineArgs commandLineArgs)
{
var angularPath = $"angular.json";
if (!File.Exists(angularPath))
{
throw new CliUsageException(
"angular.json file not found. You must run this command in the angular folder." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var url = commandLineArgs.Options.GetOrNull(Options.Url.Short, Options.Url.Long);
var target = commandLineArgs.Options.GetOrNull(Options.Target.Long);
var module = commandLineArgs.Options.GetOrNull(Options.Module.Short, Options.Module.Long) ?? "app";
var output = commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long);
var apiName = commandLineArgs.Options.GetOrNull(Options.ApiName.Short, Options.ApiName.Long);
var source = commandLineArgs.Options.GetOrNull(Options.Source.Short, Options.Source.Long);
var workDirectory = commandLineArgs.Options.GetOrNull(Options.WorkDirectory.Short, Options.WorkDirectory.Long) ?? Directory.GetCurrentDirectory();
var folder = commandLineArgs.Options.GetOrNull(Options.Folder.Long);
return new GenerateProxyArgs(CommandName, workDirectory, module, url, output, target, apiName, source, folder, commandLineArgs.Options);
}
public string GetUsageInfo()
public virtual string GetUsageInfo()
{
var sb = new StringBuilder();
@ -129,11 +82,16 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine("");
sb.AppendLine("Options:");
sb.AppendLine("");
sb.AppendLine("-m|--module <module-name> (default: 'app') The name of the backend module you wish to generate proxies for.");
sb.AppendLine("-a|--api-name <module-name> (default: 'default') The name of the API endpoint defined in the /src/environments/environment.ts.");
sb.AppendLine("-s|--source <source-name> (default: 'defaultProject') Angular project name to resolve the root namespace & API definition URL from.");
sb.AppendLine("-t|--target <target-name> (default: 'defaultProject') Angular project name to place generated code in.");
sb.AppendLine("-p|--prompt Asks the options from the command line prompt (for the missing options)");
sb.AppendLine("-m|--module <module-name> (default: 'app') The name of the backend module you wish to generate proxies for.");
sb.AppendLine("-t|--type <generate-type> The name of generate type (csharp, js, ng).");
sb.AppendLine("-wd|--working-directory <directory-path> Execution directory.");
sb.AppendLine("-u|--url <url> API definition URL from.");
sb.AppendLine("-a|--api-name <module-name> (default: 'default') The name of the API endpoint defined in the /src/environments/environment.ts.");
sb.AppendLine("-s|--source <source-name> (default: 'defaultProject') Angular project name to resolve the root namespace & API definition URL from.");
sb.AppendLine("-o|--output <output-name> JavaScript file path or folder to place generated code in.");
sb.AppendLine("-p|--prompt Asks the options from the command line prompt (for the missing options)");
sb.AppendLine("--target <target-name> (default: 'defaultProject') Angular project name to place generated code in.");
sb.AppendLine("--folder <folder-name> (default: 'ClientProxies') Folder name to place generated CSharp code in.");
sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
@ -150,6 +108,12 @@ namespace Volo.Abp.Cli.Commands
public const string Long = "module";
}
public static class GenerateType
{
public const string Short = "t";
public const string Long = "type";
}
public static class ApiName
{
public const string Short = "a";
@ -161,10 +125,14 @@ namespace Volo.Abp.Cli.Commands
public const string Short = "s";
public const string Long = "source";
}
public static class Output
{
public const string Short = "o";
public const string Long = "output";
}
public static class Target
{
public const string Short = "t";
public const string Long = "target";
}
@ -173,6 +141,23 @@ namespace Volo.Abp.Cli.Commands
public const string Short = "p";
public const string Long = "prompt";
}
public static class Folder
{
public const string Long = "folder";
}
public static class Url
{
public const string Short = "u";
public const string Long = "url";
}
public static class WorkDirectory
{
public const string Short = "wd";
public const string Long = "working-directory";
}
}
}
}

31
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs

@ -1,21 +1,40 @@
namespace Volo.Abp.Cli.Commands
using System.Text;
using Microsoft.Extensions.Options;
using Volo.Abp.Cli.ServiceProxying;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class RemoveProxyCommand : ProxyCommandBase
public class RemoveProxyCommand : ProxyCommandBase<RemoveProxyCommand>
{
public const string Name = "remove-proxy";
protected override string CommandName => Name;
protected override string SchematicsCommandName => "proxy-remove";
public RemoveProxyCommand(
IOptions<AbpCliServiceProxyOptions> serviceProxyOptions,
IHybridServiceScopeFactory serviceScopeFactory)
: base(serviceProxyOptions, serviceScopeFactory)
{
}
public RemoveProxyCommand(CliService cliService)
: base(cliService)
public override string GetUsageInfo()
{
var sb = new StringBuilder(base.GetUsageInfo());
sb.AppendLine("");
sb.AppendLine("Examples:");
sb.AppendLine("");
sb.AppendLine(" abp remove-proxy -t ng");
sb.AppendLine(" abp remove-proxy -t js -m identity -o Pages/Identity/client-proxies.js");
sb.AppendLine(" abp remove-proxy -t csharp --folder MyProxies/InnerFolder");
return sb.ToString();
}
public override string GetShortDescription()
{
return "Remove Angular service proxies and DTOs to consume HTTP APIs.";
return "Remove client service proxies and DTOs to consume HTTP APIs.";
}
}
}

15
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/AbpCliServiceProxyOptions.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Cli.ServiceProxying
{
public class AbpCliServiceProxyOptions
{
public IDictionary<string, Type> Generators { get; }
public AbpCliServiceProxyOptions()
{
Generators = new Dictionary<string, Type>();
}
}
}

115
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/Angular/AngularServiceProxyGenerator.cs

@ -0,0 +1,115 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using NuGet.Versioning;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.ServiceProxying.Angular
{
public class AngularServiceProxyGenerator : ServiceProxyGeneratorBase<AngularServiceProxyGenerator> , ITransientDependency
{
public const string Name = "NG";
private readonly CliService _cliService;
public AngularServiceProxyGenerator(
CliHttpClientFactory cliHttpClientFactory,
IJsonSerializer jsonSerializer,
CliService cliService) :
base(cliHttpClientFactory, jsonSerializer)
{
_cliService = cliService;
}
public override async Task GenerateProxyAsync(GenerateProxyArgs args)
{
CheckAngularJsonFile();
await CheckNgSchematicsAsync();
var schematicsCommandName = args.CommandName == RemoveProxyCommand.Name ? "proxy-remove" : "proxy-add";
var prompt = args.ExtraProperties.ContainsKey("p") || args.ExtraProperties.ContainsKey("prompt");
var defaultValue = prompt ? null : "__default";
var module = args.Module ?? defaultValue;
var apiName = args.ApiName ?? defaultValue;
var source = args.Source ?? defaultValue;
var target = args.Target ?? defaultValue;
var commandBuilder = new StringBuilder("npx ng g @abp/ng.schematics:" + schematicsCommandName);
if (module != null)
{
commandBuilder.Append($" --module {module}");
}
if (apiName != null)
{
commandBuilder.Append($" --api-name {apiName}");
}
if (source != null)
{
commandBuilder.Append($" --source {source}");
}
if (target != null)
{
commandBuilder.Append($" --target {target}");
}
CmdHelper.RunCmd(commandBuilder.ToString());
}
private async Task CheckNgSchematicsAsync()
{
var packageJsonPath = $"package.json";
if (!File.Exists(packageJsonPath))
{
throw new CliUsageException(
"package.json file not found"
);
}
var schematicsVersion =
(string) JObject.Parse(File.ReadAllText(packageJsonPath))["devDependencies"]?["@abp/ng.schematics"];
if (schematicsVersion == null)
{
throw new CliUsageException(
"\"@abp/ng.schematics\" NPM package should be installed to the devDependencies before running this command!"
);
}
var parseError = SemanticVersion.TryParse(schematicsVersion.TrimStart('~', '^', 'v'), out var semanticSchematicsVersion);
if (parseError)
{
Logger.LogWarning("Couldn't determinate version of \"@abp/ng.schematics\" package.");
return;
}
var cliVersion = await _cliService.GetCurrentCliVersionAsync(typeof(CliService).Assembly);
if (semanticSchematicsVersion < cliVersion)
{
Logger.LogWarning("\"@abp/ng.schematics\" version is lower than ABP Cli version.");
}
}
private static void CheckAngularJsonFile()
{
var angularPath = $"angular.json";
if (!File.Exists(angularPath))
{
throw new CliUsageException(
"angular.json file not found. You must run this command in the angular folder."
);
}
}
}
}

404
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs

@ -0,0 +1,404 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.ServiceProxying.CSharp
{
public class CSharpServiceProxyGenerator : ServiceProxyGeneratorBase<CSharpServiceProxyGenerator>, ITransientDependency
{
public const string Name = "CSHARP";
private const string UsingPlaceholder = "<using placeholder>";
private const string MethodPlaceholder = "<method placeholder>";
private const string ClassName = "<className>";
private const string ServiceInterface = "<serviceInterface>";
private const string ServicePostfix = "AppService";
private const string DefaultNamespace = "ClientProxies";
private const string Namespace = "<namespace>";
private const string AppServicePrefix = "Volo.Abp.Application.Services";
private readonly string _clientProxyGeneratedTemplate = "// This file is automatically generated by ABP framework to use MVC Controllers from CSharp" +
$"{Environment.NewLine}<using placeholder>" +
$"{Environment.NewLine}" +
$"{Environment.NewLine}// ReSharper disable once CheckNamespace" +
$"{Environment.NewLine}namespace <namespace>" +
$"{Environment.NewLine}{{" +
$"{Environment.NewLine} public partial class <className>" +
$"{Environment.NewLine} {{" +
$"{Environment.NewLine} <method placeholder>" +
$"{Environment.NewLine} }}" +
$"{Environment.NewLine}}}" +
$"{Environment.NewLine}";
private readonly string _clientProxyTemplate = "// This file is part of <className>, you can customize it here" +
$"{Environment.NewLine}using Volo.Abp.DependencyInjection;" +
$"{Environment.NewLine}using Volo.Abp.Http.Client.ClientProxying;" +
$"{Environment.NewLine}<using placeholder>" +
$"{Environment.NewLine}" +
$"{Environment.NewLine}// ReSharper disable once CheckNamespace" +
$"{Environment.NewLine}namespace <namespace>" +
$"{Environment.NewLine}{{" +
$"{Environment.NewLine} [Dependency(ReplaceServices = true)]" +
$"{Environment.NewLine} [ExposeServices(typeof(<serviceInterface>), typeof(<className>))]" +
$"{Environment.NewLine} public partial class <className> : ClientProxyBase<<serviceInterface>>, <serviceInterface>" +
$"{Environment.NewLine} {{" +
$"{Environment.NewLine} }}" +
$"{Environment.NewLine}}}" +
$"{Environment.NewLine}";
private readonly List<string> _usingNamespaceList = new()
{
"using System;",
"using System.Threading.Tasks;",
"using Volo.Abp.Application.Dtos;",
"using Volo.Abp.Http.Client;",
"using Volo.Abp.Http.Modeling;"
};
public CSharpServiceProxyGenerator(
CliHttpClientFactory cliHttpClientFactory,
IJsonSerializer jsonSerializer) :
base(cliHttpClientFactory, jsonSerializer)
{
}
public override async Task GenerateProxyAsync(GenerateProxyArgs args)
{
CheckWorkDirectory(args.WorkDirectory);
CheckFolder(args.Folder);
if (args.CommandName == RemoveProxyCommand.Name)
{
RemoveClientProxyFile(args);
return;
}
var applicationApiDescriptionModel = await GetApplicationApiDescriptionModelAsync(args);
foreach (var controller in applicationApiDescriptionModel.Modules.Values.SelectMany(x => x.Controllers))
{
if (ShouldGenerateProxy(controller.Value))
{
await GenerateClientProxyFileAsync(args, controller.Value);
}
}
await CreateGenerateProxyJsonFile(args, applicationApiDescriptionModel);
}
private async Task CreateGenerateProxyJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel)
{
var folder = args.Folder.IsNullOrWhiteSpace()? DefaultNamespace : args.Folder;
var filePath = Path.Combine(args.WorkDirectory, folder, $"{args.Module}-generate-proxy.json");
using (var writer = new StreamWriter(filePath))
{
await writer.WriteAsync(JsonSerializer.Serialize(applicationApiDescriptionModel, indented: true));
}
}
private void RemoveClientProxyFile(GenerateProxyArgs args)
{
var folder = args.Folder.IsNullOrWhiteSpace()? DefaultNamespace : args.Folder;
var folderPath = Path.Combine(args.WorkDirectory, folder);
if (Directory.Exists(folderPath))
{
Directory.Delete(folderPath, true);
}
Logger.LogInformation($"Delete {GetLoggerOutputPath(folderPath, args.WorkDirectory)}");
}
private async Task GenerateClientProxyFileAsync(
GenerateProxyArgs args,
ControllerApiDescriptionModel controllerApiDescription)
{
var folder = args.Folder.IsNullOrWhiteSpace()? DefaultNamespace : args.Folder;
var appServiceTypeFullName = controllerApiDescription.Interfaces.Last().Type;
var appServiceTypeName = appServiceTypeFullName.Split('.').Last();
var clientProxyName = $"{controllerApiDescription.ControllerName}ClientProxy";
var rootNamespace = $"{GetTypeNamespace(controllerApiDescription.Type)}.{folder.Replace('/', '.')}";
var clientProxyBuilder = new StringBuilder(_clientProxyTemplate);
clientProxyBuilder.Replace(ClassName, clientProxyName);
clientProxyBuilder.Replace(Namespace, rootNamespace);
clientProxyBuilder.Replace(ServiceInterface, appServiceTypeName);
clientProxyBuilder.Replace(UsingPlaceholder, $"using {GetTypeNamespace(appServiceTypeFullName)};");
var filePath = Path.Combine(args.WorkDirectory, folder, $"{clientProxyName}.cs");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
if (!File.Exists(filePath))
{
using (var writer = new StreamWriter(filePath))
{
await writer.WriteAsync(clientProxyBuilder.ToString());
}
Logger.LogInformation($"Create {GetLoggerOutputPath(filePath, args.WorkDirectory)}");
}
await GenerateClientProxyGeneratedFileAsync(
args,
controllerApiDescription,
clientProxyName,
appServiceTypeName,
appServiceTypeFullName,
rootNamespace,
folder);
}
private async Task GenerateClientProxyGeneratedFileAsync(
GenerateProxyArgs args,
ControllerApiDescriptionModel controllerApiDescription,
string clientProxyName,
string appServiceTypeName,
string appServiceTypeFullName,
string rootNamespace,
string folder)
{
var clientProxyBuilder = new StringBuilder(_clientProxyGeneratedTemplate);
var usingNamespaceList = new List<string>(_usingNamespaceList)
{
$"using {GetTypeNamespace(appServiceTypeFullName)};"
};
clientProxyBuilder.Replace(ClassName, clientProxyName);
clientProxyBuilder.Replace(Namespace, rootNamespace);
clientProxyBuilder.Replace(ServiceInterface, appServiceTypeName);
foreach (var action in controllerApiDescription.Actions.Values)
{
if (!ShouldGenerateMethod(appServiceTypeFullName, action))
{
continue;
}
GenerateMethod(action, clientProxyBuilder, usingNamespaceList);
}
foreach (var usingNamespace in usingNamespaceList)
{
clientProxyBuilder.Replace($"{UsingPlaceholder}", $"{usingNamespace}{Environment.NewLine}{UsingPlaceholder}");
}
clientProxyBuilder.Replace($"{Environment.NewLine}{UsingPlaceholder}", string.Empty);
clientProxyBuilder.Replace($"{Environment.NewLine}{Environment.NewLine} {MethodPlaceholder}", string.Empty);
var filePath = Path.Combine(args.WorkDirectory, folder, $"{clientProxyName}.Generated.cs");
using (var writer = new StreamWriter(filePath))
{
await writer.WriteAsync(clientProxyBuilder.ToString());
Logger.LogInformation($"Create {GetLoggerOutputPath(filePath, args.WorkDirectory)}");
}
}
private void GenerateMethod(
ActionApiDescriptionModel action,
StringBuilder clientProxyBuilder,
List<string> usingNamespaceList)
{
var methodBuilder = new StringBuilder();
var returnTypeName = GetRealTypeName(usingNamespaceList, action.ReturnValue.Type);
if(!action.Name.EndsWith("Async"))
{
GenerateSynchronizationMethod(action, returnTypeName, methodBuilder, usingNamespaceList);
clientProxyBuilder.Replace(MethodPlaceholder, $"{methodBuilder}{Environment.NewLine} {MethodPlaceholder}");
return;
}
GenerateAsynchronousMethod(action, returnTypeName, methodBuilder, usingNamespaceList);
clientProxyBuilder.Replace(MethodPlaceholder, $"{methodBuilder}{Environment.NewLine} {MethodPlaceholder}");
}
private void GenerateSynchronizationMethod(ActionApiDescriptionModel action, string returnTypeName, StringBuilder methodBuilder, List<string> usingNamespaceList)
{
methodBuilder.AppendLine($"public virtual {returnTypeName} {action.Name}(<args>)");
foreach (var parameter in action.Parameters.GroupBy(x => x.Name).Select( x=> x.First()))
{
methodBuilder.Replace("<args>", $"{GetRealTypeName(usingNamespaceList, parameter.Type)} {parameter.Name}, <args>");
}
methodBuilder.Replace("<args>", string.Empty);
methodBuilder.Replace(", )", ")");
methodBuilder.AppendLine(" {");
methodBuilder.AppendLine(" //Client Proxy does not support the synchronization method, you should always use asynchronous methods as a best practice");
methodBuilder.AppendLine(" throw new System.NotImplementedException(); ");
methodBuilder.AppendLine(" }");
}
private void GenerateAsynchronousMethod(
ActionApiDescriptionModel action,
string returnTypeName,
StringBuilder methodBuilder,
List<string> usingNamespaceList)
{
var returnSign = returnTypeName == "void" ? "Task": $"Task<{returnTypeName}>";
methodBuilder.AppendLine($"public virtual async {returnSign} {action.Name}(<args>)");
foreach (var parameter in action.ParametersOnMethod)
{
methodBuilder.Replace("<args>", $"{GetRealTypeName(usingNamespaceList, parameter.Type)} {parameter.Name}, <args>");
}
methodBuilder.Replace("<args>", string.Empty);
methodBuilder.Replace(", )", ")");
methodBuilder.AppendLine(" {");
if (returnTypeName == "void")
{
methodBuilder.AppendLine($" await RequestAsync(nameof({action.Name}), <args>);");
}
else
{
methodBuilder.AppendLine($" return await RequestAsync<{returnTypeName}>(nameof({action.Name}), <args>);");
}
foreach (var parameter in action.ParametersOnMethod)
{
methodBuilder.Replace("<args>", $"{parameter.Name}, <args>");
}
methodBuilder.Replace("<args>", string.Empty);
methodBuilder.Replace(", )", ")");
methodBuilder.AppendLine(" }");
}
private bool ShouldGenerateProxy(ControllerApiDescriptionModel controllerApiDescription)
{
if (!controllerApiDescription.Interfaces.Any())
{
return false;
}
var serviceInterface = controllerApiDescription.Interfaces.Last();
return serviceInterface.Type.EndsWith(ServicePostfix);
}
private bool ShouldGenerateMethod(string appServiceTypeName, ActionApiDescriptionModel action)
{
return action.ImplementFrom.StartsWith(AppServicePrefix) || action.ImplementFrom.StartsWith(appServiceTypeName);
}
private string GetTypeNamespace(string typeFullName)
{
return typeFullName.Substring(0, typeFullName.LastIndexOf('.'));
}
private string GetRealTypeName(List<string> usingNamespaceList, string typeName)
{
var filter = new []{"<", ",", ">"};
var stringBuilder = new StringBuilder();
var typeNames = typeName.Split('.');
if (typeNames.All(x => !filter.Any(x.Contains)))
{
AddUsingNamespace(usingNamespaceList, typeName);
return NormalizeTypeName(typeNames.Last());
}
var fullName = string.Empty;
foreach (var item in typeNames)
{
if (filter.Any(x => item.Contains(x)))
{
AddUsingNamespace(usingNamespaceList, $"{fullName}.{item}".TrimStart('.'));
fullName = string.Empty;
if (item.Contains('<') || item.Contains(','))
{
stringBuilder.Append(item.Substring(0, item.IndexOf(item.Contains('<') ? '<' : ',')+1));
fullName = item.Substring(item.IndexOf(item.Contains('<') ? '<' : ',') + 1);
}
else
{
stringBuilder.Append(item);
}
}
else
{
fullName = $"{fullName}.{item}";
}
}
return stringBuilder.ToString();
}
private void AddUsingNamespace(List<string> usingNamespaceList, string typeName)
{
var rootNamespace = $"using {GetTypeNamespace(typeName)};";
if (usingNamespaceList.Contains(rootNamespace))
{
return;
}
usingNamespaceList.Add(rootNamespace);
}
private string NormalizeTypeName(string typeName)
{
var nullable = string.Empty;
if (typeName.EndsWith("?"))
{
typeName = typeName.TrimEnd('?');
nullable = "?";
}
typeName = typeName switch
{
"Void" => "void",
"Boolean" => "bool",
"String" => "string",
"Int32" => "int",
"Int64" => "long",
"Double" => "double",
"Object" => "object",
"Byte" => "byte",
"Char" => "char",
_ => typeName
};
return $"{typeName}{nullable}";
}
private void CheckWorkDirectory(string directory)
{
if (!Directory.Exists(directory))
{
throw new CliUsageException("Specified directory does not exist.");
}
var projectFiles = Directory.GetFiles(directory, "*HttpApi.Client.csproj");
if (!projectFiles.Any())
{
throw new CliUsageException(
"No project file found in the directory. The working directory must have a HttpApi.Client project file.");
}
}
private void CheckFolder(string folder)
{
if (!folder.IsNullOrWhiteSpace() && Path.HasExtension(folder))
{
throw new CliUsageException("Option folder should be a directory.");
}
}
}
}

55
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/GenerateProxyArgs.cs

@ -0,0 +1,55 @@
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.Cli.ServiceProxying
{
public class GenerateProxyArgs
{
[NotNull]
public string CommandName { get; }
[NotNull]
public string WorkDirectory { get; }
public string Module { get; }
public string Url { get; }
public string Output { get; }
public string Target { get; }
public string ApiName { get; }
public string Source { get; }
public string Folder { get; }
[NotNull]
public Dictionary<string, string> ExtraProperties { get; set; }
public GenerateProxyArgs(
[NotNull] string commandName,
[NotNull] string workDirectory,
string module,
string url,
string output,
string target,
string apiName,
string source,
string folder,
Dictionary<string, string> extraProperties = null)
{
CommandName = Check.NotNullOrWhiteSpace(commandName, nameof(commandName));
WorkDirectory = Check.NotNullOrWhiteSpace(workDirectory, nameof(workDirectory));
Module = module;
Url = url;
Output = output;
Target = target;
ApiName = apiName;
Source = source;
Folder = folder;
ExtraProperties = extraProperties ?? new Dictionary<string, string>();
}
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/IServiceProxyGenerator.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.Cli.ServiceProxying
{
public interface IServiceProxyGenerator
{
Task GenerateProxyAsync(GenerateProxyArgs args);
}
}

90
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/JavaScript/JavaScriptServiceProxyGenerator.cs

@ -0,0 +1,90 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.ProxyScripting.Generators.JQuery;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.ServiceProxying.JavaScript
{
public class JavaScriptServiceProxyGenerator : ServiceProxyGeneratorBase<JavaScriptServiceProxyGenerator>, ITransientDependency
{
public const string Name = "JS";
private const string EventTriggerScript = "abp.event.trigger('abp.serviceProxyScriptInitialized');";
private const string DefaultOutput = "wwwroot/client-proxies";
private readonly JQueryProxyScriptGenerator _jQueryProxyScriptGenerator;
public JavaScriptServiceProxyGenerator(
CliHttpClientFactory cliHttpClientFactory,
IJsonSerializer jsonSerializer,
JQueryProxyScriptGenerator jQueryProxyScriptGenerator) :
base(cliHttpClientFactory, jsonSerializer)
{
_jQueryProxyScriptGenerator = jQueryProxyScriptGenerator;
}
public override async Task GenerateProxyAsync(GenerateProxyArgs args)
{
CheckWorkDirectory(args.WorkDirectory);
var output = Path.Combine(args.WorkDirectory, DefaultOutput, $"{args.Module}-proxy.js");
if (!args.Output.IsNullOrWhiteSpace())
{
output = args.Output.EndsWith(".js") ? Path.Combine(args.WorkDirectory, args.Output) : Path.Combine(args.WorkDirectory, Path.GetDirectoryName(args.Output), $"{args.Module}-proxy.js");
}
if (args.CommandName == RemoveProxyCommand.Name)
{
RemoveProxy(args, output);
return;
}
var applicationApiDescriptionModel = await GetApplicationApiDescriptionModelAsync(args);
var script = RemoveInitializedEventTrigger(_jQueryProxyScriptGenerator.CreateScript(applicationApiDescriptionModel));
Directory.CreateDirectory(Path.GetDirectoryName(output));
using (var writer = new StreamWriter(output))
{
await writer.WriteAsync(script);
}
Logger.LogInformation($"Create {GetLoggerOutputPath(output, args.WorkDirectory)}");
}
private void RemoveProxy(GenerateProxyArgs args, string filePath)
{
if (File.Exists(filePath))
{
File.Delete(filePath);
}
Logger.LogInformation($"Delete {GetLoggerOutputPath(filePath, args.WorkDirectory)}");
}
private static void CheckWorkDirectory(string directory)
{
if (!Directory.Exists(directory))
{
throw new CliUsageException("Specified directory does not exist.");
}
var projectFiles = Directory.GetFiles(directory, "*.csproj");
if (!projectFiles.Any())
{
throw new CliUsageException(
"No project file found in the directory. The working directory must have a Web project file.");
}
}
private static string RemoveInitializedEventTrigger(string script)
{
return script.Replace(EventTriggerScript, string.Empty);
}
}
}

56
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/ServiceProxyGeneratorBase.cs

@ -0,0 +1,56 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Http;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.ServiceProxying
{
public abstract class ServiceProxyGeneratorBase<T> : IServiceProxyGenerator where T: IServiceProxyGenerator
{
public IJsonSerializer JsonSerializer { get; }
public CliHttpClientFactory CliHttpClientFactory { get; }
public ILogger<T> Logger { get; set; }
protected ServiceProxyGeneratorBase(CliHttpClientFactory cliHttpClientFactory, IJsonSerializer jsonSerializer)
{
CliHttpClientFactory = cliHttpClientFactory;
JsonSerializer = jsonSerializer;
Logger = NullLogger<T>.Instance;
}
public abstract Task GenerateProxyAsync(GenerateProxyArgs args);
protected virtual async Task<ApplicationApiDescriptionModel> GetApplicationApiDescriptionModelAsync(GenerateProxyArgs args)
{
Check.NotNull(args.Url, nameof(args.Url));
var client = CliHttpClientFactory.CreateClient();
var apiDefinitionResult = await client.GetStringAsync(CliUrls.GetApiDefinitionUrl(args.Url));
var apiDefinition = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(apiDefinitionResult);
var moduleDefinition = apiDefinition.Modules.FirstOrDefault(x => string.Equals(x.Key, args.Module, StringComparison.CurrentCultureIgnoreCase)).Value;
if (moduleDefinition == null)
{
throw new CliUsageException($"Module name: {args.Module} is invalid");
}
var apiDescriptionModel = ApplicationApiDescriptionModel.Create();
apiDescriptionModel.AddModule(moduleDefinition);
return apiDescriptionModel;
}
protected string GetLoggerOutputPath(string path, string workDirectory)
{
return path.Replace(workDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
}
}
}

46
framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs → framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs

@ -7,14 +7,48 @@ using Volo.Abp;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Client.Proxying;
using Volo.Abp.Validation;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionDynamicHttpClientProxyExtensions
public static class ServiceCollectionHttpClientProxyExtensions
{
private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator();
/// <summary>
/// Registers Static HTTP Client Proxies for all public interfaces
/// extend the <see cref="IRemoteService"/> interface in the
/// given <paramref name="assembly"/>.
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="assembly">The assembly containing the service interfaces</param>
/// <param name="remoteServiceConfigurationName">
/// The name of the remote service configuration to be used by the Static HTTP Client proxies.
/// See <see cref="AbpRemoteServiceOptions"/>.
/// </param>
public static IServiceCollection AddStaticHttpClientProxies(
[NotNull] this IServiceCollection services,
[NotNull] Assembly assembly,
[NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName)
{
Check.NotNull(services, nameof(assembly));
var serviceTypes = assembly.GetTypes().Where(IsSuitableForClientProxying).ToArray();
foreach (var serviceType in serviceTypes)
{
AddHttpClientFactory(services, remoteServiceConfigurationName);
services.Configure<AbpHttpClientOptions>(options =>
{
options.HttpClientProxies[serviceType] = new HttpClientProxyConfig(serviceType, remoteServiceConfigurationName);
});
}
return services;
}
/// <summary>
/// Registers HTTP Client Proxies for all public interfaces
/// extend the <see cref="IRemoteService"/> interface in the
@ -37,7 +71,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
Check.NotNull(services, nameof(assembly));
var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicClientProxying).ToArray();
var serviceTypes = assembly.GetTypes().Where(IsSuitableForClientProxying).ToArray();
foreach (var serviceType in serviceTypes)
{
@ -101,7 +135,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.Configure<AbpHttpClientOptions>(options =>
{
options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, remoteServiceConfigurationName);
options.HttpClientProxies[type] = new HttpClientProxyConfig(type, remoteServiceConfigurationName);
});
var interceptorType = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type);
@ -178,12 +212,12 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Checks wether the type is suitable to use with the dynamic proxying.
/// Checks wether the type is suitable to use with the proxying.
/// Currently the type is checked statically against some fixed conditions.
/// </summary>
/// <param name="type">Type to check</param>
/// <returns>True, if the type is suitable for dynamic proxying. Otherwise false.</returns>
private static bool IsSuitableForDynamicClientProxying(Type type)
/// <returns>True, if the type is suitable for proxying. Otherwise false.</returns>
private static bool IsSuitableForClientProxying(Type type)
{
//TODO: Add option to change type filter

5
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs

@ -1,16 +1,17 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Client.Proxying;
namespace Volo.Abp.Http.Client
{
public class AbpHttpClientOptions
{
public Dictionary<Type, DynamicHttpClientProxyConfig> HttpClientProxies { get; set; }
public Dictionary<Type, HttpClientProxyConfig> HttpClientProxies { get; set; }
public AbpHttpClientOptions()
{
HttpClientProxies = new Dictionary<Type, DynamicHttpClientProxyConfig>();
HttpClientProxies = new Dictionary<Type, HttpClientProxyConfig>();
}
}
}

107
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs

@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Json;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Http.Client.ClientProxying
{
public class ClientProxyApiDescriptionFinder : IClientProxyApiDescriptionFinder, ISingletonDependency
{
protected IVirtualFileProvider VirtualFileProvider { get; }
protected IJsonSerializer JsonSerializer { get; }
protected Dictionary<string, ActionApiDescriptionModel> ActionApiDescriptionModels { get; }
protected ApplicationApiDescriptionModel ApplicationApiDescriptionModel { get; set; }
public ClientProxyApiDescriptionFinder(
IVirtualFileProvider virtualFileProvider,
IJsonSerializer jsonSerializer)
{
VirtualFileProvider = virtualFileProvider;
JsonSerializer = jsonSerializer;
ActionApiDescriptionModels = new Dictionary<string, ActionApiDescriptionModel>();
Initialize();
}
public ActionApiDescriptionModel FindAction(string methodName)
{
return ActionApiDescriptionModels.ContainsKey(methodName) ? ActionApiDescriptionModels[methodName] : null;
}
public ApplicationApiDescriptionModel GetApiDescription()
{
return ApplicationApiDescriptionModel;
}
private void Initialize()
{
ApplicationApiDescriptionModel = GetApplicationApiDescriptionModel();
var controllers = ApplicationApiDescriptionModel.Modules.Select(x=>x.Value).SelectMany(x => x.Controllers.Values).ToList();
foreach (var controller in controllers.Where(x => x.Interfaces.Any()))
{
var appServiceType = controller.Interfaces.Last().Type;
foreach (var actionItem in controller.Actions.Values)
{
var actionKey = $"{appServiceType}.{actionItem.Name}.{string.Join("-", actionItem.ParametersOnMethod.Select(x => x.Type))}";
if (!ActionApiDescriptionModels.ContainsKey(actionKey))
{
ActionApiDescriptionModels.Add(actionKey, actionItem);
}
}
}
}
private ApplicationApiDescriptionModel GetApplicationApiDescriptionModel()
{
var applicationApiDescription = ApplicationApiDescriptionModel.Create();
var fileInfoList = new List<IFileInfo>();
GetGenerateProxyFileInfos(fileInfoList);
foreach (var fileInfo in fileInfoList)
{
using (var streamReader = new StreamReader(fileInfo.CreateReadStream()))
{
var content = streamReader.ReadToEnd();
var subApplicationApiDescription = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(content);
foreach (var module in subApplicationApiDescription.Modules)
{
if (!applicationApiDescription.Modules.ContainsKey(module.Key))
{
applicationApiDescription.AddModule(module.Value);
}
}
}
}
return applicationApiDescription;
}
private void GetGenerateProxyFileInfos(List<IFileInfo> fileInfoList, string path = "")
{
foreach (var directoryContent in VirtualFileProvider.GetDirectoryContents(path))
{
if (directoryContent.IsDirectory)
{
GetGenerateProxyFileInfos(fileInfoList, directoryContent.PhysicalPath);
}
else
{
if (directoryContent.Name.EndsWith("generate-proxy.json"))
{
fileInfoList.Add(VirtualFileProvider.GetFileInfo(directoryContent.GetVirtualOrPhysicalPathOrNull()));
}
}
}
}
}
}

52
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs

@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.Proxying;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.Client.ClientProxying
{
public class ClientProxyBase<TService> : ITransientDependency
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService<IHttpProxyExecuter>();
protected IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder => LazyServiceProvider.LazyGetRequiredService<IClientProxyApiDescriptionFinder>();
protected virtual async Task RequestAsync(string methodName, params object[] arguments)
{
await HttpProxyExecuter.MakeRequestAsync(BuildHttpProxyExecuterContext(methodName, arguments));
}
protected virtual async Task<T> RequestAsync<T>(string methodName, params object[] arguments)
{
return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(BuildHttpProxyExecuterContext(methodName, arguments));
}
protected virtual HttpProxyExecuterContext BuildHttpProxyExecuterContext(string methodName, params object[] arguments)
{
var actionKey = GetActionKey(methodName, arguments);
var action = ClientProxyApiDescriptionFinder.FindAction(actionKey);
return new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService));
}
protected virtual Dictionary<string, object> BuildArguments(ActionApiDescriptionModel action, object[] arguments)
{
var parameters = action.Parameters.GroupBy(x => x.NameOnMethod).Select(x => x.Key).ToList();
var dict = new Dictionary<string, object>();
for (var i = 0; i < parameters.Count; i++)
{
dict[parameters[i]] = arguments[i];
}
return dict;
}
private static string GetActionKey(string methodName, params object[] arguments)
{
return $"{typeof(TService).FullName}.{methodName}.{string.Join("-", arguments.Select(x => x.GetType().FullName))}";
}
}
}

11
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs

@ -0,0 +1,11 @@
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.Client.ClientProxying
{
public interface IClientProxyApiDescriptionFinder
{
ActionApiDescriptionModel FindAction(string methodName);
ApplicationApiDescriptionModel GetApiDescription();
}
}

283
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -1,26 +1,15 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.Content;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Http.Client.Proxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;
namespace Volo.Abp.Http.Client.DynamicProxying
{
@ -29,63 +18,54 @@ namespace Volo.Abp.Http.Client.DynamicProxying
// ReSharper disable once StaticMemberInGenericType
protected static MethodInfo MakeRequestAndGetResultAsyncMethod { get; }
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
protected AbpCorrelationIdOptions AbpCorrelationIdOptions { get; }
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; }
protected IApiDescriptionFinder ApiDescriptionFinder { get; }
protected IRemoteServiceConfigurationProvider RemoteServiceConfigurationProvider { get; }
protected AbpHttpClientOptions ClientOptions { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; }
protected IHttpProxyExecuter HttpProxyExecuter { get; }
protected IProxyHttpClientFactory HttpClientFactory { get; }
protected IRemoteServiceConfigurationProvider RemoteServiceConfigurationProvider { get; }
protected IApiDescriptionFinder ApiDescriptionFinder { get; }
public ILogger<DynamicHttpProxyInterceptor<TService>> Logger { get; set; }
static DynamicHttpProxyInterceptor()
{
MakeRequestAndGetResultAsyncMethod = typeof(DynamicHttpProxyInterceptor<TService>)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.First(m => m.Name == nameof(MakeRequestAndGetResultAsync) && m.IsGenericMethodDefinition);
MakeRequestAndGetResultAsyncMethod = typeof(HttpProxyExecuter)
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.First(m => m.Name == nameof(IHttpProxyExecuter.MakeRequestAndGetResultAsync) && m.IsGenericMethodDefinition);
}
public DynamicHttpProxyInterceptor(
IDynamicProxyHttpClientFactory httpClientFactory,
IHttpProxyExecuter httpProxyExecuter,
IOptions<AbpHttpClientOptions> clientOptions,
IApiDescriptionFinder apiDescriptionFinder,
IJsonSerializer jsonSerializer,
IRemoteServiceHttpClientAuthenticator clientAuthenticator,
ICancellationTokenProvider cancellationTokenProvider,
ICorrelationIdProvider correlationIdProvider,
IOptions<AbpCorrelationIdOptions> correlationIdOptions,
ICurrentTenant currentTenant,
IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider)
IProxyHttpClientFactory httpClientFactory,
IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider,
IApiDescriptionFinder apiDescriptionFinder)
{
CancellationTokenProvider = cancellationTokenProvider;
CorrelationIdProvider = correlationIdProvider;
CurrentTenant = currentTenant;
RemoteServiceConfigurationProvider = remoteServiceConfigurationProvider;
AbpCorrelationIdOptions = correlationIdOptions.Value;
HttpProxyExecuter = httpProxyExecuter;
HttpClientFactory = httpClientFactory;
RemoteServiceConfigurationProvider = remoteServiceConfigurationProvider;
ApiDescriptionFinder = apiDescriptionFinder;
JsonSerializer = jsonSerializer;
ClientAuthenticator = clientAuthenticator;
ClientOptions = clientOptions.Value;
Logger = NullLogger<DynamicHttpProxyInterceptor<TService>>.Instance;
}
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
var context = new HttpProxyExecuterContext(
await GetActionApiDescriptionModel(invocation),
invocation.ArgumentsDictionary,
typeof(TService));
if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty())
{
await MakeRequestAsync(invocation);
await HttpProxyExecuter.MakeRequestAsync(context);
}
else
{
var result = (Task)MakeRequestAndGetResultAsyncMethod
.MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0])
.Invoke(this, new object[] { invocation });
.Invoke(HttpProxyExecuter, new object[] { context });
invocation.ReturnValue = await GetResultAsync(
result,
@ -94,230 +74,27 @@ namespace Volo.Abp.Http.Client.DynamicProxying
}
}
private async Task<object> GetResultAsync(Task task, Type resultType)
{
await task;
return typeof(Task<>)
.MakeGenericType(resultType)
.GetProperty(nameof(Task<object>.Result), BindingFlags.Instance | BindingFlags.Public)
.GetValue(task);
}
private async Task<T> MakeRequestAndGetResultAsync<T>(IAbpMethodInvocation invocation)
{
var responseContent = await MakeRequestAsync(invocation);
if (typeof(T) == typeof(IRemoteStreamContent) ||
typeof(T) == typeof(RemoteStreamContent))
{
/* returning a class that holds a reference to response
* content just to be sure that GC does not dispose of
* it before we finish doing our work with the stream */
return (T) (object) new RemoteStreamContent(
await responseContent.ReadAsStreamAsync(),
responseContent.Headers?.ContentDisposition?.FileNameStar ?? RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(),
responseContent.Headers?.ContentType?.ToString(),
responseContent.Headers?.ContentLength);
}
var stringContent = await responseContent.ReadAsStringAsync();
if (typeof(T) == typeof(string))
{
return (T)(object)stringContent;
}
if (stringContent.IsNullOrWhiteSpace())
{
return default;
}
return JsonSerializer.Deserialize<T>(stringContent);
}
private async Task<HttpContent> MakeRequestAsync(IAbpMethodInvocation invocation)
private async Task<ActionApiDescriptionModel> GetActionApiDescriptionModel(IAbpMethodInvocation invocation)
{
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName);
var client = HttpClientFactory.Create(clientConfig.RemoteServiceName);
var action = await ApiDescriptionFinder.FindActionAsync(
return await ApiDescriptionFinder.FindActionAsync(
client,
remoteServiceConfig.BaseUrl,
typeof(TService),
invocation.Method
);
var apiVersion = await GetApiVersionInfoAsync(action);
var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion);
var requestMessage = new HttpRequestMessage(action.GetHttpMethod(), url)
{
Content = RequestPayloadBuilder.BuildContent(action, invocation.ArgumentsDictionary, JsonSerializer, apiVersion)
};
AddHeaders(invocation, action, requestMessage, apiVersion);
if (action.AllowAnonymous != true)
{
await ClientAuthenticator.Authenticate(
new RemoteServiceHttpClientAuthenticateContext(
client,
requestMessage,
remoteServiceConfig,
clientConfig.RemoteServiceName
)
);
}
var response = await client.SendAsync(
requestMessage,
HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/,
GetCancellationToken(invocation)
);
if (!response.IsSuccessStatusCode)
{
await ThrowExceptionForResponseAsync(response);
}
return response.Content;
}
private async Task<ApiVersionInfo> GetApiVersionInfoAsync(ActionApiDescriptionModel action)
{
var apiVersion = await FindBestApiVersionAsync(action);
//TODO: Make names configurable?
var versionParam = action.Parameters.FirstOrDefault(p => p.Name == "apiVersion" && p.BindingSourceId == ParameterBindingSources.Path) ??
action.Parameters.FirstOrDefault(p => p.Name == "api-version" && p.BindingSourceId == ParameterBindingSources.Query);
return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion);
}
private async Task<string> FindBestApiVersionAsync(ActionApiDescriptionModel action)
{
var configuredVersion = await GetConfiguredApiVersionAsync();
if (action.SupportedVersions.IsNullOrEmpty())
{
return configuredVersion ?? "1.0";
}
if (action.SupportedVersions.Contains(configuredVersion))
{
return configuredVersion;
}
return action.SupportedVersions.Last(); //TODO: Ensure to get the latest version!
}
protected virtual void AddHeaders(
IAbpMethodInvocation invocation,
ActionApiDescriptionModel action,
HttpRequestMessage requestMessage,
ApiVersionInfo apiVersion)
{
//API Version
if (!apiVersion.Version.IsNullOrEmpty())
{
//TODO: What about other media types?
requestMessage.Headers.Add("accept", $"{MimeTypes.Text.Plain}; v={apiVersion.Version}");
requestMessage.Headers.Add("accept", $"{MimeTypes.Application.Json}; v={apiVersion.Version}");
requestMessage.Headers.Add("api-version", apiVersion.Version);
}
//Header parameters
var headers = action.Parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Header).ToArray();
foreach (var headerParameter in headers)
{
var value = HttpActionParameterHelper.FindParameterValue(invocation.ArgumentsDictionary, headerParameter);
if (value != null)
{
requestMessage.Headers.Add(headerParameter.Name, value.ToString());
}
}
//CorrelationId
requestMessage.Headers.Add(AbpCorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get());
//TenantId
if (CurrentTenant.Id.HasValue)
{
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
//Culture
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty())
{
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture));
}
//X-Requested-With
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
}
private async Task<string> GetConfiguredApiVersionAsync()
{
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(typeof(TService))
?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
return (await RemoteServiceConfigurationProvider
.GetConfigurationOrDefaultOrNullAsync(clientConfig.RemoteServiceName))?.Version;
}
private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response)
{
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat))
{
var errorResponse = JsonSerializer.Deserialize<RemoteServiceErrorResponse>(
await response.Content.ReadAsStringAsync()
);
throw new AbpRemoteCallException(errorResponse.Error)
{
HttpStatusCode = (int) response.StatusCode
};
}
throw new AbpRemoteCallException(
new RemoteServiceErrorInfo
{
Message = response.ReasonPhrase,
Code = response.StatusCode.ToString()
}
)
{
HttpStatusCode = (int) response.StatusCode
};
}
protected virtual StringSegment RemoveQuotes(StringSegment input)
{
if (!StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
{
input = input.Subsegment(1, input.Length - 2);
}
return input;
}
protected virtual CancellationToken GetCancellationToken(IAbpMethodInvocation invocation)
private async Task<object> GetResultAsync(Task task, Type resultType)
{
var cancellationTokenArg = invocation.Arguments.LastOrDefault(x => x is CancellationToken);
if (cancellationTokenArg != null)
{
var cancellationToken = (CancellationToken) cancellationTokenArg;
if (cancellationToken != default)
{
return cancellationToken;
}
}
return CancellationTokenProvider.Token;
await task;
return typeof(Task<>)
.MakeGenericType(resultType)
.GetProperty(nameof(Task<object>.Result), BindingFlags.Instance | BindingFlags.Public)
.GetValue(task);
}
}
}

4
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiVersionInfo.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/ApiVersionInfo.cs

@ -1,6 +1,6 @@
using System;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
public class ApiVersionInfo //TODO: Rename to not conflict with api versioning apis
{
@ -19,4 +19,4 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return !BindingSource.IsIn("Path");
}
}
}
}

12
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/DefaultProxyHttpClientFactory.cs

@ -1,25 +1,25 @@
using System.Net.Http;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
public class DefaultDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency
public class DefaultProxyHttpClientFactory : IProxyHttpClientFactory, ITransientDependency
{
private readonly IHttpClientFactory _httpClientFactory;
public DefaultDynamicProxyHttpClientFactory(IHttpClientFactory httpClientFactory)
public DefaultProxyHttpClientFactory(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public HttpClient Create()
public HttpClient Create()
{
return _httpClientFactory.CreateClient();
}
public HttpClient Create(string name)
public HttpClient Create(string name)
{
return _httpClientFactory.CreateClient(name);
}
}
}
}

2
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/HttpActionParameterHelper.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs

@ -2,7 +2,7 @@
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
internal static class HttpActionParameterHelper
{

8
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpClientProxyConfig.cs

@ -1,17 +1,17 @@
using System;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
public class DynamicHttpClientProxyConfig
public class HttpClientProxyConfig
{
public Type Type { get; }
public string RemoteServiceName { get; }
public DynamicHttpClientProxyConfig(Type type, string remoteServiceName)
public HttpClientProxyConfig(Type type, string remoteServiceName)
{
Type = type;
RemoteServiceName = remoteServiceName;
}
}
}
}

267
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpProxyExecuter.cs

@ -0,0 +1,267 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.Content;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;
namespace Volo.Abp.Http.Client.Proxying
{
public class HttpProxyExecuter : IHttpProxyExecuter, ITransientDependency
{
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
protected AbpCorrelationIdOptions AbpCorrelationIdOptions { get; }
protected IProxyHttpClientFactory HttpClientFactory { get; }
protected IRemoteServiceConfigurationProvider RemoteServiceConfigurationProvider { get; }
protected AbpHttpClientOptions ClientOptions { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; }
public HttpProxyExecuter(
ICancellationTokenProvider cancellationTokenProvider,
ICorrelationIdProvider correlationIdProvider,
ICurrentTenant currentTenant,
IOptions<AbpCorrelationIdOptions> abpCorrelationIdOptions,
IProxyHttpClientFactory httpClientFactory,
IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider,
IOptions<AbpHttpClientOptions> clientOptions,
IRemoteServiceHttpClientAuthenticator clientAuthenticator,
IJsonSerializer jsonSerializer)
{
CancellationTokenProvider = cancellationTokenProvider;
CorrelationIdProvider = correlationIdProvider;
CurrentTenant = currentTenant;
AbpCorrelationIdOptions = abpCorrelationIdOptions.Value;
HttpClientFactory = httpClientFactory;
RemoteServiceConfigurationProvider = remoteServiceConfigurationProvider;
ClientOptions = clientOptions.Value;
ClientAuthenticator = clientAuthenticator;
JsonSerializer = jsonSerializer;
}
public virtual async Task<T> MakeRequestAndGetResultAsync<T>(HttpProxyExecuterContext context)
{
var responseContent = await MakeRequestAsync(context);
if (typeof(T) == typeof(IRemoteStreamContent) ||
typeof(T) == typeof(RemoteStreamContent))
{
/* returning a class that holds a reference to response
* content just to be sure that GC does not dispose of
* it before we finish doing our work with the stream */
return (T) (object) new RemoteStreamContent(
await responseContent.ReadAsStreamAsync(),
responseContent.Headers?.ContentDisposition?.FileNameStar ?? RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(),
responseContent.Headers?.ContentType?.ToString(),
responseContent.Headers?.ContentLength);
}
var stringContent = await responseContent.ReadAsStringAsync();
if (typeof(T) == typeof(string))
{
return (T)(object)stringContent;
}
if (stringContent.IsNullOrWhiteSpace())
{
return default;
}
return JsonSerializer.Deserialize<T>(stringContent);
}
public virtual async Task<HttpContent> MakeRequestAsync(HttpProxyExecuterContext context)
{
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(context.ServiceType) ?? throw new AbpException($"Could not get HttpClientProxyConfig for {context.ServiceType.FullName}.");
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName);
var client = HttpClientFactory.Create(clientConfig.RemoteServiceName);
var apiVersion = await GetApiVersionInfoAsync(context);
var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + UrlBuilder.GenerateUrlWithParameters(context.Action, context.Arguments, apiVersion);
var requestMessage = new HttpRequestMessage(context.Action.GetHttpMethod(), url)
{
Content = RequestPayloadBuilder.BuildContent(context.Action, context.Arguments, JsonSerializer, apiVersion)
};
AddHeaders(context.Arguments, context.Action, requestMessage, apiVersion);
if (context.Action.AllowAnonymous != true)
{
await ClientAuthenticator.Authenticate(
new RemoteServiceHttpClientAuthenticateContext(
client,
requestMessage,
remoteServiceConfig,
clientConfig.RemoteServiceName
)
);
}
var response = await client.SendAsync(
requestMessage,
HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/,
GetCancellationToken(context.Arguments)
);
if (!response.IsSuccessStatusCode)
{
await ThrowExceptionForResponseAsync(response);
}
return response.Content;
}
private async Task<ApiVersionInfo> GetApiVersionInfoAsync(HttpProxyExecuterContext context)
{
var apiVersion = await FindBestApiVersionAsync(context);
//TODO: Make names configurable?
var versionParam = context.Action.Parameters.FirstOrDefault(p => p.Name == "apiVersion" && p.BindingSourceId == ParameterBindingSources.Path) ??
context.Action.Parameters.FirstOrDefault(p => p.Name == "api-version" && p.BindingSourceId == ParameterBindingSources.Query);
return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion);
}
private async Task<string> FindBestApiVersionAsync(HttpProxyExecuterContext context)
{
var configuredVersion = await GetConfiguredApiVersionAsync(context);
if (context.Action.SupportedVersions.IsNullOrEmpty())
{
return configuredVersion ?? "1.0";
}
if (context.Action.SupportedVersions.Contains(configuredVersion))
{
return configuredVersion;
}
return context.Action.SupportedVersions.Last(); //TODO: Ensure to get the latest version!
}
private async Task<string> GetConfiguredApiVersionAsync(HttpProxyExecuterContext context)
{
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(context.ServiceType)
?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {context.ServiceType.FullName}.");
return (await RemoteServiceConfigurationProvider
.GetConfigurationOrDefaultOrNullAsync(clientConfig.RemoteServiceName))?.Version;
}
private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response)
{
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat))
{
var errorResponse = JsonSerializer.Deserialize<RemoteServiceErrorResponse>(
await response.Content.ReadAsStringAsync()
);
throw new AbpRemoteCallException(errorResponse.Error)
{
HttpStatusCode = (int) response.StatusCode
};
}
throw new AbpRemoteCallException(
new RemoteServiceErrorInfo
{
Message = response.ReasonPhrase,
Code = response.StatusCode.ToString()
}
)
{
HttpStatusCode = (int) response.StatusCode
};
}
protected virtual void AddHeaders(
IReadOnlyDictionary<string, object> argumentsDictionary,
ActionApiDescriptionModel action,
HttpRequestMessage requestMessage,
ApiVersionInfo apiVersion)
{
//API Version
if (!apiVersion.Version.IsNullOrEmpty())
{
//TODO: What about other media types?
requestMessage.Headers.Add("accept", $"{MimeTypes.Text.Plain}; v={apiVersion.Version}");
requestMessage.Headers.Add("accept", $"{MimeTypes.Application.Json}; v={apiVersion.Version}");
requestMessage.Headers.Add("api-version", apiVersion.Version);
}
//Header parameters
var headers = action.Parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Header).ToArray();
foreach (var headerParameter in headers)
{
var value = HttpActionParameterHelper.FindParameterValue(argumentsDictionary, headerParameter);
if (value != null)
{
requestMessage.Headers.Add(headerParameter.Name, value.ToString());
}
}
//CorrelationId
requestMessage.Headers.Add(AbpCorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get());
//TenantId
if (CurrentTenant.Id.HasValue)
{
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
//Culture
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty())
{
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture));
}
//X-Requested-With
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
}
protected virtual StringSegment RemoveQuotes(StringSegment input)
{
if (!StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
{
input = input.Subsegment(1, input.Length - 2);
}
return input;
}
protected virtual CancellationToken GetCancellationToken(IReadOnlyDictionary<string, object> arguments)
{
var cancellationTokenArg = arguments.LastOrDefault();
if (cancellationTokenArg.Value is CancellationToken cancellationToken)
{
if (cancellationToken != default)
{
return cancellationToken;
}
}
return CancellationTokenProvider.Token;
}
}
}

30
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpProxyExecuterContext.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.Client.Proxying
{
public class HttpProxyExecuterContext
{
[NotNull]
public ActionApiDescriptionModel Action { get; }
[NotNull]
public IReadOnlyDictionary<string, object> Arguments { get; }
[NotNull]
public Type ServiceType { get; }
public HttpProxyExecuterContext(
[NotNull] ActionApiDescriptionModel action,
[NotNull] IReadOnlyDictionary<string, object> arguments,
[NotNull] Type serviceType)
{
ServiceType = serviceType;
Action = Check.NotNull(action, nameof(action));
Arguments = Check.NotNull(arguments, nameof(arguments));
ServiceType = Check.NotNull(serviceType, nameof(serviceType));
}
}
}

12
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/IHttpProxyExecuter.cs

@ -0,0 +1,12 @@
using System.Net.Http;
using System.Threading.Tasks;
namespace Volo.Abp.Http.Client.Proxying
{
public interface IHttpProxyExecuter
{
Task<HttpContent> MakeRequestAsync(HttpProxyExecuterContext context);
Task<T> MakeRequestAndGetResultAsync<T>(HttpProxyExecuterContext context);
}
}

6
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IDynamicProxyHttpClientFactory.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/IProxyHttpClientFactory.cs

@ -1,11 +1,11 @@
using System.Net.Http;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
public interface IDynamicProxyHttpClientFactory
public interface IProxyHttpClientFactory
{
HttpClient Create();
HttpClient Create(string name);
}
}
}

3
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/RequestPayloadBuilder.cs

@ -6,11 +6,12 @@ using System.Net.Http.Headers;
using System.Text;
using JetBrains.Annotations;
using Volo.Abp.Content;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
public static class RequestPayloadBuilder
{

3
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs → framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/UrlBuilder.cs

@ -5,11 +5,12 @@ using System.Globalization;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Localization;
namespace Volo.Abp.Http.Client.DynamicProxying
namespace Volo.Abp.Http.Client.Proxying
{
internal static class UrlBuilder
{

7
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs

@ -28,12 +28,14 @@ namespace Volo.Abp.Http.Modeling
public bool? AllowAnonymous { get; set; }
public string ImplementFrom { get; set; }
public ActionApiDescriptionModel()
{
}
public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, [CanBeNull] string httpMethod, [NotNull] IList<string> supportedVersions, bool? allowAnonymous = null)
public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, [CanBeNull] string httpMethod, [NotNull] IList<string> supportedVersions, bool? allowAnonymous = null, string implementFrom = null)
{
Check.NotNull(uniqueName, nameof(uniqueName));
Check.NotNull(method, nameof(method));
@ -53,7 +55,8 @@ namespace Volo.Abp.Http.Modeling
.Select(MethodParameterApiDescriptionModel.Create)
.ToList(),
SupportedVersions = supportedVersions,
AllowAnonymous = allowAnonymous
AllowAnonymous = allowAnonymous,
ImplementFrom = implementFrom
};
}

5
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs

@ -10,6 +10,8 @@ namespace Volo.Abp.Http.Modeling
{
public string ControllerName { get; set; }
public string ControllerGroupName { get; set; }
public string Type { get; set; }
public List<ControllerInterfaceApiDescriptionModel> Interfaces { get; set; }
@ -21,11 +23,12 @@ namespace Volo.Abp.Http.Modeling
}
public static ControllerApiDescriptionModel Create(string controllerName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
public static ControllerApiDescriptionModel Create(string controllerName, string groupName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
{
return new ControllerApiDescriptionModel
{
ControllerName = controllerName,
ControllerGroupName = groupName,
Type = type.FullName,
Actions = new Dictionary<string, ActionApiDescriptionModel>(),
Interfaces = type

4
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs

@ -49,9 +49,9 @@ namespace Volo.Abp.Http.Modeling
return Controllers[controller.Type] = controller;
}
public ControllerApiDescriptionModel GetOrAddController(string name, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
public ControllerApiDescriptionModel GetOrAddController(string name, string groupName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
{
return Controllers.GetOrAdd(type.FullName, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces));
return Controllers.GetOrAdd(type.FullName, () => ControllerApiDescriptionModel.Create(name, groupName, type, ignoredInterfaces));
}
public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions)

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs

@ -208,6 +208,8 @@ namespace Volo.Abp.Http.ProxyScripting.Generators.JQuery
.Trim()
.RemovePostFix(AppServiceCommonPostfixes)
.RemovePostFix("Controller")
.Replace(".ClientProxies", string.Empty)
.RemovePostFix("ClientProxy")
);
}

1
framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj

@ -20,6 +20,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>

42
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleModule.cs

@ -1,12 +1,21 @@
using Volo.Abp.AspNetCore.Mvc;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle.Conventions;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Swashbuckle
{
[DependsOn(
typeof(AbpVirtualFileSystemModule),
typeof(AbpAspNetCoreMvcModule))]
typeof(AbpAspNetCoreMvcModule),
typeof(AbpHttpClientModule))]
public class AbpSwashbuckleModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@ -15,6 +24,35 @@ namespace Volo.Abp.Swashbuckle
{
options.FileSets.AddEmbedded<AbpSwashbuckleModule>();
});
var swaggerConventionOptions = context.Services.ExecutePreConfiguredActions<AbpSwaggerClientProxyOptions>();
if (swaggerConventionOptions.IsEnabled)
{
context.Services.Replace(ServiceDescriptor.Transient<IAbpServiceConvention, AbpSwaggerServiceConvention>());
context.Services.AddTransient<AbpSwaggerServiceConvention>();
var partManager = context.Services.GetSingletonInstance<ApplicationPartManager>();
partManager.FeatureProviders.Add(new AbpSwaggerClientProxyControllerFeatureProvider());
}
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var swaggerConventionOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpSwaggerClientProxyOptions>>().Value;
if (swaggerConventionOptions.IsEnabled)
{
var partManager = context.ServiceProvider.GetRequiredService<ApplicationPartManager>();
foreach (var moduleAssembly in context
.ServiceProvider
.GetRequiredService<IModuleContainer>()
.Modules
.Select(m => m.Type.Assembly)
.Where(a => a.GetTypes().Any(AbpSwaggerClientProxyHelper.IsClientProxyService))
.Distinct())
{
partManager.ApplicationParts.AddIfNotContains(moduleAssembly);
}
}
}
}
}

13
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyControllerFeatureProvider.cs

@ -0,0 +1,13 @@
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Controllers;
namespace Volo.Abp.Swashbuckle.Conventions
{
public class AbpSwaggerClientProxyControllerFeatureProvider : ControllerFeatureProvider
{
protected override bool IsController(TypeInfo typeInfo)
{
return AbpSwaggerClientProxyHelper.IsClientProxyService(typeInfo);
}
}
}

16
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyHelper.cs

@ -0,0 +1,16 @@
using System;
using System.Linq;
using Volo.Abp.Application.Services;
using Volo.Abp.Http.Client.ClientProxying;
namespace Volo.Abp.Swashbuckle.Conventions
{
public static class AbpSwaggerClientProxyHelper
{
public static bool IsClientProxyService(Type type)
{
return typeof(IApplicationService).IsAssignableFrom(type) &&
type.GetBaseClasses().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ClientProxyBase<>));
}
}
}

12
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyOptions.cs

@ -0,0 +1,12 @@
namespace Volo.Abp.Swashbuckle.Conventions
{
public class AbpSwaggerClientProxyOptions
{
public bool IsEnabled { get; set; }
public AbpSwaggerClientProxyOptions()
{
IsEnabled = true;
}
}
}

249
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyServiceConvention.cs

@ -0,0 +1,249 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
namespace Volo.Abp.Swashbuckle.Conventions
{
[DisableConventionalRegistration]
public class AbpSwaggerServiceConvention : AbpServiceConvention
{
protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder;
protected readonly List<ActionModel> ActionWithAttributeRoute;
public AbpSwaggerServiceConvention(
IOptions<AbpAspNetCoreMvcOptions> options,
IConventionalRouteBuilder conventionalRouteBuilder,
IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder)
: base(options, conventionalRouteBuilder)
{
ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder;
ActionWithAttributeRoute = new List<ActionModel>();
}
protected override IList<ControllerModel> GetControllers(ApplicationModel application)
{
return application.Controllers.Where(c => !AbpSwaggerClientProxyHelper.IsClientProxyService(c.ControllerType)).ToList();
}
protected virtual IList<ControllerModel> GetClientProxyControllers(ApplicationModel application)
{
return application.Controllers.Where(c => AbpSwaggerClientProxyHelper.IsClientProxyService(c.ControllerType)).ToList();
}
protected override void ApplyForControllers(ApplicationModel application)
{
base.ApplyForControllers(application);
foreach (var controller in GetClientProxyControllers(application))
{
controller.ControllerName = controller.ControllerName.RemovePostFix("ClientProxy");
var controllerApiDescription = FindControllerApiDescriptionModel(controller);
if (controllerApiDescription != null &&
!controllerApiDescription.ControllerGroupName.IsNullOrWhiteSpace())
{
controller.ControllerName = controllerApiDescription.ControllerGroupName;
}
ConfigureClientProxySelector(controller);
ConfigureClientProxyApiExplorer(controller);
ConfigureParameters(controller);
}
}
protected virtual void ConfigureClientProxySelector(ControllerModel controller)
{
RemoveEmptySelectors(controller.Selectors);
var controllerType = controller.ControllerType.AsType();
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(controllerType.GetTypeInfo());
if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(controllerType))
{
return;
}
if (controller.Selectors.Any(selector => selector.AttributeRouteModel != null))
{
return;
}
foreach (var action in controller.Actions)
{
ConfigureClientProxySelector(controller, action);
}
}
protected virtual void ConfigureClientProxySelector(ControllerModel controller, ActionModel action)
{
RemoveEmptySelectors(action.Selectors);
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod);
if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(action.ActionMethod))
{
return;
}
var actionApiDescriptionModel = FindActionApiDescriptionModel(controller, action);
if (actionApiDescriptionModel == null)
{
return;;
}
ActionWithAttributeRoute.Add(action);
if (!action.Selectors.Any())
{
var abpServiceSelectorModel = new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel(
new RouteAttribute(template: actionApiDescriptionModel.Url)
),
ActionConstraints = { new HttpMethodActionConstraint(new[] { actionApiDescriptionModel.HttpMethod }) }
};
action.Selectors.Add(abpServiceSelectorModel);
}
else
{
foreach (var selector in action.Selectors)
{
var httpMethod = selector.ActionConstraints
.OfType<HttpMethodActionConstraint>()
.FirstOrDefault()?
.HttpMethods?
.FirstOrDefault();
if (httpMethod == null)
{
httpMethod = actionApiDescriptionModel.HttpMethod;
}
if (selector.AttributeRouteModel == null)
{
selector.AttributeRouteModel = new AttributeRouteModel(
new RouteAttribute(template: actionApiDescriptionModel.Url)
);
}
if (!selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any())
{
selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod }));
}
}
}
}
protected virtual void ConfigureClientProxyApiExplorer(ControllerModel controller)
{
if (controller.ApiExplorer.GroupName.IsNullOrEmpty())
{
controller.ApiExplorer.GroupName = controller.ControllerName;
}
if (controller.ApiExplorer.IsVisible == null)
{
controller.ApiExplorer.IsVisible = IsVisibleRemoteService(controller.ControllerType);
}
foreach (var action in controller.Actions)
{
if (ActionWithAttributeRoute.Contains(action))
{
ConfigureApiExplorer(action);
}
}
}
protected virtual ModuleApiDescriptionModel FindModuleApiDescriptionModel(ControllerModel controller)
{
var appServiceType = FindAppServiceInterfaceType(controller);
if (appServiceType == null)
{
return null;
}
var applicationApiDescriptionModel = ClientProxyApiDescriptionFinder.GetApiDescription();
foreach (var moduleApiDescription in applicationApiDescriptionModel.Modules.Values)
{
if (moduleApiDescription.Controllers.Values.Any(x => x.Interfaces.Any(t => t.Type == appServiceType.FullName)))
{
return moduleApiDescription;
}
}
return null;
}
protected virtual ControllerApiDescriptionModel FindControllerApiDescriptionModel(ControllerModel controller)
{
var appServiceType = FindAppServiceInterfaceType(controller);
if (appServiceType == null)
{
return null;
}
var applicationApiDescriptionModel = ClientProxyApiDescriptionFinder.GetApiDescription();
foreach (var controllerApiDescription in applicationApiDescriptionModel.Modules.Values.SelectMany(x => x.Controllers.Values))
{
if (controllerApiDescription.Interfaces.Any(t => t.Type == appServiceType.FullName))
{
return controllerApiDescription;
}
}
return null;
}
protected virtual ActionApiDescriptionModel FindActionApiDescriptionModel(ControllerModel controller, ActionModel action)
{
var appServiceType = FindAppServiceInterfaceType(controller);
if (appServiceType == null)
{
return null;
}
var key =
$"{appServiceType.FullName}." +
$"{action.ActionMethod.Name}." +
$"{string.Join("-", action.Parameters.Select(x => x.ParameterType.FullName))}";
var actionApiDescriptionModel = ClientProxyApiDescriptionFinder.FindAction(key);
if (actionApiDescriptionModel == null)
{
return null;
}
if (actionApiDescriptionModel.ImplementFrom.StartsWith("Volo.Abp.Application.Services"))
{
return actionApiDescriptionModel;
}
if (appServiceType.FullName != null && actionApiDescriptionModel.ImplementFrom.StartsWith(appServiceType.FullName))
{
return actionApiDescriptionModel;
}
return null;
}
protected virtual Type FindAppServiceInterfaceType(ControllerModel controller)
{
return controller.ControllerType.GetInterfaces()
.FirstOrDefault(type => !type.IsGenericType &&
type != typeof(IApplicationService) &&
typeof(IApplicationService).IsAssignableFrom(type));
}
}
}

30
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs

@ -0,0 +1,30 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Account;
using Volo.Abp.Identity;
// ReSharper disable once CheckNamespace
namespace Volo.Abp.Account.ClientProxies
{
public partial class AccountClientProxy
{
public virtual async Task<IdentityUserDto> RegisterAsync(RegisterDto input)
{
return await RequestAsync<IdentityUserDto>(nameof(RegisterAsync), input);
}
public virtual async Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input)
{
await RequestAsync(nameof(SendPasswordResetCodeAsync), input);
}
public virtual async Task ResetPasswordAsync(ResetPasswordDto input)
{
await RequestAsync(nameof(ResetPasswordAsync), input);
}
}
}

14
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of AccountClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Account;
// ReSharper disable once CheckNamespace
namespace Volo.Abp.Account.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IAccountAppService), typeof(AccountClientProxy))]
public partial class AccountClientProxy : ClientProxyBase<IAccountAppService>, IAccountAppService
{
}
}

231
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json

@ -0,0 +1,231 @@
{
"modules": {
"account": {
"rootPath": "account",
"remoteServiceName": "AbpAccount",
"controllers": {
"Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController": {
"controllerName": "Account",
"controllerGroupName": "Login",
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController",
"interfaces": [],
"actions": {
"LoginByLogin": {
"uniqueName": "LoginByLogin",
"name": "Login",
"httpMethod": "POST",
"url": "api/account/login",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "login",
"typeAsString": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo, Volo.Abp.Account.Web",
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "login",
"name": "login",
"jsonName": null,
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController"
},
"Logout": {
"uniqueName": "Logout",
"name": "Logout",
"httpMethod": "GET",
"url": "api/account/logout",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController"
},
"CheckPasswordByLogin": {
"uniqueName": "CheckPasswordByLogin",
"name": "CheckPassword",
"httpMethod": "POST",
"url": "api/account/check-password",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "login",
"typeAsString": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo, Volo.Abp.Account.Web",
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "login",
"name": "login",
"jsonName": null,
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult",
"typeSimple": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController"
}
}
},
"Volo.Abp.Account.AccountController": {
"controllerName": "Account",
"controllerGroupName": "Account",
"type": "Volo.Abp.Account.AccountController",
"interfaces": [
{
"type": "Volo.Abp.Account.IAccountAppService"
}
],
"actions": {
"RegisterAsyncByInput": {
"uniqueName": "RegisterAsyncByInput",
"name": "RegisterAsync",
"httpMethod": "POST",
"url": "api/account/register",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Account.RegisterDto, Volo.Abp.Account.Application.Contracts",
"type": "Volo.Abp.Account.RegisterDto",
"typeSimple": "Volo.Abp.Account.RegisterDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Abp.Account.RegisterDto",
"typeSimple": "Volo.Abp.Account.RegisterDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Abp.Identity.IdentityUserDto",
"typeSimple": "Volo.Abp.Identity.IdentityUserDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.IAccountAppService"
},
"SendPasswordResetCodeAsyncByInput": {
"uniqueName": "SendPasswordResetCodeAsyncByInput",
"name": "SendPasswordResetCodeAsync",
"httpMethod": "POST",
"url": "api/account/send-password-reset-code",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Account.SendPasswordResetCodeDto, Volo.Abp.Account.Application.Contracts",
"type": "Volo.Abp.Account.SendPasswordResetCodeDto",
"typeSimple": "Volo.Abp.Account.SendPasswordResetCodeDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Abp.Account.SendPasswordResetCodeDto",
"typeSimple": "Volo.Abp.Account.SendPasswordResetCodeDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.IAccountAppService"
},
"ResetPasswordAsyncByInput": {
"uniqueName": "ResetPasswordAsyncByInput",
"name": "ResetPasswordAsync",
"httpMethod": "POST",
"url": "api/account/reset-password",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Abp.Account.ResetPasswordDto, Volo.Abp.Account.Application.Contracts",
"type": "Volo.Abp.Account.ResetPasswordDto",
"typeSimple": "Volo.Abp.Account.ResetPasswordDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Abp.Account.ResetPasswordDto",
"typeSimple": "Volo.Abp.Account.ResetPasswordDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.IAccountAppService"
}
}
}
}
}
},
"types": {}
}

10
modules/account/src/Volo.Abp.Account.HttpApi.Client/Volo/Abp/Account/AbpAccountHttpApiClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Account
{
@ -11,8 +12,13 @@ namespace Volo.Abp.Account
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(typeof(AbpAccountApplicationContractsModule).Assembly,
context.Services.AddStaticHttpClientProxies(typeof(AbpAccountApplicationContractsModule).Assembly,
AccountRemoteServiceConsts.RemoteServiceName);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpAccountHttpApiClientModule>();
});
}
}
}
}

2
modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs

@ -17,7 +17,7 @@ using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Account.Web
{
[DependsOn(
typeof(AbpAccountHttpApiModule),
typeof(AbpAccountApplicationContractsModule),
typeof(AbpIdentityAspNetCoreModule),
typeof(AbpAutoMapperModule),
typeof(AbpAspNetCoreMvcUiThemeSharedModule),

6
modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj

@ -24,19 +24,23 @@
<EmbeddedResource Include="Pages\**\*.css" />
<EmbeddedResource Include="Components\**\*.js" />
<EmbeddedResource Include="Components\**\*.css" />
<EmbeddedResource Include="wwwroot\**\*.js" />
<EmbeddedResource Include="wwwroot\**\*.css" />
<Content Remove="Modules\**\*.js" />
<Content Remove="Modules\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="Components\**\*.js" />
<Content Remove="Components\**\*.css" />
<Content Remove="wwwroot\**\*.js" />
<Content Remove="wwwroot\**\*.css" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\identity\src\Volo.Abp.Identity.AspNetCore\Volo.Abp.Identity.AspNetCore.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\Volo.Abp.Account.HttpApi\Volo.Abp.Account.HttpApi.csproj" />
<ProjectReference Include="..\Volo.Abp.Account.Application.Contracts\Volo.Abp.Account.Application.Contracts.csproj" />
</ItemGroup>
<ItemGroup>

76
modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js

@ -0,0 +1,76 @@
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */
// module account
(function(){
// controller volo.abp.account.web.areas.account.controllers.account
(function(){
abp.utils.createNamespace(window, 'volo.abp.account.web.areas.account.controllers.account');
volo.abp.account.web.areas.account.controllers.account.login = function(login, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/login',
type: 'POST',
data: JSON.stringify(login)
}, ajaxParams));
};
volo.abp.account.web.areas.account.controllers.account.logout = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/logout',
type: 'GET',
dataType: null
}, ajaxParams));
};
volo.abp.account.web.areas.account.controllers.account.checkPassword = function(login, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/check-password',
type: 'POST',
data: JSON.stringify(login)
}, ajaxParams));
};
})();
// controller volo.abp.account.account
(function(){
abp.utils.createNamespace(window, 'volo.abp.account.account');
volo.abp.account.account.register = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/register',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.abp.account.account.sendPasswordResetCode = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/send-password-reset-code',
type: 'POST',
dataType: null,
data: JSON.stringify(input)
}, ajaxParams));
};
volo.abp.account.account.resetPassword = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/reset-password',
type: 'POST',
dataType: null,
data: JSON.stringify(input)
}, ajaxParams));
};
})();
})();

45
modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/BlogManagementClientProxy.Generated.cs

@ -0,0 +1,45 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Admin.Blogs;
using Volo.Blogging.Blogs.Dtos;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.Admin.ClientProxies
{
public partial class BlogManagementClientProxy
{
public virtual async Task<ListResultDto<BlogDto>> GetListAsync()
{
return await RequestAsync<ListResultDto<BlogDto>>(nameof(GetListAsync));
}
public virtual async Task<BlogDto> GetAsync(Guid id)
{
return await RequestAsync<BlogDto>(nameof(GetAsync), id);
}
public virtual async Task<BlogDto> CreateAsync(CreateBlogDto input)
{
return await RequestAsync<BlogDto>(nameof(CreateAsync), input);
}
public virtual async Task<BlogDto> UpdateAsync(Guid id, UpdateBlogDto input)
{
return await RequestAsync<BlogDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
public virtual async Task ClearCacheAsync(Guid id)
{
await RequestAsync(nameof(ClearCacheAsync), id);
}
}
}

14
modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/BlogManagementClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogManagementClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.Admin.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogManagementAppService), typeof(BlogManagementClientProxy))]
public partial class BlogManagementClientProxy : ClientProxyBase<IBlogManagementAppService>, IBlogManagementAppService
{
}
}

243
modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/ClientProxies/bloggingAdmin-generate-proxy.json

@ -0,0 +1,243 @@
{
"modules": {
"bloggingAdmin": {
"rootPath": "bloggingAdmin",
"remoteServiceName": "BloggingAdmin",
"controllers": {
"Volo.Blogging.Admin.BlogManagementController": {
"controllerName": "BlogManagement",
"controllerGroupName": "BlogManagement",
"type": "Volo.Blogging.Admin.BlogManagementController",
"interfaces": [
{
"type": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
}
],
"actions": {
"GetListAsync": {
"uniqueName": "GetListAsync",
"name": "GetListAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs/admin",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Blogs.Dtos.BlogDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Blogs.Dtos.BlogDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
},
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs/admin/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Blogs.Dtos.BlogDto",
"typeSimple": "Volo.Blogging.Blogs.Dtos.BlogDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/blogging/blogs/admin",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Blogging.Admin.Blogs.CreateBlogDto, Volo.Blogging.Admin.Application.Contracts",
"type": "Volo.Blogging.Admin.Blogs.CreateBlogDto",
"typeSimple": "Volo.Blogging.Admin.Blogs.CreateBlogDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Admin.Blogs.CreateBlogDto",
"typeSimple": "Volo.Blogging.Admin.Blogs.CreateBlogDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Blogs.Dtos.BlogDto",
"typeSimple": "Volo.Blogging.Blogs.Dtos.BlogDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
},
"UpdateAsyncByIdAndInput": {
"uniqueName": "UpdateAsyncByIdAndInput",
"name": "UpdateAsync",
"httpMethod": "PUT",
"url": "api/blogging/blogs/admin/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
},
{
"name": "input",
"typeAsString": "Volo.Blogging.Admin.Blogs.UpdateBlogDto, Volo.Blogging.Admin.Application.Contracts",
"type": "Volo.Blogging.Admin.Blogs.UpdateBlogDto",
"typeSimple": "Volo.Blogging.Admin.Blogs.UpdateBlogDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Admin.Blogs.UpdateBlogDto",
"typeSimple": "Volo.Blogging.Admin.Blogs.UpdateBlogDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Blogs.Dtos.BlogDto",
"typeSimple": "Volo.Blogging.Blogs.Dtos.BlogDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
},
"DeleteAsyncById": {
"uniqueName": "DeleteAsyncById",
"name": "DeleteAsync",
"httpMethod": "DELETE",
"url": "api/blogging/blogs/admin/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
},
"ClearCacheAsyncById": {
"uniqueName": "ClearCacheAsyncById",
"name": "ClearCacheAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs/admin/clear-cache/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
}
}
}
}
}
},
"types": {}
}

8
modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/Volo/Blogging/Admin/BloggingAdminHttpApiClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Blogging.Admin
{
@ -11,8 +12,13 @@ namespace Volo.Blogging.Admin
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(typeof(BloggingAdminApplicationContractsModule).Assembly,
context.Services.AddStaticHttpClientProxies(typeof(BloggingAdminApplicationContractsModule).Assembly,
BloggingAdminRemoteServiceConsts.RemoteServiceName);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<BloggingAdminHttpApiClientModule>();
});
}
}

2
modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminWebModule.cs

@ -11,7 +11,7 @@ using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
{
[DependsOn(
typeof(BloggingAdminHttpApiModule),
typeof(BloggingAdminApplicationContractsModule),
typeof(AbpAspNetCoreMvcUiBootstrapModule),
typeof(AbpAspNetCoreMvcUiBundlingModule),
typeof(AbpAutoMapperModule)

7
modules/blogging/src/Volo.Blogging.Admin.Web/Pages/Blogging/Admin/Blogs/Index.cshtml

@ -15,9 +15,10 @@
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/Pages/Blogging/Admin/Blogs/index.js" />
<abp-script src="/Pages/Blogging/Admin/Blogs/create.js" />
<abp-script src="/Pages/Blogging/Admin/Blogs/edit.js" />
<abp-script src="/client-proxies/bloggingAdmin-proxy.js"/>
<abp-script src="/Pages/Blogging/Admin/Blogs/index.js"/>
<abp-script src="/Pages/Blogging/Admin/Blogs/create.js"/>
<abp-script src="/Pages/Blogging/Admin/Blogs/edit.js"/>
</abp-script-bundle>
}

6
modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.csproj

@ -19,7 +19,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Packages\Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\Volo.Blogging.Admin.HttpApi\Volo.Blogging.Admin.HttpApi.csproj" />
<ProjectReference Include="..\Volo.Blogging.Admin.Application.Contracts\Volo.Blogging.Admin.Application.Contracts.csproj" />
<PackageReference Include="Markdig.Signed" Version="0.20.0" />
</ItemGroup>
@ -32,10 +32,14 @@
<EmbeddedResource Include="Pages\**\*.css" />
<EmbeddedResource Include="Components\**\*.js" />
<EmbeddedResource Include="Components\**\*.css" />
<EmbeddedResource Include="wwwroot\**\*.js" />
<EmbeddedResource Include="wwwroot\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="Components\**\*.js" />
<Content Remove="Components\**\*.css" />
<Content Remove="wwwroot\**\*.js" />
<Content Remove="wwwroot\**\*.css" />
<Content Remove="compilerconfig.json" />
</ItemGroup>

64
modules/blogging/src/Volo.Blogging.Admin.Web/wwwroot/client-proxies/bloggingAdmin-proxy.js

@ -0,0 +1,64 @@
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */
// module bloggingAdmin
(function(){
// controller volo.blogging.admin.blogManagement
(function(){
abp.utils.createNamespace(window, 'volo.blogging.admin.blogManagement');
volo.blogging.admin.blogManagement.getList = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin',
type: 'GET'
}, ajaxParams));
};
volo.blogging.admin.blogManagement.get = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin/' + id + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.admin.blogManagement.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.admin.blogManagement.update = function(id, input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin/' + id + '',
type: 'PUT',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.admin.blogManagement['delete'] = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin/' + id + '',
type: 'DELETE',
dataType: null
}, ajaxParams));
};
volo.blogging.admin.blogManagement.clearCache = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/admin/clear-cache/' + id + '',
type: 'GET',
dataType: null
}, ajaxParams));
};
})();
})();

24
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.Generated.cs

@ -0,0 +1,24 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Files;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
public partial class BlogFilesClientProxy
{
public virtual async Task<RawFileDto> GetAsync(string name)
{
return await RequestAsync<RawFileDto>(nameof(GetAsync), name);
}
public virtual async Task<FileUploadOutputDto> CreateAsync(FileUploadInputDto input)
{
return await RequestAsync<FileUploadOutputDto>(nameof(CreateAsync), input);
}
}
}

14
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogFilesClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Files;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IFileAppService), typeof(BlogFilesClientProxy))]
public partial class BlogFilesClientProxy : ClientProxyBase<IFileAppService>, IFileAppService
{
}
}

30
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogsClientProxy.Generated.cs

@ -0,0 +1,30 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
public partial class BlogsClientProxy
{
public virtual async Task<ListResultDto<BlogDto>> GetListAsync()
{
return await RequestAsync<ListResultDto<BlogDto>>(nameof(GetListAsync));
}
public virtual async Task<BlogDto> GetByShortNameAsync(string shortName)
{
return await RequestAsync<BlogDto>(nameof(GetByShortNameAsync), shortName);
}
public virtual async Task<BlogDto> GetAsync(Guid id)
{
return await RequestAsync<BlogDto>(nameof(GetAsync), id);
}
}
}

14
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogsClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogsClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogAppService), typeof(BlogsClientProxy))]
public partial class BlogsClientProxy : ClientProxyBase<IBlogAppService>, IBlogAppService
{
}
}

36
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/CommentsClientProxy.Generated.cs

@ -0,0 +1,36 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Comments;
using System.Collections.Generic;
using Volo.Blogging.Comments.Dtos;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
public partial class CommentsClientProxy
{
public virtual async Task<List<CommentWithRepliesDto>> GetHierarchicalListOfPostAsync(Guid postId)
{
return await RequestAsync<List<CommentWithRepliesDto>>(nameof(GetHierarchicalListOfPostAsync), postId);
}
public virtual async Task<CommentWithDetailsDto> CreateAsync(CreateCommentDto input)
{
return await RequestAsync<CommentWithDetailsDto>(nameof(CreateAsync), input);
}
public virtual async Task<CommentWithDetailsDto> UpdateAsync(Guid id, UpdateCommentDto input)
{
return await RequestAsync<CommentWithDetailsDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/CommentsClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of CommentsClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ICommentAppService), typeof(CommentsClientProxy))]
public partial class CommentsClientProxy : ClientProxyBase<ICommentAppService>, ICommentAppService
{
}
}

49
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/PostsClientProxy.Generated.cs

@ -0,0 +1,49 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Posts;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
public partial class PostsClientProxy
{
public virtual async Task<ListResultDto<PostWithDetailsDto>> GetListByBlogIdAndTagNameAsync(Guid blogId, string tagName)
{
return await RequestAsync<ListResultDto<PostWithDetailsDto>>(nameof(GetListByBlogIdAndTagNameAsync), blogId, tagName);
}
public virtual async Task<ListResultDto<PostWithDetailsDto>> GetTimeOrderedListAsync(Guid blogId)
{
return await RequestAsync<ListResultDto<PostWithDetailsDto>>(nameof(GetTimeOrderedListAsync), blogId);
}
public virtual async Task<PostWithDetailsDto> GetForReadingAsync(GetPostInput input)
{
return await RequestAsync<PostWithDetailsDto>(nameof(GetForReadingAsync), input);
}
public virtual async Task<PostWithDetailsDto> GetAsync(Guid id)
{
return await RequestAsync<PostWithDetailsDto>(nameof(GetAsync), id);
}
public virtual async Task<PostWithDetailsDto> CreateAsync(CreatePostDto input)
{
return await RequestAsync<PostWithDetailsDto>(nameof(CreateAsync), input);
}
public virtual async Task<PostWithDetailsDto> UpdateAsync(Guid id, UpdatePostDto input)
{
return await RequestAsync<PostWithDetailsDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/PostsClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of PostsClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Posts;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IPostAppService), typeof(PostsClientProxy))]
public partial class PostsClientProxy : ClientProxyBase<IPostAppService>, IPostAppService
{
}
}

21
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/TagsClientProxy.Generated.cs

@ -0,0 +1,21 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Blogging.Tagging;
using System.Collections.Generic;
using Volo.Blogging.Tagging.Dtos;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
public partial class TagsClientProxy
{
public virtual async Task<List<TagDto>> GetPopularTagsAsync(Guid blogId, GetPopularTagsInput input)
{
return await RequestAsync<List<TagDto>>(nameof(GetPopularTagsAsync), blogId, input);
}
}
}

14
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/TagsClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of TagsClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Tagging;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITagAppService), typeof(TagsClientProxy))]
public partial class TagsClientProxy : ClientProxyBase<ITagAppService>, ITagAppService
{
}
}

856
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/blogging-generate-proxy.json

@ -0,0 +1,856 @@
{
"modules": {
"blogging": {
"rootPath": "blogging",
"remoteServiceName": "Blogging",
"controllers": {
"Volo.Blogging.BlogFilesController": {
"controllerName": "BlogFiles",
"controllerGroupName": "BlogFiles",
"type": "Volo.Blogging.BlogFilesController",
"interfaces": [
{
"type": "Volo.Blogging.Files.IFileAppService"
}
],
"actions": {
"GetAsyncByName": {
"uniqueName": "GetAsyncByName",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/blogging/files/{name}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "name",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "name",
"name": "name",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Files.RawFileDto",
"typeSimple": "Volo.Blogging.Files.RawFileDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Files.IFileAppService"
},
"GetForWebAsyncByName": {
"uniqueName": "GetForWebAsyncByName",
"name": "GetForWebAsync",
"httpMethod": "GET",
"url": "api/blogging/files/www/{name}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "name",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "name",
"name": "name",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Microsoft.AspNetCore.Mvc.FileResult",
"typeSimple": "Microsoft.AspNetCore.Mvc.FileResult"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.BlogFilesController"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/blogging/files",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Blogging.Files.FileUploadInputDto, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Files.FileUploadInputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadInputDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Files.FileUploadInputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadInputDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Files.FileUploadOutputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadOutputDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Files.IFileAppService"
},
"UploadImageByFile": {
"uniqueName": "UploadImageByFile",
"name": "UploadImage",
"httpMethod": "POST",
"url": "api/blogging/files/images/upload",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "file",
"typeAsString": "Microsoft.AspNetCore.Http.IFormFile, Microsoft.AspNetCore.Http.Features",
"type": "Microsoft.AspNetCore.Http.IFormFile",
"typeSimple": "Microsoft.AspNetCore.Http.IFormFile",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "file",
"name": "file",
"jsonName": null,
"type": "Microsoft.AspNetCore.Http.IFormFile",
"typeSimple": "Microsoft.AspNetCore.Http.IFormFile",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "FormFile",
"descriptorName": ""
}
],
"returnValue": {
"type": "Microsoft.AspNetCore.Mvc.JsonResult",
"typeSimple": "Microsoft.AspNetCore.Mvc.JsonResult"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.BlogFilesController"
}
}
},
"Volo.Blogging.BlogsController": {
"controllerName": "Blogs",
"controllerGroupName": "Blogs",
"type": "Volo.Blogging.BlogsController",
"interfaces": [
{
"type": "Volo.Blogging.Blogs.IBlogAppService"
}
],
"actions": {
"GetListAsync": {
"uniqueName": "GetListAsync",
"name": "GetListAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Blogs.Dtos.BlogDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Blogs.Dtos.BlogDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Blogs.IBlogAppService"
},
"GetByShortNameAsyncByShortName": {
"uniqueName": "GetByShortNameAsyncByShortName",
"name": "GetByShortNameAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs/by-shortname/{shortName}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "shortName",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "shortName",
"name": "shortName",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Blogs.Dtos.BlogDto",
"typeSimple": "Volo.Blogging.Blogs.Dtos.BlogDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Blogs.IBlogAppService"
},
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/blogging/blogs/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Blogs.Dtos.BlogDto",
"typeSimple": "Volo.Blogging.Blogs.Dtos.BlogDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Blogs.IBlogAppService"
}
}
},
"Volo.Blogging.CommentsController": {
"controllerName": "Comments",
"controllerGroupName": "Comments",
"type": "Volo.Blogging.CommentsController",
"interfaces": [
{
"type": "Volo.Blogging.Comments.ICommentAppService"
}
],
"actions": {
"GetHierarchicalListOfPostAsyncByPostId": {
"uniqueName": "GetHierarchicalListOfPostAsyncByPostId",
"name": "GetHierarchicalListOfPostAsync",
"httpMethod": "GET",
"url": "api/blogging/comments/hierarchical/{postId}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "postId",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "postId",
"name": "postId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Collections.Generic.List<Volo.Blogging.Comments.Dtos.CommentWithRepliesDto>",
"typeSimple": "[Volo.Blogging.Comments.Dtos.CommentWithRepliesDto]"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Comments.ICommentAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/blogging/comments",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Blogging.Comments.Dtos.CreateCommentDto, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Comments.Dtos.CreateCommentDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.CreateCommentDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Comments.Dtos.CreateCommentDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.CreateCommentDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Comments.ICommentAppService"
},
"UpdateAsyncByIdAndInput": {
"uniqueName": "UpdateAsyncByIdAndInput",
"name": "UpdateAsync",
"httpMethod": "PUT",
"url": "api/blogging/comments/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
},
{
"name": "input",
"typeAsString": "Volo.Blogging.Comments.Dtos.UpdateCommentDto, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Comments.Dtos.UpdateCommentDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.UpdateCommentDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Comments.Dtos.UpdateCommentDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.UpdateCommentDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto",
"typeSimple": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Comments.ICommentAppService"
},
"DeleteAsyncById": {
"uniqueName": "DeleteAsyncById",
"name": "DeleteAsync",
"httpMethod": "DELETE",
"url": "api/blogging/comments/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Comments.ICommentAppService"
}
}
},
"Volo.Blogging.PostsController": {
"controllerName": "Posts",
"controllerGroupName": "Posts",
"type": "Volo.Blogging.PostsController",
"interfaces": [
{
"type": "Volo.Blogging.Posts.IPostAppService"
}
],
"actions": {
"GetListByBlogIdAndTagNameAsyncByBlogIdAndTagName": {
"uniqueName": "GetListByBlogIdAndTagNameAsyncByBlogIdAndTagName",
"name": "GetListByBlogIdAndTagNameAsync",
"httpMethod": "GET",
"url": "api/blogging/posts/{blogId}/all",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "blogId",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
},
{
"name": "tagName",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "blogId",
"name": "blogId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "tagName",
"name": "tagName",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Posts.PostWithDetailsDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Posts.PostWithDetailsDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"GetTimeOrderedListAsyncByBlogId": {
"uniqueName": "GetTimeOrderedListAsyncByBlogId",
"name": "GetTimeOrderedListAsync",
"httpMethod": "GET",
"url": "api/blogging/posts/{blogId}/all/by-time",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "blogId",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "blogId",
"name": "blogId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Posts.PostWithDetailsDto>",
"typeSimple": "Volo.Abp.Application.Dtos.ListResultDto<Volo.Blogging.Posts.PostWithDetailsDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"GetForReadingAsyncByInput": {
"uniqueName": "GetForReadingAsyncByInput",
"name": "GetForReadingAsync",
"httpMethod": "GET",
"url": "api/blogging/posts/read",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Blogging.Posts.GetPostInput, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Posts.GetPostInput",
"typeSimple": "Volo.Blogging.Posts.GetPostInput",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Url",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "BlogId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Blogging.Posts.PostWithDetailsDto",
"typeSimple": "Volo.Blogging.Posts.PostWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/blogging/posts/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Posts.PostWithDetailsDto",
"typeSimple": "Volo.Blogging.Posts.PostWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/blogging/posts",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.Blogging.Posts.CreatePostDto, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Posts.CreatePostDto",
"typeSimple": "Volo.Blogging.Posts.CreatePostDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Posts.CreatePostDto",
"typeSimple": "Volo.Blogging.Posts.CreatePostDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Posts.PostWithDetailsDto",
"typeSimple": "Volo.Blogging.Posts.PostWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"UpdateAsyncByIdAndInput": {
"uniqueName": "UpdateAsyncByIdAndInput",
"name": "UpdateAsync",
"httpMethod": "PUT",
"url": "api/blogging/posts/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
},
{
"name": "input",
"typeAsString": "Volo.Blogging.Posts.UpdatePostDto, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Posts.UpdatePostDto",
"typeSimple": "Volo.Blogging.Posts.UpdatePostDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Volo.Blogging.Posts.UpdatePostDto",
"typeSimple": "Volo.Blogging.Posts.UpdatePostDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Posts.PostWithDetailsDto",
"typeSimple": "Volo.Blogging.Posts.PostWithDetailsDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
},
"DeleteAsyncById": {
"uniqueName": "DeleteAsyncById",
"name": "DeleteAsync",
"httpMethod": "DELETE",
"url": "api/blogging/posts/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Posts.IPostAppService"
}
}
},
"Volo.Blogging.TagsController": {
"controllerName": "Tags",
"controllerGroupName": "Tags",
"type": "Volo.Blogging.TagsController",
"interfaces": [
{
"type": "Volo.Blogging.Tagging.ITagAppService"
}
],
"actions": {
"GetPopularTagsAsyncByBlogIdAndInput": {
"uniqueName": "GetPopularTagsAsyncByBlogIdAndInput",
"name": "GetPopularTagsAsync",
"httpMethod": "GET",
"url": "api/blogging/tags/popular/{blogId}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "blogId",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
},
{
"name": "input",
"typeAsString": "Volo.Blogging.Tagging.Dtos.GetPopularTagsInput, Volo.Blogging.Application.Contracts",
"type": "Volo.Blogging.Tagging.Dtos.GetPopularTagsInput",
"typeSimple": "Volo.Blogging.Tagging.Dtos.GetPopularTagsInput",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "blogId",
"name": "blogId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "input",
"name": "ResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MinimumPostCount",
"jsonName": null,
"type": "System.Int32?",
"typeSimple": "number?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "System.Collections.Generic.List<Volo.Blogging.Tagging.Dtos.TagDto>",
"typeSimple": "[Volo.Blogging.Tagging.Dtos.TagDto]"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Tagging.ITagAppService"
}
}
}
}
}
},
"types": {}
}

8
modules/blogging/src/Volo.Blogging.HttpApi.Client/Volo/Blogging/BloggingHttpApiClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Blogging
{
@ -11,8 +12,13 @@ namespace Volo.Blogging
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(typeof(BloggingApplicationContractsModule).Assembly,
context.Services.AddStaticHttpClientProxies(typeof(BloggingApplicationContractsModule).Assembly,
BloggingRemoteServiceConsts.RemoteServiceName);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<BloggingHttpApiClientModule>();
});
}
}

2
modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs

@ -15,7 +15,7 @@ using Volo.Blogging.Localization;
namespace Volo.Blogging
{
[DependsOn(
typeof(BloggingHttpApiModule),
typeof(BloggingApplicationContractsModule),
typeof(AbpAspNetCoreMvcUiBootstrapModule),
typeof(AbpAspNetCoreMvcUiBundlingModule),
typeof(AbpAutoMapperModule)

5
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml

@ -36,8 +36,9 @@
}
@section scripts {
<abp-script-bundle name="@typeof(DetailModel).FullName">
<abp-script type="@typeof(PrismjsScriptBundleContributor)" />
<abp-script src="/Pages/Blogs/Posts/detail.js" />
<abp-script src="/client-proxies/blogging-proxy.js" />
<abp-script type="@typeof(PrismjsScriptBundleContributor)"/>
<abp-script src="/Pages/Blogs/Posts/detail.js"/>
</abp-script-bundle>
}
@section styles {

5
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml

@ -17,8 +17,9 @@
}
@section scripts {
<abp-script-bundle name="@typeof(EditModel).FullName">
<abp-script type="@typeof(TuiEditorScriptContributor)" />
<abp-script src="/Pages/Blogs/Posts/edit.js" />
<abp-script src="/client-proxies/blogging-proxy.js" />
<abp-script type="@typeof(TuiEditorScriptContributor)"/>
<abp-script src="/Pages/Blogs/Posts/edit.js"/>
</abp-script-bundle>
}
<div id="edit-post-container">

1
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml

@ -15,6 +15,7 @@
}
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/client-proxies/blogging-proxy.js" />
<abp-script type="@typeof(OwlCarouselScriptContributor)" />
<abp-script src="/Pages/Blogs/Shared/Scripts/blog.js" />
</abp-script-bundle>

5
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml

@ -17,8 +17,9 @@
}
@section scripts {
<abp-script-bundle name="@typeof(NewModel).FullName">
<abp-script type="@typeof(TuiEditorScriptContributor)" />
<abp-script src="/Pages/Blogs/Posts/new.js" />
<abp-script src="/client-proxies/blogging-proxy.js" />
<abp-script type="@typeof(TuiEditorScriptContributor)"/>
<abp-script src="/Pages/Blogs/Posts/new.js"/>
</abp-script-bundle>
}
<div id="qa-new-post-container">

6
modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj

@ -19,7 +19,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Packages\Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\Volo.Blogging.HttpApi\Volo.Blogging.HttpApi.csproj" />
<ProjectReference Include="..\Volo.Blogging.Application.Contracts\Volo.Blogging.Application.Contracts.csproj" />
<PackageReference Include="Markdig.Signed" Version="0.20.0" />
</ItemGroup>
@ -32,10 +32,14 @@
<EmbeddedResource Include="Pages\**\*.css" />
<EmbeddedResource Include="Components\**\*.js" />
<EmbeddedResource Include="Components\**\*.css" />
<EmbeddedResource Include="wwwroot\**\*.js" />
<EmbeddedResource Include="wwwroot\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="Components\**\*.js" />
<Content Remove="Components\**\*.css" />
<Content Remove="wwwroot\**\*.js" />
<Content Remove="wwwroot\**\*.css" />
<Content Remove="compilerconfig.json" />
<None Include="compilerconfig.json" />
</ItemGroup>

190
modules/blogging/src/Volo.Blogging.Web/wwwroot/client-proxies/blogging-proxy.js

@ -0,0 +1,190 @@
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */
// module blogging
(function(){
// controller volo.blogging.blogFiles
(function(){
abp.utils.createNamespace(window, 'volo.blogging.blogFiles');
volo.blogging.blogFiles.get = function(name, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files/' + name + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.blogFiles.getForWeb = function(name, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files/www/' + name + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.blogFiles.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.blogFiles.uploadImage = function(file, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files/images/upload',
type: 'POST'
}, ajaxParams));
};
})();
// controller volo.blogging.blogs
(function(){
abp.utils.createNamespace(window, 'volo.blogging.blogs');
volo.blogging.blogs.getList = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs',
type: 'GET'
}, ajaxParams));
};
volo.blogging.blogs.getByShortName = function(shortName, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/by-shortname/' + shortName + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.blogs.get = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/blogs/' + id + '',
type: 'GET'
}, ajaxParams));
};
})();
// controller volo.blogging.comments
(function(){
abp.utils.createNamespace(window, 'volo.blogging.comments');
volo.blogging.comments.getHierarchicalListOfPost = function(postId, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/comments/hierarchical/' + postId + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.comments.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/comments',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.comments.update = function(id, input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/comments/' + id + '',
type: 'PUT',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.comments['delete'] = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/comments/' + id + '',
type: 'DELETE',
dataType: null
}, ajaxParams));
};
})();
// controller volo.blogging.posts
(function(){
abp.utils.createNamespace(window, 'volo.blogging.posts');
volo.blogging.posts.getListByBlogIdAndTagName = function(blogId, tagName, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/' + blogId + '/all' + abp.utils.buildQueryString([{ name: 'tagName', value: tagName }]) + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.posts.getTimeOrderedList = function(blogId, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/' + blogId + '/all/by-time',
type: 'GET'
}, ajaxParams));
};
volo.blogging.posts.getForReading = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/read' + abp.utils.buildQueryString([{ name: 'url', value: input.url }, { name: 'blogId', value: input.blogId }]) + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.posts.get = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/' + id + '',
type: 'GET'
}, ajaxParams));
};
volo.blogging.posts.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.posts.update = function(id, input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/' + id + '',
type: 'PUT',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.posts['delete'] = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/posts/' + id + '',
type: 'DELETE',
dataType: null
}, ajaxParams));
};
})();
// controller volo.blogging.tags
(function(){
abp.utils.createNamespace(window, 'volo.blogging.tags');
volo.blogging.tags.getPopularTags = function(blogId, input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/tags/popular/' + blogId + '' + abp.utils.buildQueryString([{ name: 'resultCount', value: input.resultCount }, { name: 'minimumPostCount', value: input.minimumPostCount }]) + '',
type: 'GET'
}, ajaxParams));
};
})();
})();

4
modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/Properties/launchSettings.json

@ -1,4 +1,4 @@
{
 {
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
@ -24,4 +24,4 @@
}
}
}
}
}

39
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogAdminClientProxy.Generated.cs

@ -0,0 +1,39 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
public partial class BlogAdminClientProxy
{
public virtual async Task<BlogDto> GetAsync(Guid id)
{
return await RequestAsync<BlogDto>(nameof(GetAsync), id);
}
public virtual async Task<PagedResultDto<BlogDto>> GetListAsync(BlogGetListInput input)
{
return await RequestAsync<PagedResultDto<BlogDto>>(nameof(GetListAsync), input);
}
public virtual async Task<BlogDto> CreateAsync(CreateBlogDto input)
{
return await RequestAsync<BlogDto>(nameof(CreateAsync), input);
}
public virtual async Task<BlogDto> UpdateAsync(Guid id, UpdateBlogDto input)
{
return await RequestAsync<BlogDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogAdminAppService), typeof(BlogAdminClientProxy))]
public partial class BlogAdminClientProxy : ClientProxyBase<IBlogAdminAppService>, IBlogAdminAppService
{
}
}

26
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogFeatureAdminClientProxy.Generated.cs

@ -0,0 +1,26 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Blogs;
using System.Collections.Generic;
using Volo.CmsKit.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
public partial class BlogFeatureAdminClientProxy
{
public virtual async Task<List<BlogFeatureDto>> GetListAsync(Guid blogId)
{
return await RequestAsync<List<BlogFeatureDto>>(nameof(GetListAsync), blogId);
}
public virtual async Task SetAsync(Guid blogId, BlogFeatureInputDto dto)
{
await RequestAsync(nameof(SetAsync), blogId, dto);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogFeatureAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogFeatureAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogFeatureAdminAppService), typeof(BlogFeatureAdminClientProxy))]
public partial class BlogFeatureAdminClientProxy : ClientProxyBase<IBlogFeatureAdminAppService>, IBlogFeatureAdminAppService
{
}
}

39
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.Generated.cs

@ -0,0 +1,39 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
public partial class BlogPostAdminClientProxy
{
public virtual async Task<BlogPostDto> CreateAsync(CreateBlogPostDto input)
{
return await RequestAsync<BlogPostDto>(nameof(CreateAsync), input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
public virtual async Task<BlogPostDto> GetAsync(Guid id)
{
return await RequestAsync<BlogPostDto>(nameof(GetAsync), id);
}
public virtual async Task<PagedResultDto<BlogPostListDto>> GetListAsync(BlogPostGetListInput input)
{
return await RequestAsync<PagedResultDto<BlogPostListDto>>(nameof(GetListAsync), input);
}
public virtual async Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
{
return await RequestAsync<BlogPostDto>(nameof(UpdateAsync), id, input);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/BlogPostAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of BlogPostAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Blogs.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogPostAdminAppService), typeof(BlogPostAdminClientProxy))]
public partial class BlogPostAdminClientProxy : ClientProxyBase<IBlogPostAdminAppService>, IBlogPostAdminAppService
{
}
}

29
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/CommentAdminClientProxy.Generated.cs

@ -0,0 +1,29 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Comments.ClientProxies
{
public partial class CommentAdminClientProxy
{
public virtual async Task<PagedResultDto<CommentWithAuthorDto>> GetListAsync(CommentGetListInput input)
{
return await RequestAsync<PagedResultDto<CommentWithAuthorDto>>(nameof(GetListAsync), input);
}
public virtual async Task<CommentWithAuthorDto> GetAsync(Guid id)
{
return await RequestAsync<CommentWithAuthorDto>(nameof(GetAsync), id);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/CommentAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of CommentAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Comments.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ICommentAdminAppService), typeof(CommentAdminClientProxy))]
public partial class CommentAdminClientProxy : ClientProxyBase<ICommentAdminAppService>, ICommentAdminAppService
{
}
}

29
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/EntityTagAdminClientProxy.Generated.cs

@ -0,0 +1,29 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Tags;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Tags.ClientProxies
{
public partial class EntityTagAdminClientProxy
{
public virtual async Task AddTagToEntityAsync(EntityTagCreateDto input)
{
await RequestAsync(nameof(AddTagToEntityAsync), input);
}
public virtual async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input)
{
await RequestAsync(nameof(RemoveTagFromEntityAsync), input);
}
public virtual async Task SetEntityTagsAsync(EntityTagSetDto input)
{
await RequestAsync(nameof(SetEntityTagsAsync), input);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/EntityTagAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of EntityTagAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Tags;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Tags.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IEntityTagAdminAppService), typeof(EntityTagAdminClientProxy))]
public partial class EntityTagAdminClientProxy : ClientProxyBase<IEntityTagAdminAppService>, IEntityTagAdminAppService
{
}
}

24
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MediaDescriptorAdminClientProxy.Generated.cs

@ -0,0 +1,24 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.MediaDescriptors;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.MediaDescriptors.ClientProxies
{
public partial class MediaDescriptorAdminClientProxy
{
public virtual async Task<MediaDescriptorDto> CreateAsync(string entityType, CreateMediaInputWithStream inputStream)
{
return await RequestAsync<MediaDescriptorDto>(nameof(CreateAsync), entityType, inputStream);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MediaDescriptorAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of MediaDescriptorAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.MediaDescriptors;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.MediaDescriptors.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IMediaDescriptorAdminAppService), typeof(MediaDescriptorAdminClientProxy))]
public partial class MediaDescriptorAdminClientProxy : ClientProxyBase<IMediaDescriptorAdminAppService>, IMediaDescriptorAdminAppService
{
}
}

50
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MenuItemAdminClientProxy.Generated.cs

@ -0,0 +1,50 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Menus;
using Volo.CmsKit.Menus;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Menus.ClientProxies
{
public partial class MenuItemAdminClientProxy
{
public virtual async Task<ListResultDto<MenuItemDto>> GetListAsync()
{
return await RequestAsync<ListResultDto<MenuItemDto>>(nameof(GetListAsync));
}
public virtual async Task<MenuItemDto> GetAsync(Guid id)
{
return await RequestAsync<MenuItemDto>(nameof(GetAsync), id);
}
public virtual async Task<MenuItemDto> CreateAsync(MenuItemCreateInput input)
{
return await RequestAsync<MenuItemDto>(nameof(CreateAsync), input);
}
public virtual async Task<MenuItemDto> UpdateAsync(Guid id, MenuItemUpdateInput input)
{
return await RequestAsync<MenuItemDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
public virtual async Task MoveMenuItemAsync(Guid id, MenuItemMoveInput input)
{
await RequestAsync(nameof(MoveMenuItemAsync), id, input);
}
public virtual async Task<PagedResultDto<PageLookupDto>> GetPageLookupAsync(PageLookupInputDto input)
{
return await RequestAsync<PagedResultDto<PageLookupDto>>(nameof(GetPageLookupAsync), input);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/MenuItemAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of MenuItemAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Menus;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Menus.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IMenuItemAdminAppService), typeof(MenuItemAdminClientProxy))]
public partial class MenuItemAdminClientProxy : ClientProxyBase<IMenuItemAdminAppService>, IMenuItemAdminAppService
{
}
}

39
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/PageAdminClientProxy.Generated.cs

@ -0,0 +1,39 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Pages;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Pages.ClientProxies
{
public partial class PageAdminClientProxy
{
public virtual async Task<PageDto> GetAsync(Guid id)
{
return await RequestAsync<PageDto>(nameof(GetAsync), id);
}
public virtual async Task<PagedResultDto<PageDto>> GetListAsync(GetPagesInputDto input)
{
return await RequestAsync<PagedResultDto<PageDto>>(nameof(GetListAsync), input);
}
public virtual async Task<PageDto> CreateAsync(CreatePageInputDto input)
{
return await RequestAsync<PageDto>(nameof(CreateAsync), input);
}
public virtual async Task<PageDto> UpdateAsync(Guid id, UpdatePageInputDto input)
{
return await RequestAsync<PageDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/PageAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of PageAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Pages;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Pages.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IPageAdminAppService), typeof(PageAdminClientProxy))]
public partial class PageAdminClientProxy : ClientProxyBase<IPageAdminAppService>, IPageAdminAppService
{
}
}

46
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/TagAdminClientProxy.Generated.cs

@ -0,0 +1,46 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Tags;
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Tags.ClientProxies
{
public partial class TagAdminClientProxy
{
public virtual async Task<TagDto> CreateAsync(TagCreateDto input)
{
return await RequestAsync<TagDto>(nameof(CreateAsync), input);
}
public virtual async Task DeleteAsync(Guid id)
{
await RequestAsync(nameof(DeleteAsync), id);
}
public virtual async Task<TagDto> GetAsync(Guid id)
{
return await RequestAsync<TagDto>(nameof(GetAsync), id);
}
public virtual async Task<PagedResultDto<TagDto>> GetListAsync(TagGetListInput input)
{
return await RequestAsync<PagedResultDto<TagDto>>(nameof(GetListAsync), input);
}
public virtual async Task<TagDto> UpdateAsync(Guid id, TagUpdateDto input)
{
return await RequestAsync<TagDto>(nameof(UpdateAsync), id, input);
}
public virtual async Task<List<TagDefinitionDto>> GetTagDefinitionsAsync()
{
return await RequestAsync<List<TagDefinitionDto>>(nameof(GetTagDefinitionsAsync));
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/TagAdminClientProxy.cs

@ -0,0 +1,14 @@
// This file is part of TagAdminClientProxy, you can customize it here
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Admin.Tags;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Admin.Tags.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITagAdminAppService), typeof(TagAdminClientProxy))]
public partial class TagAdminClientProxy : ClientProxyBase<ITagAdminAppService>, ITagAdminAppService
{
}
}

1967
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json

File diff suppressed because it is too large

8
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/Volo/CmsKit/Admin/CmsKitAdminHttpApiClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.CmsKit.Admin
{
@ -11,10 +12,15 @@ namespace Volo.CmsKit.Admin
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(
context.Services.AddStaticHttpClientProxies(
typeof(CmsKitAdminApplicationContractsModule).Assembly,
CmsKitAdminRemoteServiceConsts.RemoteServiceName
);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<CmsKitAdminHttpApiClientModule>();
});
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs

@ -15,7 +15,7 @@ using Volo.Abp.AutoMapper;
namespace Volo.CmsKit.Admin.Web
{
[DependsOn(
typeof(CmsKitAdminHttpApiModule),
typeof(CmsKitAdminApplicationContractsModule),
typeof(CmsKitCommonWebModule)
)]
public class CmsKitAdminWebModule : AbpModule

8
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml

@ -26,6 +26,8 @@
<abp-script type="typeof(TuiEditorScriptContributor)"/>
<abp-script type="typeof(UppyScriptContributor)"/>
<abp-script type="typeof(SlugifyScriptContributor)"/>
<abp-script src="/client-proxies/cms-kit-common-proxy.js"/>
<abp-script src="/client-proxies/cms-kit-admin-proxy.js"/>
<abp-script src="/Pages/CmsKit/BlogPosts/create.js"/>
</abp-script-bundle>
}
@ -59,11 +61,11 @@
<abp-input asp-for="ViewModel.Title" />
<abp-input asp-for="ViewModel.Slug" />
<abp-form-content />
<div class="content-editor cms-kit-editor"
id="ContentEditor"
<div class="content-editor cms-kit-editor"
id="ContentEditor"
data-input-id="@Html.IdFor(x => x.ViewModel.Content)"
data-language="@(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName)">
</div>

10
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml

@ -17,12 +17,14 @@
}
@section scripts {
<abp-script src="/Pages/CmsKit/BlogPosts/index.js" />
<abp-script src="/client-proxies/cms-kit-common-proxy.js"/>
<abp-script src="/client-proxies/cms-kit-admin-proxy.js"/>
<abp-script src="/Pages/CmsKit/BlogPosts/index.js"/>
}
@section content_toolbar {
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName })
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new {pageName = typeof(IndexModel).FullName})
}
<abp-card class="mb-4">
@ -36,9 +38,9 @@
</div>
</abp-card-body>
</abp-card>
<abp-card>
<abp-card-body>
<abp-table striped-rows="true" id="BlogPostsTable" class="nowrap"></abp-table>
</abp-card-body>
</abp-card>
</abp-card>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save