AutoMapper.Mapper.CreateMap報“System.NullReferenceException: 未將對象引用設置到對象的實例。”異常復現

来源:http://www.cnblogs.com/buguge/archive/2017/10/17/7682095.html
-Advertisement-
Play Games

對AutoMapper.Mapper.CreateMap使用不當,導致併發情況下出現異常System.NullReferenceException、System.InvalidOperationException ...


navigation:

>>Ⅰ.國慶假期問題出現

>>Ⅱ.雙休日異常再次出現

>>Ⅲ.排障

>>Ⅳ.異常復盤

>>Ⅴ.修複後監測

>>Ⅵ.結束

Ⅰ.國慶假期問題出現TOP

國慶假期期間——10月5號——發現支付中心頻繁報異常“System.NullReferenceException: 未將對象引用設置到對象的實例。”,通過分析異常堆棧信息,代碼出現在QRCodeService的GetQRCode方法里如下第8行代碼:

 1 /// <summary>
 2 /// 掃碼支付 獲取支付碼
 3 /// </summary>
 4 /// <param name="reqModel"></param>
 5 /// <returns></returns>
 6 public ResponseModelBase GetQRCode(QRCodeRequestModel reqModel)
 7 {
 8     AutoMapper.Mapper.CreateMap<QRCodeRequestModel, QRCodeRequestDTO>();
 9     var reqDto = AutoMapper.Mapper.Map<QRCodeRequestDTO>(reqModel);
10     if (reqDto.valid_minutes == 0)
11     {
12         reqDto.valid_minutes = 20;//預設設置為20分鐘
13     }
14 
15     if (string.IsNullOrEmpty(reqModel.order_no))
16     {
17         throw new ResponseErrorException("未獲取訂單ID,請重新檢查訂單信息");
18     }
19     if (reqModel.pay_money <= 0)
20     {
21         throw new ResponseErrorException("訂單價格有誤,請重新驗證該訂單");
22     }
23     if (string.IsNullOrEmpty(reqModel.goods_name))
24     ......
25     ......
26 }

 

異常日誌:

 1 2017/10/5 14:03:40    [GetQRCode_140340241_DCB85]請求支付中心參數:{"biz_system":"5","goods_name":"W17720171005140403733142/qdrpayment3577421317952512T/","merchant_id":"102573307097-102125439412","notify_url":"http://papi1.shenbianhui.cn//OrderPayBack/BackResult","order_no":"DD2017100500470030","order_time":"20171005140340","pay_channel":"12","pay_money":"30000","remark":"","return_url":"http://120.55.16.195/pay/returnYimeiCallBack.do","sign":"de101b203758cbbe7f83ce04f20d6fb1","third_pay_platform":"61","valid_minutes":"10"}
 2 2017/10/5 14:03:40    [GetQRCode_140340241_DCB85]支付中心驗簽通過。
 3 2017/10/5 14:03:40    [GetQRCode_140340241_DCB85]獲取二維碼進入
 4 2017/10/5 14:03:40    [GetQRCode_140340241_DCB85]系統異常:System.NullReferenceException: 未將對象引用設置到對象的實例。
 5    在 AutoMapper.TypeMapFactory.<>c__DisplayClass3_0.<MapDestinationPropertyToSource>b__0(IMemberConfiguration _)
 6    在 System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
 7    在 AutoMapper.TypeMapFactory.CreateTypeMap(Type sourceType, Type destinationType, IProfileConfiguration options, MemberList memberList)
 8    在 AutoMapper.ConfigurationStore.<>c__DisplayClass80_0.<CreateTypeMap>b__0(TypePair tp)
 9    在 System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
10    在 AutoMapper.ConfigurationStore.CreateMap[TSource,TDestination](String profileName, MemberList memberList)
11    在 PaymentService.QRCodeService.GetQRCode(QRCodeRequestModel reqModel)
12    在 PaymentPlatform.QRCode.GetQRCode.MyBiz(String requestJson)
13    在 PaymentPlatform.QRCode.HandlerBase.ProcessRequest(HttpContext context)

從第9行有ConcurrentDictionary,難不成是併發導致的?當時系統TPS併發在50以上。

系統運行數月來,以前從未遇到這樣的問題呢。

 

進一步排查,這個異常出現之後,後面所有對這個介面的請求處理都報這個異常。另外,三個負載節點中,只有其中的9177節點接連報這個異常。

直覺懷疑,隨著線上每周一兩次的發版,會不會是3個節點AutoMapper.DLL版本不一致呢。為了將影響減到最低,緊急聯繫運維,將9177節點的站點文件刪掉,從其他節點copy過來一份。 運維告知處理完畢後,問題未再復現。

此後的幾天,線上也沒有再發生類似事故。我也因此認為是文件版本問題所致,就不再關註。

Ⅱ.雙休日異常再次出現TOP

誰知,就在上周末的兩天,這個異常又出現了,還是出現在9177節點。

那這回,就不能理解了。文件版本應該是一致了呀。

迅速聯繫運維,幫忙回收一下站點的應用程式池。

誰知回收完後,問題依舊。

咨詢運維,為什麼只有這個節點報這個異常,運維披露10月5號也並未copy文件,只是重啟了一下iis。

那隻好應急讓運維再重啟一下iis了。 此事暫時平息。

 

Ⅲ.排障TOP

為了可以消停地過下個周末,決定今天把這個問題根治一下。

大家初步的分析是,AutoMapper.Mapper.CreateMap是靜態方法,多線程時可能會出現問題。

我也一直知道,AutoMapper建議把映射關係在程式啟動時做一次性初始化,而非在每次轉換對象時都做初始化。

我當時在用AutoMapper時,也並未重視這一點。就寫成了每次都是先創建映射接著轉換對象。

 

欠下的賬總是要還的。 系統此前沒出現這樣的異常,只能說時間不到。

就像墨菲定理說的,該發生的事情總會發生。 這不,不早不晚,就在國慶節和上周末兩個節假日出現了。

 

Ⅳ.異常復盤TOP

有必要復現一下那個異常。當然,小概率問題,並不容易測出來。

好在,我有JMeter。

在項目里新建了AutoMapperTest.ashx文件,ProcessRequest方法體如下:

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";
    
    LogHelperUtil logHelper = new LogHelperUtil("", LogType.HFAgentPayService);
    LogHelper.Write("[AutoMapperTest]");
    
    Thread.Sleep(new Random().Next(1, 100));
    
    try
    {
        QRCodeRequestModel reqModel = new QRCodeRequestModel();

        AutoMapper.Mapper.CreateMap<QRCodeRequestModel, QRCodeRequestDTO>();
        var reqDto = AutoMapper.Mapper.Map<QRCodeRequestDTO>(reqModel);

        Thread.Sleep(new Random().Next(100, 1000));
        context.Response.Write(JsonConvert.SerializeObject(reqDto));
    }
    catch (Exception ex)
    {
        logHelper.Write("[AutoMapperTestException]" + ex.ToString());
        context.Response.Write(ex.ToString());
    }
}

 

發佈到測試環境。

接下來,創建JMeter的測試計劃,模擬1000個線程數來壓測這個ashx。

持續執行了20分鐘。

過程中,

  • 重新覆蓋了一下站點的文件,AutoMapper.Mapper.CreateMap語句出現如下異常,在11:08:08這一秒出現了160次。
2017/10/17 11:08:08	[AutoMapperTestException]System.InvalidOperationException: 集合已修改;可能無法執行枚舉操作。
   在 System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   在 System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
   在 AutoMapper.TypeMapFactory.CreateTypeMap(Type sourceType, Type destinationType, IProfileConfiguration options, MemberList memberList)
   在 AutoMapper.ConfigurationStore.<>c__DisplayClass80_0.<CreateTypeMap>b__0(TypePair tp)
   在 System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   在 AutoMapper.ConfigurationStore.CreateMap[TSource,TDestination](String profileName, MemberList memberList)
   在 PaymentPlatform.Test.AutoMapperTest.ProcessRequest(HttpContext context)

 

  • 中午找運維手動回收了一下應用程式池,AutoMapper.Mapper.CreateMap語句出現如下異常,和節假日出現的異常一樣。這個異常在12:02:04~12:03:17之間出現了43351次。
2017/10/17 12:02:04	[AutoMapperTestException]System.NullReferenceException: 未將對象引用設置到對象的實例。
   在 AutoMapper.TypeMapFactory.<>c__DisplayClass3_0.<MapDestinationPropertyToSource>b__0(IMemberConfiguration _)
   在 System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
   在 AutoMapper.TypeMapFactory.CreateTypeMap(Type sourceType, Type destinationType, IProfileConfiguration options, MemberList memberList)
   在 AutoMapper.ConfigurationStore.<>c__DisplayClass80_0.<CreateTypeMap>b__0(TypePair tp)
   在 System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   在 AutoMapper.ConfigurationStore.CreateMap[TSource,TDestination](String profileName, MemberList memberList)
   在 PaymentPlatform.Test.AutoMapperTest.ProcessRequest(HttpContext context)

 

貼上JMeter壓測截圖:

 

Ⅴ.修複後監測TOP

正如第《Ⅲ.排障》節所說,解決方案就是在全局的Application_Start時,定義所有的AutoMapper類型映射。這樣,就保證了映射關係的一次性初始化。後續代碼不需再定義,只關註對象轉換就可以了。

發佈到測試環境。

再次啟動JMeter測試計劃,14分鐘內,無論在壓測過程中更新文件,還是回收站點應用程式池,都未出現那些併發帶來的AutoMapper創建類型映射的異常。

Ⅵ.結束 TOP

再次強調,你應該儘量統一管理AutoMapper的映射定義並且只做一次性初始化。

在博客園的一篇AutoMapper的《AutoMapper 最佳實踐》文章中介紹:

雖然AutoMapper並不強制要求在程式啟動時一次性提供所有配置,但是這樣做有如下好處:
a) 可以在程式啟動時對所有的配置進行嚴格的驗證(後文詳述)。
b) 可以統一指定DTO向Entity映射時的通用行為(後文詳述)。
c) 邏輯內聚:新增配置時方便模仿以前寫過的配置;對項目中一共有多少DTO以及它們與實體的映射關係也容易有直觀的把握。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 買了Bandwagon的vps,連接上預設terminal是英文的,有時沒有中文方便,所以想讓其支持中文。 主要步驟為以下兩步: 1. 安裝中文包 chinese-support: 安裝非常簡單,如是其他版本linux系統,使用相應的線上升級命令即可,如apt-get 2.修改字元編碼配置文件 可以 ...
  • 1.背景介紹 作為運維,在公司經常遇到一些機械性重覆工作要做,例如:為新機器裝系統,一臺兩台機器裝系統,可以用光碟、U盤等介質安裝,1小時也完成了,但是如果有成百台的伺服器還要用光碟、U盤去安裝,就顯得有些力不從心了。PXE技術就能很好的解決這個問題,本文將會對PXE的工作原理有所介紹,而cobbl ...
  • ubuntu16.04,Apache2,modsecurity,自定義規則,開源WAF,示例,實驗 ...
  • 僅以此篇謹記自己,以後加油 ...
  • 對於QQ截圖,肯定是早就有認識了,只是一直沒有去認真觀察這個操作的具體實現步驟。所以這裡將自己的記憶中的步驟簡單的寫一下: 習慣性用QQ或者TIM的人,一般是使用Ctrl+Alt+A 快捷鍵(熱鍵)快速實現截圖。 因為考慮到截圖模式的時候 一般只能顯示一個窗體 所以就考慮使用單例模式 在Screen ...
  • http://www.cnblogs.com/shenba/archive/2011/04/16/2018441.html ...
  • 1、列舉ASP.NET頁面之間傳值的幾種方式。 答:使用QueryString,如.../id=1;response.Redirect() 使用Session 使用Server.Transfer 使用Cookie 2、簡述private、protected、public、internal修飾符的訪問 ...
  • 用法 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...