【问题标题】:How to implement an Action Filter in NopCommerce如何在 NopCommerce 中实现动作过滤器
【发布时间】:2014-11-01 15:31:35
【问题描述】:

我想从 CheckoutController 更改 OpcSaveBilling 操作中的一些代码。我不想改变 NopCommerce 的核心代码,所以我需要尝试用我自己的自定义代码覆盖代码。

我已阅读这篇文章以帮助我入门 http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions。从我读过的内容来看,您可以在执行操作之前和执行操作之后执行自己的代码。但我没有得到的是文章未打开的部分(需要执行的实际代码)。

我基本上想要的是与原始代码相同的功能,但有一些自定义调整。我在 OnePageCheckout 视图中添加了一个复选框,并且基于该复选框,它需要跳过结帐中的输入送货地址部分。 (使用账单地址作为送货地址)

我已经在核心代码中添加了该代码,这项工作并跳过了这一步(注意:我知道我仍然需要手动添加账单地址作为送货地址)但就像我说的我不想改变NopCommerce 核心中的代码,但覆盖它。

如果我的问题无法理解并且您需要更多代码或解释,我很乐意提供更多。如果我这样做的方式不适合我想要的,如果您告诉我,我将不胜感激!

我的代码:

动作过滤器类:

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
    }
}

}

在同一个 Nop 插件的 DependencyRegistar 中注册了类

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

其中包含自定义代码的工作示例。但这是核心行动。

  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 });
        }
    }

【问题讨论】:

    标签: c# asp.net-mvc nopcommerce action-filter


    【解决方案1】:

    没有人能告诉您需要在 OnActionExecuting 中添加什么,因为您可以在其中做很多事情。

    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
        }
    

    经验法则?编写任何代码,就像编写动作一样。唯一的调整是,您应该设置 filterContext.Result 而不是返回 ActionResult(您不能返回任何内容,因为这是一个 void 方法)。

    例如,设置以下内容将在执行您覆盖的操作之前重定向到主页。

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

    记住这是 OnActionExecuting,所以它会在您覆盖的 Action 之前执行。如果您将其重定向到另一个页面,它不会调用您正在覆盖的操作。 :)

    【讨论】:

    • 感谢您的回复。如果我将重定向到自定义控制器 + 操作,就像在您的回复中一样,有没有办法发送使用该重定向调用 OpcSaveBilling 时获取的 FormCollection 参数,以便我可以在自定义操作中使用它?
    猜你喜欢
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 2016-02-21
    • 2017-08-05
    • 2014-09-23
    • 2018-04-03
    • 1970-01-01
    相关资源
    最近更新 更多