2017/12/18

初始化 AutoMapper 的建議,以避免「Mapper 已初始化錯誤」

先前簡單寫過 AutoMapper 的使用方法,這對需要進行 Model/ ViewModel 資料對映作業來說,確實方便許多。過去常寫 Web,因此至今尚未遇到什麼讓人摸不著頭緒的問題。而最近開始寫 API,雖然開發的流程跟過去寫 Web 的 MVC 沒有什麼差異,但過去初始化 AutoMapper 的方法卻在 API 的專案中發現問題。

Mapper.Initialize(x => x.CreateMap());
var model = Mapper.Map(_ViewModel);

上面是過去在 Web 專案中的初始化方法。這種寫法在 API 專案中同樣可以使用,但當使用者重新呼叫相同的 API 後,會跳出這個錯誤訊息:
Mapper already initialized.You must call Initialize once per application domain/ process.
(Mapper 已經初始化。一個 Domain 或程序只能初始化一次)

會產生這問題,最關鍵的地方,在於這是用「靜態方式」初始化 Mapper 的方法。

由於在 Web 中,每呼叫一次 View,便會產生一次實體,因此用靜態方法初始化 Mapper 不會遇到這種問題。然而 API 則不同,因此初始化的方法勢必得跟著調整為下面方式:
var mapper = new MapperConfiguration(cfg => cfg.CreateMap<UserViewModel, UserModel>()
                                            .ForMember(x => x.EntityReference, opt => opt.Ignore())).CreateMapper();
var _model = mapper.Map<ContactModel>(_ViewModel);

若仍要使用靜態方法設定初始化,首先可先在 App_Start 資料夾內建立 AutoMapperConfig.cs 進行初始化設定:
public class AutoMapperConfig
{
  public static void Initialize()
  {
    Mapper.Initialize(cfg =>
    {
      cfg.CreateMap<UserViewModel, UserModel>();
      //...
    });
  }
}

再到 Global.cs 中的
Application_Start()
呼叫定義好的方法:
protected void Application_Start()
{
  //...
  App_Start.AutoMapperConfig.Initialize();
}

現在,可以在 Controller 中透過
AutoMapper.Mapper.Map(...)
對映 Model/ViewModel 了。

※以上強烈建議採用 AutoMapper 6.2.0 以上版本使用新的方法呼叫。

參考來源:
  1. Getting Started Guide (Official Guildline docs)
  2. Automapper - Mapper already initialized error

沒有留言 :

張貼留言

注意:只有此網誌的成員可以留言。