How to: have one class per endpoint - instead of one applicationservice with all the endpoints #18365
Replies: 1 comment
-
After fiddling around with the code and debugging abp a bit, I guess I found a solution. The goals were
Now starting from a fresh layered abp solution:
... I created multiple dummy endpoints for handling books. For each request/method added a separate interface in public interface IGetBookEndpoint : IApplicationService
{
Task<BookDto> GetAsync(Guid id);
}
public class BookDto
{
public Guid Id { get; set; }
public string Name { get; set; }
} Notice that the interface must implement IApplciationService or the Auto API Controllers feature will not work. This class is then implemented in the typical manner in [ControllerName("book")]
public class GetBookEndpoint : BookStoreAppService, IGetBookEndpoint
{
public Task<BookDto> GetAsync(Guid id)
{
return Task.FromResult(new BookDto
{
Id = id,
Name = "Dune"
});
}
} One thing to note here is the By default, this does not do anything at all. In order to apply this private void ConfigureConventionalControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
// COMBINED: - added controllermodelconfigurer that takes the name for the controller from the ControllerNameAttribute
opts.ControllerModelConfigurer = controllerModel =>
{
var attr = (ControllerNameAttribute)controllerModel.ControllerType.GetCustomAttribute(typeof(ControllerNameAttribute), true);
if (attr != null)
controllerModel.ControllerName = attr.Name;
};
});
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(IRemoteStreamContent));
});
}
as you can see, my Now, the last goal was to still have a single interface to inject to blazor. // COMBINED: - created the interface that should be forwarded to the client:
// it simply combines all the endpoint-interfaces to one single client-side interface
// that way, while the endpoints are all separated (separate application service each)
// the client sees a single interface that combines all the endpoints
public interface IBookEndpoints : ICreateBookEndpoint, IGetBookEndpoint, IUploadBookCoverEndpoint, IDownloadBookCoverEndpoint
{
} Now I simply injected it in some blazor component and called one of its methods..... The reason turned out to be, that the And of course, our combined public async Task<ActionApiDescriptionModel> FindActionAsync(
HttpClient client,
string baseUrl,
Type serviceType,
MethodInfo method)
{
var apiDescription = await GetApiDescriptionAsync(client, baseUrl);
//TODO: Cache finding?
var methodParameters = method.GetParameters().ToArray();
foreach (var module in apiDescription.Modules.Values)
{
foreach (var controller in module.Controllers.Values)
{
if (!controller.Implements(serviceType) &&
// COMBINED: for the dynamic api clients to work, we need to tweak this logic a bit,
// because it expects all controllers to implement the service type.
// However, no controller actually implements our combined client interface! (actually, _nothing_ implements it!)
!(serviceType.IsInterface && serviceType.GetInterfaces()
.Any(i => typeof(IApplicationService).IsAssignableFrom(i) &&
controller.Implements(i))))
{
continue;
} as you see, I modified the condition to also accept the controller if
Now, I can use the What do you think of the approach? @hikalkan It would be nice if I
|
Beta Was this translation helpful? Give feedback.
-
The Problem
We have a lot of experience with aspnetboilerplate. Our main problem is/was, that applicationservices tend to get bloated and too big, because we add all the service methods to them.
This still seems to be the "best practice" in abp.io.
However, we would like to have one class per endpoint.
The only way to achive this at the moment is to use a library like MediatR like so:
This, however is far from ideal, as it requires us to add yet another layer of DTOs to the mix:
We have the DTOs that are fed into the application service.
And then we need to convert them to the
Request
andResponse
"Dtos" for MediatR.I would like to avoid this.
Now with MinimalAPI, there is a new framework that does exactly what we seek for: FastEndPoints
However, it does not bring any of abp's functionalities that we so rely on.
The Question
Is there a way to achieve a "one class per endpoint" approach with ABP?
It would be great if it worked like this:
The pros would be:
Alternatively, does anyone have experiences with integrating FastEndPoints to abp?
Beta Was this translation helpful? Give feedback.
All reactions