Esempio n. 1
0
        public async Task <UserViewModel> Handle(CreateUserCommand request, CancellationToken cancellationToken)
        {
            // Validate the username is not in use
            var existingUserByUserName = await _userManager.FindByNameAsync(request.User.Username);

            if (existingUserByUserName != null)
            {
                throw new ConduitApiException($"Username {request.User.Username} is already in use", HttpStatusCode.BadRequest);
            }

            // Validate the email is not in use
            var existingUserByEmail = await _userManager.FindByEmailAsync(request.User.Email);

            if (existingUserByEmail != null)
            {
                throw new ConduitApiException($"Email {request.User.Email} is already in use", HttpStatusCode.BadRequest);
            }

            // Instantiate and attempt to create the user
            var newUser = new ConduitUser
            {
                UserName = request.User.Username,
                Email    = request.User.Email,
            };
            var createUserResult = await _userManager.CreateAsync(newUser, request.User.Password);

            // Instantiate the creation exception and errors, if necessary
            if (!createUserResult.Succeeded)
            {
                var exception = new ConduitApiException($"Could not create user with [{request.User.Username}]", HttpStatusCode.BadRequest);

                foreach (var error in createUserResult.Errors)
                {
                    var conduitError = new ConduitApiError(error.Code, error.Description);
                    exception.ApiErrors.Add(conduitError);
                }

                throw exception;
            }

            // Generate the token and map the user
            var token         = _tokenService.CreateToken(newUser);
            var userViewModel = new UserViewModel
            {
                User = _mapper.Map <UserDto>(newUser)
            };

            userViewModel.User.Token = token;

            await _context.AddActivityAndSaveChangesAsync(ActivityType.UserCreated, TransactionType.ConduitUser, newUser.Id, cancellationToken);

            _logger.LogInformation($"{request.User.Username}] created successfully");
            return(userViewModel);
        }
        /// <summary>
        /// Handles any exception thrown during the pipeline process and in the application layer. Note that model state
        /// validation failures made in the web layer are handled by the ASP.NET Core model state validation failure filter.
        /// </summary>
        /// <param name="context">HTTP context from the request pipeline</param>
        /// <param name="exception">Exceptions thrown during pipeline processing</param>
        /// <returns>Writes the API response to the context to be returned in the web layer</returns>
        private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            ErrorDto             errors;
            ICollection <object> errorList = new List <object>();

            /*
             * Handle exceptions based on type, while defaulting to generic internal server error for unexpected exceptions.
             * Each case handles binding the API response message, API response status code, the HTTP response status code,
             * and any errors incurred in the application layer. Validation failures returned from Fluent Validation will
             * be added to the API response if there are any instances.
             */
            switch (exception)
            {
            case ConduitApiException conduitApiException:
                errors = new ErrorDto(conduitApiException.Message);
                context.Response.StatusCode = (int)conduitApiException.StatusCode;
                if (conduitApiException.ApiErrors.Any())
                {
                    errors.Details = conduitApiException.ApiErrors;
                }

                break;

            case ValidationException validationException:
                context.Response.StatusCode = (int)HttpStatusCode.UnsupportedMediaType;
                foreach (var validationFailure in validationException.Errors)
                {
                    var conduitValidationError = new ConduitApiError(validationFailure.ErrorMessage, validationFailure.PropertyName);
                    errorList.Add(conduitValidationError);
                }

                errors = new ErrorDto(ConduitErrorMessages.ValidationError, errorList);
                break;

            default:
                errors = new ErrorDto(ConduitErrorMessages.InternalServerError);
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                break;
            }

            // Instantiate the response
            context.Response.ContentType = "application/json";
            var errorResponse = new ErrorViewModel(errors);

            // Serialize the response and write out to the context buffer to return
            var result = JsonConvert.SerializeObject(errorResponse, ConduitConstants.ConduitJsonSerializerSettings);
            await context.Response.WriteAsync(result);
        }