Loading...
Area: Episerver B2B Commerce

Working with Handlers

Recommended reading 

Handlers serve as an extension point because you can add new handlers to any handler chain. This allows you to add new or change existing functionality. For example, to the GetCartHandler chain you could add a handler that selectively displays taxes based on a custom property. In order to add a new handler to an existing handler chain, you must correctly implement and configure the new handler.

How to Add a New Handler

In order for a handler to be used within a handler chain, it must do the following:

  • Implement the IHandler<TIn, TOut> interface
  • Be decorated with the DependencyName attribute
  • Return a result from the "Execute" method
  • Specify an order via the "Order" property

The IHandler<TIn, TOut> interface requires the handler to implement the "Execute" method, specify handler order using the "Order" property, and associate the handler with a handler chain. The "Execute" method is the sole entry point into a handler. This method also contains all of the business logic used by the handler to complete it's work. The "Order" property is used to specify the ordering of the handler within the handler chain.

Handlers are ordered in ascending order within a handler chain using the values specified by each handler in the "Order" property. Handler chains start with the handler with the lowest order value. By default, all handler chains have at least one handler with an order value of 100. From there, additional handlers usually increment the order by 100. For example, if a handler chain has three handlers, the order values would be 100, 200, and 300. This ordering scheme allows you to both insert a new handler in between existing handlers or add a new handler to the start or end of a handler chain. To insert a new handler into the second position in the handler chain, the handler can be given an order value between 101 and 199. To add the handler to the start or end of the handler chain, the handler can be given an order less than 100 or greater than 300, respectively.

A handler is associated with a handler chain according to the parameter and result object types (TIn and TOut). All handlers with the same object types will be executed within the same handler chain. Below is a code sample explaining the association further.

// These two handlers are part of the same handler chain
// because they both declare the same parameter and result
// object types.
public class GetCart : HandlerBase<GetCartParameter, GetCartResult>
public class GetCartLines : HandlerBase<GetCartParameter, GetCartResult>
 
// This handler is part of a different handler chain because
// it declares different parameter and result object types
// than the two handlers above.
public class ApplyPromotion : HandlerBase<AddPromotionHandler, AddPromotionResult>

Notice that the handlers above do not directly implement the IHandler<,> interface. Instead, they inherit from the HandlerBase class. This base class directly implements the IHandler<,> interface while providing utility methods for returning error results and passing execution to the next handler. As a best practice, all handlers should inherit from the HandlerBase class. The association to a handler chain is complete at this point. However, the handler requires a bit more configuration to function within ISC.

The final configuration involves the dependency locator. All handlers must be decorated with the DependencyName attribute. This allows the handler to be retrieved by name via the dependency locator.

Once you have configured the new handler, you can build the solution and run the application. The next time the handler chain executes, your new handler should be included in the chain. To help explain the handler chain further, the following section walks through adding a new handler to a handler chain.

Add a New Handler

The following section adds a new handler to the GetCartHandler chain. This new handler selectively returns the cart taxes based on the current user's role.

Preconditions

  • ISC SDK installed

Steps

  1. In your Extensions project, create a new handler class.

    public class ShowTaxAndShippingForBuyer3
    {
    }
  2. Implement the IHandler<TIn, TOut> interface by inheriting from HandlerBase<TIn, TOut>. For the TIn and TOut parameter and result object types, specify GetCartParameter and GetCartResult, respectively. Remember, this is how a handler is associated with a handler chain. It's important to specify the correct types. Also remember that the HandlerBase base class provides utility methods for returning error results. You can see these utility methods in action in later steps.

    public class ShowTaxAndShippingForBuyer3 : HandlerBase<GetCartParameter, GetCartResult>
    {
    }
  3. Decorate the handler with the DependencyName attribute. Use the name of the class for the dependency name.

    [DependencyName(nameof(ShowTaxAndShippingForBuyer3))]
    public class ShowTaxAndShippingForBuyer3 : HandlerBase<GetCartParameter, GetCartResult>
    {
    }
  4. Specify a value for the Order property. Remember, all handler chains start at an order of 100. Within the handler chain, all handlers provided by B2B Cloud increment the order by 100.

    public override int Order => 3000;
  5. Implement the Execute method. Remember, this is the sole entry point to the handler. Additionally, this method must either continue the handler chain or break it. Both methods are explained in the sample.

    This handler logic requires the Order Management > Cart > Show Tax & Shipping Amount in Cart setting to be set to "Yes". This precondition is only for this specific example. You can add a handler regardless of the value of this setting.

    public override GetCartResult Execute(IUnitOfWork unitOfWork, GetCartParameter parameter, GetCartResult result)
    {
        if (result.Cart == null)
        {
            // This is one of the utility methods for returning an error result
            // provided by the base class. These error results will be propagated
            // all the way up to the REST API and returned as a result.
            // Any following handlers will not execute.
            return this.CreateErrorServiceResult(result, SubCode.CartServiceCartNotFound, "A cart could not be found.");
        }
     
        result.ShowTaxAndShipping = result.UserRoles != null && result.UserRoles.Split(',').Contains(BuiltInRoles.Buyer3);
     
        // Once your handler is finished with it's work, if
        // you execute the next handler, execution will continue
        // in the handler chain with control being handed over to
        // the next handler.
        return this.NextHandler.Execute(unitOfWork, parameter, result);
     
        // Returning the result breaks the handler chain.
        // Any following handlers will not execute.
        return result;
    }

    For reference, below is the completed handler class.

    [DependencyName(nameof(ShowTaxAndShippingForBuyer3))]
    public class ShowTaxAndShippingForBuyer3 : HandlerBase<GetCartParameter, GetCartResult>
    {
        public override GetCartResult Execute(IUnitOfWork unitOfWork, GetCartParameter parameter, GetCartResult result)
        {
            result.ShowTaxAndShipping = result.UserRoles != null && result.UserRoles.Split(',').Contains(BuiltInRoles.Buyer3);
     
            return this.NextHandler.Execute(unitOfWork, parameter, result);
        }
     
        public override int Order => 3000;
    }
  6. Build your solution.

If the rest of your application is set up correctly, the next time you add a product to the cart and navigate to the Cart page, you may or may not see the shipping and taxes (depending on your role).

Removing or Replacing Handlers

In previous versions, developers could derive new view models, derive new .NET controllers from existing functionality and override methods to change the behavior of the platform. Epi B2B Commerce 4.0 is prescriptive when it comes to extending the platform. Module handlers are a primary extension point to the platform where developers can add additional business logic and provide additional data to the objects used for the interface.

To remove or replace a handler, give it the same dependency name as an existing handler. By Inversion of Control within Epi B2B Commerce you can create instance that implements HandlerBase with AddAccountParameter and AddAccountResult and same dependency name, your custom class will override the standard Epi B2B Commerce handler. Creating a custom class that derives from HandlerBase and using the same dependency name will void the need for using the Order property.

Note: You cannot "remove" a handler, but you can create an implementation of it that does nothing.

Do you find this information helpful? Please log in to provide feedback.

Last updated: Dec 11, 2020

Recommended reading