ASP.NET Web API load test problem

Status
Not open for further replies.

raysefo

Well-known member
Joined
Feb 22, 2019
Messages
361
Programming Experience
10+
Hi,

I have a rest asp.net web API. I am load testing with Jmeter. I got this error;

C#:
A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.

I couldn't detect the location of this error because I haven't deployed the PDBs yet. But I wonder there is this basic authentication filter in my web API which queries the database for the client. This query is NOT async, could this be a reason?

C#:
public class UserValidate : IUserValidate
    {
        private readonly UnitOfWork _unitOfWork;

        /// <summary>
        /// Public constructor.
        /// </summary>
        public UserValidate(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        /// <summary>
        /// Public method to authenticate user by user name and password.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public bool Login(string userName, string password)
        {
            var user = _unitOfWork.UserRepository.Get(u => u.userName.Equals(userName, StringComparison.OrdinalIgnoreCase) && u.password == password);
            if (user == null) return false;
            return true;
        }
    }

Stack trace indicates this method below but there are no such compilation warnings (cs4014) and I couldn't find any missing await in this code below;

C#:
private async Task<HttpResponseMessage> CallRazerService(RequestDto requestDto)
        {
            HttpResponseMessage response = null;
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                //Transform DTO into GameRequest for calling Razer Initiate
                var config = new MapperConfiguration(cfg =>
                {
                    cfg.CreateMap<RequestDto, GameRequest>();
                    cfg.CreateMap<GameRequest, GameConfirmRequest>();
                    cfg.CreateMap<GameConfirmResponse, GameConfirmResponseDto>();
                    cfg.CreateMap<Coupon, CouponDto>();
                });
                var iMapper = config.CreateMapper();
                var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
                //Unique reference ID
                gameRequest.referenceId = Guid.NewGuid().ToString();
                //Create signature
                gameRequest = Utilities.CreateSignature(gameRequest, RequestType.Initiate);


                //Add initiation request into database
                _unitOfWork.GameRepository.Insert(gameRequest);

                #region Call Razer initiate/confirm

                //Call Razer for initiation
                response = await Utilities.CallRazer(gameRequest, "purchaseinitiation");

                //Read response
                var htmlResponse = await response.Content.ReadAsStringAsync();
                var gameResponse = JsonConvert.DeserializeObject<GameResponse>(htmlResponse);

                //Adding initiation response into database
                _unitOfWork.GameResponseRepository.Insert(gameResponse);

                if (gameResponse.initiationResultCode == "00")
                {
                    gameRequest.validatedToken = gameResponse.validatedToken;
                    //Create signature
                    var gameConfirmRequest = Utilities.CreateSignature(gameRequest, RequestType.Confirm);

                    //Transform DTO into GameRequest for calling Razer Initiate
                    var gameConfirmRequests = iMapper.Map<GameRequest, GameConfirmRequest>(gameConfirmRequest);

                    //Add confirm request into database
                    _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests);

                    //Call Razer for confirm
                    response = await Utilities.CallRazer(gameRequest, "purchaseconfirmation");

                    //Read response
                    htmlResponse = await response.Content.ReadAsStringAsync();
                    var gameConfirmResponse = JsonConvert.DeserializeObject<GameConfirmResponse>(htmlResponse);

                    //Add confirm response into database
                    _unitOfWork.GameConfirmResponseRepository.Insert(gameConfirmResponse);

                }

                #endregion

                await _unitOfWork.SaveAsync();
                scope.Complete();
            }

            return response;
        }

Any guidance will be appreciated :)
 
Also, by convention, Entity Framework has a set of naming rules by which it assumes which field corresponds to which columns. Furthermore, from what I recall, columns named "Id" or having a suffix of "Id' are assumed to be the primary key. Since you have both in your class, I am guessing that it picked "Id" over "referenceId". So even if you are generating GUIDs for "referenceId", it won't matter if the primary key if "Id".

(Please take what I wrote above with a huge grain of salt, as I don't use Entity Framework, as well as In fall into the NoSql camp.)
 
I changed a couple of things. First of all, I was setting referenceId which is a unique GUID manually. Then adding an entity with this referenceId. After that, I am using this same referenceId in another entity to add into the database.

Now SQL server generates referenceId for me as follows:
C#:
public class GameRequest
    {
        public int Id { get; set; }
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public Guid referenceId { get; set; }
...

Here is my code now. But the problem is how can I get the generated refenerceId when I insert it into the database. AFAIK, after SaveAsync insertion is made. Somehow I need to use this SQL generated referenceId in order to use it call Razer for confirming.

Forgot to mention that, I am getting this error when I changed the referenceId to GUID.

System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'GameRequests' when IDENTITY_INSERT is set to OFF.
C#:
...
var config = new MapperConfiguration(cfg =>
                {
                    cfg.CreateMap<RequestDto, GameRequest>();
                    cfg.CreateMap<GameRequest, GameConfirmRequest>();
                    cfg.CreateMap<GameConfirmResponse, GameConfirmResponseDto>();
                    cfg.CreateMap<Coupon, CouponDto>();
                    cfg.CreateMap<GameRequest, GameRequestDto>();
                });
                var iMapper = config.CreateMapper();
                var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
                //Unique reference ID
                //gameRequest.referenceId = Guid.NewGuid().ToString();

                var gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);

                //Create signature
                gameRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Initiate);

                //Add initiation request into database
                _unitOfWork.GameRepository.Insert(gameRequest);

                #region Call Razer initiate/confirm

                //Call Razer for initiation
                response = await Utilities.CallRazer(gameRequest, "purchaseinitiation");

                //Read response
                var htmlResponse = await response.Content.ReadAsStringAsync();
                var gameResponse = JsonConvert.DeserializeObject<GameResponse>(htmlResponse);

                //Adding initiation response into database
                _unitOfWork.GameResponseRepository.Insert(gameResponse);

                if (gameResponse.initiationResultCode == "00")
                {
                    gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);
                    gameRequestDto.validatedToken = gameResponse.validatedToken;
                    //Create signature
                    var gameConfirmRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Confirm);

                    //Transform DTO into GameRequest for calling Razer Initiate
                    var gameConfirmRequests = iMapper.Map<GameRequest, GameConfirmRequest>(gameConfirmRequest);

                    //Add confirm request into database
                    _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests);

                    //Call Razer for confirm
                    response = await Utilities.CallRazer(gameRequest, "purchaseconfirmation");
...
              
                   await _unitOfWork.SaveAsync();
 
Instead of running two parallel threads about essentially the same problem. I recommend ignoring this thread and continuing the discussion on the other thread.
 
Status
Not open for further replies.
Back
Top Bottom