问题 为什么不将错误写入数据库?

Raysefo

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

我有未处理的异常记录器,它将每个错误记录到表中。实际上,它可以工作,但是当我对超过1000个用户进行负载测试时,情况很少,错误不会写入此表中。 (成功950次,出现50个错误)为什么会发生这种情况?有任何想法吗? 50位用户甚至由于某种原因而没有开始?

C#:
public class UnhandledExceptionLogger : ExceptionLogger
    {
        public override void Log(ExceptionLoggerContext context)
        {
            var ex = context.Exception;

            string strLogText = "";
            strLogText += Environment.NewLine + "Source ---\n{0}" + ex.Source;
            strLogText += Environment.NewLine + "StackTrace ---\n{0}" + ex.StackTrace;
            strLogText += Environment.NewLine + "TargetSite ---\n{0}" + ex.TargetSite;

            if (ex.InnerException != null)
            {
                strLogText += Environment.NewLine + "Inner Exception is {0}" + ex.InnerException;//error prone
            }
            if (ex.Message != null)
            {
                strLogText += Environment.NewLine + "Message ---\n{0}" + ex.Message;//error prone
            }

            var requestedURi = (string)context.Request.RequestUri.AbsoluteUri;
            var requestMethod = context.Request.Method.ToString();
            var timeUtc = DateTime.Now;

            SqlErrorLogging sqlErrorLogging = new SqlErrorLogging();
            ApiError apiError = new ApiError()
            {
                Message = strLogText,
                RequestUri = requestedURi,
                RequestMethod = requestMethod,
                TimeUtc = DateTime.Now
            };
            sqlErrorLogging.InsertErrorLog(apiError);
        }
    }

C#:
public void InsertErrorLog(ApiError apiError)
        {
            using (var sqlConnection =
                new SqlConnection(ConfigurationManager.ConnectionStrings["GameContext"].ConnectionString))
            {
                try
                {
                    sqlConnection.Open();
                    using (SqlCommand cmd =
                        new SqlCommand(
                            "INSERT INTO [dbo].[API_Error] ([Message],[RequestMethod],[RequestUri],[TimeUtc]) VALUES (@Message, @RequestMethod, @RequestUri, @TimeUtc)",
                            sqlConnection))
                    {
                        cmd.Parameters.AddWithValue("@TimeUtc", apiError.TimeUtc);
                        cmd.Parameters.AddWithValue("@RequestUri", apiError.RequestUri);
                        cmd.Parameters.AddWithValue("@Message", apiError.Message);
                        cmd.Parameters.AddWithValue("@RequestMethod", apiError.RequestMethod);

                        cmd.ExecuteNonQuery();
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
                finally
                {
                    sqlConnection.Close();
                }
            }
        }
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
由于您没有向我们展示您在if块中调用的方法的主体,因此很难说出来。我们如何知道它们是否正确实施?

Also, with those await keywords there and not knowing what context your async method is being called, how will we know if any database connections that are being using within those method bodies that you are hiding do or do not have any thread affinities. In the past, I've seen people stash connection information in thread local storage and assume that they can clean up when the background worker thread terminates. It worked great until somebody thought: "我将使用线程池,而不是使用后台工作线程,而不必支付启动任何新线程的成本。",但没有意识到他们使用的代码具有线程相似性。
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
对不起 @跳伞 ,这是if部分:
C#:
            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(gameConfirmRequest, "purchaseconfirmation");

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

                //Set service
                gameConfirmResponse.service = "RAZER";
                //Add confirm response into database
                _unitOfWork.GameConfirmResponseRepository.Insert(gameConfirmResponse);
            }

这是创建签名:
C#:
public class Utilities
    {
        private static readonly HttpClient _httpClient = new HttpClient();


        public static GameRequest CreateSignature(GameRequestDto game, GameServices.RequestType type)
        {
            var applicationCode = WebConfigurationManager.AppSettings["ApplicationCode"];
            var secretKey = WebConfigurationManager.AppSettings["SecretKey"];
            var version = WebConfigurationManager.AppSettings["Version"];
            string source = null;
            if (type == GameServices.RequestType.Initiate)
            {
                source = applicationCode + game.productCode + game.quantity + game.referenceId + version +
                         secretKey;
            }
            else if (type == GameServices.RequestType.Confirm)
            {
                source = applicationCode + game.referenceId + version + game.validatedToken + secretKey;
            }
            else
            {
                source = applicationCode + version + secretKey;
            }


            using (var md5Hash = MD5.Create())
            {
                var hash = GetMd5Hash(md5Hash, source);
                game.signature = hash;
                game.ApplicationCode = applicationCode;
                game.version = version;
            }

            //Transform GameRequest into ProductDTO
            var config = new MapperConfiguration(cfg => { cfg.CreateMap<GameRequestDto, GameRequest>(); });
            var iMapper = config.CreateMapper();
            var gameRequest = iMapper.Map<GameRequestDto, GameRequest>(game);

            return gameRequest;
        }
    //some code here

这是剃须刀:
C#:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Configuration;
using AutoMapper;
using BusinessEntity;
using Newtonsoft.Json.Linq;

namespace BusinessService.Utility
{
    public class Utilities
    {
        private static readonly HttpClient _httpClient = new HttpClient();


        //some code here

        public static async Task<HttpResponseMessage> CallRazer(GameRequest gameRequest, string url)
        {
            try
            {
                FormUrlEncodedContent content = null;

                if (url == "Product/")
                {
                    try
                    {
                        //Transform GameRequest into ProductDTO
                        var config =
                            new MapperConfiguration(cfg => { cfg.CreateMap<GameRequest, ProductRequestDto>(); });
                        var iMapper = config.CreateMapper();
                        var productRequest = iMapper.Map<GameRequest, ProductRequestDto>(gameRequest);

                        //Convert request
                        var keyValues = productRequest.ToKeyValue();
                        content = new FormUrlEncodedContent(keyValues);

                        //Call Game Sultan
                        var response = await _httpClient.PostAsync("//teststore.gamesultan.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
                else
                {
                    try
                    {
                        //Convert request
                        var keyValues = gameRequest.ToKeyValue();
                        content = new FormUrlEncodedContent(keyValues);

                        //Call Game Sultan
                        var response = await _httpClient.PostAsync("//teststore.gamesultan.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        
    }

    public static class ObjectExtensions
    {
        public static IDictionary<string, string> ToKeyValue(this object metaToken)
        {
            if (metaToken == null)
            {
                return null;
            }

            JToken token = metaToken as JToken;
            if (token == null)
            {
                return ToKeyValue(JObject.FromObject(metaToken));
            }

            if (token.HasValues)
            {
                var contentData = new Dictionary<string, string>();
                
                foreach (var child in token.Children().ToList())
                {
                    var childContent = child.ToKeyValue();
                    if (childContent != null)
                    {
                        contentData = contentData.Concat(childContent)
                            .ToDictionary(k => k.Key, v => v.Value);
                    }
                }

                return contentData;
            }

            var jValue = token as JValue;
            if (jValue?.Value == null)
            {
                return null;
            }

            var value = jValue?.Type == JTokenType.Date
                ? jValue?.ToString("o", CultureInfo.InvariantCulture)
                : jValue?.ToString(CultureInfo.InvariantCulture);

            return new Dictionary<string, string> {{token.Path, value}};
        }
    }
}
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
我使用其他方法之一进行了负载测试。如果没有记录,则可容纳800位用户。 (如果(gameBankResult == null))但是,如果有记录,它将开始出现错误。 (成功600次,出错200次)
错误如下:
C#:
Message --- Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.
--- End Inner Exception ---
Message --- The underlying provider failed on Open.

C#:
Message --- Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.
--- End Inner Exception ---
Message --- The underlying provider failed on Open.

样本FailedReqLogFile:
C#:
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<!-- saved from url=(0014)about:internet -->
<failedRequest url="http://185.201.212.218:1907/api/v2/game/purchase"
               siteId="3"
               appPoolId="EPIN"
               processId="5548"
               verb="POST"
               remoteUserName=""
               userName=""
               tokenUserName="NT AUTHORITY\IUSR"
               authenticationType="anonymous"
               activityId="{00000000-0000-0000-0C00-00800120003F}"
               failureReason="STATUS_CODE"
               statusCode="500"
               triggerStatusCode="500"
               timeTaken="52946"
               xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
               >
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>4</Level>
  <Opcode>44</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:16:13.103Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="AuthType"></Data>
  <Data Name="UserName"></Data>
  <Data Name="SupportsIsInRole">true</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>USER_SET</Opcode>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>4</Level>
  <Opcode>43</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:16:13.103Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="OldHandlerName">ExtensionlessUrlHandler-Integrated-4.0</Data>
  <Data Name="NewHandlerName">System.Web.Http.WebHost.HttpControllerHandler</Data>
  <Data Name="NewHandlerModules">ManagedPipelineHandler</Data>
  <Data Name="NewHandlerScriptProcessor"></Data>
  <Data Name="NewHandlerType">System.Web.Http.WebHost.HttpControllerHandler, System.Web.Http.WebHost, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>HANDLER_CHANGED</Opcode>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>5</Level>
  <Opcode>52</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:17:06.049Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="Reason">2</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>GENERAL_NOT_SEND_CUSTOM_ERROR</Opcode>
  <freb:Description Data="Reason">SETSTATUS_TRYSKIP</freb:Description>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>4</Level>
  <Opcode>35</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:17:06.049Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>GENERAL_FLUSH_RESPONSE_START</Opcode>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>4</Level>
  <Opcode>47</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:17:06.049Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="Headers">Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>GENERAL_RESPONSE_HEADERS</Opcode>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>4</Level>
  <Opcode>36</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:17:06.049Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="BytesSent">276</Data>
  <Data Name="ErrorCode">0</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>GENERAL_FLUSH_RESPONSE_END</Opcode>
  <freb:Description Data="ErrorCode">The operation completed successfully.
 (0x0)</freb:Description>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
 <System>
  <Provider Name="WWW Server" Guid="{3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}"/>
  <EventID>0</EventID>
  <Version>1</Version>
  <Level>0</Level>
  <Opcode>2</Opcode>
  <Keywords>0x0</Keywords>
  <TimeCreated SystemTime="2019-08-15T19:17:06.049Z"/>
  <Correlation ActivityID="{00000000-0000-0000-0C00-00800120003F}"/>
  <Execution ProcessID="5548" ThreadID="6288"/>
  <Computer>WINDOWS1</Computer>
 </System>
 <EventData>
  <Data Name="ContextId">{00000000-0000-0000-0C00-00800120003F}</Data>
  <Data Name="BytesSent">276</Data>
  <Data Name="BytesReceived">418</Data>
  <Data Name="HttpStatus">500</Data>
  <Data Name="HttpSubStatus">0</Data>
 </EventData>
 <RenderingInfo Culture="en-US">
  <Opcode>GENERAL_REQUEST_END</Opcode>
 </RenderingInfo>
 <ExtendedTracingInfo xmlns="http://schemas.microsoft.com/win/2004/08/events/trace">
  <EventGuid>{D42CF7EF-DE92-473E-8B6C-621EA663113A}</EventGuid>
 </ExtendedTracingInfo>
</Event>
</failedRequest>

Even though 600 successful responses but in the database only 13 records updated. (_unitOfWork.GameBankRepository.Update(gameBankResult[k]);) Isn't it strange?

由于限制,我无法发布该方法。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
由于限制,我无法发布该方法。
在新回复中回复剩余信息的帖子。每个帖子都有一个字符限制。您在代码块中超出了它
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
Here is the method I tested. Without this (if (gameBankResult != null)) it works as I said in my previous post.

C#:
private async Task<HttpResponseMessage> CallGameNew(RequestDto requestDto)
        {
            HttpResponseMessage response = null;

            //Transform DTO into GameRequest for calling Game Initiate
            var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<RequestDto, GameRequest>();
                cfg.CreateMap<GameRequest, GameConfirmRequest>();
                cfg.CreateMap<GameBank, GameConfirmResponse>();
                cfg.CreateMap<GameBankPin, Coupon>();
                cfg.CreateMap<GameRequest, GameRequestDto>();
            });
            var iMapper = config.CreateMapper();

            var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
            //Unique reference ID
            gameRequest.referenceId = Guid.NewGuid();

            var gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);
            //Create signature
            gameRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Initiate);

            //Set service
            gameRequest.service = "OUR";

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

            //Query GameBank database
            var gameBankResult = await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
                g.productCode == requestDto.productCode && g.referenceId == Guid.Empty);
            
            if (gameBankResult != null)
            {
                //Narrow the list based on quantity
                if (gameBankResult.Count > 0)
                {
                    gameBankResult = gameBankResult.Take(requestDto.quantity).ToList();
                }

                if (gameBankResult.Count() >= requestDto.quantity)
                {
                    var k = requestDto.quantity - 1;
                    for (var i = k; i >= 0; --i)
                    {
                        gameBankResult[i].referenceId = gameRequest.referenceId;
                        gameBankResult[i].requestDateTime = DateTime.Now;
                        gameBankResult[i].responseDateTime = DateTime.Now;
                    }

                    //Update GameBank
                    _unitOfWork.GameBankRepository.Update(gameBankResult[k]);

                    var gameBankConfirmResponse =
                        iMapper.Map<IList<GameBank>, IList<GameConfirmResponse>>(gameBankResult);

                    if (requestDto.quantity == 1)
                    {
                        gameBankConfirmResponse[k].purchaseStatusDate = DateTime.Now;

                        var resultResponse = JsonConvert.SerializeObject(gameBankConfirmResponse[k],
                            Formatting.Indented,
                            new JsonSerializerSettings()
                            {
                                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                            });
                        response = new HttpResponseMessage
                        {
                            StatusCode = System.Net.HttpStatusCode.OK,
                            Content = new StringContent(resultResponse, System.Text.Encoding.UTF8,
                                "application/json"),
                        };
                        //Set service
                        gameBankConfirmResponse[k].service = "OUR";

                        _unitOfWork.GameConfirmResponseRepository.Insert(gameBankConfirmResponse[k]);
                    }
                    else if (requestDto.quantity > 1)
                    {
                        var gameResult = new GameConfirmResponse {coupons = new List<Coupon>()};
                        var price = 0.0;
                        var quantity = 0;

                        foreach (var item in gameBankResult)
                        {
                            price = price + item.unitPrice;
                            quantity = quantity + 1;
                            foreach (var coupons in item.coupons)
                            {
                                var gameCouponResult = new Coupon()
                                {
                                    expiryDate = coupons.expiryDate, Pin = coupons.Pin, Serial = coupons.Serial
                                };
                                //Add coupon values
                                gameResult.coupons.Add(gameCouponResult);
                            }
                        }

                        //Set summed/counted values
                        gameResult.referenceId = gameBankResult[0].referenceId;
                        gameResult.productCode = gameBankResult[0].productCode;
                        gameResult.quantity = quantity;
                        gameResult.currency = gameBankResult[0].currency;
                        gameResult.unitPrice = gameBankResult[0].unitPrice;
                        gameResult.totalPrice = price;
                        gameResult.productDescription = gameBankResult[0].productDescription;
                        gameResult.purchaseStatusDate = DateTime.Now;
                        gameResult.totalPayablePrice = price;
                        //Set service
                        gameRequest.service = "OUR";

                        //Add confirm response into database
                        _unitOfWork.GameConfirmResponseRepository.Insert(gameResult);
                        var resultResponse = JsonConvert.SerializeObject(gameResult, Formatting.Indented,
                            new JsonSerializerSettings()
                            {
                                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                            });
                        response = new HttpResponseMessage
                        {
                            StatusCode = System.Net.HttpStatusCode.OK,
                            Content = new StringContent(resultResponse, System.Text.Encoding.UTF8,
                                "application/json"),
                        };
                    }
                }
            }

            await _unitOfWork.SaveAsync();

            return response;
        }
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
Is your UnitOfWork still the same as the one you presented in your 其他线程?

Can I correctly assume that the GameContext is simply a subclass of the Entity Framework DbContext?

If so, when is the UnitOfWork being disposed? Is the GameContext that is injected into the UnitOfWork disposed?

您是否注意到英孚的这些 文件资料?
默认情况下,上下文管理与数据库的连接。上下文根据需要打开和关闭连接。

在确定上下文的生存期时,有一些通用准则:
  • 使用Web应用程序时,每个请求使用一个上下文实例。
  • :
  • 如果上下文实例是由依赖项注入容器创建的,则通常由容器负责处理上下文。
  • 如果上下文是在应用程序代码中创建的,请记住在不再需要该上下文时将其丢弃。
  • 使用长时间运行的上下文时,请考虑以下事项:
    • :
    • 该上下文不是线程安全的,因此不应在同时对其进行工作的多个线程之间共享该上下文。
    • :

Note the last bullet above about the context not being thread safe. When you use await in an ASP.NET SynchronizationContext, you have no guarantees that your code will continue running on the same thread pool thread that initially accepted the web request. If you created your GameContext/DbContext on that incoming web request thread, then you now just crossed over to another thread.

见史蒂芬·克雷里(Stephen Cleary) 并行计算-全部与SynchronizationContext有关.
:
AspNetSynchronizationContext (System.Web.dll:System.Web [内部类])ASP.NET SynchronizationContext安装在线程池线程执行页面代码时。当委托排队到捕获的AspNetSynchronizationContext时,它将还原原始页面的标识和区域性,然后直接执行委托。即使通过调用Post将其“异步”排队,也可以直接调用该委托。

从概念上讲,AspNetSynchronizationContext的上下文很复杂。在异步页的生存期内,上下文仅从ASP.NET线程池中的一个线程开始。启动异步请求后,上下文将不包含任何线程。随着异步请求的完成,执行其完成例程的线程池线程将进入上下文。这些线程可能是发起请求的线程,但更有可能是操作完成时空闲的任何线程。

如果对同一应用程序一次完成多个操作,AspNetSynchronizationContext将确保它们一次执行一个。它们可以在任何线程上执行,但是该线程将具有原始页面的标识和区域性。

一个常见的示例是在异步网页中使用的WebClient。 DownloadDataAsync将捕获当前的SynchronizationContext,稍后将在该上下文中执行其DownloadDataCompleted事件。当页面开始执行时,ASP.NET将分配其线程之一以执行该页面中的代码。该页面可以调用DownloadDataAsync然后返回; ASP.NET会统计未完成的异步操作,因此它知道页面不完整。 WebClient对象下载了请求的数据后,它将在线程池线程上收到通知。该线程将在捕获的上下文中引发DownloadDataCompleted。上下文将保留在同一线程上,但将确保事件处理程序以正确的身份和区域性运行。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
默认情况下,上下文管理与数据库的连接。上下文根据需要打开和关闭连接。
自从他上任以来,我一直在这么说。是的,连接已经在EF中进行了预管理。 OP的代码种类繁多,很难记住或跟踪,但我可以肯定,单位或工作正在被处置:
公共无效Dispose(){_unitOfWork.Dispose(); }
那里和其他地方...
//向数据库_unitOfWork.GameRepository.Insert(gameRequest);添加启动请求
现在,如果您要处置它,然后再次调用它,那将是相当糟糕的编程,并且需要重新考虑,尤其是如果没有再次实例化的话。毕竟是在凌晨05:00,我可能是对还是错,我宁愿疲倦地重复输入您的代码以再次查看一下,但是如果其余的GameRepository /另一个正在尝试启动执行另一个命令,除非再次实例化它,否则您将在这里遇到问题。

晚安吧
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
谢谢 @跳伞@谢平。我将退出异步并尝试在没有异步的情况下加载测试。

Is your UnitOfWork still the same as the one you presented in your 其他线程?
是的,它是相同的UOW。
Can I correctly assume that the GameContext is simply a subclass of the Entity Framework DbContext?
是的,你是对的。
C#:
namespace DataModels
{
    public class GameContext : DbContext
    {
        public GameContext() : base("GameContext")
        {
        }

        public DbSet<GameRequest> Initiates { get; set; }
        public DbSet<GameResponse> InitiatesResponses { get; set; }
        public DbSet<GameConfirmResponse> GameConfirmResponses { get; set; }
        public DbSet<Coupon> Coupons { get; set; }
        public DbSet<GameConfirmRequest> GameConfirmRequests { get; set; }
        public DbSet<GameBank> GameBanks { get; set; }
        public DbSet<GameBankPin> GameBankPins { get; set; }
        public DbSet<ConfirmCancel> ConfirmCancels { get; set; }
        public DbSet<Company> Companies { get; set; }
        public DbSet<Recon> Recons { get; set; }
        public DbSet<ReconDetail> ReconDetails { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //Configure Null Column
            modelBuilder.Entity<GameRequest>()
                .Property(p => p.referenceId)
                .IsOptional();
            modelBuilder.Entity<GameRequest>().Property(t => t.referenceId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

        }
    }
}
If so, when is the UnitOfWork being disposed? Is the GameContext that is injected into the UnitOfWork disposed?
它位于GameServices中:
C#:
public async Task<HttpResponseMessage> GamePurchase(RequestDto requestDto)
        {
            HttpResponseMessage response = null;
            using (_unitOfWork)
            {
                response = await CallGameNew(requestDto) ?? await CallRazerService(requestDto);
                return response;
            }
        }
是的,在UOW中注入了上下文。
C#:
namespace DataModels
{
    public class UnitOfWork : IDisposable
    {
        private readonly GameContext _context;
        
        //Some code here

        public UnitOfWork(GameContext context)
        {
            _context = context;
        }
        //Some code here
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

这是Unity配置:
C#:
public static void RegisterTypes(IUnityContainer container)
{
            // Default empty Time manager!
            container.RegisterType<IGameServices, GameServices>().RegisterType<UnitOfWork>(new TransientLifetimeManager());
            container.RegisterType<IUserValidate, UserValidate>(new TransientLifetimeManager());
            
}
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
我删除了异步查询数据库,更新和插入。只需保持异步即可调用第三方Rest API。结果是成功测试了1500个用户  :)
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
我尝试了2000个用户,但出现了一些错误。他们不知何故没有写入数据库。如何查看错误详细信息?事件日志中也没有跟踪。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
他们不知何故没有写入数据库。
Which part of my previous reply did you not understand about doing this. I find it amusing, almost funny that you're experiencing connection pool issues and yet you are trying to log your errors to the database? :unsure: Why are you still trying to insert your errors into the database? Log them to a file man until you sort out your business model.
 

Raysefo

知名会员
已加入
2019年2月22日
留言内容
194
编程经验
10+
@谢平 谢谢你。此时间错误与数据库连接无关。如下:

C#:
StackTrace ---    at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
TargetSite --- System.Object ChangeType(System.Object, System.Type, System.IFormatProvider)
Message --- Null object cannot be converted to a value type.
--- End Inner Exception ---
Message --- Error converting value {null} to type 'System.Int32'. Path 'quantity', line 1, position 111.

我试图弄清楚为什么只发生了这一件事。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,536
地点
弗吉尼亚州切萨皮克
编程经验
10+
当您尝试弄清楚这一点时,我建议您还阅读以下博客文章系列:
IDisposable的Unity生命周期管理,第1部分
IDisposable的Unity生命周期管理,第2部分
IDisposable的Unity生命周期管理,第3部分

第一部分还强调了我在另一个线程中指出的相同问题,如果您使用的是依赖注入,则不应处置注入到对象中的引用。第一部分还将在另一个线程中确认您的断言,即Unity的TransientLifetimeManager不知道如何处置IDisposable对象。

我偶然发现该博客的原因是,当我看到没有对象被放置在这个简单的代码中时,我感到非常震惊:
C#:
using System;
using Unity;
using Unity.Lifetime;

namespace TestUnityIoC
{
    class A : IDisposable
    {
        public A()
        {
            Console.WriteLine(nameof(A));
        }

        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            Console.WriteLine(nameof(Dispose));
            if (!disposedValue)
            {
                if (disposing)
                {
                }

                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Console.WriteLine(nameof(Dispose));
            Dispose(true);
        }
    }

    interface IB
    {
        void DoIt();
    }

    class B : IB, IDisposable
    {
        A _a;

        public B(A a)
        {
            Console.WriteLine(nameof(B));
            _a = a;
        }

        public void DoIt()
        {
            Console.WriteLine(nameof(DoIt));
        }

        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            Console.WriteLine(nameof(Dispose));
            if (!disposedValue)
            {
                if (disposing)
                {
                    _a.Dispose();
                }

                _a = null;
                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Console.WriteLine(nameof(Dispose));
            Dispose(true);
        }
    }

    class Program
    {
        static void Main()
        {
            using (var container = new UnityContainer())
            {
                container.RegisterType<IB, B>(new TransientLifetimeManager());

                var b = container.Resolve<IB>();
                b.DoIt();
            }
        }
    }
}
Autofac可以通过处理一次性物品的预期行为来处理此问题。具有讽刺意味的是,Unity来自“模式与实践”小组,正是该小组帮助推广了"least surprise"在设计对象和接口时。
 
最佳 底部