How to implement an Action Filter in NopCommerce

淺唱寂寞╮ 提交于 2019-12-01 20:06:13

问题


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.

I've read this article to get me started http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions. 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).

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)

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.

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!

My code:

The 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 the class in DependencyRegistar in the same Nop plugin

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

A working example with custom code in it. But this is in the core 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'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 && 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 });
        }
    }

回答1:


Nobody can tell you what you need to put in OnActionExecuting, because there is so much you can do in it.

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
    }

Rule of thumb? Write any code like how you'll write an Action. The only tweak is, instead of returning ActionResult, you should set filterContext.Result (you can't return anything as this is a void method).

For example, setting the following will redirect to home page before even executing the action you are overriding.

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

Remember this is OnActionExecuting, so this is executed before the Action you are overriding. And if you redirects it to another page, it'll not call the Action you are overriding. :)



来源:https://stackoverflow.com/questions/25723821/how-to-implement-an-action-filter-in-nopcommerce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!