46 changed files with 1607 additions and 2 deletions
@ -0,0 +1,14 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Wrapper |
||||
|
{ |
||||
|
public class AbpWrapperModule: AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Wrapper |
||||
|
{ |
||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] |
||||
|
public class IgnoreWrapResultAttribute : Attribute |
||||
|
{ |
||||
|
public IgnoreWrapResultAttribute() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Wrapper |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class WrapResult: WrapResult<object> |
||||
|
{ |
||||
|
public WrapResult() { } |
||||
|
public WrapResult( |
||||
|
string code, |
||||
|
string message, |
||||
|
string details = null) |
||||
|
: base(code, message, details) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public WrapResult( |
||||
|
string code, |
||||
|
object result, |
||||
|
string message = "OK") |
||||
|
: base(code, result, message) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Wrapper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 返回值包装结构
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TResult"></typeparam>
|
||||
|
[Serializable] |
||||
|
public class WrapResult<TResult> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 错误代码
|
||||
|
/// </summary>
|
||||
|
public string Code { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 错误提示消息
|
||||
|
/// </summary>
|
||||
|
public string Message { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 补充消息
|
||||
|
/// </summary>
|
||||
|
public string Details { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 返回值
|
||||
|
/// </summary>
|
||||
|
public TResult Result { get; set; } |
||||
|
public WrapResult() { } |
||||
|
public WrapResult( |
||||
|
string code, |
||||
|
string message, |
||||
|
string details = null) |
||||
|
{ |
||||
|
Code = code; |
||||
|
Message = message; |
||||
|
Details = details; |
||||
|
} |
||||
|
|
||||
|
public WrapResult( |
||||
|
string code, |
||||
|
TResult result, |
||||
|
string message = "OK") |
||||
|
{ |
||||
|
Code = code; |
||||
|
Result = result; |
||||
|
Message = message; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="LINGYUN\Abp\AspNetCore\Mvc\Wrapper\Localization\Resources\en.json" /> |
||||
|
<None Remove="LINGYUN\Abp\AspNetCore\Mvc\Wrapper\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\AspNetCore\Mvc\Wrapper\Localization\Resources\en.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\AspNetCore\Mvc\Wrapper\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\common\LINGYUN.Abp.Wrapper\LINGYUN.Abp.Wrapper.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,65 @@ |
|||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Filters; |
||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Localization; |
||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ApiExploring; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ProxyScripting; |
||||
|
using Volo.Abp.Http.Modeling; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpWrapperModule), |
||||
|
typeof(AbpAspNetCoreMvcModule))] |
||||
|
public class AbpAspNetCoreMvcWrapperModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAspNetCoreMvcWrapperModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<AbpMvcWrapperResource>("en") |
||||
|
.AddVirtualJson("/LINGYUN/Abp/AspNetCore/Mvc/Wrapper/Localization/Resources"); |
||||
|
}); |
||||
|
|
||||
|
Configure<MvcOptions>(mvcOptions => |
||||
|
{ |
||||
|
// Wrap Result Filter
|
||||
|
mvcOptions.Filters.AddService(typeof(AbpWrapResultFilter)); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAspNetCoreMvcWrapperOptions>(options => |
||||
|
{ |
||||
|
// 即使重写端点也不包装返回结果
|
||||
|
// api/abp/api-definition
|
||||
|
options.IgnoreReturnTypes.Add<ApplicationApiDescriptionModel>(); |
||||
|
// api/abp/application-configuration
|
||||
|
options.IgnoreReturnTypes.Add<ApplicationConfigurationDto>(); |
||||
|
// Abp/ServiceProxyScript
|
||||
|
options.IgnoreControllers.Add<AbpServiceProxyScriptController>(); |
||||
|
|
||||
|
// 官方模块不包装结果
|
||||
|
options.IgnoreNamespaces.Add("Volo.Abp"); |
||||
|
|
||||
|
// 返回本地化的 404 错误消息
|
||||
|
options.MessageWithEmptyResult = (serviceProvider) => |
||||
|
{ |
||||
|
var localizer = serviceProvider.GetRequiredService<IStringLocalizer<AbpMvcWrapperResource>>(); |
||||
|
return localizer["Wrapper:NotFound"]; |
||||
|
}; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net; |
||||
|
using Volo.Abp.Collections; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
{ |
||||
|
public class AbpAspNetCoreMvcWrapperOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 是否启用包装器
|
||||
|
/// </summary>
|
||||
|
public bool IsEnabled { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 资源有效时返回代码
|
||||
|
/// 默认:0
|
||||
|
/// </summary>
|
||||
|
public string CodeWithFound { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 资源为空时返回代码
|
||||
|
/// 默认:404
|
||||
|
/// </summary>
|
||||
|
public Func<IServiceProvider, string> CodeWithEmptyResult { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 资源为空时返回错误消息
|
||||
|
/// </summary>
|
||||
|
public Func<IServiceProvider, string> MessageWithEmptyResult { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 包装后的返回状态码
|
||||
|
/// 默认:200 HttpStatusCode.OK
|
||||
|
/// </summary>
|
||||
|
public HttpStatusCode HttpStatusCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 忽略Url开头类型
|
||||
|
/// </summary>
|
||||
|
public IList<string> IgnorePrefixUrls { get; } |
||||
|
/// <summary>
|
||||
|
/// 忽略指定命名空间
|
||||
|
/// </summary>
|
||||
|
public IList<string> IgnoreNamespaces { get; } |
||||
|
/// <summary>
|
||||
|
/// 忽略控制器
|
||||
|
/// </summary>
|
||||
|
public ITypeList IgnoreControllers { get; } |
||||
|
/// <summary>
|
||||
|
/// 忽略返回值
|
||||
|
/// </summary>
|
||||
|
public ITypeList IgnoreReturnTypes { get; } |
||||
|
/// <summary>
|
||||
|
/// 忽略异常
|
||||
|
/// </summary>
|
||||
|
public ITypeList<Exception> IgnoreExceptions { get; } |
||||
|
|
||||
|
public AbpAspNetCoreMvcWrapperOptions() |
||||
|
{ |
||||
|
CodeWithFound = "0"; |
||||
|
HttpStatusCode = HttpStatusCode.OK; |
||||
|
|
||||
|
IgnorePrefixUrls = new List<string>(); |
||||
|
IgnoreNamespaces = new List<string>(); |
||||
|
|
||||
|
IgnoreControllers = new TypeList(); |
||||
|
IgnoreReturnTypes = new TypeList(); |
||||
|
IgnoreExceptions = new TypeList<Exception>(); |
||||
|
|
||||
|
CodeWithEmptyResult = (_) => "404"; |
||||
|
MessageWithEmptyResult = (_) => "Not Found"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
{ |
||||
|
public static class AbpHttpWrapConsts |
||||
|
{ |
||||
|
public const string AbpWrapResult = "_AbpWrapResult"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.ExceptionHandling; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.ExceptionHandling |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices(typeof(AbpExceptionPageFilter))] |
||||
|
public class AbpExceptionPageWrapResultFilter: AbpExceptionPageFilter, ITransientDependency |
||||
|
{ |
||||
|
protected override bool ShouldHandleException(PageHandlerExecutingContext context) |
||||
|
{ |
||||
|
if (!context.ActionDescriptor.CanWarpRsult()) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
return base.ShouldHandleException(context); |
||||
|
} |
||||
|
|
||||
|
protected override async Task HandleAndWrapException(PageHandlerExecutedContext context) |
||||
|
{ |
||||
|
var wrapResultChecker = context.GetRequiredService<IWrapResultChecker>(); |
||||
|
if (!wrapResultChecker.WrapOnException(context)) |
||||
|
{ |
||||
|
await base.HandleAndWrapException(context); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var wrapResultOptions = context.GetRequiredService<IOptions<AbpAspNetCoreMvcWrapperOptions>>().Value; |
||||
|
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value; |
||||
|
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>(); |
||||
|
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); |
||||
|
|
||||
|
var logLevel = context.Exception.GetLogLevel(); |
||||
|
|
||||
|
var remoteServiceErrorInfoBuilder = new StringBuilder(); |
||||
|
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); |
||||
|
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true)); |
||||
|
|
||||
|
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true"); |
||||
|
|
||||
|
var logger = context.GetService<ILogger<AbpExceptionPageWrapResultFilter>>(NullLogger<AbpExceptionPageWrapResultFilter>.Instance); |
||||
|
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); |
||||
|
|
||||
|
logger.LogException(context.Exception, logLevel); |
||||
|
|
||||
|
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception)); |
||||
|
|
||||
|
// Warp Error Response
|
||||
|
string errorCode = remoteServiceErrorInfo.Code; |
||||
|
if (context.Exception is IHasErrorCode exceptionWithErrorCode) |
||||
|
{ |
||||
|
if (!exceptionWithErrorCode.Code.IsNullOrWhiteSpace() && |
||||
|
exceptionWithErrorCode.Code.Contains(":")) |
||||
|
{ |
||||
|
errorCode = exceptionWithErrorCode.Code.Split(':')[1]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
errorCode = exceptionWithErrorCode.Code; |
||||
|
} |
||||
|
} |
||||
|
context.Result = new ObjectResult(new WrapResult(errorCode, remoteServiceErrorInfo.Message, remoteServiceErrorInfo.Details)); |
||||
|
|
||||
|
context.Exception = null; //Handled!
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.ExceptionHandling; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.ExceptionHandling |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices(typeof(AbpExceptionFilter))] |
||||
|
public class AbpExceptionWrapResultFilter : AbpExceptionFilter, ITransientDependency |
||||
|
{ |
||||
|
protected override bool ShouldHandleException(ExceptionContext context) |
||||
|
{ |
||||
|
var wrapResultChecker = context.GetRequiredService<IWrapResultChecker>(); |
||||
|
|
||||
|
if (!wrapResultChecker.WrapOnException(context)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
return base.ShouldHandleException(context); |
||||
|
} |
||||
|
|
||||
|
protected override async Task HandleAndWrapException(ExceptionContext context) |
||||
|
{ |
||||
|
//TODO: Trigger an AbpExceptionHandled event or something like that.
|
||||
|
var wrapResultOptions = context.GetRequiredService<IOptions<AbpAspNetCoreMvcWrapperOptions>>().Value; |
||||
|
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value; |
||||
|
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>(); |
||||
|
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); |
||||
|
|
||||
|
var logLevel = context.Exception.GetLogLevel(); |
||||
|
|
||||
|
var remoteServiceErrorInfoBuilder = new StringBuilder(); |
||||
|
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); |
||||
|
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true)); |
||||
|
|
||||
|
var logger = context.GetService<ILogger<AbpExceptionWrapResultFilter>>(NullLogger<AbpExceptionWrapResultFilter>.Instance); |
||||
|
|
||||
|
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); |
||||
|
|
||||
|
logger.LogException(context.Exception, logLevel); |
||||
|
|
||||
|
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception)); |
||||
|
|
||||
|
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); |
||||
|
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true"); |
||||
|
context.HttpContext.Response.StatusCode = (int)wrapResultOptions.HttpStatusCode; |
||||
|
|
||||
|
// Warp Error Response
|
||||
|
string errorCode = remoteServiceErrorInfo.Code; |
||||
|
if (context.Exception is IHasErrorCode exceptionWithErrorCode) |
||||
|
{ |
||||
|
if (!exceptionWithErrorCode.Code.IsNullOrWhiteSpace() && |
||||
|
exceptionWithErrorCode.Code.Contains(":")) |
||||
|
{ |
||||
|
errorCode = exceptionWithErrorCode.Code.Split(':')[1]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
errorCode = exceptionWithErrorCode.Code; |
||||
|
} |
||||
|
} |
||||
|
context.Result = new ObjectResult(new WrapResult(errorCode, remoteServiceErrorInfo.Message, remoteServiceErrorInfo.Details)); |
||||
|
|
||||
|
context.Exception = null; //Handled!
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Filters |
||||
|
{ |
||||
|
public class AbpWrapResultFilter : IAsyncResultFilter, ITransientDependency |
||||
|
{ |
||||
|
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) |
||||
|
{ |
||||
|
if (ShouldWrapResult(context)) |
||||
|
{ |
||||
|
await HandleAndWrapResult(context); |
||||
|
} |
||||
|
|
||||
|
await next(); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ShouldWrapResult(ResultExecutingContext context) |
||||
|
{ |
||||
|
var wrapResultChecker = context.GetRequiredService<IWrapResultChecker>(); |
||||
|
|
||||
|
return wrapResultChecker.WrapOnExecution(context); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task HandleAndWrapResult(ResultExecutingContext context) |
||||
|
{ |
||||
|
var actionResultWrapperFactory = context.GetRequiredService<IActionResultWrapperFactory>(); |
||||
|
actionResultWrapperFactory.CreateFor(context).Wrap(context); |
||||
|
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true"); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
{ |
||||
|
public interface IWrapResultChecker |
||||
|
{ |
||||
|
bool WrapOnExecution(FilterContext context); |
||||
|
|
||||
|
bool WrapOnException(ExceptionContext context); |
||||
|
|
||||
|
bool WrapOnException(PageHandlerExecutedContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("AbpMvcWrapper")] |
||||
|
public class AbpMvcWrapperResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Wrapper:NotFound": "The requested resource was not found on the server." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Wrapper:NotFound": "在服务器中没有找到请求的资源." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,157 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.AspNetCore.Mvc.Abstractions; |
||||
|
using Microsoft.AspNetCore.Mvc.Controllers; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Http; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
{ |
||||
|
public class WrapResultChecker : IWrapResultChecker, ISingletonDependency |
||||
|
{ |
||||
|
protected AbpAspNetCoreMvcWrapperOptions Options { get; } |
||||
|
|
||||
|
public WrapResultChecker(IOptionsMonitor<AbpAspNetCoreMvcWrapperOptions> optionsMonitor) |
||||
|
{ |
||||
|
Options = optionsMonitor.CurrentValue; |
||||
|
} |
||||
|
|
||||
|
public bool WrapOnException(ExceptionContext context) |
||||
|
{ |
||||
|
if (!CheckForBase(context)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return CheckForException(context.Exception); |
||||
|
} |
||||
|
|
||||
|
public bool WrapOnException(PageHandlerExecutedContext context) |
||||
|
{ |
||||
|
return CheckForException(context.Exception); |
||||
|
} |
||||
|
|
||||
|
public bool WrapOnExecution(FilterContext context) |
||||
|
{ |
||||
|
return CheckForBase(context); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
protected virtual bool CheckForBase(FilterContext context) |
||||
|
{ |
||||
|
if (context.ActionDescriptor is ControllerActionDescriptor descriptor) |
||||
|
{ |
||||
|
if (!context.ActionDescriptor.HasObjectResult()) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
//if (!context.HttpContext.Request.CanAccept(MimeTypes.Application.Json))
|
||||
|
//{
|
||||
|
// return false;
|
||||
|
//}
|
||||
|
|
||||
|
if (!CheckForUrl(context)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!CheckForNamespace(descriptor)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!CheckForController(descriptor)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!CheckForMethod(descriptor)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!CheckForReturnType(descriptor)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForUrl(FilterContext context) |
||||
|
{ |
||||
|
if (!Options.IgnorePrefixUrls.Any()) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
var url = BuildUrl(context.HttpContext); |
||||
|
return !Options.IgnorePrefixUrls.Any(urlPrefix => urlPrefix.StartsWith(url)); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForController(ControllerActionDescriptor controllerActionDescriptor) |
||||
|
{ |
||||
|
if (controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(IgnoreWrapResultAttribute), true)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return !Options.IgnoreControllers.Any(controller => |
||||
|
controller.IsAssignableFrom(controllerActionDescriptor.ControllerTypeInfo)); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForMethod(ControllerActionDescriptor controllerActionDescriptor) |
||||
|
{ |
||||
|
return !controllerActionDescriptor.MethodInfo.IsDefined(typeof(IgnoreWrapResultAttribute), true); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForNamespace(ControllerActionDescriptor controllerActionDescriptor) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(controllerActionDescriptor.ControllerTypeInfo.Namespace)) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return !Options.IgnoreNamespaces.Any(nsp => |
||||
|
controllerActionDescriptor.ControllerTypeInfo.Namespace.StartsWith(nsp)); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForReturnType(ControllerActionDescriptor controllerActionDescriptor) |
||||
|
{ |
||||
|
if (controllerActionDescriptor.MethodInfo.ReturnType.IsDefined(typeof(IgnoreWrapResultAttribute), true)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return !Options.IgnoreReturnTypes.Any(type => |
||||
|
controllerActionDescriptor.MethodInfo.ReturnType.IsAssignableFrom(type)); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool CheckForException(Exception exception) |
||||
|
{ |
||||
|
return !Options.IgnoreExceptions.Any(ex => ex.IsAssignableFrom(exception.GetType())); |
||||
|
} |
||||
|
|
||||
|
protected virtual string BuildUrl(HttpContext httpContext) |
||||
|
{ |
||||
|
//TODO: Add options to include/exclude query, schema and host
|
||||
|
|
||||
|
var uriBuilder = new UriBuilder(); |
||||
|
|
||||
|
uriBuilder.Scheme = httpContext.Request.Scheme; |
||||
|
uriBuilder.Host = httpContext.Request.Host.Host; |
||||
|
uriBuilder.Path = httpContext.Request.Path.ToString(); |
||||
|
uriBuilder.Query = httpContext.Request.QueryString.ToString(); |
||||
|
|
||||
|
return uriBuilder.Uri.AbsolutePath; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public class ActionResultWrapperFactory : IActionResultWrapperFactory |
||||
|
{ |
||||
|
public IActionResultWrapper CreateFor(FilterContext context) |
||||
|
{ |
||||
|
Check.NotNull(context, nameof(context)); |
||||
|
|
||||
|
switch (context) |
||||
|
{ |
||||
|
case ResultExecutingContext resultExecutingContext when resultExecutingContext.Result is ObjectResult: |
||||
|
return new ObjectActionResultWrapper(); |
||||
|
|
||||
|
case ResultExecutingContext resultExecutingContext when resultExecutingContext.Result is JsonResult: |
||||
|
return new JsonActionResultWrapper(); |
||||
|
|
||||
|
case ResultExecutingContext resultExecutingContext when resultExecutingContext.Result is EmptyResult: |
||||
|
return new EmptyActionResultWrapper(); |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext when pageHandlerExecutedContext.Result is ObjectResult: |
||||
|
return new ObjectActionResultWrapper(); |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext when pageHandlerExecutedContext.Result is JsonResult: |
||||
|
return new JsonActionResultWrapper(); |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext when pageHandlerExecutedContext.Result is EmptyResult: |
||||
|
return new EmptyActionResultWrapper(); |
||||
|
|
||||
|
default: |
||||
|
return new NullActionResultWrapper(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public class EmptyActionResultWrapper : IActionResultWrapper |
||||
|
{ |
||||
|
public void Wrap(FilterContext context) |
||||
|
{ |
||||
|
var options = context.GetRequiredService<IOptions<AbpAspNetCoreMvcWrapperOptions>>().Value; |
||||
|
var code = options.CodeWithEmptyResult(context.HttpContext.RequestServices); |
||||
|
var message = options.MessageWithEmptyResult(context.HttpContext.RequestServices); |
||||
|
switch (context) |
||||
|
{ |
||||
|
case ResultExecutingContext resultExecutingContext: |
||||
|
resultExecutingContext.Result = new ObjectResult(new WrapResult(code, message)); |
||||
|
return; |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext: |
||||
|
pageHandlerExecutedContext.Result = new ObjectResult(new WrapResult(code, message)); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public interface IActionResultWrapper |
||||
|
{ |
||||
|
void Wrap(FilterContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public interface IActionResultWrapperFactory : ITransientDependency |
||||
|
{ |
||||
|
IActionResultWrapper CreateFor(FilterContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public class JsonActionResultWrapper : IActionResultWrapper |
||||
|
{ |
||||
|
public void Wrap(FilterContext context) |
||||
|
{ |
||||
|
JsonResult jsonResult = null; |
||||
|
|
||||
|
switch (context) |
||||
|
{ |
||||
|
case ResultExecutingContext resultExecutingContext: |
||||
|
jsonResult = resultExecutingContext.Result as JsonResult; |
||||
|
break; |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext: |
||||
|
jsonResult = pageHandlerExecutedContext.Result as JsonResult; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (jsonResult == null) |
||||
|
{ |
||||
|
throw new ArgumentException("Action Result should be JsonResult!"); |
||||
|
} |
||||
|
|
||||
|
if (!(jsonResult.Value is WrapResult)) |
||||
|
{ |
||||
|
var options = context.GetRequiredService<IOptions<AbpAspNetCoreMvcWrapperOptions>>().Value; |
||||
|
|
||||
|
jsonResult.Value = new WrapResult(options.CodeWithFound, jsonResult.Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public class NullActionResultWrapper : IActionResultWrapper |
||||
|
{ |
||||
|
public void Wrap(FilterContext context) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Filters; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.Wraping |
||||
|
{ |
||||
|
public class ObjectActionResultWrapper : IActionResultWrapper |
||||
|
{ |
||||
|
public void Wrap(FilterContext context) |
||||
|
{ |
||||
|
ObjectResult objectResult = null; |
||||
|
|
||||
|
switch (context) |
||||
|
{ |
||||
|
case ResultExecutingContext resultExecutingContext: |
||||
|
objectResult = resultExecutingContext.Result as ObjectResult; |
||||
|
break; |
||||
|
|
||||
|
case PageHandlerExecutedContext pageHandlerExecutedContext: |
||||
|
objectResult = pageHandlerExecutedContext.Result as ObjectResult; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (objectResult == null) |
||||
|
{ |
||||
|
throw new ArgumentException("Action Result should be ObjectResult!"); |
||||
|
} |
||||
|
|
||||
|
if (!(objectResult.Value is WrapResult)) |
||||
|
{ |
||||
|
var options = context.GetRequiredService<IOptions<AbpAspNetCoreMvcWrapperOptions>>().Value; |
||||
|
|
||||
|
if (objectResult.Value != null) |
||||
|
{ |
||||
|
objectResult.Value = new WrapResult(options.CodeWithFound, objectResult.Value); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var code = options.CodeWithEmptyResult(context.HttpContext.RequestServices); |
||||
|
var message = options.MessageWithEmptyResult(context.HttpContext.RequestServices); |
||||
|
objectResult.Value = new WrapResult(code, message); |
||||
|
} |
||||
|
|
||||
|
objectResult.DeclaredType = typeof(WrapResult); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc.Abstractions; |
||||
|
using Microsoft.AspNetCore.Mvc.Controllers; |
||||
|
|
||||
|
namespace Microsoft.AspNetCore.Mvc |
||||
|
{ |
||||
|
public static class ActionContextExtensions |
||||
|
{ |
||||
|
public static bool CanWarpRsult(this ActionDescriptor actionDescriptor) |
||||
|
{ |
||||
|
if (actionDescriptor is ControllerActionDescriptor descriptor) |
||||
|
{ |
||||
|
if (descriptor.MethodInfo.IsDefined(typeof(IgnoreWrapResultAttribute), true)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (descriptor.ControllerTypeInfo.IsDefined(typeof(IgnoreWrapResultAttribute), true)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
# LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
||||
|
|
||||
|
返回值包装器 |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpAspNetCoreMvcWrapperModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpAspNetCoreMvcWrapperOptions>(options => |
||||
|
{ |
||||
|
// 启用包装器 |
||||
|
options.IsEnabled = true; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
## 配置项说明 |
||||
|
|
||||
|
* AbpAspNetCoreMvcWrapperOptions.IsEnabled 是否包装返回结果,默认: false |
||||
|
* AbpAspNetCoreMvcWrapperOptions.CodeWithFound 响应成功代码,默认: 0 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.HttpStatusCode 包装后的Http响应代码, 默认: 200 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.CodeWithEmptyResult 当返回空对象时返回错误代码,默认: 404 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.MessageWithEmptyResult 当返回空对象时返回错误消息, 默认: 本地化之后的 NotFound |
||||
|
|
||||
|
* AbpAspNetCoreMvcWrapperOptions.IgnorePrefixUrls 指定哪些Url开头的地址不需要处理 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.IgnoreNamespaces 指定哪些命名空间开头不需要处理 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.IgnoreControllers 指定哪些控制器不需要处理 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.IgnoreReturnTypes 指定哪些返回结果类型不需要处理 |
||||
|
* AbpAspNetCoreMvcWrapperOptions.IgnoreExceptions 指定哪些异常类型不需要处理 |
||||
|
|
||||
|
|
||||
|
## 其他 |
||||
|
|
||||
@ -0,0 +1,39 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Content Remove="LINGYUN\Abp\AspNetCore\Mvc\Localization\Resources\en.json" /> |
||||
|
<Content Remove="LINGYUN\Abp\AspNetCore\Mvc\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\AspNetCore\Mvc\Localization\Resources\en.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\AspNetCore\Mvc\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="4.4.0" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="coverlet.collector" Version="3.0.2"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.*" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\mvc\LINGYUN.Abp.AspNetCore.Mvc.Wrapper\LINGYUN.Abp.AspNetCore.Mvc.Wrapper.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.AspNetCore.Tests\LINGYUN.Abp.AspNetCore.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc |
||||
|
{ |
||||
|
public abstract class AbpAspNetCoreMvcTestBase : AbpAspNetCoreTestBase<Startup> |
||||
|
{ |
||||
|
protected override IHostBuilder CreateHostBuilder() |
||||
|
{ |
||||
|
return base.CreateHostBuilder(); |
||||
|
} |
||||
|
|
||||
|
private static string CalculateContentRootPath(string projectFileName, string contentPath) |
||||
|
{ |
||||
|
var currentDirectory = Directory.GetCurrentDirectory(); |
||||
|
while (!ContainsFile(currentDirectory, projectFileName)) |
||||
|
{ |
||||
|
currentDirectory = new DirectoryInfo(currentDirectory).Parent.FullName; |
||||
|
} |
||||
|
|
||||
|
return Path.Combine(currentDirectory, contentPath); |
||||
|
} |
||||
|
|
||||
|
private static bool ContainsFile(string currentDirectory, string projectFileName) |
||||
|
{ |
||||
|
return Directory |
||||
|
.GetFiles(currentDirectory, "*.*", SearchOption.TopDirectoryOnly) |
||||
|
.Any(f => Path.GetFileName(f) == projectFileName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,144 @@ |
|||||
|
using LINGYUN.Abp.AspNetCore.Mvc.GlobalFeatures; |
||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Localization; |
||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Results; |
||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; |
||||
|
using Localization.Resources.AbpUi; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ApiExploring; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Localization; |
||||
|
using Volo.Abp.AspNetCore.Security.Claims; |
||||
|
using Volo.Abp.AspNetCore.TestBase; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Localization.ExceptionHandling; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.Validation.Localization; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAspNetCoreMvcWrapperModule), |
||||
|
typeof(AbpAspNetCoreTestBaseModule), |
||||
|
typeof(AbpAspNetCoreMvcModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class AbpAspNetCoreMvcTestModule : AbpModule |
||||
|
{ |
||||
|
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); |
||||
|
|
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.AddAssemblyResource( |
||||
|
typeof(MvcTestResource), |
||||
|
typeof(AbpAspNetCoreMvcTestModule).Assembly |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
OneTimeRunner.Run(() => |
||||
|
{ |
||||
|
GlobalFeatureManager.Instance.Modules.GetOrAdd(AbpAspNetCoreMvcTestFeatures.ModuleName, |
||||
|
() => new AbpAspNetCoreMvcTestFeatures(GlobalFeatureManager.Instance)) |
||||
|
.EnableAll(); |
||||
|
}); |
||||
|
|
||||
|
context.Services.AddAuthentication(options => |
||||
|
{ |
||||
|
options.DefaultChallengeScheme = "Bearer"; |
||||
|
options.DefaultForbidScheme = "Cookie"; |
||||
|
}).AddCookie("Cookie").AddJwtBearer("Bearer", _ => { }); |
||||
|
|
||||
|
context.Services.AddAuthorization(options => |
||||
|
{ |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAspNetCoreMvcOptions>(options => |
||||
|
{ |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAspNetCoreMvcWrapperOptions>(options => |
||||
|
{ |
||||
|
options.IsEnabled = true; |
||||
|
|
||||
|
// 测试先清空
|
||||
|
options.IgnoreControllers.Clear(); |
||||
|
options.IgnoreExceptions.Clear(); |
||||
|
options.IgnoreNamespaces.Clear(); |
||||
|
options.IgnorePrefixUrls.Clear(); |
||||
|
options.IgnoreReturnTypes.Clear(); |
||||
|
|
||||
|
// api/abp/api-definition
|
||||
|
options.IgnoreControllers.Add<AbpApiDefinitionController>(); |
||||
|
// api/abp/application-configuration
|
||||
|
options.IgnoreReturnTypes.Add<ApplicationConfigurationDto>(); |
||||
|
|
||||
|
options.IgnorePrefixUrls.Add("/api/dont/wrap-result-test"); |
||||
|
|
||||
|
options.IgnoreExceptions.Add<HasDbException>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAspNetCoreMvcTestModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<MvcTestResource>("en") |
||||
|
.AddBaseTypes( |
||||
|
typeof(AbpUiResource), |
||||
|
typeof(AbpValidationResource) |
||||
|
).AddVirtualJson("/LINGYUN/Abp/AspNetCore/Mvc/Localization/Resources"); |
||||
|
|
||||
|
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
||||
|
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
||||
|
}); |
||||
|
|
||||
|
Configure<RazorPagesOptions>(options => |
||||
|
{ |
||||
|
options.RootDirectory = "/LINGYUN/Abp/AspNetCore/Mvc"; |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpClaimsMapOptions>(options => |
||||
|
{ |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
Configure<AbpExceptionLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.ErrorCodeNamespaceMappings.Add("Test", typeof(MvcTestResource)); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
|
||||
|
app.UseCorrelationId(); |
||||
|
app.UseStaticFiles(); |
||||
|
app.UseAbpRequestLocalization(); |
||||
|
app.UseAbpSecurityHeaders(); |
||||
|
app.UseRouting(); |
||||
|
app.UseAbpClaimsMap(); |
||||
|
app.UseAuthentication(); |
||||
|
app.UseAuthorization(); |
||||
|
app.UseAuditing(); |
||||
|
app.UseUnitOfWork(); |
||||
|
app.UseConfiguredEndpoints(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.GlobalFeatures |
||||
|
{ |
||||
|
public class AbpAspNetCoreMvcTestFeatures : GlobalModuleFeatures |
||||
|
{ |
||||
|
public const string ModuleName = "AbpAspNetCoreMvcTest"; |
||||
|
|
||||
|
public AbpAspNetCoreMvcTestFeatures([NotNull] GlobalFeatureManager featureManager) |
||||
|
: base(featureManager) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Localization |
||||
|
{ |
||||
|
public class MvcTestResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Test:1001": "Test the wrapped exception message." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Test:1001": "测试包装后的异常消息." |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
||||
|
{ |
||||
|
[Route("api/dont/wrap-result-test")] |
||||
|
public class DontWrapResultController: AbpController |
||||
|
{ |
||||
|
[HttpGet] |
||||
|
public TestResultObject Wrap() |
||||
|
{ |
||||
|
return new TestResultObject |
||||
|
{ |
||||
|
Id = Guid.NewGuid(), |
||||
|
DateTime = Clock.Now, |
||||
|
Double = 3.141592653d, |
||||
|
Integer = 100, |
||||
|
Name = "Not Wrap", |
||||
|
Properties = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "TestKey", "TestValue" } |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Data.Common; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
||||
|
{ |
||||
|
public class HasDbException: DbException |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
||||
|
{ |
||||
|
public class TestResultObject |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
public DateTime DateTime { get; set; } |
||||
|
public int Integer { get; set; } |
||||
|
public double Double { get; set; } |
||||
|
public Dictionary<string , string> Properties { get; set; } |
||||
|
public TestResultObject() { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
using LINGYUN.Abp.AspNetCore.Mvc.Localization; |
||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Data.Common; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
||||
|
{ |
||||
|
[Route("api/wrap-result-test")] |
||||
|
public class WrapResultController: AbpController |
||||
|
{ |
||||
|
public WrapResultController() |
||||
|
{ |
||||
|
LocalizationResource = typeof(MvcTestResource); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("exception")] |
||||
|
public TestResultObject WrapBusinessException() |
||||
|
{ |
||||
|
throw new BusinessException("Test:1001"); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("wrap")] |
||||
|
public TestResultObject Wrap() |
||||
|
{ |
||||
|
return new TestResultObject |
||||
|
{ |
||||
|
Id = Guid.NewGuid(), |
||||
|
DateTime = Clock.Now, |
||||
|
Double = 3.141592653d, |
||||
|
Integer = 100, |
||||
|
Name = "Wrap", |
||||
|
Properties = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "TestKey", "TestValue" } |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("wrap-empty")] |
||||
|
public TestResultObject WrapEmpty() |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("not-wrap")] |
||||
|
[IgnoreWrapResult] |
||||
|
public TestResultObject NotWrap() |
||||
|
{ |
||||
|
return new TestResultObject |
||||
|
{ |
||||
|
Id = Guid.NewGuid(), |
||||
|
DateTime = Clock.Now, |
||||
|
Double = 3.141592653d, |
||||
|
Integer = 100, |
||||
|
Name = "Not Wrap", |
||||
|
Properties = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "TestKey", "TestValue" } |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("not-wrap-exception")] |
||||
|
public TestResultObject NotWrapHasDbException() |
||||
|
{ |
||||
|
throw new HasDbException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
using LINGYUN.Abp.Wrapper; |
||||
|
using Shouldly; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.Http.Modeling; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
||||
|
{ |
||||
|
public class WrapResultController_Tests : AbpAspNetCoreMvcTestBase |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task Should_Return_Not_Wrap_Result_For_Abp_Api_Definition() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<ApplicationApiDescriptionModel>("/api/abp/api-definition"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Not_Wrap_Result_For_Return_Application_Configuration_Dto() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<ApplicationConfigurationDto>("/api/abp/application-configuration"); |
||||
|
|
||||
|
result.ShouldNotBeNull(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Not_Wrap_Result_For_Url_Prefix_With_Dont_Wrapper() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<TestResultObject>("/api/dont/wrap-result-test"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Name.ShouldBe("Not Wrap"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Wrap_Result_For_Bussiness_Exception() |
||||
|
{ |
||||
|
using (CultureHelper.Use("zh-Hans")) |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<WrapResult<TestResultObject>>("/api/wrap-result-test/exception"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Code.ShouldBe("1001"); |
||||
|
result.Message.ShouldBe("测试包装后的异常消息."); |
||||
|
} |
||||
|
|
||||
|
using (CultureHelper.Use("en")) |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<WrapResult<TestResultObject>>("/api/wrap-result-test/exception"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Code.ShouldBe("1001"); |
||||
|
result.Message.ShouldBe("Test the wrapped exception message."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Not_Wrap_Result_For_Has_Db_Exception() |
||||
|
{ |
||||
|
using (CultureHelper.Use("zh-Hans")) |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<RemoteServiceErrorResponse>("/api/wrap-result-test/not-wrap-exception", System.Net.HttpStatusCode.InternalServerError); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Error.ShouldNotBeNull(); |
||||
|
result.Error.Message.ShouldBe("对不起,在处理你的请求期间,产生了一个服务器内部错误!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Wrap_Result_For_Object_Return_Value() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<WrapResult<TestResultObject>>("/api/wrap-result-test/wrap"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Result.Name.ShouldBe("Wrap"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Wrap_Result_For_Empty_Object_Return_Value() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<WrapResult<TestResultObject>>("/api/wrap-result-test/wrap-empty"); |
||||
|
result.Code.ShouldBe("404"); |
||||
|
result.Result.ShouldBeNull(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Return_Not_Wrap_Result_For_Object_Return_Value() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<TestResultObject>("/api/wrap-result-test/not-wrap"); |
||||
|
result.ShouldNotBeNull(); |
||||
|
result.Name.ShouldBe("Not Wrap"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore.Mvc |
||||
|
{ |
||||
|
public class Startup |
||||
|
{ |
||||
|
public void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddApplication<AbpAspNetCoreMvcTestModule>(); |
||||
|
} |
||||
|
|
||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) |
||||
|
{ |
||||
|
app.InitializeApplication(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
{ |
||||
|
"iisSettings": { |
||||
|
"windowsAuthentication": false, |
||||
|
"anonymousAuthentication": true, |
||||
|
"iisExpress": { |
||||
|
"applicationUrl": "http://localhost:53117/", |
||||
|
"sslPort": 44307 |
||||
|
} |
||||
|
}, |
||||
|
"profiles": { |
||||
|
"IIS Express": { |
||||
|
"commandName": "IISExpress", |
||||
|
"launchBrowser": true, |
||||
|
"environmentVariables": { |
||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
|
} |
||||
|
}, |
||||
|
"LINGYUN.Abp.AspNetCore.Mvc.Tests": { |
||||
|
"commandName": "Project", |
||||
|
"launchBrowser": true, |
||||
|
"environmentVariables": { |
||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
|
}, |
||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="coverlet.collector" Version="3.0.2"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="Shouldly" Version="3.0.2" /> |
||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.TestBase" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,49 @@ |
|||||
|
using Microsoft.Net.Http.Headers; |
||||
|
using Shouldly; |
||||
|
using System.Globalization; |
||||
|
using System.Net; |
||||
|
using System.Net.Http; |
||||
|
using System.Text.Json; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.TestBase; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore |
||||
|
{ |
||||
|
public class AbpAspNetCoreTestBase : AbpAspNetCoreTestBase<Startup> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public abstract class AbpAspNetCoreTestBase<TStartup> : AbpAspNetCoreIntegratedTestBase<TStartup> |
||||
|
where TStartup : class |
||||
|
{ |
||||
|
protected virtual async Task<T> GetResponseAsObjectAsync<T>(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) |
||||
|
{ |
||||
|
var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); |
||||
|
return JsonSerializer.Deserialize<T>(strResponse, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> GetResponseAsStringAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) |
||||
|
{ |
||||
|
using (var response = await GetResponseAsync(url, expectedStatusCode)) |
||||
|
{ |
||||
|
return await response.Content.ReadAsStringAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<HttpResponseMessage> GetResponseAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, bool xmlHttpRequest = false) |
||||
|
{ |
||||
|
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, url)) |
||||
|
{ |
||||
|
requestMessage.Headers.Add("Accept-Language", CultureInfo.CurrentUICulture.Name); |
||||
|
if (xmlHttpRequest) |
||||
|
{ |
||||
|
requestMessage.Headers.Add(HeaderNames.XRequestedWith, "XMLHttpRequest"); |
||||
|
} |
||||
|
var response = await Client.SendAsync(requestMessage); |
||||
|
response.StatusCode.ShouldBe(expectedStatusCode); |
||||
|
return response; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AspNetCore; |
||||
|
using Volo.Abp.AspNetCore.TestBase; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAspNetCoreTestBaseModule), |
||||
|
typeof(AbpAspNetCoreModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class AbpAspNetCoreTestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAspNetCoreTestModule>(); |
||||
|
//options.FileSets.ReplaceEmbeddedByPhysical<AbpAspNetCoreTestModule>(FindProjectPath(hostingEnvironment));
|
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
|
||||
|
app.UseCorrelationId(); |
||||
|
app.UseStaticFiles(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AspNetCore |
||||
|
{ |
||||
|
public class Startup |
||||
|
{ |
||||
|
public void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddApplication<AbpAspNetCoreTestModule>(); |
||||
|
} |
||||
|
|
||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) |
||||
|
{ |
||||
|
app.InitializeApplication(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue