ASP.NET Web API负载测试问题

状态
不接受进一步答复。

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
你好,

我有一个休息的asp.net Web API。我正在用Jmeter进行负载测试。我收到了这个错误;

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.

我尚未检测到此错误的位置,因为尚未部署PDB。但我想知道我的Web API中是否存在此基本身份验证过滤器,该过滤器可查询数据库中的客户端。该查询不是异步的,这可能是原因吗?

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;
        }
    }

堆栈跟踪在下面指示了此方法,但是没有此类编译警告(cs4014),并且在下面的这段代码中找不到任何丢失的等待对象;

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;
        }

任何指导将不胜感激 :)
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
平行是什么意思?上面的代码中没有并行查询。当我进行负载测试时会发生这种情况。

我简化了代码,是否错过了任何并行查询?

C#:
private async Task<HttpResponseMessage> CallRazerService(RequestDto requestDto)
        {
            HttpResponseMessage response = null;
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
              
               //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")
                {
                    
                    //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;
        }
 
Last edited:

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
如果要进行负载测试,则要执行多个查询。我敢打赌,在每种情况下,它都是相同的工作单元,因此会有并行的查询。我确实提供了两种解决方案。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
如果您的工作单元包含上下文,则要使用多个上下文,您需要使用多个工作单元。如果您有多个用户同时使用您的服务,那么他们都将拥有自己的工作单元,因此应该进行测试。
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
可能是由于Unity生命周期设置造成的吗?有人说,我没有使用正确的生命周期管理器。每个mvc请求都需要一个唯一的dbcontext,该dbcontext无法在请求之间共享,否则会出现并发操作错误。


C#:
using System;
using BusinessService;
using DataModels;
using Unity;
using Unity.Lifetime;

namespace Game
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public static class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              return container;
          });

        /// <summary>
        /// Configured Unity Container.
        /// </summary>
        public static IUnityContainer Container => container.Value;
        #endregion

        
        public static void RegisterTypes(IUnityContainer container)
        {
            
            container.RegisterType<IGameServices, GameServices>().RegisterType<UnitOfWork>(new HierarchicalLifetimeManager());
            container.RegisterType<IUserValidate, UserValidate>();
            
       }
    }
}
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
在连续搜索执行查询时,我发现了很多结果。那么,您认为您需要做什么?

Who said this I am not using the correct lifetime manager. and where?

您是否已经解决了这个问题: 统一容器/统一
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
由于asp.net允许同一线程上有多个并发请求,因此我认为使用此请求似乎更合适。

ContainerControlledTransientManager

对于这个生命周期管理器,Unity会为每次调用创建并返回所请求类型的新实例。 解决 方法。这个终身经理类似于 瞬态管理器 唯一的区别是它保留了对每个创建的一次性实例的引用,并在处理容器时对其进行处理。与基于会话的子容器一起用于基于会话的设计时,此管理器很有用。
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
现在我收到此错误:

已成功提交对数据库的更改,但是在更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:由于多个“ BusinessEntity.GameRequest”类型的实体具有相同的主键值,因此保存或接受更改失败。确保显式设置的主键值是唯一的。确保在数据库和实体框架模型中正确配置了数据库生成的主键。将实体设计器用于数据库优先/模型优先配置。使用'HasDatabaseGeneratedOption"流畅的API或“代码优先”配置的“ DatabaseGeneratedAttribute”。
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
我认为这个问题是由于交易引起的。我应该使用这样的东西。您对此有何看法?
C#:
using (var transaction = _unitOfWork.BeginTransaction())
    {
        try
        {
            Save(entity);
            await _unitOfWork.SaveChangesAsync();

            transaction.Commit();
        }
        catch (DbEntityValidationException e)
        {
        }
    }
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
该警告与交易无关。问题出在您的主键值管理上。
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
因此,正如我在其他文章中所张贴的,SQL可以为我生成GUID吗?
C#:
//Unique reference ID
  gameRequest.referenceId = Guid.NewGuid().ToString();
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
SQL Server can generate GUIDs in exactly the same way that it generates integer IDs, i.e. you create a column of the appropriate type - uniqueidentifier for SQL Server - and then you make that column an identity. That said, a SQL Server table can only have one identity column, so if you are already generating integers that way then you cannot generate GUIDs in the same table. I'm not sure whether SQL Server can generate GUIDs outside of that but, if I wanted to know, I'd open my favourite search engine and type something like "SQL服务器生成GUID"看看回来了。我现在可以尝试回答您的问题,但是您自己也可以这样做。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
同样,按照惯例,实体框架具有一组命名规则,通过该命名规则,假设哪个字段对应于哪些列。此外,据我所知,列名为"Id"或后缀为"Id'被假定为主键。既然你们两个都上课了,我猜它选了"Id" over "referenceId"。因此,即使您正在为生成GUID"referenceId",如果主键是否"Id".

(请注意我上面写的内容,因为我不使用Entity Framework,以及In NoSql阵营。)
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
我改变了几件事。首先,我手动设置了referenceId,它是唯一的GUID。然后添加带有该referenceId的实体。之后,我在另一个实体中使用相同的referenceId来添加到数据库中。

现在,SQL Server为我生成referenceId,如下所示:
C#:
public class GameRequest
    {
        public int Id { get; set; }
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public Guid referenceId { get; set; }
...

现在是我的代码。但是问题是当我获取生成的refenerceId时 插入 将其导入数据库。 AFAIK,在完成SaveAsync插入之后。我需要某种方式使用此SQL生成的referenceId才能使用它调用Razer进行确认。

忘了提及这一点,当我将referenceId更改为GUID时,出现了此错误。

System.Data.SqlClient.SqlException:当IDENTITY_INSERT设置为OFF时,无法在表'GameRequests'中为身份列插入显式值。
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();
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
而不是运行两个基本相同的线程。我建议忽略此线程,并继续讨论其他线程。
 
状态
不接受进一步答复。
最佳 底部