/// <summary>
        ///     Gets ifnromation about the seat types.
        /// </summary>
        /// <remarks>
        ///     Because the seat type contains the number of available seats, and this information can change often, notice
        ///     how we manage the risks associated with displaying data that is very stale by adjusting caching duration
        ///     or not even caching at all if only a few seats remain.
        ///     For more information on the optimizations we did for V3
        ///     see <see cref="http://go.microsoft.com/fwlink/p/?LinkID=258557"> Journey chapter 7</see>.
        /// </remarks>
        public IList <SeatType> GetPublishedSeatTypes(Guid conferenceId)
        {
            var key       = "ConferenceDao_PublishedSeatTypes_" + conferenceId;
            var seatTypes = cache.Get(key) as IList <SeatType>;

            if (seatTypes == null)
            {
                seatTypes = decoratedDao.GetPublishedSeatTypes(conferenceId);
                if (seatTypes != null)
                {
                    // determine how long to cache depending on criticality of using stale data.
                    TimeSpan timeToCache;
                    if (seatTypes.All(x => x.AvailableQuantity > 200 || x.AvailableQuantity <= 0))
                    {
                        timeToCache = TimeSpan.FromMinutes(5);
                    }
                    else if (seatTypes.Any(x => x.AvailableQuantity < 30 && x.AvailableQuantity > 0))
                    {
                        // there are just a few seats remaining. Do not cache.
                        timeToCache = TimeSpan.Zero;
                    }
                    else if (seatTypes.Any(x => x.AvailableQuantity < 100 && x.AvailableQuantity > 0))
                    {
                        timeToCache = TimeSpan.FromSeconds(20);
                    }
                    else
                    {
                        timeToCache = TimeSpan.FromMinutes(1);
                    }

                    if (timeToCache > TimeSpan.Zero)
                    {
                        cache.Set(key, seatTypes, new CacheItemPolicy {
                            AbsoluteExpiration = DateTimeOffset.UtcNow.Add(timeToCache)
                        });
                    }
                }
            }

            return(seatTypes);
        }
예제 #2
0
        public OrderTotal CalculateTotal(Guid conferenceId, ICollection <SeatQuantity> seatItems)
        {
            var seatTypes = conferenceDao.GetPublishedSeatTypes(conferenceId);
            var lineItems = new List <OrderLine>();

            foreach (var item in seatItems)
            {
                var seatType = seatTypes.FirstOrDefault(x => x.Id == item.SeatType);
                if (seatType == null)
                {
                    throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture, "Invalid seat type ID '{0}' for conference with ID '{1}'", item.SeatType, conferenceId));
                }

                lineItems.Add(new SeatOrderLine {
                    SeatType = item.SeatType, Quantity = item.Quantity, UnitPrice = seatType.Price, LineTotal = Math.Round(seatType.Price * item.Quantity, 2)
                });
            }

            return(new OrderTotal {
                Total = lineItems.Sum(x => x.LineTotal),
                Lines = lineItems
            });
        }