Example #1
0
        public UpdateInfo(ChangeStreamDocument <T> changeStreamDocument)
        {
            switch (changeStreamDocument.OperationType)
            {
            case ChangeStreamOperationType.Insert:
                UpdateType = UpdateTypes.Insert;
                break;

            case ChangeStreamOperationType.Update:
                UpdateType = UpdateTypes.Update;
                break;

            case ChangeStreamOperationType.Replace:
                UpdateType = UpdateTypes.Replace;
                break;

            case ChangeStreamOperationType.Delete:
                UpdateType = UpdateTypes.Delete;
                break;

            default:
                UpdateType = UpdateTypes.Undefined;
                break;
            }

            Document = changeStreamDocument.FullDocument;
        }
Example #2
0
        static void Main(string[] args)
        {
            var noSql = new MFlixNoSqlDbContext(
                "mongodb+srv://######:########@freecluster-omk9a.mongodb.net/test?retryWrites=true&w=majority",
                "sample_mflix"
                );

            FilterDefinition <ChangeStreamDocument <Movie> > filterBuilder =
                Builders <ChangeStreamDocument <Movie> > .Filter
                .In(x => x.OperationType, new[] { ChangeStreamOperationType.Insert }.ToList());

            var options = new ChangeStreamOptions {
                FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
            };

            PipelineDefinition <ChangeStreamDocument <Movie>, ChangeStreamDocument <Movie> > pipeline =
                new EmptyPipelineDefinition <ChangeStreamDocument <Movie> >()
                .Match <ChangeStreamDocument <Movie>, ChangeStreamDocument <Movie> >(filterBuilder);

            IChangeStreamCursor <ChangeStreamDocument <Movie> > cursor = noSql.GetCollection <Movie>("movies")
                                                                         .Watch(pipeline, options);

            using (IEnumerator <ChangeStreamDocument <Movie> > enumerator = cursor.ToEnumerable().GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    ChangeStreamDocument <Movie> doc = enumerator.Current;
                    Console.WriteLine(doc?.DocumentKey);
                    Console.WriteLine(doc?.FullDocument.Title);
                }
            }

            Console.WriteLine("Done!");
        }
Example #3
0
 private void MessageEncountered(ChangeStreamDocument <CompanyDto> document)
 {
     OnEmitMessage(new CompanyMessageEventArgs
     {
         MessageInfo  = $"coming from OnEmitMessage: {document.FullDocument.Id} - {document.FullDocument.Name}",
         DocumentData = document.FullDocument
     });
 }
        public static BaseMongoDbRepository <T> GetSubscribingRepository()
        {
            if (CurrentSubscribingRepository == null)
            {
                lock (subscriberLockObject)
                {
                    var currentDocumentType = typeof(T);
                    var currentAssembly     = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic)
                                              .Single(query => query.FullName == currentDocumentType.Assembly.FullName);

                    foreach (Type exportedType in currentAssembly.GetExportedTypes().Where(query => query.BaseType != null && query.BaseType.UnderlyingSystemType != null && query.BaseType.UnderlyingSystemType.IsGenericType))
                    {
                        if (exportedType.BaseType.UnderlyingSystemType.GetGenericArguments().FirstOrDefault() == currentDocumentType)
                        {
                            CurrentSubscribingRepository = Activator.CreateInstance(exportedType) as BaseMongoDbRepository <T>;

                            var pipeline = new EmptyPipelineDefinition <ChangeStreamDocument <T> >().Match("{ operationType: /^[^d]/  }");
                            ChangeStreamOptions options = new ChangeStreamOptions()
                            {
                                FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
                            };
                            var changeStream = CurrentSubscribingRepository.CurrentCollection.Watch(pipeline, options).ToEnumerable().GetEnumerator();

                            var task = Task.Run(() =>
                            {
                                while (true)
                                {
                                    try
                                    {
                                        changeStream.MoveNext();
                                        ChangeStreamDocument <T> next = changeStream.Current;
                                        var currentData = next.FullDocument;

                                        if (CurrentSubscribingRepository.SubscriptionTriggered == null)
                                        {
                                            continue;
                                        }

                                        var receivers = CurrentSubscribingRepository.SubscriptionTriggered.GetInvocationList();
                                        foreach (SubscriptionTriggeredEventHandler receiver in receivers)
                                        {
                                            receiver.BeginInvoke(CurrentSubscribingRepository, currentData, null, null);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                    }
                                }
                            });

                            break;
                        }
                    }
                }
            }

            return(CurrentSubscribingRepository);
        }
Example #5
0
        private void AssertChangeStreamDocumentPropertyValuesAgainstBackingDocument(ChangeStreamDocument <BsonDocument> actualDocument)
        {
            var backingDocument = actualDocument.BackingDocument;

            backingDocument.Should().NotBeNull();

            var clusterTime = actualDocument.ClusterTime;

            if (backingDocument.Contains("clusterTime"))
            {
                clusterTime.Should().Be(backingDocument["clusterTime"].AsBsonTimestamp);
            }
            else
            {
                clusterTime.Should().BeNull();
            }

            var collectionNamespace = actualDocument.CollectionNamespace;

            collectionNamespace.DatabaseNamespace.DatabaseName.Should().Be(backingDocument["ns"]["db"].AsString);
            collectionNamespace.CollectionName.Should().Be(backingDocument["ns"]["coll"].AsString);

            var documentKey = actualDocument.DocumentKey;

            documentKey.Should().Be(backingDocument["documentKey"].AsBsonDocument);

            var fullDocument = actualDocument.FullDocument;

            if (backingDocument.Contains("fullDocument"))
            {
                fullDocument.Should().Be(backingDocument["fullDocument"].AsBsonDocument);
            }
            else
            {
                fullDocument.Should().BeNull();
            }

            var operationType = actualDocument.OperationType;

            operationType.ToString().ToLowerInvariant().Should().Be(backingDocument["operationType"].AsString);

            var resumeToken = actualDocument.ResumeToken;

            resumeToken.Should().Be(backingDocument["_id"].AsBsonDocument);

            var updateDescription = actualDocument.UpdateDescription;

            if (backingDocument.Contains("updateDescription"))
            {
                updateDescription.Should().Be(backingDocument["updateDescription"].AsBsonDocument);
            }
            else
            {
                updateDescription.Should().BeNull();
            }
        }
Example #6
0
        /// <summary>
        /// Generic method for revoking updates by _id
        /// </summary>
        /// <param name="deletedEntity"></param>
        /// <returns></returns>
        protected Task processNotificableEntityWasDeleted <EntityType>(ChangeStreamDocument <EntityType> deletedEntity)
        {
            var deletedEntityId = deletedEntity.DocumentKey["_id"].ToString();

            if (deletedEntityId == null)
            {
                logger.Fatal($"document without id was received", deletedEntity);
                return(Task.CompletedTask);
            }
            return(updateSenderProxy.revokeNotificationForObject(deletedEntityId));
        }
        public OperationResult Convert(ChangeStreamDocument <BsonDocument> result)
        {
            var document = new BsonDocument
            {
                { "operationType", result.OperationType.ToString().ToLowerInvariant() },
                { "ns", ConvertNamespace(result.CollectionNamespace) },
                { "fullDocument", result.FullDocument }
            };

            return(OperationResult.FromResult(document));
        }
Example #8
0
        private void ProcessEvent(ChangeStreamDocument <EventWrapper> change)
        {
            var @event = change.FullDocument;

            using (var factory = serviceScopeFactory.CreateScope())
            {
                Type handlerGenericType = typeof(IEventHandler <>).MakeGenericType(Type.GetType(@event.EventType));
                var  service            = factory.ServiceProvider.GetRequiredService(handlerGenericType);
                HandleEvent(service, @event);
            }
        }
Example #9
0
        public OperationResult Convert(ChangeStreamDocument <BsonDocument> result)
        {
            var document = new BsonDocument
            {
                { "operationType", result.OperationType.ToString().ToLowerInvariant() },
                { "ns", ConvertNamespace(result.CollectionNamespace) },
                { "fullDocument", () => result.FullDocument, result.FullDocument != null },
                { "updateDescription", () => ConvertUpdateDescription(result.UpdateDescription), result.UpdateDescription != null }
            };

            return(OperationResult.FromResult(document));
        }
Example #10
0
        /// <summary>
        /// Stage A.1: Process entity one
        /// </summary>
        /// <param name="newentity"></param>
        /// <returns></returns>
        private Task ProcessentityInsert(ChangeStreamDocument <SomeModelOne> newentity)
        {
            bool isAdminCompetency = (newentity.FullDocument.positionId == null);

            if (isAdminCompetency)
            {
                return(sendNotificationsToAdmins(newentity.FullDocument));
            }
            else
            {
                return(sendNotificationsToPositionsOwners(newentity.FullDocument));
            }
        }
Example #11
0
        private static string ConvertChangeStreamBsonDocumentToJson(ChangeStreamDocument <BsonDocument> changeStreamDocument)
        {
            string json;
            var    subject = new ChangeStreamDocumentSerializer <BsonDocument>(BsonDocumentSerializer.Instance);

            using (var textWriter = new StringWriter())
                using (var writer = new MongoDB.Bson.IO.JsonWriter(textWriter))
                {
                    {
                        var context = BsonSerializationContext.CreateRoot(writer);
                        subject.Serialize(context, changeStreamDocument);
                        json = textWriter.ToString();
                    }
                }
            return(json);
        }
        private async Task WatchChange <T>(ChangeStreamDocument <T> arg, CancellationToken cancellationToken)
        {
            var input = new TriggeredFunctionData
            {
                TriggerValue = arg,
            };

            try
            {
                await _contextExecutor.TryExecuteAsync(input, cancellationToken);
            }
            catch
            {
                // We don't want any function errors to stop the execution
                // schedule. Errors will be logged to Dashboard already.
            }
        }
Example #13
0
        /// <summary>
        /// Launch required action depending on performed action (delete/insert/update)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private Task Brancher(ChangeStreamDocument <SomeModelOne> entity)
        {
            switch (entity.OperationType)
            {
            case ChangeStreamOperationType.Delete:
                return(processNotificableEntityWasDeleted(entity));

            case ChangeStreamOperationType.Insert:
                return(ProcessentityInsert(entity));

            case ChangeStreamOperationType.Update:
            case ChangeStreamOperationType.Replace:
                return(ProcessentityUpdated(entity));

            default:
                logger.Fatal($"{nameof(entity.OperationType)} is not implemented");
                return(Task.CompletedTask);
            }
        }
Example #14
0
        private void AssertChangeStreamDocument(ChangeStreamDocument <BsonDocument> actualDocument, BsonDocument expectedDocument)
        {
            JsonDrivenHelper.EnsureAllFieldsAreValid(expectedDocument, "_id", "documentKey", "operationType", "ns", "fullDocument");

            AssertChangeStreamDocumentPropertyValuesAgainstBackingDocument(actualDocument);

            if (expectedDocument.Contains("_id"))
            {
                actualDocument.ResumeToken.Should().NotBeNull();
            }

            if (expectedDocument.Contains("documentKey"))
            {
                actualDocument.DocumentKey.Should().NotBeNull();
            }

            if (expectedDocument.Contains("operationType"))
            {
                var expectedOperationType = (ChangeStreamOperationType)Enum.Parse(typeof(ChangeStreamOperationType), expectedDocument["operationType"].AsString, ignoreCase: true);
                actualDocument.OperationType.Should().Be(expectedOperationType);
            }

            if (expectedDocument.Contains("ns"))
            {
                var ns = expectedDocument["ns"].AsBsonDocument;
                JsonDrivenHelper.EnsureAllFieldsAreValid(ns, "db", "coll");
                var expectedDatabaseName        = ns["db"].AsString;
                var expectedCollectionName      = ns["coll"].AsString;
                var expectedCollectionNamespace = new CollectionNamespace(new DatabaseNamespace(expectedDatabaseName), expectedCollectionName);
                actualDocument.CollectionNamespace.Should().Be(expectedCollectionNamespace);
            }

            if (expectedDocument.Contains("fullDocument"))
            {
                var actualFullDocument = actualDocument.FullDocument;
                actualFullDocument.Remove("_id");
                var expectedFullDocument = expectedDocument["fullDocument"].AsBsonDocument;
                actualFullDocument.Should().Be(expectedFullDocument);
            }
        }
        public static DocumentChange <T> ToDocumentChange <T>(this ChangeStreamDocument <T> change)
            where T : IMongoDbDocument, new()
        {
            if (change.OperationType == ChangeStreamOperationType.Delete)
            {
                var oldDevice = new T()
                {
                    _id = change.DocumentKey["_id"].AsString
                };
                return(new DocumentChange <T>(oldDevice, DocumentChangeKind.Delete));
            }

            var device     = change.FullDocument;
            var changeKind = change.OperationType switch
            {
                ChangeStreamOperationType.Insert => DocumentChangeKind.Insert,
                ChangeStreamOperationType.Update => DocumentChangeKind.Update,
                ChangeStreamOperationType.Replace => DocumentChangeKind.Replace,
                _ => throw new InvalidEnumArgumentException($"[BUGCHECK] Unexpected ChangeStreamOperationType ({change.OperationType})."),
            };

            return(new DocumentChange <T>(device, changeKind));
        }
Example #16
0
        public void StartCollectionWatch(MongoClient mongoClient)
        {
            var cargoCollection = mongoClient.GetDatabase(APIConstant.LogisticsDatabase)
                                  .GetCollection <Models.Cargo>(APIConstant.CargoCollection);

            var options = new ChangeStreamOptions {
                FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
            };
            var pipeline = new EmptyPipelineDefinition <ChangeStreamDocument <Cargo> >().Match("{ operationType: { $in: [ 'insert'] } }");

            var cursor = cargoCollection.Watch <ChangeStreamDocument <Cargo> >(pipeline, options);

            var enumerator = cursor.ToEnumerable().GetEnumerator();

            while (true)
            {
                enumerator.MoveNext();
                //var ct = cursor.GetResumeToken();
                ChangeStreamDocument <Cargo> doc = enumerator.Current;
                // Do something here with your document
                Console.WriteLine(doc.DocumentKey);
            }
        }
Example #17
0
        /// <summary>
        /// Stage B.1: Branch algo for choosing required notification type
        /// </summary>
        /// <param name="updatedentity"></param>
        /// <returns></returns>
        private async Task ProcessentityUpdated(ChangeStreamDocument <SomeModelOne> updatedentity)
        {
            if (updatedentity.OperationType == ChangeStreamOperationType.Update ||
                updatedentity.OperationType == ChangeStreamOperationType.Replace)
            {
                var buildingId = (await somewhatRepositoryOne.getBuildingIdByApartId(updatedentity.FullDocument.apartId)).buildingId;
                switch (updatedentity.FullDocument.status)
                {
                case SomeModelOne.entitiestatus.Rejected:
                    await sendentityRejectedStatus(updatedentity.FullDocument, buildingId);

                    return;

                case SomeModelOne.entitiestatus.Finished:
                    await sendentityFinishedStatus(updatedentity.FullDocument, buildingId);

                    return;

                case SomeModelOne.entitiestatus.Assigned:
                    await sendentityInProgress(updatedentity.FullDocument, buildingId, true);
                    await sendentityInProgress(updatedentity.FullDocument, buildingId);

                    return;

                case SomeModelOne.entitiestatus.Reviewed:
                case SomeModelOne.entitiestatus.Closed:
                    await sendentityInProgress(updatedentity.FullDocument, buildingId);

                    return;

                default:
                    logger.Warn($"entity status {nameof(updatedentity.FullDocument.status)} is not supported in `processentityUpdated`");
                    return;
                }
            }
        }
Example #18
0
 private void NotifyEntityChangeWatchers(ChangeStreamDocument <BsonDocument> changeStreamDocument)
 {
     DocumentChangeObserver.Instance.OnChanged(new DocumentChangeEventArgs(changeStreamDocument));
 }
 /// <summary>
 /// This API supports the MongoDb infrastructure and is not intended
 /// to be used directly from your code. This API may change or be removed in future releases.
 /// </summary>
 public DocumentChangeEventArgs(ChangeStreamDocument <BsonDocument> document)
 {
     Document = document;
 }