Merge pull request #7766 from acjh/patch-4

Support extending a controller
pull/7869/head
Halil İbrahim Kalkan 5 years ago committed by GitHub
commit a4dffd33f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -196,12 +196,16 @@ This example replaces the `AccountController` (An API Controller defined in the
**`[ExposeServices(typeof(AccountController))]` is essential** here since it registers this controller for the `AccountController` in the dependency injection system. `[Dependency(ReplaceServices = true)]` is also recommended to clear the old registration (even the ASP.NET Core DI system selects the last registered one).
In addition, The `AccountController` will be removed from [`ApplicationModel`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationmodels.applicationmodel.controllers) because it defines `ExposeServicesAttribute`. If you don't want to remove it, you can configure `AbpAspNetCoreMvcOptions`:
In addition, the `MyAccountController` will be removed from [`ApplicationModel`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationmodels.applicationmodel.controllers) because it defines `ExposeServicesAttribute`.
If `IncludeSelf = true` is specified, i.e. `[ExposeServices(typeof(AccountController), IncludeSelf = true)]`, then `AccountController` will be removed instead. This is useful for **extending** a controller.
If you don't want to remove either controller, you can configure `AbpAspNetCoreMvcOptions`:
```csharp
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.IgnoredControllersOnModelExclusion.AddIfNotContains(typeof(AccountController));
options.IgnoredControllersOnModelExclusion.AddIfNotContains(typeof(MyAccountController));
});
```

@ -73,7 +73,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
protected virtual void RemoveDuplicateControllers(ApplicationModel application)
{
var derivedControllerModels = new List<ControllerModel>();
var controllerModelsToRemove = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers)
{
@ -87,19 +87,42 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
continue;
}
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var exposedControllerModels = application.Controllers
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
controllerModelsToRemove.AddRange(exposedControllerModels);
Logger.LogInformation($"Removing the controller{(exposedControllerModels.Length > 1 ? "s" : "")} {exposeServicesAttr.ServiceTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")} from the application model since {(exposedControllerModels.Length > 1 ? "they are" : "it is")} replaced by the controller: {controllerModel.ControllerType.AssemblyQualifiedName}");
continue;
}
var baseControllerTypes = controllerModel.ControllerType
.GetBaseClasses(typeof(Controller), includeObject: false)
.Where(t => !t.IsAbstract)
.ToArray();
if (baseControllerTypes.Length > 0)
if (baseControllerTypes.Length == 0)
{
derivedControllerModels.Add(controllerModel);
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
continue;
}
var baseControllerModels = application.Controllers
.Where(cm => baseControllerTypes.Contains(cm.ControllerType))
.ToArray();
if (baseControllerModels.Length == 0)
{
continue;
}
controllerModelsToRemove.Add(controllerModel);
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
}
application.Controllers.RemoveAll(derivedControllerModels);
application.Controllers.RemoveAll(controllerModelsToRemove);
}
protected virtual void ConfigureRemoteService(ControllerModel controller, [CanBeNull] ConventionalControllerSetting configuration)

@ -0,0 +1,143 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Shouldly;
using System;
using System.Reflection;
using Volo.Abp.DependencyInjection;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Conventions
{
public class AbpServiceConvention_Tests : AspNetCoreMvcTestBase
{
private readonly IConventionalRouteBuilder _conventionalRouteBuilder;
private readonly IOptions<AbpAspNetCoreMvcOptions> _options;
public AbpServiceConvention_Tests()
{
_conventionalRouteBuilder = GetRequiredService<IConventionalRouteBuilder>();
_options = GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
}
[Fact]
public void Should_Not_Remove_Derived_Controller_If_Not_Expose_Service()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(DerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(baseControllerModel);
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Remove_Exposed_Controller_If_Expose_Self()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceIncludeSelfDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldNotContain(baseControllerModel);
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Not_Remove_Derived_Controller_If_No_Base_Controller_Model()
{
// Arrange
var applicationModel = new ApplicationModel();
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Remove_Derived_Controller_If_Expose_Service()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(baseControllerModel);
applicationModel.Controllers.ShouldNotContain(derivedControllerModel);
}
}
public class BaseController : Controller
{
}
public class DerivedController : BaseController
{
}
[ExposeServices(typeof(BaseController))]
public class ExposeServiceDerivedController : BaseController
{
}
[ExposeServices(typeof(BaseController), IncludeSelf = true)]
public class ExposeServiceIncludeSelfDerivedController : BaseController
{
}
}
Loading…
Cancel
Save