diff --git a/Directory.Packages.props b/Directory.Packages.props index ca6058bed5..53a7f30cbb 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,7 +11,8 @@ - + + diff --git a/docs/en/API/API-Versioning.md b/docs/en/API/API-Versioning.md index d0f94f2259..741eafbb75 100644 --- a/docs/en/API/API-Versioning.md +++ b/docs/en/API/API-Versioning.md @@ -8,11 +8,10 @@ ABP Framework integrates the [ASPNET-API-Versioning](https://github.com/dotnet/a ```cs public override void ConfigureServices(ServiceConfigurationContext context) { + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; }); @@ -239,11 +238,10 @@ public override void ConfigureServices(ServiceConfigurationContext context) preActions.Configure(options); }); + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; @@ -263,27 +261,22 @@ public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context) { + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; + }).AddApiExplorer(options => { + // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service + // note: the specified format code will format the version as "'v'major[.minor][-status]" + options.GroupNameFormat = "'v'VVV"; + + // note: this option is only necessary when versioning by url segment. the SubstitutionFormat + // can also be used to control the format of the API version in route templates + options.SubstituteApiVersionInUrl = true; }); - context.Services.AddVersionedApiExplorer( - options => - { - // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service - // note: the specified format code will format the version as "'v'major[.minor][-status]" - options.GroupNameFormat = "'v'VVV"; - - // note: this option is only necessary when versioning by url segment. the SubstitutionFormat - // can also be used to control the format of the API version in route templates - options.SubstituteApiVersionInUrl = true; - }); - context.Services.AddTransient, ConfigureSwaggerOptions>(); context.Services.AddAbpSwaggerGen( @@ -322,7 +315,7 @@ public override void OnApplicationInitialization(ApplicationInitializationContex app.UseAbpRequestLocalization(); app.UseSwagger(); - app.UseSwaggerUI( + app.UseAbpSwaggerUI( options => { var provider = app.ApplicationServices.GetRequiredService(); diff --git a/docs/zh-Hans/API/API-Versioning.md b/docs/zh-Hans/API/API-Versioning.md index 81bb6574c6..3e63ec045e 100644 --- a/docs/zh-Hans/API/API-Versioning.md +++ b/docs/zh-Hans/API/API-Versioning.md @@ -7,11 +7,10 @@ ABP框架集成了[ASPNET-API-版本控制](https://github.com/dotnet/aspnet-api ```cs public override void ConfigureServices(ServiceConfigurationContext context) { + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; }); @@ -238,11 +237,10 @@ public override void ConfigureServices(ServiceConfigurationContext context) preActions.Configure(options); }); + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; @@ -262,27 +260,22 @@ public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context) { + // Show neutral/versionless APIs. + context.Services.AddTransient(); context.Services.AddAbpApiVersioning(options => { - // Show neutral/versionless APIs. - options.UseApiBehavior = false; - options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; + }).AddApiExplorer(options => { + // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service + // note: the specified format code will format the version as "'v'major[.minor][-status]" + options.GroupNameFormat = "'v'VVV"; + + // note: this option is only necessary when versioning by url segment. the SubstitutionFormat + // can also be used to control the format of the API version in route templates + options.SubstituteApiVersionInUrl = true; }); - context.Services.AddVersionedApiExplorer( - options => - { - // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service - // note: the specified format code will format the version as "'v'major[.minor][-status]" - options.GroupNameFormat = "'v'VVV"; - - // note: this option is only necessary when versioning by url segment. the SubstitutionFormat - // can also be used to control the format of the API version in route templates - options.SubstituteApiVersionInUrl = true; - }); - context.Services.AddTransient, ConfigureSwaggerOptions>(); context.Services.AddAbpSwaggerGen( @@ -321,7 +314,7 @@ public override void OnApplicationInitialization(ApplicationInitializationContex app.UseAbpRequestLocalization(); app.UseSwagger(); - app.UseSwaggerUI( + app.UseAbpSwaggerUI( options => { var provider = app.ApplicationServices.GetRequiredService(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs index c3f93fc06c..ac841bb5f8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs @@ -11,7 +11,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class AbpApiVersioningExtensions { - public static IServiceCollection AddAbpApiVersioning( + public static IApiVersioningBuilder AddAbpApiVersioning( this IServiceCollection services, Action? apiVersioningOptionsSetupAction = null, Action? mvcApiVersioningOptionsSetupAction = null) @@ -21,9 +21,7 @@ public static class AbpApiVersioningExtensions apiVersioningOptionsSetupAction ??= _ => { }; mvcApiVersioningOptionsSetupAction ??= _ => { }; - services.AddApiVersioning(apiVersioningOptionsSetupAction).AddMvc(mvcApiVersioningOptionsSetupAction); - - return services; + return services.AddApiVersioning(apiVersioningOptionsSetupAction).AddMvc(mvcApiVersioningOptionsSetupAction); } public static void ConfigureAbp(this MvcApiVersioningOptions options, AbpAspNetCoreMvcOptions mvcOptions) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index c52ec08b2a..a6e2edc2cf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -32,6 +32,7 @@ + diff --git a/npm/ng-packs/packages/schematics/src/commands/api/index.ts b/npm/ng-packs/packages/schematics/src/commands/api/index.ts index 5f064e8f3f..c04ca1d433 100644 --- a/npm/ng-packs/packages/schematics/src/commands/api/index.ts +++ b/npm/ng-packs/packages/schematics/src/commands/api/index.ts @@ -48,21 +48,28 @@ export default function (schema: GenerateProxySchema) { const createProxyConfigWriter = createProxyConfigWriterCreator(targetPath); const data = readProxyConfig(tree); data.types = sanitizeTypeNames(data.types); + const types = data.types; const modules = data.modules; const serviceType = schema.serviceType || defaultEServiceType; - if (!types || !modules) throw new SchematicsException(Exception.InvalidApiDefinition); + + if (!types || !modules) { + throw new SchematicsException(Exception.InvalidApiDefinition); + } const definition = data.modules[moduleName]; - if (!definition) + if (!definition) { throw new SchematicsException(interpolate(Exception.InvalidModule, moduleName)); + } const apiName = definition.remoteServiceName; data.modules[moduleName].controllers = sanitizeControllerTypeNames(definition.controllers); + const controllers = filterControllersByServiceType( serviceType, data.modules[moduleName].controllers, ); + const serviceImports: Record = {}; const generateServices = createServiceGenerator({ targetPath, @@ -90,8 +97,12 @@ export default function (schema: GenerateProxySchema) { modelImports, }); - if (!data.generated.includes(moduleName)) data.generated.push(moduleName); + if (!data.generated.includes(moduleName)) { + data.generated.push(moduleName); + } + data.generated.sort(); + const json = generateProxyConfigJson(data); const overwriteProxyConfig = createProxyConfigWriter('overwrite', json); @@ -129,11 +140,18 @@ function createModelGenerator(params: ModelGeneratorParams) { const { targetPath, serviceImports, modelImports } = params; const reduceImportRefsToModels = createImportRefsToModelReducer(params); const models = Object.values(serviceImports).reduce(reduceImportRefsToModels, []); + models.forEach(({ imports }) => imports.forEach(({ refs, path }) => refs.forEach(ref => { - if (path === '@abp/ng.core') return; - if (!modelImports[path]) return (modelImports[path] = [ref]); + if (path === '@abp/ng.core') { + return; + } + + if (!modelImports[path]) { + return (modelImports[path] = [ref]); + } + modelImports[path] = [...new Set([...modelImports[path], ref])]; }), ), diff --git a/npm/ng-packs/packages/schematics/src/utils/model.ts b/npm/ng-packs/packages/schematics/src/utils/model.ts index 11ff88d15a..52b9b36be0 100644 --- a/npm/ng-packs/packages/schematics/src/utils/model.ts +++ b/npm/ng-packs/packages/schematics/src/utils/model.ts @@ -71,23 +71,30 @@ export function createImportRefsToModelReducer(params: ModelGeneratorParams) { model.interfaces.forEach(_interface => { const { baseType } = types[_interface.ref]; - if (baseType && parseNamespace(solution, baseType) !== model.namespace){ + if (baseType && parseNamespace(solution, baseType) !== model.namespace) { const baseTypeWithGenericParams = parseBaseTypeWithGenericTypes(baseType); baseTypeWithGenericParams.forEach(t => { toBeImported.push({ type: t, isEnum: false, }); - }) + }); + } -} [..._interface.properties, ..._interface.generics].forEach(prop => { prop.refs.forEach(ref => { const propType = types[ref]; - if (!propType) return; - if (propType.isEnum) toBeImported.push({ type: ref, isEnum: true }); - else if (parseNamespace(solution, ref) !== model.namespace) + if (!propType) { + return; + } + + if (propType.isEnum) { + toBeImported.push({ type: ref, isEnum: true }); + } + + if (parseNamespace(solution, ref) !== model.namespace) { toBeImported.push({ type: ref, isEnum: false }); + } }); }); }); @@ -176,20 +183,21 @@ export function createRefToImportReducerCreator(params: ModelGeneratorParams) { } function isOptionalProperty(prop: PropertyDef) { - return (prop.typeSimple.endsWith('?') || (prop.typeSimple === 'string' && !prop.isRequired)); + return prop.typeSimple.endsWith('?') || (prop.typeSimple === 'string' && !prop.isRequired); } -export function parseBaseTypeWithGenericTypes(type: string): string[] { +export function parseBaseTypeWithGenericTypes(type: string): string[] { const parsedTypeNode = parseGenerics(type); - const nodeToText = (node: TypeNode,acc:string[] = []): string[] => { + const nodeToText = (node: TypeNode, acc: string[] = []): string[] => { acc.push(node.data); - if(node.children && node.children.length > 0){ + if (node.children && node.children.length > 0) { node.children.forEach(child => { - nodeToText(child,acc); - }) + nodeToText(child, acc); + }); } return acc; - } + }; + return nodeToText(parsedTypeNode); } diff --git a/npm/ng-packs/packages/schematics/src/utils/type.ts b/npm/ng-packs/packages/schematics/src/utils/type.ts index a5c83f8e63..63c69c7aec 100644 --- a/npm/ng-packs/packages/schematics/src/utils/type.ts +++ b/npm/ng-packs/packages/schematics/src/utils/type.ts @@ -14,7 +14,7 @@ export function createTypeSimplifier() { ); type = /any${array}` : identifier; }); @@ -64,12 +64,21 @@ export function createTypesToImportsReducer(solution: string, namespace: string) return (imports: Import[], types: TypeWithEnum[]) => { types.forEach(({ type, isEnum }) => { const newImport = mapTypeToImport(type, isEnum); - if (!newImport) return; + if (!newImport) { + return; + } + + if(newImport.specifiers.some(f => f.toLocaleLowerCase() === type.toLocaleLowerCase())){ + return; + } const existingImport = imports.find( ({ keyword, path }) => keyword === newImport.keyword && path === newImport.path, ); - if (!existingImport) return imports.push(newImport); + + if (!existingImport){ + return imports.push(newImport); + } existingImport.refs = [...new Set([...existingImport.refs, ...newImport.refs])]; existingImport.specifiers = [ @@ -91,11 +100,15 @@ export function createTypeToImportMapper(solution: string, namespace: string) { const modelNamespace = parseNamespace(solution, type); const refs = [removeTypeModifiers(type)]; const specifiers = [adaptType(simplifyType(refs[0]).split('<')[0])]; - const path = VOLO_REGEX.test(type) - ? '@abp/ng.core' - : isEnum - ? relativePathToEnum(namespace, modelNamespace, specifiers[0]) - : relativePathToModel(namespace, modelNamespace); + let path = relativePathToModel(namespace, modelNamespace); + + if (VOLO_REGEX.test(type)) { + path = '@abp/ng.core'; + } + + if (isEnum) { + path = relativePathToEnum(namespace, modelNamespace, specifiers[0]); + } return new Import({ keyword: eImportKeyword.Type, path, refs, specifiers }); };