/// <summary>
        /// This will soft delete the single entity. This may delete other dependent
        /// </summary>
        /// <param name="softDeleteThisEntity">Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns status. If not errors then Result return 1 to say it worked. Zero if error</returns>
        public async Task <IStatusGeneric <int> > SetSoftDeleteAsync(TInterface softDeleteThisEntity, bool callSaveChanges = true)
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }
            _context.ThrowExceptionIfPrincipalOneToOne(softDeleteThisEntity);

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity))
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            _config.SetSoftDeleteValue(softDeleteThisEntity, true);
            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextSoftDeletedPastTense} this entry";
            status.SetResult(1);        //one changed
            return(status);
        }
        /*******************************************************************
         #A This method returns a status with the created Order, which is null if there are no errors
         #B The PlaceOrderInDto contains a TandC bool and a collection of BookIds and number of books
         #C This status is used to gather and errors and, if no errors, return an Order
         #D These validate the user's input
         #E The _dbAccess contains the code to find each book - see listing 4.3
         #F This method creates list of bookId and number of books - see end of listing 4.2
         #G If any errors were found while checking each order line, then it returns the error status
         #H This calls the Order static factory. It is the Order's job to form the Order with LineItems
         #I Again, any errors will abort the Order and the errors returned
         #J The _dbAccess contains the code add the Order and call SaveChangesAsync
         #K Finally it returns a successful status with the created Order entity
         ****************************************************************/

        private IStatusGeneric <List <OrderBookDto> > FormLineItemsWithErrorChecking
            (IEnumerable <OrderLineItem> lineItems,
            IDictionary <int, BookView> booksDict)
        {
            var status = new StatusGenericHandler <List <OrderBookDto> >();
            var result = new List <OrderBookDto>();

            foreach (var lineItem in lineItems)
            {
                if (!booksDict.ContainsKey(lineItem.BookId))
                {
                    throw new InvalidOperationException(
                              $"An order failed because book, id = {lineItem.BookId} was missing.");
                }

                var bookView = booksDict[lineItem.BookId];
                if (bookView.ActualPrice <= 0)
                {
                    status.AddError($"Sorry, the book '{bookView.Title}' is not for sale.");
                }
                else
                {
                    //Valid, so add to the order
                    result.Add(new OrderBookDto(bookView, lineItem.NumBooks));
                }
            }
            return(status.SetResult(result));
        }
예제 #3
0
        public static async Task <IStatusGeneric <RoleToPermissions> > CreateRoleWithPermissionsAsync(
            string roleName,
            string description,
            IEnumerable <Permission> permissionInRole,
            IAuthorizationRepository repository)
        {
            if (roleName == null)
            {
                throw new ArgumentNullException(nameof(roleName));
            }
            if (repository == null)
            {
                throw new ArgumentNullException(nameof(repository));
            }

            var status = new StatusGenericHandler <RoleToPermissions>();
            RoleToPermissions roleToPermissions = await repository.GetRoleToPermissionAsync(roleName);

            if (roleToPermissions != null)
            {
                status.AddError("That role already exists");
                return(status);
            }

            return(status.SetResult(new RoleToPermissions(roleName, description, permissionInRole)));
        }
        private IStatusGeneric <int> ReturnSuccessFullResult(CascadeSoftDelWhatDoing whatDoing, int numFound)
        {
            var status = new StatusGenericHandler <int>();

            status.SetResult(numFound);
            switch (whatDoing)
            {
            case CascadeSoftDelWhatDoing.SoftDelete:
                status.Message = FormMessage("soft deleted", numFound);
                break;

            case CascadeSoftDelWhatDoing.ResetSoftDelete:
                status.Message = FormMessage("recovered", numFound);
                break;

            case CascadeSoftDelWhatDoing.CheckWhatWillDelete:
                status.Message = numFound == 0
                        ? "No entries will be hard deleted"
                        : $"Are you sure you want to hard delete this entity{DependentsSuffix(numFound)}";
                break;

            case CascadeSoftDelWhatDoing.HardDeleteSoftDeleted:
                status.Message = FormMessage("hard deleted", numFound);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(status);
        }
        /// <summary>
        /// This converts the <see cref="ActionResult{WebApiMessageAndResult{T}}"/> created by <see cref="CreateResponse"/> into a GenericServices.IStatusGeneric
        /// </summary>
        /// <param name="actionResult"></param>
        /// <returns>a status which is similar to the original status (errors might not be in the exact same form)</returns>
        public static IStatusGeneric <T> CopyToStatus <T>(this ActionResult <WebApiMessageAndResult <T> > actionResult)
        {
            var testStatus = new StatusGenericHandler <T>();
            var objResult  = (actionResult.Result as ObjectResult);

            if (objResult == null)
            {
                throw new NullReferenceException("Could not cast the response to ObjectResult");
            }
            var errorPart = objResult as BadRequestObjectResult;

            if (errorPart != null)
            {
                //It has errors, so copy errors to status
                testStatus.AddValidationResults(ExtractErrors(errorPart));
                return(testStatus);
            }

            var decodedValue = objResult.Value as WebApiMessageAndResult <T>;

            if (decodedValue == null)
            {
                throw new NullReferenceException($"Could not cast the response value to WebApiMessageAndResult<{typeof(T).Name}>");
            }
            testStatus.Message = decodedValue.Message;
            testStatus.SetResult(decodedValue.Results);

            return(testStatus);
        }
예제 #6
0
        private IStatusGeneric <int> //#A
        CallSaveChangesWithExceptionHandler
            (DbContext context,
            Func <int> callBaseSaveChanges)                //#B
        {
            var status = new StatusGenericHandler <int>(); //#C

            do                                             //#D
            {
                try
                {
                    int numUpdated = callBaseSaveChanges(); //#E
                    status.SetResult(numUpdated);           //#F
                    break;                                  //#F
                }
                catch (Exception e)                         //#G
                {
                    IStatusGeneric handlerStatus = null;    //#H
                    if (handlerStatus == null)              //#I
                    {
                        throw;                              //#I
                    }
                    status.CombineStatuses(handlerStatus);  //#J
                }
            } while (status.IsValid);                       //#K

            return(status);                                 //#L
        }
        public static IStatusGeneric <UserToRole> AddRoleToUser(string userId, string roleName, ExtraAuthorizeDbContext context)
        {
            if (userId == null)
            {
                throw new ArgumentNullException(nameof(userId));
            }
            if (roleName == null)
            {
                throw new ArgumentNullException(nameof(roleName));
            }

            var status = new StatusGenericHandler <UserToRole>();

            if (context.Find <UserToRole>(userId, roleName) != null)
            {
                status.AddError($"The user already has the Role '{roleName}'.");
                return(status);
            }
            var roleToAdd = context.Find <RoleToPermissions>(roleName);

            if (roleToAdd == null)
            {
                status.AddError($"I could not find the Role '{roleName}'.");
                return(status);
            }

            return(status.SetResult(new UserToRole(userId, roleToAdd)));
        }
예제 #8
0
        /// <summary>
        /// This runs the events before and after the base SaveChangesAsync method is run
        /// </summary>
        /// <param name="context">The current DbContext</param>
        /// <param name="getTrackedEntities">A function to get the tracked entities</param>
        /// <param name="callBaseSaveChangesAsync">A function that is linked to the base SaveChangesAsync in your DbContext</param>
        /// <returns>Returns the status with the numUpdated number from SaveChanges</returns>
        public async Task <IStatusGeneric <int> > RunEventsBeforeAfterSaveChangesAsync(DbContext context, Func <IEnumerable <EntityEntry <EntityEvents> > > getTrackedEntities,
                                                                                       Func <Task <int> > callBaseSaveChangesAsync)
        {
            var status = new StatusGenericHandler <int>();

            status.CombineStatuses(RunBeforeSaveChangesEvents(getTrackedEntities));
            if (!status.IsValid)
            {
                return(status);
            }

            //Call SaveChangesAsync with catch for exception handler
            do
            {
                try
                {
                    status.SetResult(await callBaseSaveChangesAsync.Invoke().ConfigureAwait(false));
                    break; //This breaks out of the do/while
                }
                catch (Exception e)
                {
                    var exceptionStatus = _config.SaveChangesExceptionHandler?.Invoke(e, context);
                    if (exceptionStatus == null)
                    {
                        //This means the SaveChangesExceptionHandler doesn't cover this type of Concurrency Exception
                        throw;
                    }
                    //SaveChangesExceptionHandler ran, so combine its error into the outer status
                    status.CombineStatuses(exceptionStatus);
                }
                //If the SaveChangesExceptionHandler fixed the problem then we call SaveChanges again, but with the same exception catching.
            } while (status.IsValid);
            RunAfterSaveChangesEvents(getTrackedEntities);
            return(status);
        }
예제 #9
0
        //----------------------------------------------
        //create methods

        /// <summary>
        /// This creates a Sale entry, and also update the ShopStock number in stock
        /// </summary>
        /// <param name="numBought"></param>
        /// <param name="shopStockId"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static IStatusGeneric <ShopSale> CreateSellAndUpdateStock(int numBought, int shopStockId,
                                                                         DbContext context)
        {
            if (numBought < 0)
            {
                throw new ArgumentException("must be positive", nameof(numBought));
            }
            var status = new StatusGenericHandler <ShopSale>();

            var stock = context.Find <ShopStock>(shopStockId);

            if (stock == null)
            {
                status.AddError("Could not find the stock item you requested.");
                return(status);
            }
            stock.NumInStock = stock.NumInStock - numBought;
            if (stock.NumInStock < 0)
            {
                status.AddError("There are not enough items of that product to sell.");
                return(status);
            }
            var sale = new ShopSale(numBought, null, shopStockId);

            return(status.SetResult(sale));
        }
        public async Task <IStatusGeneric <Order> >          //#A
        CreateOrderAndSaveAsync(PlaceOrderInDto dto)         //#B
        {
            var status = new StatusGenericHandler <Order>(); //#C

            if (!dto.AcceptTAndCs)                           //#D
            {
                return(status.AddError("You must accept the T&Cs to place an order."));
            }
            if (!dto.LineItems.Any())                 //#D
            {
                return(status.AddError("No items in your basket."));
            }

            var booksDict = await _dbAccess                            //#E
                            .FindBooksByIdsAsync                       //#E
                                (dto.LineItems.Select(x => x.BookId)); //#E

            var linesStatus = FormLineItemsWithErrorChecking           //#F
                                  (dto.LineItems, booksDict);          //#F

            if (status.CombineStatuses(linesStatus).HasErrors)         //#G
            {
                return(status);                                        //#G
            }
            var orderStatus = Order.CreateOrder(                       //#H
                dto.UserId, linesStatus.Result);                       //#H

            if (status.CombineStatuses(orderStatus).HasErrors)         //#I
            {
                return(status);                                        //#I
            }
            await _dbAccess.AddAndSave(orderStatus.Result);            //#J

            return(status.SetResult(orderStatus.Result));              //#K
        }
예제 #11
0
        /// <summary>
        /// This will soft delete the single entity. This may delete other dependent
        /// </summary>
        /// <param name="softDeleteThisEntity">Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns status. If not errors then Result return 1 to say it worked. Zero if error</returns>
        public async Task <IStatusGeneric <int> > SetSoftDeleteAsync(TInterface softDeleteThisEntity, bool callSaveChanges = true)
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }

            var keys = _context.Entry(softDeleteThisEntity).Metadata.GetForeignKeys();

            if (!keys.All(x => x.DependentToPrincipal?.IsCollection == true || x.PrincipalToDependent?.IsCollection == true))
            {
                //This it is a one-to-one entity - setting a one-to-one as soft deleted causes problems when you try to create a replacement
                throw new InvalidOperationException("You cannot soft delete a one-to-one relationship. " +
                                                    "It causes problems if you try to create a new version.");
            }

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity))
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            _config.SetSoftDeleteValue(softDeleteThisEntity, true);
            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextSoftDeletedPastTense} this entry";
            status.SetResult(1);        //one changed
            return(status);
        }
예제 #12
0
        /// <summary>
        /// This hard deletes (i.e. calls EF Core's Remove method) for this entity ONLY if it first been soft deleted.
        /// This will delete the entity and possibly delete other dependent entities.
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="hardDeleteThisEntity">The entity to delete</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges yourself</param>
        /// <returns>The number of entities that were deleted. This will include any dependent entities that that had a cascade delete behaviour</returns>
        public async Task <IStatusGeneric <int> > HardDeleteSoftDeletedEntryAsync <TEntity>(TEntity hardDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (hardDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(hardDeleteThisEntity));
            }
            var status = new StatusGenericHandler <int>();

            if (!_config.GetSoftDeleteValue.Compile().Invoke(hardDeleteThisEntity))
            {
                return(status.AddError($"This entry isn't {_config.TextSoftDeletedPastTense}."));
            }

            _context.Remove(hardDeleteThisEntity);
            var numDeleted = 1;

            if (callSaveChanges)
            {
                numDeleted = await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextHardDeletedPastTense} this entry";
            status.SetResult(numDeleted);
            return(status);
        }
예제 #13
0
 public static IStatusGeneric<Target1> Create(int myInt, string myString)
 {
     var status =
         new StatusGenericHandler<Target1>
         {
             Message = "Static"
         };
     return status.SetResult(new Target1(myInt, myString));
 }
예제 #14
0
        }                    //Needed by EF Core

        public static IStatusGeneric <Book> CreateBook(
            string title, DateTime publishedOn,
            bool estimatedDate,
            string publisher, decimal price, string imageUrl,
            ICollection <Author> authors,
            ICollection <Tag> tags = null)
        {
            var status = new StatusGenericHandler <Book>();

            if (string.IsNullOrWhiteSpace(title))
            {
                status.AddError(
                    "The book title cannot be empty.");
            }

            var book = new Book
            {
                Title         = title,
                PublishedOn   = publishedOn,
                EstimatedDate = estimatedDate,
                Publisher     = publisher,
                OrgPrice      = price,
                ActualPrice   = price,
                ImageUrl      = imageUrl,
                //We need to initialise the AuthorsOrdered string when the entry is created
                //NOTE: We must NOT initialise the ReviewsCount and the ReviewsAverageVotes as they default to zero
                AuthorsOrdered = string.Join(", ", authors.Select(x => x.Name)),

                _tags = tags != null
                    ? new HashSet <Tag>(tags)
                    : new HashSet <Tag>(),
                _reviews = new HashSet <Review>()       //We add an empty list on create. I allows reviews to be added when building test data
            };

            if (authors == null)
            {
                throw new ArgumentNullException(nameof(authors));
            }

            byte order = 0;

            book._authorsLink = new HashSet <BookAuthor>(
                authors.Select(a =>
                               new BookAuthor(book, a, order++)));
            if (!book._authorsLink.Any())
            {
                status.AddError(
                    "You must have at least one Author for a book.");
            }

            if (status.IsValid)
            {
                book.AddEvent(new BookChangedEvent(BookChangeTypes.Added), EventToSend.DuringSave);
            }

            return(status.SetResult(book));
        }
예제 #15
0
        public static IStatusGeneric <object> RunMethodOrCtorViaLinq(MethodCtorMatch ctorOrMethod, dynamic dto,
                                                                     List <PropertyMatch> propertyMatches, DbContext context)
        {
            var result = new StatusGenericHandler <object>();

            if (ctorOrMethod.Constructor != null)
            {
                var ctor = CallConstructor(ctorOrMethod.Constructor, dto.GetType(), propertyMatches);
                return(propertyMatches.Any(x => x.MatchSource == MatchSources.DbContext)
                    ? result.SetResult(ctor(dto, context))
                    : result.SetResult(ctor(dto)));
            }

            //Otherwise its static method
            var staticFunc = CallStaticCreator(ctorOrMethod.Method, dto.GetType(), propertyMatches);

            return(propertyMatches.Any(x => x.MatchSource == MatchSources.DbContext)
                ? staticFunc(dto, context)
                : staticFunc(dto));
        }
        public void TestGenericStatusGeneicSetResultOk()
        {
            //SETUP

            //ATTEMPT
            var status = new StatusGenericHandler <string>();

            status.SetResult("Hello world");

            //VERIFY
            status.IsValid.ShouldBeTrue();
            status.Result.ShouldEqual("Hello world");
        }
        public static IStatusGeneric <DecodedDto> GetOrCreateDtoInfo(this Type classType, DecodedEntityClass entityInfo,
                                                                     IGenericServicesConfig publicConfig, PerDtoConfig perDtoConfig)
        {
            var status = new StatusGenericHandler <DecodedDto>();

            if (classType.IsPublic || classType.IsNestedPublic)
            {
                return(status.SetResult(DecodedDtoCache.GetOrAdd(classType, type => new DecodedDto(classType, entityInfo, publicConfig, perDtoConfig))));
            }

            status.AddError($"Sorry, but the DTO/ViewModel class '{classType.Name}' must be public for GenericServices to work.");
            return(status);
        }
예제 #18
0
        public static IStatusGeneric <RoleToPermissions> CreateRoleWithPermissions(string roleName, string description, ICollection <Permissions> permissionInRole,
                                                                                   ExtraAuthorizeDbContext context)
        {
            var status = new StatusGenericHandler <RoleToPermissions>();

            if (context.Find <RoleToPermissions>(roleName) != null)
            {
                status.AddError("That role already exists");
                return(status);
            }

            return(status.SetResult(new RoleToPermissions(roleName, description, permissionInRole)));
        }
        public void TestGenericStatusGeneicSetResultThenErrorOk()
        {
            //SETUP

            //ATTEMPT
            var status = new StatusGenericHandler <string>();

            status.SetResult("Hello world");
            status.AddError("This is an error.");

            //VERIFY
            status.IsValid.ShouldBeFalse();
            status.Result.ShouldEqual(null);
        }
예제 #20
0
        public IStatusGeneric <string> CheckUpdateBookCacheProperties()
        {
            var status          = new StatusGenericHandler <string>();
            var errorStrings    = new StringBuilder();
            var numBooksChecked = 0;
            var numErrors       = 0;

            foreach (var book in _context.Books
                     .Include(x => x.Reviews)
                     .Include(x => x.AuthorsLink).ThenInclude(x => x.Author))
            {
                var error = Errors.None;
                numBooksChecked++;

                var authorsOrdered      = book.FormAuthorOrderedString();
                var reviewsCount        = book.Reviews.Count();
                var reviewsAverageVotes = reviewsCount == 0 ? 0 : book.Reviews.Sum(x => x.NumStars) / (double)book.ReviewsCount;

                if (authorsOrdered != book.AuthorsOrdered)
                {
                    book.AuthorsOrdered = authorsOrdered;
                    error = Errors.AuthorsWrong;
                }
                if (reviewsCount != book.ReviewsCount || reviewsAverageVotes != book.ReviewsAverageVotes)
                {
                    book.ReviewsCount        = reviewsCount;
                    book.ReviewsAverageVotes = reviewsAverageVotes;
                    error |= Errors.ReviewWrong;
                }

                if (error != Errors.None)
                {
                    errorStrings.AppendLine($"Book: {book.Title} had the following errors: {error.ToString()}");
                    numErrors++;
                }
            }

            if (numErrors > 0)
            {
                _context.SaveChanges();
            }

            status.SetResult(errorStrings.ToString());
            status.Message = numErrors == 0
                ? $"Processed {numBooksChecked} and no cache errors found"
                : $"Processed {numBooksChecked} books and {numErrors} errors found. See returned string for details";

            return(status);
        }
예제 #21
0
        public static IStatusGeneric <DddStaticCreateEntity> Create(int myInt, string myString)
        {
            var status = new StatusGenericHandler <DddStaticCreateEntity>();
            var result = new DddStaticCreateEntity
            {
                MyInt    = myInt,
                MyString = myString,
            };

            if (myString == null)
            {
                status.AddError("The string should not be null.");
            }

            return(status.SetResult(result)); //This will return null if there are errors
        }
예제 #22
0
        public IStatusGeneric <string> StatusGenericNumReturnString(int i)
        {
            var status = new StatusGenericHandler <string>();

            //add error and return immediately
            if (i <= 0)
            {
                return(status.AddError("input must be positive", nameof(i)));
            }

            //This sets the Result property in the generic status
            status.SetResult(i.ToString());

            //If there are errors then the Result is set to the default value for generic type
            return(status);
        }
예제 #23
0
        public static IStatusGeneric <Book> CreateBook(string title, string description, DateTime publishedOn,
                                                       string publisher, decimal price, string imageUrl, ICollection <Author> authors,
                                                       ICollection <Tag> tags = null)
        {
            var status = new StatusGenericHandler <Book>();

            if (string.IsNullOrWhiteSpace(title))
            {
                status.AddError("The book title cannot be empty.");
            }

            var book = new Book
            {
                Title       = title,
                Description = description,
                PublishedOn = publishedOn,
                Publisher   = publisher,
                ActualPrice = price,
                OrgPrice    = price,
                ImageUrl    = imageUrl,
                _tags       = tags != null
                    ? new HashSet <Tag>(tags)
                    : new HashSet <Tag>(),

                _reviews = new HashSet <Review>()       //We add an empty list on create. I allows reviews to be added when building test data
            };

            if (authors == null)
            {
                throw new ArgumentNullException(nameof(authors));
            }

            byte order = 0;

            book._authorsLink = new HashSet <BookAuthor>(authors.Select(a => new BookAuthor(book, a, order++)));
            if (!book._authorsLink.Any())
            {
                status.AddError("You must have at least one Author for a book.");
            }

            return(status.SetResult(book));
        }
예제 #24
0
        //----------------------------------------------

        public static IStatusGeneric <BookWithEvents> CreateBook(string title, string description, DateTime publishedOn,
                                                                 string publisher, decimal price, string imageUrl, ICollection <AuthorWithEvents> authors)
        {
            var status = new StatusGenericHandler <BookWithEvents>();

            if (string.IsNullOrWhiteSpace(title))
            {
                status.AddError("The bookWithEvents title cannot be empty.");
            }

            var book = new BookWithEvents
            {
                BookId      = Guid.NewGuid(),
                Title       = title,
                Description = description,
                PublishedOn = publishedOn,
                Publisher   = publisher,
                ActualPrice = price,
                OrgPrice    = price,
                ImageUrl    = imageUrl,
                //We need to initialise the AuthorsOrdered string when the entry is created
                AuthorsOrdered = string.Join(", ", authors.Select(x => x.Name)),
                //We don't need to initialise the ReviewsCount and the ReviewsAverageVotes  as they default to zero
                _reviews = new HashSet <ReviewWithEvents>()       //We add an empty list on create. I allows reviews to be added when building test data
            };

            if (authors == null)
            {
                throw new ArgumentNullException(nameof(authors));
            }

            byte order = 0;

            book._authorsLink = new HashSet <BookAuthorWithEvents>(authors.Select(a => new BookAuthorWithEvents(book, a, order++)));
            if (!book._authorsLink.Any())
            {
                status.AddError("You must have at least one Author for a bookWithEvents.");
            }

            return(status.SetResult(book));
        }
예제 #25
0
        }                   //Needed by EF Core

        public static IStatusGeneric <Order> CreateOrder(string customerName,
                                                         IEnumerable <OrderBooksDto> bookOrders)
        {
            var status = new StatusGenericHandler <Order>();
            var order  = new Order
            {
                CustomerName = customerName,
                Status       = OrderStatuses.Created,
                OrderedUtc   = DateTime.UtcNow
            };

            byte lineNum = 1;

            order._lineItems = new HashSet <LineItem>(bookOrders
                                                      .Select(x => new LineItem(x.numBooks, x.ChosenBook, lineNum++)));
            if (!order._lineItems.Any())
            {
                status.AddError("No items in your basket.");
            }

            return(status.SetResult(order)); //don't worry, the Result will return default(T) if there are errors
        }
예제 #26
0
        private async Task <IStatusGeneric <int> > CallSaveChangesWithExceptionHandlerAsync(DbContext context, Func <Task <int> > callBaseSaveChangesAsync)
        {
            var status = new StatusGenericHandler <int>();

            do
            {
                try
                {
                    context.ChangeTracker.AutoDetectChangesEnabled = false;

                    status.SetResult(await callBaseSaveChangesAsync().ConfigureAwait(false));
                    break; //This breaks out of the do/while
                }
                catch (Exception e)
                {
                    IStatusGeneric exceptionStatus = null;
                    if (_config.ExceptionHandlerDictionary.TryGetValue(context.GetType(), out var exceptionHandler))
                    {
                        exceptionStatus = exceptionHandler(e, context);
                    }
                    if (exceptionStatus == null)
                    {
                        //This means the SaveChangesExceptionHandler doesn't cover this type of Concurrency Exception
                        throw;
                    }
                    //SaveChangesExceptionHandler ran, so combine its error into the outer status
                    status.CombineStatuses(exceptionStatus);
                }
                finally
                {
                    context.ChangeTracker.AutoDetectChangesEnabled = true;
                }

                //If the SaveChangesExceptionHandler fixed the problem then we call SaveChanges again, but with the same exception catching.
            } while (status.IsValid);

            return(status);
        }
예제 #27
0
        public static IStatusGeneric <Order> CreateOrder     //#A
            (Guid userId,                                    //#B
            IEnumerable <OrderBookDto> bookOrders)           //#C
        {
            var status = new StatusGenericHandler <Order>(); //#D
            var order  = new Order                           //#E
            {                                                //#E
                UserId         = userId,                     //#E
                DateOrderedUtc = DateTime.UtcNow             //#E
            };                                               //#E

            byte lineNum = 1;

            order._lineItems = new HashSet <LineItem>(       //#F
                bookOrders                                   //#F
                .Select(x => new LineItem(x, lineNum++)));   //#F

            if (!order._lineItems.Any())                     //#G
            {
                status.AddError("No items in your basket."); //#G
            }
            return(status.SetResult(order));                 //#H
        }
예제 #28
0
        /// <summary>
        /// This creates the order and, if successful clears the cookie
        /// </summary>
        /// <returns>Returns the OrderId, or zero if errors</returns>
        public async Task <IStatusGeneric <int> > PlaceOrderAndClearBasketAsync(bool acceptTAndCs)
        {
            var status = new StatusGenericHandler <int>();

            var checkoutService = new CheckoutCookieService(
                _basketCookie.GetValue());

            var bizStatus = await _placeOrder.CreateOrderAndSaveAsync(
                new PlaceOrderInDto(acceptTAndCs, checkoutService.UserId, checkoutService.LineItems));


            if (status.CombineStatuses(bizStatus).HasErrors)
            {
                return(status);
            }

            //successful so clear the cookie line items
            checkoutService.ClearAllLineItems();
            _basketCookie.AddOrUpdateCookie(
                checkoutService.EncodeForCookie());

            return(status.SetResult(bizStatus.Result.OrderId));
        }
예제 #29
0
        public static async Task <IStatusGeneric <UserToRole> > AddRoleToUserAsync(
            string userId,
            string roleName,
            IAuthorizationRepository repository)
        {
            if (userId == null)
            {
                throw new ArgumentNullException(nameof(userId));
            }
            if (roleName == null)
            {
                throw new ArgumentNullException(nameof(roleName));
            }
            if (repository == null)
            {
                throw new ArgumentNullException(nameof(repository));
            }

            var        status     = new StatusGenericHandler <UserToRole>();
            UserToRole userToRole = await repository.GetUserToRoleAsync(userId, roleName);

            if (userToRole != null)
            {
                status.AddError($"The user already has the Role '{roleName}'.");
                return(status);
            }

            RoleToPermissions roleToAdd = await repository.GetRoleToPermissionAsync(roleName);

            if (roleToAdd == null)
            {
                status.AddError($"Could not find the Role '{roleName}'.");
                return(status);
            }

            return(status.SetResult(new UserToRole(userId, roleToAdd)));
        }
예제 #30
0
        public static IStatusGeneric <Book> CreateBook(     //#B
            string title, DateTime publishedOn,             //#C
            decimal price,                                  //#C
            ICollection <Author> authors)                   //#C
        {
            var status = new StatusGenericHandler <Book>(); //#D

            if (string.IsNullOrWhiteSpace(title))           //#E
            {
                status.AddError(                            //#E
                    "The book title cannot be empty.");     //#E
            }
            var book = new Book                             //#F
            {                                               //#F
                Title       = title,                        //#F
                PublishedOn = publishedOn,                  //#F
                OrgPrice    = price,                        //#F
                ActualPrice = price,                        //#F
            };

            if (authors == null)                                      //#G
            {
                throw new ArgumentNullException(nameof(authors));     //#G
            }
            byte order = 0;                                           //#H

            book._authorsLink = new HashSet <BookAuthor>(             //#H
                authors.Select(a =>                                   //#H
                               new BookAuthor(book, a, order++)));    //#H

            if (!book._authorsLink.Any())                             //#I
            {
                status.AddError(                                      //#I
                    "You must have at least one Author for a book."); //#I
            }
            return(status.SetResult(book));                           //#J
        }