How to implement an action filter in NopCommerce

I want to change some code in the action action of the OpcSaveBilling from CheckoutController. I don’t want to change the main NopCommerce code, so I need to try to redefine the code using my own code.

I read this article to get started http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions . From what I read, you can execute your own code before the action is completed and after the action is completed. But what I am not getting is that the article remains open (the actual code that needs to be executed).

What I basically want is the same source code features, but with some user preferences. I added a flag in the OnePageCheckout view and based on this flag, he needs to skip part of the incoming delivery addresses at the box office or not. (Use billing address for shipping address)

I already have the code added to the main code and this work and will skip this step (NOTE: I know that I still need to manually add the billing address as the delivery address), but as I said, I don’t want to change code in the core of NopCommerce, but override it.

If my question is incomprehensible and you need more code or explanations, I gladly provided more. If the way I do this is not suitable for what I want, I would appreciate it if you told me.

My code is:

Action Filter Class:

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<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext.Controller is CheckoutController && actionDescriptor.ActionName.Equals("OpcSaveBilling", StringComparison.InvariantCultureIgnoreCase)) { return new List<Filter>() { new Filter(this, FilterScope.Action, 0) }; } return new List<Filter>(); } 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 } } 

}

Registered a class in DependencyRegistar in the same Nop plugin

  builder.RegisterType<ShippingAddressOverideActionFilter>().As<System.Web.Mvc.IFilterProvider>(); 

Working example with custom code. But this is the main action.

  public ActionResult OpcSaveBilling(FormCollection form) { try { //validation var cart = _workContext.CurrentCustomer.ShoppingCartItems .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart) .Where(sci => 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() && !_orderSettings.AnonymousCheckoutAllowed)) throw new Exception("Anonymous checkout is not allowed"); int billingAddressId = 0; int.TryParse(form["billing_address_id"], out billingAddressId); if (billingAddressId > 0) { //existing address var address = _workContext.CurrentCustomer.Addresses.FirstOrDefault(a => 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 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 && address.CountryId.Value > 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<ShippingOption>(_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 }); } } 
+5
source share
1 answer

No one can tell you what you need to include in OnActionExecuting, because there is something in it that you can do.

 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 } 

The rule of the thumb? Write any code, how, how you write the action. The only setting is that instead of returning an ActionResult, you should set filterContext.Result (you cannot return anything, since it is a void method).

For example, setting the next will be redirected to the home page before even performing the action that you override.

 filterContext.Result = new RedirectToRouteResult("HomePage", null); 

Remember that this is OnActionExecuting, so this is done before the action you override. And if you redirect it to another page, it will not trigger the action that you override. :)

+6
source

Source: https://habr.com/ru/post/1202070/


All Articles