asp.net-mvc - أين تضع AutoMapper.CreateMaps؟





design-patterns configuration (9)


لأولئك منكم الذين التقيد بما يلي:

  1. باستخدام حاوية ioc
  2. لا تحب كسر مفتوحة لهذا الغرض
  3. لا يعجبك ملف تهيئة أحادي

لقد قمت بعمل تحويلة بين الملفات الشخصية والاستفادة من حاوية ioc الخاصة بي:

تكوين IoC:

public class Automapper : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());

        container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
        {
            Profile[] profiles = k.ResolveAll<Profile>();

            Mapper.Initialize(cfg =>
            {
                foreach (var profile in profiles)
                {
                    cfg.AddProfile(profile);
                }
            });

            profiles.ForEach(k.ReleaseComponent);

            return Mapper.Engine;
        }));
    }
}

مثال التكوين:

public class TagStatusViewModelMappings : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
    }
}

مثال على الاستخدام:

public class TagStatusController : ApiController
{
    private readonly IFooService _service;
    private readonly IMappingEngine _mapper;

    public TagStatusController(IFooService service, IMappingEngine mapper)
    {
        _service = service;
        _mapper = mapper;
    }

    [Route("")]
    public HttpResponseMessage Get()
    {
        var response = _service.GetTagStatus();

        return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response)); 
    }
}

المقايضة هي أنه عليك الرجوع إلى مخطط بواسطة واجهة IMappingEngine بدلا من مخطط ثابت ، ولكن هذا هو الاتفاقية التي يمكنني العيش معها.

أنا أستخدم AutoMapper في ASP.NET MVC . قيل لي أنه يجب أن نقل AutoMapper.CreateMap أي مكان آخر لأن لديهم الكثير من النفقات العامة. لست متأكدًا من كيفية تصميم التطبيق الخاص بي لوضع هذه المكالمات في مكان واحد فقط.

لدي طبقة ويب وطبقة خدمة وطبقة بيانات. كل مشروع من تلقاء نفسها. أنا استخدم Ninject ل DI كل شيء. AutoMapper في كل من طبقات الويب والخدمة.

إذن ما هو إعداد برنامج AutoMapper الخاص ببرنامج CreateMap؟ أين وضعه؟ كيف يمكنك أن نسميها؟




بالإضافة إلى أفضل إجابة ، هناك طريقة جيدة تستخدم Autofac IoC liberary لإضافة بعض الأتمتة. مع هذا يمكنك فقط تعريف ملفات التعريف الخاصة بك بغض النظر عن المبتدئين.

   public static class MapperConfig
    {
        internal static void Configure()
        {

            var myAssembly = Assembly.GetExecutingAssembly();

            var builder = new ContainerBuilder();

            builder.RegisterAssemblyTypes(myAssembly)
                .Where(t => t.IsSubclassOf(typeof(Profile))).As<Profile>();

            var container = builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                var profiles = container.Resolve<IEnumerable<Profile>>();

                foreach (var profile in profiles)
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfile(profile);
                    });                    
                }

            }

        }
    }

واستدعاء هذا السطر في أسلوب Application_Start :

MapperConfig.Configure();

يعرض الرمز أعلاه جميع الطبقات الفرعية للملفات الشخصية وابدأ تشغيلها تلقائيًا.




تحديث: النهج المنشور هنا ليس أكثر صلاحية كما تمت إزالة SelfProfiler اعتبارا من SelfProfiler v2.

أود أن أتخذ نفس النهج مثل Thoai. ولكن يمكنني استخدام SelfProfiler<> فئة SelfProfiler<> لمعالجة الخرائط ، ثم استخدم الدالة Mapper.SelfConfigure لتهيئة.

باستخدام هذا الكائن كمصدر:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public string GetFullName()
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }
}

وهذه كوجهة:

public class UserViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class UserWithAgeViewModel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Age { get; set; }
}

يمكنك إنشاء ملفات التعريف هذه:

public class UserViewModelProfile : SelfProfiler<User,UserViewModel>
{
    protected override void DescribeConfiguration(IMappingExpression<User, UserViewModel> map)
    {
    //This maps by convention, so no configuration needed
    }
}

public class UserWithAgeViewModelProfile : SelfProfiler<User, UserWithAgeViewModel>
{
    protected override void DescribeConfiguration(IMappingExpression<User, UserWithAgeViewModel> map)
    {
    //This map needs a little configuration
        map.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Now.Year - s.BirthDate.Year));
    }
}

للتهيئة في تطبيقك ، قم بإنشاء هذا الفصل

 public class AutoMapperConfiguration
 {
      public static void Initialize()
      {
          Mapper.Initialize(x=>
          {
              x.SelfConfigure(typeof (UserViewModel).Assembly);
              // add assemblies as necessary
          });
      }
 }

أضف هذا السطر إلى ملف global.asax.cs الخاص بك: AutoMapperConfiguration.Initialize()

يمكنك الآن وضع فئات رسم الخرائط الخاصة بك حيث تكون منطقية بالنسبة لك ولا تقلق بشأن فئة رسم أحادية موحد.




يمكنك فعلاً وضعها في أي مكان طالما أن مشروعك على الويب يشير إلى التجميع الذي هو فيه. في وضعك أضعه في طبقة الخدمة حيث يمكن الوصول إليه بواسطة طبقة الويب وطبقة الخدمة وفي وقت لاحق إذا قررت قم بتنفيذ تطبيق وحدة التحكم أو كنت تقوم بعمل مشروع اختبار وحدة ، وستكون تكوين الخرائط متاحًا من تلك المشاريع أيضًا.

في Global.asax ستقوم بالاتصال بالطريقة التي تقوم بتعيين جميع خرائطك. انظر أدناه:

ملف AutoMapperBootStrapper.cs

public static class AutoMapperBootStrapper
{
     public static void BootStrap()
     {  
         AutoMapper.CreateMap<Object1, Object2>();
         // So on...


     }
}

Global.asax على بدء التطبيق

اتصل وحسب

AutoMapperBootStrapper.BootStrap();

الآن قد يجادل بعض الناس ضد هذه الطريقة ينتهك بعض المبادئ الصلبة ، والتي لديهم حجج صحيحة. هنا هم للقراءة.

تكوين Automapper في Bootstrapper ينتهك مبدأ مفتوح مغلق؟




للمبرمجين vb.net باستخدام الإصدار الجديد (5.x) من AutoMapper.

Global.asax.vb:

Public Class MvcApplication
    Inherits System.Web.HttpApplication

    Protected Sub Application_Start()
        AutoMapperConfiguration.Configure()
    End Sub
End Class

AutoMapperConfiguration:

Imports AutoMapper

Module AutoMapperConfiguration
    Public MapperConfiguration As IMapper
    Public Sub Configure()
        Dim config = New MapperConfiguration(
            Sub(cfg)
                cfg.AddProfile(New UserProfile())
                cfg.AddProfile(New PostProfile())
            End Sub)
        MapperConfiguration = config.CreateMapper()
    End Sub
End Module

مظهر:

Public Class UserProfile
    Inherits AutoMapper.Profile
    Protected Overrides Sub Configure()
        Me.CreateMap(Of User, UserViewModel)()
    End Sub
End Class

رسم الخرائط:

Dim ViewUser = MapperConfiguration.Map(Of UserViewModel)(User)



بالنسبة لأولئك الذين (ضائع) باستخدام:

  • WebAPI 2
  • SimpleInjector 3.1
  • AutoMapper 4.2.1 (مع الملفات الشخصية)

وإليك كيفية إدارة دمج AutoMapper في " https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API ". أيضا ، شكر كبير لهذه الإجابة (والسؤال)

1 - إنشاء مجلد في مشروع WebAPI يسمى "ProfileMappers". في هذا المجلد أضع جميع فئات ملفات التعريف الخاصة بي والتي تقوم بإنشاء التعيينات الخاصة بي:

public class EntityToViewModelProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<User, UserViewModel>();
    }

    public override string ProfileName
    {
        get
        {
            return this.GetType().Name;
        }
    }
}

2 - في App_Start الخاص بي ، لدي SimpleInjectorApiInitializer الذي يقوم بتكوين حاوية SimpleInjector الخاصة بي:

public static Container Initialize(HttpConfiguration httpConfig)
{
    var container = new Container();

    container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

    //Register Installers
    Register(container);

    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

    //Verify container
    container.Verify();

    //Set SimpleInjector as the Dependency Resolver for the API
    GlobalConfiguration.Configuration.DependencyResolver =
       new SimpleInjectorWebApiDependencyResolver(container);

    httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

    return container;
}

private static void Register(Container container)
{
     container.Register<ISingleton, Singleton>(Lifestyle.Singleton);

    //Get all my Profiles from the assembly (in my case was the webapi)
    var profiles =  from t in typeof(SimpleInjectorApiInitializer).Assembly.GetTypes()
                    where typeof(Profile).IsAssignableFrom(t)
                    select (Profile)Activator.CreateInstance(t);

    //add all profiles found to the MapperConfiguration
    var config = new MapperConfiguration(cfg =>
    {
        foreach (var profile in profiles)
        {
            cfg.AddProfile(profile);
        }
    });

    //Register IMapper instance in the container.
    container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));

    //If you need the config for LinqProjections, inject also the config
    //container.RegisterSingleton<MapperConfiguration>(config);
}

3 - Startup.cs

//Just call the Initialize method on the SimpleInjector class above
var container = SimpleInjectorApiInitializer.Initialize(configuration);

4 - ثم ، في وحدة التحكم الخاصة بك فقط حقن كما عادة واجهة IMAPER:

private readonly IMapper mapper;

public AccountController( IMapper mapper)
{
    this.mapper = mapper;
}

//Using..
var userEntity = mapper.Map<UserViewModel, User>(entity);



إن وضع منطق المنطق في موقع واحد ليس ممارسة جيدة بالنسبة لي. لأن فئة رسم الخرائط ستكون كبيرة للغاية وصعبة للغاية.

أوصي بوضع مواد رسم الخرائط مع فئة ViewModel في ملف cs نفسه. يمكنك التنقل بسهولة إلى تعريف التعيين الذي تريده باتباع هذه الاتفاقية. علاوة على ذلك ، أثناء إنشاء فئة التعيين ، يمكنك الرجوع إلى خصائص ViewModel بشكل أسرع لأنها موجودة في نفس الملف.

لذا ستبدو فئة نموذج المشاهدة لديك كما يلي:

public class UserViewModel
{
    public ObjectId Id { get; set; }

    public string Firstname { get; set; }

    public string Lastname { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }
}

public class UserViewModelMapping : IBootStrapper // Whatever
{
    public void Start()
    {
        Mapper.CreateMap<User, UserViewModel>();
    }
}



لا يهم ، طالما أنها فئة ثابتة. كل شيء عن الاتفاقية .

لدينا اتفاقية هي أن كل "طبقة" (الويب ، الخدمات ، البيانات) تحتوي على ملف واحد يسمى AutoMapperXConfiguration.cs ، مع طريقة واحدة تسمى Configure() ، حيث X هي الطبقة.

استدعاء الأسلوب Configure() ثم أساليب private لكل منطقة.

في ما يلي مثال على تهيئة طبقة الويب لدينا:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      ConfigureUserMapping();
      ConfigurePostMapping();
   }

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

   // ... etc
}

ننشئ طريقة لكل "تجميع" (مستخدم ، مشاركة) ، لذلك يتم فصل الأشياء بشكل جيد.

ثم لديك Global.asax :

AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc

إنه نوع من "واجهة الكلمات" - لا يمكن تطبيقه ، لكنك تتوقعه ، لذا يمكنك أن تكتب (و refactor) إذا لزم الأمر.

تصحيح:

فقط فكرت في أن أذكر أنني الآن استخدام profiles AutoMapper ، لذلك يصبح المثال أعلاه:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      Mapper.Initialize(cfg =>
      {
        cfg.AddProfile(new UserProfile());
        cfg.AddProfile(new PostProfile());
      });
   }
}

public class UserProfile : Profile
{
    protected override void Configure()
    {
         Mapper.CreateMap<User,UserViewModel>();
    }
}

أكثر نظافة / أكثر قوة.




يوفر لك MVC طريقة OnAuthorize التي يتم تعليقها من فئات وحدة التحكم الخاصة بك. أو يمكنك استخدام فلتر إجراء مخصص لإجراء التفويض. يجعل MVC من السهل القيام به. لقد نشرت منشورًا بالبريد عن هذا هنا. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0







asp.net-mvc design-patterns configuration automapper