Extending a SearchService

I am trying to extend the VirtoCommerce.PaymentModule module. Specifically, it is my goal restrict which payment methods appear in the Platform UI based on some data (ideally scoped stores configured for a custom Payment Method, but open to a database call that has permissions).

To set up the environment:

  • Multi-Tenant (a “store admin” will be configured to only view and manage their store)
  • Flexible (our or a tenant’s development team may want to introduce a payment method)
  • Restricted (a custom payment method should not be available for all stores)

In the spirit of modularity, I do not want to modify the Virto module, but instead create something like an AdvancedPaymentModule. This leads me to the approach of Extending using Type Inheritance. My thought was to create an AdvancedPaymentMethodsSearchService and then re-implementing the search with the store-based restrictions, allowing the returned list of available methods to be filtered based on store.

Unfortunately, while I’m able to extend (override) the virtual methods such as BuildQuery and BuildSortExpression, the main method SearchPaymentMethodsAsync is still being invoked by the original class. My

Initialize

serviceCollection.AddTransient<IPaymentMethodsSearchService, AdvancedPaymentMethodsSearchService>();

PostInitialize

AbstractTypeFactory<IPaymentMethodsSearchService>.OverrideType<PaymentMethodsSearchService, AdvancedPaymentMethodsSearchService>();

AdvancedPaymentMethodsSearchService

public class AdvancedPaymentMethodsSearchService : PaymentMethodsSearchService
{
   ...
   public AdvancedPaymentMethodsSearchService(...) : base (...) { ... }
   public new async Task<PaymentMethodsSearchResult> SearchPaymentMethodsAsync(PaymentMethodsSearchCriteria criteria) { ... }
   protected override IQueryable<StorePaymentMethodEntity> BuildQuery(IPaymentRepository repository, PaymentMethodsSearchCriteria criteria) { ... }
   protected override IList<SortInfo> BuildSortExpression(PaymentMethodsSearchCriteria criteria) { ... }

Alternatively, an option would be to override the PaymentModuleController.SearchPaymentMethods API endpoint itself via this new module, but there doesn’t seem to be support for that level of extension.

My question is:

  • Am I doing something wrong with how I’m using OverrideType?
  • If not, is there a way to override an API endoint that’s been established in another module?

Thank you in advance!

Thanks for a good problem explanation!

Initially, I would like to answer your direct technical questions regarding the IPaymentMethodsSearchService overriding.
This line in the startup.cs of your custom module is enough to replace default service implementation

serviceCollection.AddTransient<IPaymentMethodsSearchService, AdvancedPaymentMethodsSearchService>();

But make sure that you add reference to VirtoCommerce.Payment module in your custom module. manifest
See example:

This is a mandatory step that guarantees the modules are initialized in the correct order, without this your module is initialized in undetermined order, and default PaymentMethodsSearchService might be added into DI afterward of your AdvancedPaymentMethodsSearchService.

So, now back to your main requirements and the key reason why do you need such an extension.
Did you consider using for this task the Imperative resource-based authorization? For me this is would be the better choice for that task, because of the two reasons:

  • The good design decision is you always should avoid mixing the Authorization logic with DAL layers. If you included authorization check into AdvancedPaymentMethodsSearchService it will be violation of this principle.
  • Virto provides sufficient mechanics and examples on how to filter the data based on the current user permissions and context. There is an example, that filters the orders that have only specified statuses that a user can see vc-module-order/CustomOrderAuthorizationHandler.cs at dev · VirtoCommerce/vc-module-order · GitHub

But, to be able to use this approach, Virto team must add the Authorization policy check to the PaymentModuleController first.

If you are interested in this approach, let me know and I will get back to you with ETA about this improvement in PaymentModuleController.

1 Like