Interupting AddToCart via ActionFilter and give out a warning

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
9 years ago
i've written an ActionFilter that interrupts the AddToCart process and checks if an attribute in the product has already been seen in the past. if so it SHOULD issue the standard cart warning and not proceed. just like the validation in ShoppingCartService adds a warning which essentially returns:

            if (addToCartWarnings.Count > 0)
            {
                //cannot be added to the cart
                //let's display standard warnings
                return Json(new
                {
                    success = false,
                    message = addToCartWarnings.ToArray()
                });
            }


i'm trying to mimic this behavior by doing the following in my ActionFilter:
                if (addToCartWarnings.Count > 0)
                {
                    filterContext.Result = new JsonResult
                    {
                        Data = new { success = false, message = addToCartWarnings.ToArray() }
                    };
                }


but this does essentially nothing. do i have to use a RedirectToRoute and return a Json object from my controller or is it somehow possible from within the ActionFilter? Would the RedirectToRoute even work?
9 years ago
AAlexx wrote:
i've written an ActionFilter that interrupts the AddToCart process and checks if an attribute in the product has already been seen in the past. if so it SHOULD issue the standard cart warning and not proceed. just like the validation in ShoppingCartService adds a warning which essentially returns:

            if (addToCartWarnings.Count > 0)
            {
                //cannot be added to the cart
                //let's display standard warnings
                return Json(new
                {
                    success = false,
                    message = addToCartWarnings.ToArray()
                });
            }


i'm trying to mimic this behavior by doing the following in my ActionFilter:
                if (addToCartWarnings.Count > 0)
                {
                    filterContext.Result = new JsonResult
                    {
                        Data = new { success = false, message = addToCartWarnings.ToArray() }
                    };
                }


but this does essentially nothing. do i have to use a RedirectToRoute and return a Json object from my controller or is it somehow possible from within the ActionFilter? Would the RedirectToRoute even work?


It's certainly possible.  Are you performing this on OnActionExecuted and not OnActionExecuting?  Also, you may need to add extra properties to your JsonResult.  


  filterContext.Result = new JsonResult
                    {
                        Data = new { success = false, message = addToCartWarnings.ToArray() },
                        ContentType = [contentType],
                        ContentEncoding = [contentEncoding],
                        JsonRequestBehavior = [behavior],
                        MaxJsonLength = Int32.MaxValue //or whatever you'd like it to be
                    };
9 years ago
thank you for your reply.

i was not doing this in OnExecuted()... should i save the warnings in a global variable and return them @ OnExecuted()? any best practice advice?
9 years ago
AAlexx wrote:
thank you for your reply.

i was not doing this in OnExecuted()... should i save the warnings in a global variable and return them @ OnExecuted()? any best practice advice?


The best practice for using action filters is to Be Careful - make sure you have plenty of error checking / handling.  Otherwise, it depends on what you're trying to accomplish.  You can assign the ActionParameters (which may contain a model depending on the Action) to instance properties of your ActionFilter OnActionExecuting and then use them later OnActionExecuted.  You can obtain the model from your FilterContext.Result OnActionExecuted and modify it before being sent down.

-Adam
9 years ago
my approach isn't working. i want to give out a warning and not add the product to the cart without having to rewrite  ShoppingCartController.cs. i though an action filter would work, but it's really counter intuitive. have no idea what is happening with the filterContext.Result of OnActionExecuted, but some EMPTY message window pops up and the item is still added to the cart. so something is happening, but i can't tell what exactly, or why the message window is empty.

is there no simple way of doing this? do i have to redirect to the controller and return the json from there? is there a difference? i suppose i have to redirect the route somehow, otherwise the ShoppingCartController is still called and the item is still added to the cart even IF the warning was displayed correctly. i really don't want to add code to the ShoppingCartController.

please help!
9 years ago
AAlexx wrote:
my approach isn't working. i want to give out a warning and not add the product to the cart without having to rewrite  ShoppingCartController.cs. i though an action filter would work, but it's really counter intuitive. have no idea what is happening with the filterContext.Result of OnActionExecuted, but some EMPTY message window pops up and the item is still added to the cart. so something is happening, but i can't tell what exactly, or why the message window is empty.

is there no simple way of doing this? do i have to redirect to the controller and return the json from there? is there a difference? i suppose i have to redirect the route somehow, otherwise the ShoppingCartController is still called and the item is still added to the cart even IF the warning was displayed correctly. i really don't want to add code to the ShoppingCartController.

please help!


If you provide code samples I can help give you some direction.
9 years ago
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;
using Nop.Core;
using Nop.Core.Infrastructure;
using Nop.Services.Customers;
using Nop.Services.Catalog;
using Nop.Services.Configuration;
using Nop.Services.Logging;
using Nop.Plugin.Misc.ValueMaster.Service;
using Nop.Plugin.Misc.ValueMaster.Domain;
using Nop.Services.Orders;
using Nop.Core.Domain.Catalog;

namespace Nop.Plugin.Misc.ValueMaster
{
    public class ValueMasterActionFilter : ActionFilterAttribute, IFilterProvider
    {
        private IList<string> _addToCartWarnings;
        private IValueMasterService _valueMasterService;
        private IWorkContext _workContext;

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            if (controllerContext.Controller.ToString().Contains("ShoppingCart") &&
                actionDescriptor.ActionName.Contains("ToCart") ||
                controllerContext.Controller.ToString() == "Nop.Web.Controllers.CheckOutController" &&
                actionDescriptor.ActionName.Equals("Completed", StringComparison.InvariantCultureIgnoreCase) ||
                controllerContext.Controller.ToString() == "Nop.Web.Controllers.CustomerController" &&
                actionDescriptor.ActionName.Equals("AccountActivation", StringComparison.InvariantCultureIgnoreCase))
            {
                return new List<Filter>() { new Filter(this, FilterScope.Action, 0)};
            }
            
            return new List<Filter>();
        }
        
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            _addToCartWarnings = new List<string>();
            _valueMasterService = EngineContext.Current.Resolve<IValueMasterService>();
            _workContext = EngineContext.Current.Resolve<IWorkContext>();

            var storeContext = EngineContext.Current.Resolve<IStoreContext>();
            var logger = EngineContext.Current.Resolve<ILogger>();
            var shoppingCartService = EngineContext.Current.Resolve<IShoppingCartService>();
            var c = _workContext.CurrentCustomer;

            if (filterContext.Controller.ControllerContext.Controller.ToString() ==  "Nop.Web.Controllers.CustomerController" && c != null && c.Username != null && c.Active)
            {
                try
                {
                    var s = new CU_WebAPISoapClient();
                    var list = s.WebService()
                    foreach (var p in list)
                    {
                        if (c.Username == p.CompanyName)
                            return;
                    }
                                        
                    //client.CU_Add_Modify_Partner(
                    //    auth,
                    //    a.FirstOrDefault(x => x.Name.Equals("CompanyID")),
                    //    a.FirstOrDefault(x => x.Name.Equals("CompanyName")),
                    //    1,

                }
                catch (Exception ex)
                {
                    logger.Error(ex.Message, ex, c);
                    return;
                }
            }

            //add the terminal ids from the shopping cart item attributes to a list
            if (filterContext.Controller.ControllerContext.Controller.ToString().Contains("ShoppingCart"))
            {
                var dbTerminals = _valueMasterService.GetTerminalsByCustomerId(c.Id).ToList<ValueMasterCustomerTerminalsEntity>();
                var productAttributes = ParseProductAttributes((int)filterContext.ActionParameters["productId"], (FormCollection)filterContext.ActionParameters["form"]);
                var addToCartTerminals = GetTerminalListFromAttributes(productAttributes);
                var shoppingCartTerminals = new List<ValueMasterCustomerTerminalsEntity>();

                foreach (var activationProduct in c.ShoppingCartItems.Where(p => p.Product.Name.StartsWith("Activation")))
                {
                    shoppingCartTerminals.AddRange(GetTerminalListFromAttributes(activationProduct.AttributesXml));
                }

                foreach (var cT in addToCartTerminals)
                {
                    if (dbTerminals.Count(t => t.TerminalId == cT.TerminalId && t.TerminalGroupId == cT.TerminalGroupId) > 0)
                    {
                        _addToCartWarnings.Add("Terminal ID <" + cT.TerminalId + "> already activated!");
                    }

                    if (shoppingCartTerminals.Count(t => t.TerminalId == cT.TerminalId && t.TerminalGroupId == cT.TerminalGroupId) >0)
                    {
                        _addToCartWarnings.Add("Terminal ID <" + cT.TerminalId + "> already in shopping cart!");
                    }
                }
            }
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (_addToCartWarnings.Count > 0)
            {
                filterContext.Result = new JsonResult
                {
                    Data = new { success = false, message = _addToCartWarnings.ToArray() },
                    ContentType = "application/json",
                    ContentEncoding = System.Text.Encoding.UTF8,
                    JsonRequestBehavior = JsonRequestBehavior.DenyGet,
                    MaxJsonLength = Int32.MaxValue //or whatever you'd like it to be
                };
            }
        }

        private List<ValueMasterCustomerTerminalsEntity> GetTerminalListFromAttributes(string productAttributes)
        {
            var tList = new List<ValueMasterCustomerTerminalsEntity>();
            var productAttributeParser = EngineContext.Current.Resolve<IProductAttributeParser>();
            var terminalGroups = _valueMasterService.GetTerminalGroupsByCustomerId(_workContext.CurrentCustomer.Id);
            var terminalGroupId = terminalGroups != null ? terminalGroups.First().Id : 0;

            //add the terminal ids from the add-to-cart item attributes to a list
            foreach (var attribute in productAttributeParser.ParseProductVariantAttributes(productAttributes))
            {
                if (attribute.ProductAttribute.Name.StartsWith("Terminal ID"))
                {
                    var val = productAttributeParser.ParseValues(productAttributes, attribute.Id).FirstOrDefault();
                    if (!string.IsNullOrEmpty(val) && val != "00000000")
                    {
                        var terminal = new ValueMasterCustomerTerminalsEntity();
                        terminal.Activated = false;
                        terminal.TerminalGroupId = terminalGroupId;
                        terminal.TerminalId = val;

                        tList.Add(terminal);
                    }
                }
            }

            return tList;
        }

        private string ParseProductAttributes(int productId, FormCollection form)
        {
            var productAttributeService = EngineContext.Current.Resolve<IProductAttributeService>();
            var productAttributeParser = EngineContext.Current.Resolve<IProductAttributeParser>();
            var selectedAttributes = string.Empty;
            var productVariantAttributes = productAttributeService.GetProductVariantAttributesByProductId(productId);

            foreach (var attribute in productVariantAttributes)
            {
                string controlId = string.Format("product_attribute_{0}_{1}_{2}", attribute.ProductId, attribute.ProductAttributeId, attribute.Id);
                switch (attribute.AttributeControlType)
                {
                    case AttributeControlType.TextBox:
                        {
                            var ctrlAttributes = form[controlId];

                            if (!String.IsNullOrEmpty(ctrlAttributes))
                            {
                                string enteredText = ctrlAttributes.Trim();

                                selectedAttributes = productAttributeParser.AddProductAttribute(selectedAttributes, attribute, enteredText);
                            }
                        }
                        break;
                    default:
                        break;
                }

            }
            return selectedAttributes;
        }
    }
}
9 years ago
You'll have to remove / update the offending product(s) from the user's cart OnActionExecuted, or redirect to a custom JsonResult method OnActionExecuting.    As far as the empty message, try playing around with the additional JsonResult properties you're returning, like setting the ContentType to "application/json; charset=utf-8" or maybe getting rid of the extra properties altogether and only sending Data.
9 years ago
so i should remove the item from the cart after it was added or is there a way to prevent the add altogether... with a redirecttoroute or redirectoaction or something? can i do that in the action filter or do i need to reroute in a controller?
9 years ago
AAlexx wrote:
so i should remove the item from the cart after it was added or is there a way to prevent the add altogether... with a redirecttoroute or redirectoaction or something? can i do that in the action filter or do i need to reroute in a controller?


Yep, you can return a RedirectResult from OnActionExecuting to redirect to a custom JsonResult (in a custom controller) so no products will be added.

Edit (so this is on page 1)

Actually in your case, you should be able to return the JsonResult OnActionExecuting as long as you're intercepting an Ajax request.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.