مقدمه ای بر AutoMapper
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: یک دقیقه

AutoMapper کتابخانه ای ساده و سبک برای نگاشت اطلاعات یک شی به شی دیگر به صورت خودکار هست و...
اگه این پست رو مطالعه کرده باشید یه مشکل امنیتی بنام «Mass Assignment» مطرح شد.برای رفع این مشکل یک روش استفاده از ViewModel بود.
فرض کنید Model ما
 public class User
    {
        public int Id { get; set; }
       
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string UserName { get; set; }

        public string Password { get; set; }

        public bool IsAdmin { get; set; }

        public virtual ICollection<BlogPost> BlogPosts { get; set; }
    }
و ViewModel ما
 public class UserViewModel
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Password { get; set; }
    }
باشه(توجه کنید در واقع من برای View ی مورد نظرم فقط به نام , نام خانوادگی و پسورد نیاز دارم)
برای استفاده UserViewModel بعنوان Model در View ی مورد نظر باید شی UserViewModel رو با اطلاعات شی User مقدار دهی کنیم مثلا با کدی مثل این در کنترلر.
 
public ActionResult Index(int id = 1)
        {
            var user = _userService.GetById(id);
            var userViewModel = new UserViewModel
                {
                    FirstName = user.FirstName,
                    LastName = user.LastName,
                    Password = user.Password
                };

            return View(userViewModel);
        }
رهایی از نوشتن اینجور کدهای تکراری و خسته کننده باعث پیدایش AutoMapper شد...
برای استفاده از AutoMapper از نوگت استفاده میکنیم.
PM> Install-Package AutoMapper
در شروع برنامه نگاشت‌ها رو تعریف میکنم.یک روش ابداعی تعریف نگاشت‌ها در یک کلاس استاتیک و فراخوانی اون تو متد  Application_Start هست.
public static class AutoMapperWebConfiguration
    {

        public static void Configure()
        {
            ConfigureUserMapping();
        }

        private static void ConfigureUserMapping()
        {
            Mapper.CreateMap<User, UserViewModel>();
        }
    }

اولین پارامتر نوع مبدا و دومین پارامتر نوع مقصد هست.
برای انجام نگاشت هم از متد Map استفاده میکنیم.
public ActionResult Index(int id=1)
        {
            var user = _userService.GetById(id);
            var userViewModel=new UserViewModel();
            AutoMapper.Mapper.Map(user, userViewModel);
            
            return View(userViewModel);
        }
همنطور که میبنید با نوشتن چندین خط کد عملیات نگاشت اطلاعات یک شی به شی دیگه انجام شد.
ادامه دارد...
  • #
    ‫۱۲ سال و ۳ ماه قبل، سه‌شنبه ۱۳ تیر ۱۳۹۱، ساعت ۲۲:۰۲
    دمت گرم مدتیه معطل همین مپینگ‌ها به صورت دستی هستم
  • #
    ‫۱۲ سال و ۳ ماه قبل، سه‌شنبه ۱۳ تیر ۱۳۹۱، ساعت ۲۲:۰۳
    سلام
    ممنون،
    راه حل ساده واقعا لذت بخش هست...
  • #
    ‫۱۲ سال و ۳ ماه قبل، چهارشنبه ۱۴ تیر ۱۳۹۱، ساعت ۰۱:۴۳
    تو Compact Framwork از valueinjecter باید استفاده کرد.
  • #
    ‫۱۲ سال و ۳ ماه قبل، چهارشنبه ۱۴ تیر ۱۳۹۱، ساعت ۰۳:۳۲
    خیلی ممنونم ... میشه این سمپل رو ضمیمه کنید؟!
    • #
      ‫۱۲ سال و ۳ ماه قبل، چهارشنبه ۱۴ تیر ۱۳۹۱، ساعت ۱۶:۴۶
      سمپل خاصی نیست کدها رو از یک پروژه کشیدم بیرون...
      تنها قسمتی که تو این پست نذاشتم(و البته نیاز هم نبود) View ش بود.
      @model DotnetDevBlog.Web.Models.UserViewModel
      
      @{
          ViewBag.Title = "Index";
      }
      
      <h2>Index</h2>
      @Html.DisplayForModel()

  • #
    ‫۱۲ سال و ۳ ماه قبل، چهارشنبه ۱۴ تیر ۱۳۹۱، ساعت ۰۴:۱۶
    تشکر بابت معرفی.
    کاربرد این Auto Mapper در اینجور نگاشت‌ها معنی میده فقط؟ یعنی نگاشت یه شیِ جزء به شیِ کل؟ یا مثلا کاربردهایی مثل ORM هم میتواند داشته باشد؟
    • #
      ‫۱۲ سال و ۳ ماه قبل، چهارشنبه ۱۴ تیر ۱۳۹۱، ساعت ۱۳:۵۱
      یکی از مهمترین کاربردهاش نگاشت از یک مدل بزرگ و پیچیده به یک مدل ساده هست که بهش Flattening میگن و کاربردهای دیگه مثلا Projection و... که همنطور که آخر پست گفتم تو پست‌های بعدی تکمیلش میکنم.
      برای مطالعه بیشتر همه به این ویکی مراجعه کنید.

  • #
    ‫۱۱ سال و ۳ ماه قبل، یکشنبه ۲ تیر ۱۳۹۲، ساعت ۲۰:۴۹
    با سلام 
    ممنون از مطلب مفیدتون 
    میخواستم بدونم اگه از چند model بخواهیم استفاده کنیم باید چکار کنیم؟
  • #
    ‫۱۱ سال و ۳ ماه قبل، دوشنبه ۱۰ تیر ۱۳۹۲، ساعت ۱۸:۲۸
    با سلام میخواستم ببینم آیا امکان استفاده از automapper بدین صورت هم وجود داره؟
     public void Edit_news_ajax(News news)
            {
                using (var Context = new ProCamContext())
                {
                    var q=Context.News.Find(news.id);
                    AutoMapper.Mapper.Map(news,q);
                   //NewsRepository.EditNews(news.id, q);
                    Context.SaveChanges();
                }//end news
            }
    با تشکر
    • #
      ‫۱۱ سال و ۳ ماه قبل، دوشنبه ۱۰ تیر ۱۳۹۲، ساعت ۱۹:۰۰
      اگه q از نوع news هست که نیاز ی به AutoMapper  نداری!
      AutoMapper.Mapper.Map(news,q);
      این خط مشکلی نداره

      • #
        ‫۱۱ سال و ۳ ماه قبل، دوشنبه ۱۰ تیر ۱۳۹۲، ساعت ۱۹:۳۵
        من میخوام  محتویات news  رو (که توسط model binding پر شده) رو در سطری از جدولم بریزم (با اون آیدی که با find پیدا کردم جایگزین بشه) اینکار با AutoMapper  امکان پذیر هست؟
        برای اینکار نیاز به create.map هم دارم؟
        با تشکر 
        • #
          ‫۱۱ سال و ۳ ماه قبل، سه‌شنبه ۱۱ تیر ۱۳۹۲، ساعت ۱۵:۵۷
          اگه نوع هاشون متفاوته بله باید Mapper.CreateMap رو تعریف کنی.
  • #
    ‫۷ سال و ۴ ماه قبل، سه‌شنبه ۲۶ اردیبهشت ۱۳۹۶، ساعت ۱۵:۰۶
    از آنجا که این مقاله جز مقالاتی است که به دلیل عنوان مقدمه در آن ارجاع به آن اول صورت میگیرد، این نکته رو اضافه کنم که در نسخه‌های جدیدتر Automapper استفاده از حالت استاتیک مردود اعلام شده و نحوه نوشتن به شکل زیر میباشد:
    var config = new MapperConfiguration(cfg => {
      cfg.CreateMap<Source, Dest>();
    });
    
    IMapper mapper = config.CreateMapper();
    var source = new Source();
    var dest = mapper.Map<Source, Dest>(source);
  • #
    ‫۶ سال و ۱۱ ماه قبل، یکشنبه ۲۳ مهر ۱۳۹۶، ساعت ۰۱:۱۵
    از آنجا که automapper امروز یک جز جدانشدنی از سیستم محسوب میشه برای استفاده از Dot net Core به شکل زیر عمل میکنیم:
    install-package automapper
    از آنجا core شامل پیاده سازی پیش فرض تزریق وابستگی‌ها میباشد کتابخانه دیگری جهت کار تزریق این کتابخانه به پروژه اضافه میکنیم:
    Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
    بعد از اضافه کردن این کتابخانه به  پروژه سرویس جدیدی اضافه میشود که میتوانید آن در startup صدا بزنید:
      using AutoMapper;  
    public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAutoMapper(); }
    حالا یک پروفایل  برای نقل و انتقالی خاص می‌نویسیم:
    public class UserMappingProfile:Profile
        {
            public UserMappingProfile()
            {
                CreateMap<User, UserPost>();
                CreateMap<UserPost,User >()
                    
                    .ForMember(dest=>dest.Username,src=>src.Ignore())
                    .ForMember(dest=>dest.Email,src=>src.Ignore());
            }
        }
    در نهایت به شکل زیر استفاده میشود:
     private readonly IMapper _mapper;
            public UserController(IMapper mapper) 
            {
                _mapper = mapper;
            }
    
     public async Task<UserPost> FindUser(string username)
            {
                var users = await _userServices.GetUser(username);
                var user = _mapper.Map<User,UserPost>(users);
                return user;
            }
    • #
      ‫۵ سال و ۷ ماه قبل، چهارشنبه ۱۰ بهمن ۱۳۹۷، ساعت ۰۳:۳۵
      کجا Profile رو به Automapper معرفی میکنیم؟
      من این روش رو اجرا کردم خطای Configuration not fond میده
      • #
        ‫۵ سال و ۷ ماه قبل، چهارشنبه ۱۰ بهمن ۱۳۹۷، ساعت ۰۳:۵۷
        از این روش استفاده کردم جواب داد
                    var profiles = typeof(UserMappingProfile).Assembly.GetTypes().Where(types => typeof(Profile).IsAssignableFrom(types)).Select(types => (Profile)Activator.CreateInstance(types));
                    services.AddAutoMapper(cfg =>
                    {
                        foreach (var profile in profiles)
                            cfg.AddProfile(profile);
                    });

      • #
        ‫۵ سال و ۷ ماه قبل، چهارشنبه ۱۰ بهمن ۱۳۹۷، ساعت ۰۳:۵۸
         services.AddAutoMapper(typeof(UserMappingProfile).GetTypeInfo().Assembly); // اسکن خودکار یک اسمبلی، اگر پروفایل‌ها در یک اسمبلی دیگر هستند