Base solution for your next web application
Open Closed

Validations and Error handling instead of throwing Exception #2459


User avatar
0
alex created

Hi,

I have a method in Application layer. It is responsible for validating and adding an account. It is very much the same as what you have done with OrganizationUnit. The problem is that I can not use it this way in my custom API which is in a custom project. (added manually to the solution). I want to send almost the same message as AjaxResponse in the ABP Framework.

public async Task<AccountDto> Create(CreateAccountInput input)
        {
            var account = new Account
            {
                Id = (input.Id == Guid.Empty ? Guid.NewGuid() : input.Id),
                AccountNumber = input.AccountNumber,
                Name = input.Name
            };

            // When not valid, it throws the first exception and immediately bubbles up to the caller.
            if (account.Name.IsNullOrWhiteSpace())
                throw new UserFriendlyException(111, L("AccountName_IsMandatory", account.Name));

            if (account.Name.Length < 3)
                throw new UserFriendlyException(112, L("AccountName_IsTooShort", account.Name));

            if (await AccountNameAlreadyExists(account.ParentId, account.Name))
                throw new UserFriendlyException(113, L("AccountName_AlreadyExists", account.Name));

            // Save
            using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                await _accountRepository.InsertAsync(account);
                UnitOfWorkManager.Current.Completed += (sender, args) => { /* TODO: Send email to assigned person or do something else */ };
                await unitOfWork.CompleteAsync();
            }
            return account.MapTo<AccountDto>();
        }

This is an example. In reality I would like to know 'exactly' which error was the cause of failure. Throwing "UserFriendlyException" for a validation is not something I could use and test. Look at the code below from the test project:

[Fact]
        public async Task Should_Not_Create_Account_With_Same_Name_In_Same_Level2()
        {
            //Arrange
            var account = new CreateAccountInput
            {
                AccountNumber = "123",
                Name = "Same Name"
            };

            UsingDbContext(
                context =>
                {
                    context.Accounts.Add(
                        new Account
                        {
                            Name = account.Name, // "Same Name"
                            AccountNumber = "456"
                        });
                });

            //Act & Assert -- This just tells me that there was an "UserFriendlyException". Nothing more.
            var ex = await Assert.ThrowsAsync<UserFriendlyException>(
                () => _accountAppService.Create(account)
                );

            Assert.NotNull(ex);
            ex.Code.ShouldBe(113);

        }

I have to say that I have many custom API's which I put in their own project in the solution. Their project is a copy of the xx.Web.Host project. They are not intended for the UI. They have their own controller and just call the Application App services. You recommended this approach to me.

By the way I saw AjaxResponse and ErrorInfo classes in the ABP. Should I use them or is there any other better way? I want to response message for all of my custom API's are very much like the AjaxResponse.

Thanks.


No answer yet!