Пример #1
0
        public void SendWelcomeEmail(Guid userId)
        {
            /*
             * Demo of forcing the creation of a new DbContextScope
             * to ensure that changes made to the model in this service
             * method are persisted even if that method happens to get
             * called within the scope of a wider business transaction
             * that eventually fails for any reason.
             *
             * This is an advanced feature that should be used as rarely
             * as possible (and ideally, never).
             */

            // We're going to send a welcome email to the provided user
            // (if one hasn't been sent already). Once sent, we'll update
            // that User entity in our DB to record that its Welcome email
            // has been sent.

            // Emails can't be rolled-back. Once they're sent, they're sent.
            // So once the email has been sent successfully, we absolutely
            // must persist this fact in our DB. Even if that method is called
            // by another busines logic service method as part of a wider
            // business transaction and even if that parent business transaction
            // ends up failing for any reason, we still must ensure that
            // we have recorded the fact that the Welcome email has been sent.
            // Otherwise, we would risk spamming our users with repeated Welcome
            // emails.

            // Force the creation of a new DbContextScope so that the changes we make here are
            // guaranteed to get persisted regardless of what happens after this method has completed.
            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create(DbContextScopeOption.ForceCreateNew))
            {
                UserManagementDbContext dbContext = dbContextScope.DbContexts.Get <UserManagementDbContext>();
#if EF6
                User user = dbContext.Users.Find(userId);
#elif EFCore
                var user = dbContext.Users.SingleOrDefault(x => x.Id == userId);
#endif

                if (user == null)
                {
                    throw new ArgumentException($"Invalid userId provided: {userId}. Couldn't find a User with this ID.");
                }

                if (!user.WelcomeEmailSent)
                {
                    SendEmail(user.Email);
                    user.WelcomeEmailSent = true;
                }

                dbContextScope.SaveChanges();

                // When you force the creation of a new DbContextScope, you must force the parent
                // scope (if any) to reload the entities you've modified here. Otherwise, the method calling
                // you might not be able to see the changes you made here.
                dbContextScope.RefreshEntitiesInParentScope(new List <User> {
                    user
                });
            }
        }
Пример #2
0
        public void UpdateCreditScoreForAllUsers()
        {
            /*
             * Demo of DbContextScope + parallel programming.
             */

            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
            {
                //-- Get all users
                UserManagementDbContext dbContext = dbContextScope.DbContexts.Get <UserManagementDbContext>();
                List <Guid>             userIds   = dbContext.Users.Select(u => u.Id).ToList();

                Console.WriteLine("Found {0} users in the database. Will calculate and store their credit scores in parallel.", userIds.Count);

                //-- Calculate and store the credit score of each user
                // We're going to imagine that calculating a credit score of a user takes some time.
                // So we'll do it in parallel.

                // You MUST call SuppressAmbientContext() when kicking off a parallel execution flow
                // within a DbContextScope. Otherwise, this DbContextScope will remain the ambient scope
                // in the parallel flows of execution, potentially leading to multiple threads
                // accessing the same DbContext instance.
                using (_dbContextScopeFactory.SuppressAmbientContext())
                {
                    Parallel.ForEach(userIds, UpdateCreditScore);
                }

                // Note: SaveChanges() isn't going to do anything in this instance since all the changes
                // were actually made and saved in separate DbContextScopes created in separate threads.
                dbContextScope.SaveChanges();
            }
        }
Пример #3
0
        /// <summary>
        /// Create a new game
        /// </summary>
        /// <param name="playerName"></param>
        /// <param name="numberOfPlayers"></param>
        /// <returns>Game info</returns>
        public Game Create(string playerName, int numberOfPlayers)
        {
            using (IDbContextScope contextScope = _dbContextFactory.Create())
            {
                //create player
                var player = new Player()
                {
                    Name = playerName
                };

                //create game
                var game = new Game()
                {
                    NumberOfPlayers = numberOfPlayers, Status = numberOfPlayers > 1 ? 0 : 1
                };

                //add player to game
                game.Players.Add(player);

                //add game and player to database
                _gameService.Add(game);
                contextScope.SaveChanges();

                game.PlayerId = player.Id;

                return(game);
            }
        }
Пример #4
0
        public void CreateUser(UserCreationSpec userToCreate)
        {
            if (userToCreate == null)
            {
                throw new ArgumentNullException(nameof(userToCreate));
            }

            userToCreate.Validate();

            /*
             * Typical usage of DbContextScope for a read-write business transaction.
             * It's as simple as it looks.
             */
            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
            {
                //-- Build domain model
                User user = new User()
                {
                    Id               = userToCreate.Id,
                    Name             = userToCreate.Name,
                    Email            = userToCreate.Email,
                    WelcomeEmailSent = false,
                    CreatedOn        = DateTime.UtcNow
                };

                //-- Persist
                _userRepository.Add(user);
                dbContextScope.SaveChanges();
            }
        }
Пример #5
0
        public void CreateListOfUsersWithIntentionalFailure(params UserCreationSpec[] usersToCreate)
        {
            /*
             * Here, we'll verify that inner DbContextScopes really join the parent scope and
             * don't persist their changes until the parent scope completes successfully.
             */

            bool firstUser = true;

            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
            {
                foreach (UserCreationSpec toCreate in usersToCreate)
                {
                    if (firstUser)
                    {
                        CreateUser(toCreate);
                        Console.WriteLine("Successfully created a new User named '{0}'.", toCreate.Name);
                        firstUser = false;
                    }
                    else
                    {
                        // OK. So we've successfully persisted one user.
                        // We're going to simulate a failure when attempting to
                        // persist the second user and see what ends up getting
                        // persisted in the DB.
                        throw new Exception($"Oh no! An error occurred when attempting to create user named '{toCreate.Name}' in our database.");
                    }
                }

                dbContextScope.SaveChanges();
            }
        }
Пример #6
0
 protected T RunInNewContextScope <T>(Func <T> function)
 {
     using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create(DbContextScopeOption.ForceCreateNew))
     {
         T result = function();
         dbContextScope.SaveChanges();
         return(result);
     }
 }
Пример #7
0
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                {
                    scope.DbContexts.Get <TDbContext>().ChangeTracker.DetectChanges();

                    scope.SaveChanges();
                    scope.Dispose();
                }
            }
Пример #8
0
 protected T RunInContextScope <T>(Func <T> function, bool isReadOnly = false)
 {
     if (isReadOnly)
     {
         using (IDbContextReadOnlyScope dbContextScope = _dbContextScopeFactory.CreateReadOnly())
         {
             return(function());
         }
     }
     else
     {
         using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
         {
             T result = function();
             dbContextScope.SaveChanges();
             return(result);
         }
     }
 }
Пример #9
0
        /// <summary>
        /// Join a new player to an existing game
        /// </summary>
        /// <param name="playerName"></param>
        /// <param name="gameId"></param>
        /// <returns>Game info</returns>
        public async Task <Game> Join(string playerName, Guid gameId)
        {
            using (IDbContextScope contextScope = _dbContextFactory.Create())
            {
                var game = await _gameService.GetAsync(gameId);

                //check if game exists
                if (game == null)
                {
                    throw new ApplicationException("Invalid game");
                }

                //check status and number of players allowed
                if (game.NumberOfPlayers == 1 || game.Status != 0)
                {
                    throw new ApplicationException("This game is not available for new players");
                }

                //add player to game
                var player = new Player()
                {
                    Name = playerName, GameId = gameId
                };
                game.Players.Add(player);

                //if game reach the number of player, change game status
                if (game.NumberOfPlayers == game.Players.Count)
                {
                    game.Status = 1;
                }

                //update database
                _gameService.Update(game);
                contextScope.SaveChanges();

                game.PlayerId = player.Id;

                return(game);
            }
        }
Пример #10
0
        public void CreateListOfUsers(params UserCreationSpec[] usersToCreate)
        {
            /*
             * Example of DbContextScope nesting in action.
             *
             * We already have a service method - CreateUser() - that knows how to create a new user
             * and implements all the business rules around the creation of a new user
             * (e.g. validation, initialization, sending notifications to other domain model objects...).
             *
             * So we'll just call it in a loop to create the list of new users we've
             * been asked to create.
             *
             * Of course, since this is a business logic service method, we are making
             * an implicit guarantee to whoever is calling us that the changes we make to
             * the system will be either committed or rolled-back in an atomic manner.
             * I.e. either all the users we've been asked to create will get persisted
             * or none of them will. It would be disastrous to have a partial failure here
             * and end up with some users but not all having been created.
             *
             * DbContextScope makes this trivial to implement.
             *
             * The inner DbContextScope instance that the CreateUser() method creates
             * will join our top-level scope. This ensures that the same DbContext instance is
             * going to be used throughout this business transaction.
             *
             */

            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
            {
                foreach (UserCreationSpec toCreate in usersToCreate)
                {
                    CreateUser(toCreate);
                }

                // All the changes will get persisted here
                dbContextScope.SaveChanges();
            }
        }
Пример #11
0
        public void UpdateCreditScore(Guid userId)
        {
            using (IDbContextScope dbContextScope = _dbContextScopeFactory.Create())
            {
                UserManagementDbContext dbContext = dbContextScope.DbContexts.Get <UserManagementDbContext>();
#if EF6
                User user = dbContext.Users.Find(userId);
#elif EFCore
                var user = dbContext.Users.SingleOrDefault(x => x.Id == userId);
#endif
                if (user == null)
                {
                    throw new ArgumentException($"Invalid userId provided: {userId}. Couldn't find a User with this ID.");
                }

                // Simulate the calculation of a credit score taking some time
                Random random = new Random(Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(random.Next(300, 1000));

                user.CreditScore = random.Next(1, 100);
                dbContextScope.SaveChanges();
            }
        }
Пример #12
0
        /// <summary>
        /// Verify the player's guess
        /// </summary>
        /// <param name="playerId"></param>
        /// <param name="gameId"></param>
        /// <param name="sequence">the player's guess</param>
        /// <returns>Game info</returns>
        public async Task <Game> Guess(Guid playerId, Guid gameId, string sequence)
        {
            using (IDbContextScope contextScope = _dbContextFactory.Create())
            {
                var game = await _gameService.GetAsync(gameId);

                //check if game exists
                if (game == null)
                {
                    throw new ApplicationException("Invalid game");
                }

                //check if player belongs to the game
                if (!game.Players.Any(p => p.Id == playerId))
                {
                    throw new ApplicationException("Player dont belong to this game");
                }

                var playerGuesses = game.Players.First(p => p.Id == playerId).Guesses;

                if (game.Guesses.Count() > 0)
                {
                    //check if there are players that didnt play
                    if (game.Players.Select(p => p.Guesses.Count).Min() < playerGuesses.Count())
                    {
                        throw new ApplicationException("Wait for other players guess");
                    }

                    //check if the game is finished
                    if (game.Players.Select(p => p.Guesses.Count).Min() == game.Players.Select(p => p.Guesses.Count).Max() && game.Status == 2)
                    {
                        throw new ApplicationException("Game is finished");
                    }
                }

                var guess = new Guess()
                {
                    GameId   = gameId,
                    PlayerId = playerId,
                    Sequence = sequence
                };

                //check the guess hits
                guess.CheckHits(game.Sequence);

                //if the player founds the sequence, change game status
                if (guess.ExactCount == game.SequenceLength)
                {
                    game.Status = 2;
                    game.Players.First(p => p.Id == playerId).Winner = true;
                }

                //add guess to game
                game.Guesses.Add(guess);

                game.PlayerId = playerId;

                _gameService.Update(game);
                contextScope.SaveChanges();

                return(game);
            }
        }
Пример #13
0
        public int SaveChanges()
        {
            var i = _dbContextScope.SaveChanges();

            return(i);
        }