public virtual async Task HandleEventAsync(NotificationEventData eventData) { var notification = NotificationDefinitionManager.Get(eventData.Name); var notificationInfo = new NotificationInfo { Name = notification.Name, CreationTime = eventData.CreationTime, Data = eventData.Data, Severity = eventData.Severity, Lifetime = notification.NotificationLifetime, TenantId = eventData.TenantId, Type = notification.NotificationType }; notificationInfo.SetId(SnowflakeIdGenerator.Create()); notificationInfo.Data = NotificationDataConverter.Convert(notificationInfo.Data); Logger.LogDebug($"Persistent notification {notificationInfo.Name}"); // 持久化通知 await NotificationStore.InsertNotificationAsync(notificationInfo); var providers = Enumerable .Reverse(NotificationPublishProviderManager.Providers); await PublishFromProvidersAsync(providers, eventData.Users, notificationInfo); }
public static string GenerateToken() { // Attempt to grab operationId for App Insights. // If available, assign as correlationToken. // If not, generate with Snowflake var appInsightOperationKey = System.Diagnostics.Activity.Current.RootId; return(!string.IsNullOrEmpty(appInsightOperationKey) ? $"{SnowflakeEnum.Correlation}-{appInsightOperationKey}" : SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Correlation)); }
private void SnowflakeIdGeneratorTask(object workerId) { int generatorMax = (int)Math.Pow(10, 3); SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator((int)workerId, 1); var iDGeneratorDictionary = new Dictionary <string, long>(); for (int i = 0; i < generatorMax; i++) { long temp = idGenerator.nextId(); iDGeneratorDictionary.Add(string.Format("idGenerators-{0}-{1}->{2}", (int)workerId, i + 1, temp), temp); } lock (lockObj) { idGeneratorList.AddRange(iDGeneratorDictionary); } }
/// <summary> /// Sets the cookie value for the basketId or creates a new ID if null /// </summary> /// <param name="basketId"> /// The <see cref="BasketDto.BasketId">Basket ID</see>. /// If null create a new ID /// </param> /// <returns>the new The <see cref="BasketDto.BasketId">Basket ID</see></returns> public string SetBasketId(string basketId = null) { //A GUID to hold the basketId. if (string.IsNullOrWhiteSpace(basketId)) { // Use SnowflakeIdGenerator to generate BasketId basketId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Basket); } var options = new CookieOptions { Expires = DateTime.UtcNow.AddDays(7), HttpOnly = true }; _httpContextAccessor.HttpContext.Response.Cookies.Append(CookieName, basketId, options); return(basketId); }
public Order( string customerSystemId, string checkOutSystemId, decimal total, string correlationToken) //List<OrderDetail> orderDetails) { OrderSystemId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Order); OrderId = Guid.NewGuid().ToString(); OrderDate = DateTime.UtcNow; CustomerSystemId = customerSystemId; CheckOutSystemId = checkOutSystemId; Total = total; CorrelationToken = correlationToken; // Set status to Pending OrderStatusId = (int)OrderStatusEnum.Pending; OrderDetails = new List <OrderDetail>(); }
public virtual async Task HandleEventAsync(NotificationEventData eventData) { // 这样做的话就要注意了 // 当只有一个消费者订阅时,事件总线会认为消息已经处理,从而发布Ack指令,从消息队列中移除此消息 // 可能造成通知数据丢失 var application = Options.Application ?? "Abp"; if (!string.Equals(application, eventData.Application, StringComparison.InvariantCultureIgnoreCase)) { // 不是当前监听应用的消息不做处理 return; } // 如果上面过滤了应用程序,这里可以使用Get方法,否则,最好使用GetOrNull加以判断 var notification = NotificationDefinitionManager.Get(eventData.Name); var notificationInfo = new NotificationInfo { Name = notification.Name, CreationTime = eventData.CreationTime, Data = eventData.Data, Severity = eventData.Severity, Lifetime = notification.NotificationLifetime, TenantId = eventData.TenantId, Type = notification.NotificationType }; notificationInfo.SetId(SnowflakeIdGenerator.Create()); // TODO: 可以做成一个接口来序列化消息 notificationInfo.Data = NotificationDataConverter.Convert(notificationInfo.Data); Logger.LogDebug($"Persistent notification {notificationInfo.Name}"); // 持久化通知 await NotificationStore.InsertNotificationAsync(notificationInfo); var providers = Enumerable .Reverse(NotificationPublishProviderManager.Providers); await PublishFromProvidersAsync(providers, eventData.Users, notificationInfo); }
protected async Task <string> PublishNofiterAsync( string name, NotificationData data, IEnumerable <UserIdentifier> users = null, Guid?tenantId = null, NotificationSeverity severity = NotificationSeverity.Info) { var eto = new NotificationEto <NotificationData>(data) { Id = SnowflakeIdGenerator.Create(), TenantId = tenantId, Users = users?.ToList(), Name = name, CreationTime = DateTime.Now, Severity = severity }; await DistributedEventBus.PublishAsync(eto); return(eto.Id.ToString()); }
public void SnowflakeIdGeneratorOne() { try { int generatorindex = 0; int generatorMax = (int)Math.Pow(10, 6); SnowflakeIdGenerator idWorker1 = new SnowflakeIdGenerator(1, 1); var idGeneratorDictionary = new Dictionary <string, long>(); for (int i = generatorindex; i < generatorMax; i++) { long temp = idWorker1.nextId(); idGeneratorDictionary.Add(string.Format("{0}->{1}", i + 1, temp), temp); } Console.WriteLine(JsonConvert.SerializeObject(idGeneratorDictionary, Formatting.Indented)); } catch (Exception ex) { Console.WriteLine(ex.ToString()); throw; } }
/// <summary> /// Add single line item to shopping basket /// </summary> /// <param name="productId">Id of productEntity to add</param> /// <param name="correlationToken">Tracks request - can be any value</param> /// <param name="basketId">Id of shopping basket</param> /// <returns>BasketItemEntity</returns> public async Task <BasketEntity> AddItemToBasket(int productId, string correlationToken, string basketId) { //* Materialized View Pattern //* Fetch product entity data from a read-only store contained in shopping basket service. //* ProductEntity ID is row key in underlying Azure table. //* Returns a ProductTableEntity class var productTableEntity = await _productRepository.GetItem(ProductPartitionKey, productId.ToString(), correlationToken); // Fallback logic if (productTableEntity == null) { // Fallback: // If product not available from local read store, fetch it from catalog service by // making direct HTTP call to Catalog Service. var product = await _restClient.GetAsync <ProductEntity>(ServiceEnum.Catalog, $"api/Catalog/Music/{productId}", correlationToken); if (product == null) { throw new Exception( $"Cannot add item to shopping basket: ProductEntity #{productId} does not exist for Request {correlationToken}. Have you created the ProductEntity Read Model for the Shopping BasketEntity microservice?"); } // Transform product into an entity class for table storage productTableEntity = new ProductTableEntity { // parition key is constant PartitionKey = ProductPartitionKey, // row key is productId RowKey = product.Data.Id.ToString(), Title = product.Data.Title, Id = product.Data.Id, GenreName = product.Data.GenreName, ArtistName = product.Data.ArtistName, Price = product.Data.Price.ToString() }; // Add product entity tolocal read store, implementing a cache-aside pattern await _productRepository.Insert(productTableEntity, correlationToken); _logger.LogInformation( $"Added productEntity information for item {productId} for Request {correlationToken} to the read model."); } BasketEntity basket = null; // Does basketID exist? if (basketId == "-1") { basketId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Basket); } else { basket = await _distributedCacheRepository.GetBasketAsync(basketId, correlationToken, _telemetryClient); } // Get basket from cache if (basket == null) { // BasketEntity is null, add new single item to it basket = new BasketEntity { BuyerId = "2", BasketId = basketId, CorrelationToken = correlationToken, Items = { new BasketItemEntity { CorrelationToken = correlationToken, //DateCreated = DateTime.Now, Title = productTableEntity.Title, UnitPrice = productTableEntity.Price.ToString(), Artist = productTableEntity.ArtistName, Genre = productTableEntity.GenreName, Quantity = 1, ProductId = productId, } } }; basket = await _distributedCacheRepository.UpdateBasketAsync(basket, correlationToken, _telemetryClient); _logger.LogInformation($"Created new shopping basket {basketId} and added productEntity {productTableEntity.Title} for Request {correlationToken} "); } else { // BasketEntity is not null // Determine if the same productEntity has already been added to the basket var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == Int32.Parse(productTableEntity.RowKey)); if (itemInBasket == null) { // ProductEntity does not exist in basket, add it basket.Items.Add(new BasketItemEntity() { CorrelationToken = correlationToken, //DateCreated = DateTime.Now, Title = productTableEntity.Title, UnitPrice = productTableEntity.Price.ToString(), Artist = productTableEntity.ArtistName, Genre = productTableEntity.GenreName, Quantity = 1, ProductId = Int32.Parse(productTableEntity.RowKey) }); _logger.LogInformation($"Added productEntity Id {productId} to shopping basket {basketId} for request {correlationToken}"); } else { // Idempotency write-check // Ensure that update with same correlation token does not already exist. // This could happen if we've already committed the write, but have gotten caught-up in retry logic. if (itemInBasket.CorrelationToken != null && itemInBasket.CorrelationToken == correlationToken) { _logger.LogWarning($"ProductEntity Id {productId} already added to shopping basket {basketId} for Request {correlationToken}"); return(basket); } // ProductEntity already exists in basket. Increment its count. basket.Items.FirstOrDefault(x => x.ProductId == Int32.Parse(productTableEntity.RowKey)).Quantity++; _logger.LogInformation($"Added productEntity Id {productId} to existing shopping basket {basketId} for request {correlationToken}"); } basket = await _distributedCacheRepository.UpdateBasketAsync(basket, correlationToken, _telemetryClient); } return(basket); }
/// <summary> /// Invokes check-out process /// </summary> /// <param name="checkout">User information to create new order</param> /// <param name="correlationToken">Tracks request - can be any value</param> /// <returns></returns> public async Task <CheckoutEntity> Checkout(CheckoutDto checkout, string correlationToken) { // The shopping basket service is responsible for managing the user's shopping experirence. // It does not create or manage with orders. // Construct and publish the checkout event so that other services can manage those tasks. var total = 0m; var basketId = checkout.BasketId; // TODO: Capture UserID from Security Prinicpal //var userName = ClaimsPrincipal.Current.Identity.Name ?? "Generic User"; //https://davidpine.net/blog/principal-architecture-changes/ // Get user's shopping basket from storage var basket = await GetBasketById(basketId, correlationToken); // Create the OrderInformationModel var orderInformationModel = new OrderInformationModel(); // Create buyer information object var buyer = new OrderInformationModel.BuyerInformation() { Username = checkout.Username, FirstName = checkout.FirstName, LastName = checkout.LastName, Address = checkout.Address, City = checkout.City, State = checkout.State, PostalCode = checkout.PostalCode, Email = checkout.Email, Phone = checkout.Phone, }; // Create payment information object var payment = new OrderInformationModel.PaymentInformation() { CreditCardNumber = checkout.CreditCardNumber, SecurityCode = checkout.SecurityCode, CardholderName = checkout.CardholderName, ExpirationDate = checkout.ExpirationDate }; // Create event class that will contain shopping basket, buyer, and payment information // to create a new order. orderInformationModel.BasketId = basketId; // Generate system checkoutId using snowflake orderInformationModel.CheckoutId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Checkout); orderInformationModel.Total = basket.Items.Sum(x => decimal.Parse(x.UnitPrice) * x.Quantity); orderInformationModel.Buyer = buyer; orderInformationModel.Payment = payment; foreach (var item in basket.Items) { orderInformationModel.LineItems.Add(new OrderInformationModel.LineItem() { ProductId = item.ProductId, Title = item.Title, Artist = item.Artist, Genre = item.Genre, UnitPrice = item.UnitPrice, Quantity = item.Quantity }); } var checkoutEvent = new CheckOutEvent { OrderInformationModel = orderInformationModel, CorrelationToken = correlationToken }; _logger.LogInformation($"Check-out operation invoked for shopping basket {basketId} for Request {correlationToken}"); //************** Publish Event ************************* // Publish customer checkout event // Ordering subscribes to event and creates order. // Once created, Ordering publishes event to have BasketEntity remove basket. await _eventBusPublisher.Publish <CheckOutEvent>(checkoutEvent); return(new CheckoutEntity { CheckoutSystemId = checkoutEvent.OrderInformationModel.CheckoutId, BuyerEmail = checkoutEvent.OrderInformationModel.Buyer.Email, CorrelationId = correlationToken }); }