Использование статического автомаппера в практиках производительности C # asp.net - PullRequest
0 голосов
/ 17 мая 2018

Заранее прошу прощения, если на этот вопрос уже был дан ответ где-то еще; Но я нашел много смешанных результатов по этому вопросу.

Я использую:

  • .net Framework 4.6.1
  • Microsoft.AspNet.Mvc 5.2.6
  • AutoMapper 6.2.2
  • EntityFramework 6.2.0

Я довольно новичок в ASP.net и C #, и в последнее время я стал поклонником пакета AutoMapper. Я в основном использовал его для преобразования моих сущностей, которые я получаю из моих ApplicationDbContext в мои DTO (объекты передачи данных) или ViewModel.

Теперь я использую эту настройку в моих приложениях для инициализации и использования Mapper в моих Controller:

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        Mapper.Initialize(AutoMapperConfiguration.Configure);

        // Other configuration for MVC application...
    }
}

AutoMapperConfiguration.cs

public static class AutoMapperConfiguration
{
    public static void Configure(IMapperConfigurationExpression config)
    {
        config.CreateMap<Post, Post.DetailsViewModel>().ForMember(post => post.CanEdit, cfg => cfg.ResolveUsing((src, dst, arg3, context) => context.Options.Items["UserId"]?.ToString() == src.UserId));
    }
}

PostsController.cs и Post.cs

public class PostsController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    public ActionResult Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        Post post = db.Posts.Find(id);

        if (post == null)
        {
            return HttpNotFound();
        }

        return View(Mapper.Map<Post.DetailsViewModel>(post, options => options.Items["UserId"] = User.Identity?.GetUserId()));
    }
}


// Post.cs

public class Post
{
    public int Id { get; set; }

    public string UserId { get; set; }

    public virtual ApplicationUser User { get; set; }

    public string Title { get; set; }

    public string Content { get; set; }

    public DateTime PostedAt { get; set; } = DateTime.Now;

    public class DetailsViewModel
    {
        public int Id { get; set; }

        public string UserId { get; set; }

        public ApplicationUser User { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        /// <summary>
        /// A value indicating whether the current logged in user can edit the model
        /// </summary>
        public bool CanEdit { get; set; }

        public DateTime PostedAt { get; set; }
    }
}

Сводная информация по коду

Я настраиваю Mapper в статическом классе (AutoMapperConfiguration), который содержит метод Config, который вызывается из файла Global.asax.cs и отображает необходимые классы.

Затем в моем Controller я использую статический метод Mapper.Map, чтобы сопоставить мой Post с DetailsViewModel.

Вопрос

Как это использование AutoMapper (статическим методом Mapper.Map) влияет на производительность, и есть ли лучший способ сделать это?

Некоторые уточнения:

Например: что если я получу 100 запросов в секунду на разных действиях контроллера; Насколько я знаю, каждый запрос будет иметь отдельный поток, но будет иметь доступ к той же памяти для метода Mapper.Map (если я прав). Что, насколько мне известно, означает, что на производительность будет оказано серьезное влияние.

Вопрос, который я уже рассматривал, но получил смешанные результаты:

Нестатические AutoMapper и ASP.NET MVC -> Где разместить AutoMapper.CreateMaps?

Пожалуйста, поправьте меня, если я ошибаюсь.

Ответы [ 2 ]

0 голосов
/ 15 мая 2019

Не знаю, поможет ли это вам, но я обновил AutoMapper до версии 8.1.0, и производительность стала лучше.Я видел, что производительность была исправлена ​​в версии 7.0.0, но в последней версии может быть лучше.Зависит от вашей реализации, влияние обновления минимально.

0 голосов
/ 17 мая 2018

Как это использование AutoMapper (через статический метод Mapper.Map) влияет на производительность, и есть ли лучший способ сделать это?

Правильно ли вы используете AutoMapper.Инициализация при запуске приложения - это лучшая практика.Вызывая Mapper.Initialize, вы инициализируете маппер, который является статическим экземпляром интерфейса IMapper (доступ через статическое свойство Mapper.Instance).При использовании статических членов класса Mapper вы имеете дело с Mapper.Instance, и это один и тот же экземпляр для всех объектов в одном и том же AppDomain.Вы не будете влиять на производительность до тех пор, пока вы используете один и тот же AppDomain и не занимает много времени в вашей конфигурации сопоставления (кто-то может поместить некоторую бизнес-логику или отнимающую много времени логику в AfterMap, BeforeMap, ResolveUsing, MapFrom и т. Д.).

Что если я получу 100 запросов в секунду на различные действия контроллера;Насколько я знаю, каждый запрос будет иметь отдельный поток, но будет иметь доступ к той же памяти для метода Mapper.Map (если я правильно).Что, насколько мне известно, означает, что на производительность будет оказано серьезное влияние.

Ваше приложение использует один экземпляр AppDomain, каждый запрос получит новый поток, но этот поток будет выполняться в том же AppDomainэто запустило ваше приложение, которое выполнило метод Application_Start, и, наконец, вы получите тот же экземпляр Mapper.Instance, поэтому план вашей конфигурации будет скомпилирован и кэширован только при поступлении первого запроса.Будет затронут только первый запрос, а не следующий.Другие запросы будут использовать план конфигурации из кэша.Так что никакого влияния на производительность не будет, если вы находитесь в том же AppDomain и не используете трудоемкую логику в пользовательской альтернативе сопоставления, которую позволяет AutoMapper.

Кроме того, AutoMapper поставляется с некоторыми конфигурациями, которые можно активировать или деактивировать и повысить производительность.

Явная компиляция

Как я уже говорил, первый запрос, использующий отображение, скомпилирует вашплан конфигурации.Как говорится в документации AutoMapper :

Поскольку компиляция выражений может быть немного ресурсоемкой, AutoMapper лениво компилирует планы карты типов на первой карте.Однако такое поведение не всегда желательно, поэтому вы можете указать AutoMapper скомпилировать его сопоставления напрямую.Для нескольких сотен сопоставлений это может занять пару секунд.

Вы можете явно составить план, выполнив это сразу после настройки сопоставления:

Mapper.Configuration.CompileMappings();

Я использую этои объединить его с «прогревом» приложения, когда мое приложение запускается автоматически вместо ожидания первого запроса на сопоставление и компилирует план моей конфигурации.Вы можете посмотреть этот ответ о том, как включить эту функцию.

Встроенное отображение

С 6.2.0 AutoMapper поставляется с новой функцией, которая называется встроенное отображение , которое позволяет создавать карту типов на лету, а не настраивать их с помощью метода Mapper.Initialize.Поскольку встроенное отображение создается на лету, поэтому они компилируются в это время, поэтому выигрыш, который вы ищете в явном виде при составлении плана, не очень помогает.Итак, что я делаю в своих проектах, я деактивирую эту функцию, чтобы никто не мог ею воспользоваться.Чтобы отключить его, вы делаете это:

cfg.CreateMissingTypeMaps = false;

Редактировать 26/02/2019

Создатель AutoMapper только что добавил запись в блоге сегодня (26/02/2019) о Правила использования AutoMapper .Необходимо прочитать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...