title: How to implement an Action Filter in NopCommerce
body: <p>I want to change some code in an action of the OpcSaveBilling action from the CheckoutController. I don't want to alter the core code of NopCommerce so i need to try to overide the code with my own custom code.</p>
  
  <p>I've read this article to get me started <a href="http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions" rel="noreferrer">http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions</a>. From what I've read you can execute your own code before an action is executed and after an action is executed. But what I am not getting is the part that the article is leaving open (the actual code that needs to be executed).</p>
  
  <p>What I basicly want is the same function of the original code but with some custom tweaks. I've added a checkbox in the OnePageCheckout view and based on that checkbox it needs to skip the enter shipping addresss part in the checkout or not. (Use the billing address for the shipping address)</p>
  
  <p>I already have that code added to in the core code and this work and skips the step (NOTE: I know I still need to manually add the billing address as shipping address) but like i said i don't want to alter the code in the core of NopCommerce but override of it. </p>
  
  <p>If my question is not understandable and you need more code or explanation I'm happy to provide more. If the way I am doing this is not suitable for what I want, i would appreciate if you tell me!</p>
  
  <p>My code:</p>
  
  <p>The Action Filter class:</p>
  
  <pre><code>using Nop.Web.Controllers;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Web.Mvc;
  
  namespace Nop.Plugin.Misc.MyProject.ActionFilters
  {
  class ShippingAddressOverideActionFilter : ActionFilterAttribute, IFilterProvider
  {
      public IEnumerable&lt;Filter&gt; GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
      {
          if (controllerContext.Controller is CheckoutController &amp;&amp; actionDescriptor.ActionName.Equals("OpcSaveBilling", StringComparison.InvariantCultureIgnoreCase))
          {
              return new List&lt;Filter&gt;() { new Filter(this, FilterScope.Action, 0) };
          }
          return new List&lt;Filter&gt;();
      }
  
      public override void OnActionExecuting(ActionExecutingContext filterContext)
      {
          // What do I put in here? So that I have the code of the core action but with my custom tweaks in it
      }
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Registered the class in DependencyRegistar in the same Nop plugin</p>
  
  <pre><code> builder.RegisterType&lt;ShippingAddressOverideActionFilter&gt;().As&lt;System.Web.Mvc.IFilterProvider&gt;();
  </code></pre>
  
  <p>A working example with custom code in it. But this is in the core action.</p>
  
  <pre><code>  public ActionResult OpcSaveBilling(FormCollection form)
      {
          try
          {
              //validation
              var cart = _workContext.CurrentCustomer.ShoppingCartItems
                  .Where(sci =&gt; sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
              .Where(sci =&gt; sci.StoreId == _storeContext.CurrentStore.Id)
                  .ToList();
              if (cart.Count == 0)
                  throw new Exception("Your cart is empty");
  
              if (!UseOnePageCheckout())
                  throw new Exception("One page checkout is disabled");
  
              if ((_workContext.CurrentCustomer.IsGuest() &amp;&amp; !_orderSettings.AnonymousCheckoutAllowed))
                  throw new Exception("Anonymous checkout is not allowed");
  
              int billingAddressId = 0;
              int.TryParse(form["billing_address_id"], out billingAddressId);
  
  
  
              if (billingAddressId &gt; 0)
              {
                  //existing address
                  var address = _workContext.CurrentCustomer.Addresses.FirstOrDefault(a =&gt; a.Id == billingAddressId);
                  if (address == null)
                      throw new Exception("Address can't be loaded");
  
                  _workContext.CurrentCustomer.BillingAddress = address;
                  _customerService.UpdateCustomer(_workContext.CurrentCustomer);
              }
              else
              {
                  //new address
                  var model = new CheckoutBillingAddressModel();
                  TryUpdateModel(model.NewAddress, "BillingNewAddress");
                  //validate model
                  TryValidateModel(model.NewAddress);
                  if (!ModelState.IsValid)
                  {
                      //model is not valid. redisplay the form with errors
                      var billingAddressModel = PrepareBillingAddressModel(selectedCountryId: model.NewAddress.CountryId);
                      billingAddressModel.NewAddressPreselected = true;
                      return Json(new
                      {
                          update_section = new UpdateSectionJsonModel()
                          {
                              name = "billing",
                              html = this.RenderPartialViewToString("OpcBillingAddress", billingAddressModel)
                          },
                          wrong_billing_address = true,
                      });
                  }
  
                  //try to find an address with the same values (don't duplicate records)
                  var address = _workContext.CurrentCustomer.Addresses.ToList().FindAddress(
                      model.NewAddress.FirstName, model.NewAddress.LastName, model.NewAddress.PhoneNumber,
                      model.NewAddress.Email, model.NewAddress.FaxNumber, model.NewAddress.Company,
                      model.NewAddress.Address1, model.NewAddress.Address2, model.NewAddress.City,
                      model.NewAddress.StateProvinceId, model.NewAddress.ZipPostalCode, model.NewAddress.CountryId);
                  if (address == null)
                  {
                      //address is not found. let's create a new one
                      address = model.NewAddress.ToEntity();
                      address.CreatedOnUtc = DateTime.UtcNow;
                      //some validation
                      if (address.CountryId == 0)
                          address.CountryId = null;
                      if (address.StateProvinceId == 0)
                          address.StateProvinceId = null;
                      if (address.CountryId.HasValue &amp;&amp; address.CountryId.Value &gt; 0)
                      {
                          address.Country = _countryService.GetCountryById(address.CountryId.Value);
                      }
                      _workContext.CurrentCustomer.Addresses.Add(address);
                  }
                  _workContext.CurrentCustomer.BillingAddress = address;
                  _customerService.UpdateCustomer(_workContext.CurrentCustomer);
              }
  
              // Get value of checkbox from the one page checkout view
              var useSameAddress = false;
              Boolean.TryParse(form["billing-address-same"], out useSameAddress);
  
              // If it is checked copy the billing address to shipping address and skip the shipping address part of the checkout
              if (useSameAddress)
              {
                  var shippingMethodModel = PrepareShippingMethodModel(cart);
  
                  return Json(new
                  {
                      update_section = new UpdateSectionJsonModel()
                      {
                          name = "shipping-method",
                          html = this.RenderPartialViewToString("OpcShippingMethods", shippingMethodModel)
                      },
                      goto_section = "shipping_method"
                  });
              }
              // If it isn't checked go to the enter shipping address part of the checkout
              else
              {
                  if (cart.RequiresShipping())
                  {
                      //shipping is required
                      var shippingAddressModel = PrepareShippingAddressModel(prePopulateNewAddressWithCustomerFields: true);
                      return Json(new
                      {
                          update_section = new UpdateSectionJsonModel()
                          {
                              name = "shipping",
                              html = this.RenderPartialViewToString("OpcShippingAddress", shippingAddressModel)
                          },
                          goto_section = "shipping"
                      });
                  }
                  else
                  {
                      //shipping is not required
                      _genericAttributeService.SaveAttribute&lt;ShippingOption&gt;(_workContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedShippingOption, null, _storeContext.CurrentStore.Id);
  
                      //load next step
                      return OpcLoadStepAfterShippingMethod(cart);
                  }
              }
          }
          catch (Exception exc)
          {
              _logger.Warning(exc.Message, exc, _workContext.CurrentCustomer);
              return Json(new { error = 1, message = exc.Message });
          }
      }
  </code></pre>