diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/Abstractions/ActionDescriptorExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/Abstractions/ActionDescriptorExtensions.cs index 97b5a6c61b..f54375c844 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/Abstractions/ActionDescriptorExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/Abstractions/ActionDescriptorExtensions.cs @@ -38,31 +38,6 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions { return actionDescriptor is ControllerActionDescriptor; } - - public static PageActionDescriptor AsPageActionDescriptor(this ActionDescriptor actionDescriptor) - { - if (!actionDescriptor.IsPageAction()) - { - throw new AbpException($"{nameof(actionDescriptor)} should be type of {typeof(PageActionDescriptor).AssemblyQualifiedName}"); - } - - return actionDescriptor as PageActionDescriptor; - } - - public static MethodInfo GetPageActionMethodInfo(this ActionDescriptor actionDescriptor) - { - return actionDescriptor.AsPageActionDescriptor().GetMethodInfo(); - } - - public static Type GetPageActionReturnType(this PageActionDescriptor actionDescriptor) - { - return actionDescriptor.GetPageActionMethodInfo().ReturnType; - } - - public static bool HasObjectResult(this PageActionDescriptor actionDescriptor) - { - return ActionResultHelper.IsObjectResult(actionDescriptor.GetReturnType()); - } public static bool IsPageAction(this ActionDescriptor actionDescriptor) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 668e7a77dc..4d970acd45 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; @@ -12,7 +12,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.Extensions.Hosting; using Volo.Abp.ApiVersioning; using Volo.Abp.AspNetCore.Mvc.Conventions; @@ -114,6 +116,9 @@ namespace Volo.Abp.AspNetCore.Mvc //Use DI to create view components context.Services.Replace(ServiceDescriptor.Singleton()); + //Use DI to create razor page + context.Services.Replace(ServiceDescriptor.Singleton()); + //Add feature providers var partManager = context.Services.GetSingletonInstance(); var application = context.Services.GetSingletonInstance(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs index 64d9daca93..f1225f1abf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs @@ -39,10 +39,10 @@ namespace Volo.Abp.AspNetCore.Mvc private static void AddPageFilters(MvcOptions options) { + options.Filters.AddService(typeof(AbpExceptionPageFilter)); options.Filters.AddService(typeof(AbpAuditPageFilter)); options.Filters.AddService(typeof(AbpFeaturePageFilter)); options.Filters.AddService(typeof(AbpUowPageFilter)); - options.Filters.AddService(typeof(AbpExceptionPageFilter)); } private static void AddModelBinders(MvcOptions options) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs index 23e94790e9..6e9996574c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs @@ -84,7 +84,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing return false; } - if (!_auditingHelper.ShouldSaveAudit(context.ActionDescriptor.GetMethodInfo(), true)) + if (!_auditingHelper.ShouldSaveAudit(context.HandlerMethod.MethodInfo, true)) { return false; } @@ -92,8 +92,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing auditLog = auditLogScope.Log; auditLogAction = _auditingHelper.CreateAuditLogAction( auditLog, - context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(), - context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo, + context.HandlerMethod.GetType(), + context.HandlerMethod.MethodInfo, context.HandlerArguments ); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index 8aa45688ca..fb0a7c5a1f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -63,7 +63,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling //TODO: Create DontWrap attribute to control wrapping..? if (context.ActionDescriptor.IsPageAction() && - context.ActionDescriptor.HasObjectResult()) + ActionResultHelper.IsObjectResult(context.HandlerMethod.MethodInfo.ReturnType)) { return true; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs index ceb117d2ff..83e26ace9c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features return; } - var methodInfo = context.ActionDescriptor.GetMethodInfo(); + var methodInfo = context.HandlerMethod.MethodInfo; using (AbpCrossCuttingConcerns.Applying(context.HandlerInstance, AbpCrossCuttingConcerns.FeatureChecking)) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs index aeed982173..993a12b0e7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs @@ -33,12 +33,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow return; } - var methodInfo = context.ActionDescriptor.GetMethodInfo(); + var methodInfo = context.HandlerMethod.MethodInfo; var unitOfWorkAttr = UnitOfWorkHelper.GetUnitOfWorkAttributeOrNull(methodInfo); context.HttpContext.Items["_AbpActionInfo"] = new AbpActionInfoInHttpContext { - IsObjectResult = context.ActionDescriptor.HasObjectResult() + IsObjectResult = ActionResultHelper.IsObjectResult(context.HandlerMethod.MethodInfo.ReturnType) }; if (unitOfWorkAttr?.IsDisabled == true) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj index ddb3f5bc44..d47b369902 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj @@ -24,6 +24,7 @@ + @@ -39,6 +40,24 @@ PreserveNewest + + + true + PreserveNewest + + + true + PreserveNewest + + + true + PreserveNewest + + + true + PreserveNewest + + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index 5e74ec4bfa..39b7d9af5f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -1,6 +1,9 @@ -using System; +using System; +using System.Linq; using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Authorization; using Volo.Abp.AspNetCore.Mvc.Localization; @@ -73,6 +76,11 @@ namespace Volo.Abp.AspNetCore.Mvc options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); }); + + Configure(options => + { + options.RootDirectory = "/Volo/Abp/AspNetCore/Mvc"; + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs index 49bc689e14..3f934d5fe8 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs @@ -51,6 +51,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing await _auditingStore.Received().SaveAsync(Arg.Any()); } + [Fact] public async Task Should_Trigger_Middleware_And_AuditLog_Exception_When_Returns_Object() { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml new file mode 100644 index 0000000000..bf85af77ef --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml @@ -0,0 +1,19 @@ +@page +@model Volo.Abp.AspNetCore.Mvc.Auditing.AuditTestPage + +@{ + Layout = null; +} + + + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml.cs new file mode 100644 index 0000000000..6425d6585b --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage.cshtml.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Auditing; + +namespace Volo.Abp.AspNetCore.Mvc.Auditing +{ + public class AuditTestPage : AbpPageModel + { + private readonly AbpAuditingOptions _options; + + public AuditTestPage(IOptions options) + { + _options = options.Value; + } + + public IActionResult OnGetAuditSuccessForGetRequests() + { + return new OkResult(); + } + + public IActionResult OnGetAuditFailForGetRequests() + { + throw new UserFriendlyException("Exception occurred!"); + } + + public ObjectResult OnGetAuditFailForGetRequestsReturningObject() + { + throw new UserFriendlyException("Exception occurred!"); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs new file mode 100644 index 0000000000..7d5298e253 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using NSubstitute; +using Volo.Abp.Auditing; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Auditing +{ + public class AuditTestPage_Tests : AspNetCoreMvcTestBase + { + private readonly AbpAuditingOptions _options; + private IAuditingStore _auditingStore; + + public AuditTestPage_Tests() + { + _options = ServiceProvider.GetRequiredService>().Value; + _auditingStore = ServiceProvider.GetRequiredService(); + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + _auditingStore = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(_auditingStore)); + base.ConfigureServices(context, services); + } + + [Fact] + public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_GetRequests() + { + _options.IsEnabledForGetRequests = true; + _options.AlwaysLogOnException = false; + await GetResponseAsync("/Auditing/AuditTestPage?handler=AuditSuccessForGetRequests"); + await _auditingStore.Received().SaveAsync(Arg.Any()); + } + + [Fact] + public async Task Should_Trigger_Middleware_And_AuditLog_Exception_Always() + { + _options.IsEnabled = true; + _options.AlwaysLogOnException = true; + + try + { + await GetResponseAsync("/Auditing/AuditTestPage?handler=AuditFailForGetRequests", System.Net.HttpStatusCode.Forbidden); + } + catch { } + + await _auditingStore.Received().SaveAsync(Arg.Any()); + } + + [Fact] + public async Task Should_Trigger_Middleware_And_AuditLog_Exception_When_Returns_Object() + { + _options.IsEnabled = true; + _options.AlwaysLogOnException = true; + + await GetResponseAsync("/Auditing/AuditTestPage?handler=AuditFailForGetRequestsReturningObject", System.Net.HttpStatusCode.Forbidden); + + await _auditingStore.Received().SaveAsync(Arg.Any()); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs index 0de46fbe55..46cdd073e7 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs @@ -30,9 +30,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling result.Error.ShouldNotBeNull(); result.Error.Message.ShouldBe("This is a sample exception!"); +#pragma warning disable 4014 _fakeExceptionSubscriber .Received() .HandleAsync(Arg.Any()); +#pragma warning restore 4014 } [Fact] @@ -44,9 +46,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling ) ); +#pragma warning disable 4014 _fakeExceptionSubscriber .DidNotReceive() .HandleAsync(Arg.Any()); +#pragma warning restore 4014 } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml new file mode 100644 index 0000000000..7ba36da037 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml @@ -0,0 +1,19 @@ +@page +@model Volo.Abp.AspNetCore.Mvc.ExceptionHandling.ExceptionTestPage + +@{ + Layout = null; +} + + + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs new file mode 100644 index 0000000000..717d31effe --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage.cshtml.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling +{ + public class ExceptionTestPage : AbpPageModel + { + public void OnGetUserFriendlyException1() + { + throw new UserFriendlyException("This is a sample exception!"); + } + + public IActionResult OnGetUserFriendlyException2() + { + throw new UserFriendlyException("This is a sample exception!"); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs new file mode 100644 index 0000000000..7013c0c676 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs @@ -0,0 +1,56 @@ +using System.Net; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NSubstitute; +using Shouldly; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Http; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling +{ + public class ExceptionTestPage_Tests : AspNetCoreMvcTestBase + { + private IExceptionSubscriber _fakeExceptionSubscriber; + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + + _fakeExceptionSubscriber = Substitute.For(); + + services.AddSingleton(_fakeExceptionSubscriber); + } + + [Fact] + public async Task Should_Return_RemoteServiceErrorResponse_For_UserFriendlyException_For_Void_Return_Value() + { + var result = await GetResponseAsObjectAsync("/ExceptionHandling/ExceptionTestPage?handler=UserFriendlyException1", HttpStatusCode.Forbidden); + result.Error.ShouldNotBeNull(); + result.Error.Message.ShouldBe("This is a sample exception!"); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .Received() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + + [Fact] + public async Task Should_Not_Handle_Exceptions_For_ActionResult_Return_Values() + { + await Assert.ThrowsAsync( + async () => await GetResponseAsObjectAsync( + "/ExceptionHandling/ExceptionTestPage?handler=UserFriendlyException2" + ) + ); + +#pragma warning disable 4014 + _fakeExceptionSubscriber + .DidNotReceive() + .HandleAsync(Arg.Any()); +#pragma warning restore 4014 + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml new file mode 100644 index 0000000000..8f0450becb --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml @@ -0,0 +1,19 @@ +@page +@model Volo.Abp.AspNetCore.Mvc.Features.FeatureTestPage + +@{ + Layout = null; +} + + + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml.cs new file mode 100644 index 0000000000..6a051a29ee --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage.cshtml.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Features; + +namespace Volo.Abp.AspNetCore.Mvc.Features +{ + public class FeatureTestPage : AbpPageModel + { + [RequiresFeature("AllowedFeature")] + public Task OnGetAllowedFeatureAsync() + { + return Task.CompletedTask; + } + + [RequiresFeature("NotAllowedFeature")] + public void OnGetNotAllowedFeature() + { + + } + + public ObjectResult OnGetNoFeature() + { + return new ObjectResult(42); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage_Tests.cs new file mode 100644 index 0000000000..91226f1938 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestPage_Tests.cs @@ -0,0 +1,34 @@ +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Features +{ + public class FeatureTestPage_Tests : AspNetCoreMvcTestBase + { + [Fact] + public async Task Should_Allow_Enabled_Features() + { + await GetResponseAsStringAsync( + "/Features/FeatureTestPage?handler=AllowedFeature" + ); + } + + [Fact] + public async Task Should_Not_Allow_Not_Enabled_Features() + { + await GetResponseAsStringAsync( + "/Features/FeatureTestPage?handler=NotAllowedFeature", + HttpStatusCode.Unauthorized + ); + } + + [Fact] + public async Task Should_Allow_Actions_With_No_Feature() + { + await GetResponseAsStringAsync( + "/Features/FeatureTestPage?handler=NoFeature" + ); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs new file mode 100644 index 0000000000..b09d3ca2c9 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs @@ -0,0 +1,37 @@ +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Http; +using Volo.Abp.Json; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Uow +{ + public class UnitOfWorkPageFilter_Exception_Rollback_Tests : AspNetCoreMvcTestBase + { + [Fact] + public async Task Should_Rollback_Transaction_For_Handled_Exceptions() + { + var result = await GetResponseAsObjectAsync("/Uow/UnitOfWorkTestPage?handler=HandledException", HttpStatusCode.Forbidden); + result.Error.ShouldNotBeNull(); + result.Error.Message.ShouldBe("This is a sample exception!"); + } + + [Fact] + public async Task Should_Gracefully_Handle_Exceptions_On_Complete() + { + var response = await GetResponseAsync("/Uow/UnitOfWorkTestPage?handler=ExceptionOnComplete", HttpStatusCode.Forbidden); + + response.Headers.GetValues(AbpHttpConsts.AbpErrorFormat).FirstOrDefault().ShouldBe("true"); + + var resultAsString = await response.Content.ReadAsStringAsync(); + + var result = ServiceProvider.GetRequiredService().Deserialize(resultAsString); + + result.Error.ShouldNotBeNull(); + result.Error.Message.ShouldBe(TestUnitOfWorkConfig.ExceptionOnCompleteMessage); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Tests.cs new file mode 100644 index 0000000000..820ccf91b7 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Tests.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Uow +{ + public class UnitOfWorkPageFilter_Tests: AspNetCoreMvcTestBase + { + [Fact] + public async Task Get_Actions_Should_Not_Be_Transactional() + { + await GetResponseAsStringAsync("/Uow/UnitOfWorkTestPage?handler=RequiresUow"); + } + + [Fact] + public async Task Non_Get_Actions_Should_Be_Transactional() + { + var result = await Client.PostAsync("/Uow/UnitOfWorkTestPage?handler=RequiresUow", null); + result.IsSuccessStatusCode.ShouldBeTrue(); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml new file mode 100644 index 0000000000..da30a64818 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml @@ -0,0 +1,19 @@ +@page +@model Volo.Abp.AspNetCore.Mvc.Uow.UnitOfWorkTestPage + +@{ + Layout = null; +} + + + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml.cs new file mode 100644 index 0000000000..ce54e8d34f --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestPage.cshtml.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Mvc; +using Shouldly; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Uow; + +namespace Volo.Abp.AspNetCore.Mvc.Uow +{ + [IgnoreAntiforgeryToken] + public class UnitOfWorkTestPage : AbpPageModel + { + private readonly TestUnitOfWorkConfig _testUnitOfWorkConfig; + + public UnitOfWorkTestPage(TestUnitOfWorkConfig testUnitOfWorkConfig) + { + _testUnitOfWorkConfig = testUnitOfWorkConfig; + } + + public IActionResult OnGetRequiresUow() + { + CurrentUnitOfWork.ShouldNotBeNull(); + CurrentUnitOfWork.Options.IsTransactional.ShouldBeFalse(); + + return Content("OK"); + } + + public IActionResult OnPostRequiresUow() + { + CurrentUnitOfWork.ShouldNotBeNull(); + CurrentUnitOfWork.Options.IsTransactional.ShouldBeTrue(); + + return Content("OK"); + } + + [UnitOfWork(isTransactional: true)] + public void OnGetHandledException() + { + CurrentUnitOfWork.ShouldNotBeNull(); + CurrentUnitOfWork.Options.IsTransactional.ShouldBeTrue(); + + throw new UserFriendlyException("This is a sample exception!"); + } + + public ObjectResult OnGetExceptionOnComplete() + { + CurrentUnitOfWork.ShouldNotBeNull(); + CurrentUnitOfWork.Options.IsTransactional.ShouldBeFalse(); + + _testUnitOfWorkConfig.ThrowExceptionOnComplete = true; + + //Prevent rendering of pages. + return new ObjectResult(""); + } + } +} \ No newline at end of file