0
votes

I was looking through some code in an ASP.NET Core application and I noticed the repository services are added with AddScope, while in mine i am using addTransient. I have looked about the difference but i still do not understand how would this change my actual applicationn.

this is the code i am using and the services i use on pages for Get / Post actions.

    services.AddHttpContextAccessor();
    services.AddSingleton<IFileProvider>(new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files")));
    services.AddTransient<IAuthorizationHandler, HasArranqueActivoHandler>();
    services.AddTransient<IAuthorizationHandler, HasArranqueInactivoHandler>();
    services.AddTransient<IAuthorizationHandler, IsParagemNotOnGoingHandler>();
    services.AddTransient<IAuthorizationHandler, IsParagemOnGoingHandler>();


    services.AddTransient<Services.Interfaces.IUserService, Services.UserService>();


        #region AreaProduction
        services.AddTransient<Production.Interfaces.IComponenteService, Production.ComponenteService>();
        services.AddTransient<Production.Interfaces.IReferenciaService, Production.ReferenciaService>();
        services.AddTransient<Production.Interfaces.IProducaoRegistoService, Production.ProducaoRegistoService>();
        services.AddTransient<Production.Interfaces.IParagemService, Production.ParagemService>();
        services.AddTransient<Production.Interfaces.ICelulaService, Production.CelulaService>();
        services.AddTransient<Production.Interfaces.IUapService, Production.UapService>();
        services.AddTransient<Production.Interfaces.ICelulaTipoService, CelulaTipoService>();
        services.AddTransient<Production.Interfaces.IMatrizService, MatrizService>();
        services.AddTransient<Production.Interfaces.IOperadorService, Production.OperadorService>();
        services.AddTransient<Production.Interfaces.IEtiquetaService, Production.EtiquetaService>();
        services.AddTransient<Production.Interfaces.IPokayokeService, Production.PokayokeService>();
        services.AddTransient<Production.Interfaces.IGeometriaService, Production.GeometriaService>();
        services.AddTransient<Production.Interfaces.IEmpregadoService, Production.EmpregadoService>();
        services.AddTransient<Production.Interfaces.IPecaService, Production.PecaService>();
        services.AddTransient<Production.Interfaces.IDefeitoService, Production.DefeitoService>();
        #endregion

        #region AreaRobotics
        services.AddTransient<Robotics.Interfaces.ITurnoService, Robotics.TurnoService>();
        services.AddTransient<Robotics.Interfaces.ICelulaService, Robotics.CelulaService>();
        services.AddTransient<Robotics.Interfaces.ICheckListService, Robotics.CheckListService>();
        services.AddTransient<Robotics.Interfaces.IProducaoService, Robotics.ProducaoService>();
        services.AddTransient<Robotics.Interfaces.IReferenciaService, Robotics.ReferenciaService>();
        services.AddTransient<Robotics.Interfaces.IDefeitoService, Robotics.DefeitoService>();
        services.AddTransient<Robotics.Interfaces.IDefeitoCodigoService, Robotics.DefeitoCodigoService>();
        services.AddTransient<Robotics.Interfaces.IParagemService, Robotics.ParagemService>();
        services.AddTransient<Robotics.Interfaces.IParagemCodigoService, Robotics.ParagemCodigoService>();
        services.AddTransient<Robotics.Interfaces.IPecaService, Robotics.PecaService>();
        services.AddTransient<Robotics.Interfaces.IUapService, Robotics.UapService>();
        services.AddTransient<Robotics.Interfaces.IOperadorService, Robotics.OperadorService>();
        #endregion

    #region AreaRobotics
    services.AddTransient<Areas.Robotics.Services.Interfaces.ITurnoService, Areas.Robotics.Services.TurnoService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.ICelulaService, Areas.Robotics.Services.CelulaService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.ICheckListService, Areas.Robotics.Services.CheckListService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IProducaoService, Areas.Robotics.Services.ProducaoService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IReferenciaService, Areas.Robotics.Services.ReferenciaService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IDefeitoService, Areas.Robotics.Services.DefeitoService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IDefeitoCodigoService, Areas.Robotics.Services.DefeitoCodigoService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IParagemService, Areas.Robotics.Services.ParagemService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IParagemCodigoService, Areas.Robotics.Services.ParagemCodigoService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IPecaService, Areas.Robotics.Services.PecaService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IUapService, Areas.Robotics.Services.UapService>();
    services.AddTransient<Areas.Robotics.Services.Interfaces.IOperadorService, Areas.Robotics.Services.OperadorService>();
    #endregion

I would like to know what the impact of changing from AddTransient to AddScoped for my services in my application

Here is a simple Create page with many transient Services to populate select lists

    public class CreateModel : PageModel
    {
        private readonly IMatrizService _matrizService;
        private readonly IReferenciaService _referenciaService;
        private readonly IUapService _uapService;
        private readonly ICelulaTipoService _celulaTipoService;
        private readonly ICelulaService _celulaService;
        private readonly IToastNotification _toastNotification;
        private readonly ILogger<CreateModel> _logger;

        public CreateModel(IToastNotification toastNotification, 
                           ICelulaTipoService celulaTipoService,
                           ICelulaService celulaService,
                           IUapService uapService,
                           IReferenciaService referenciaService,
                           IMatrizService matrizService,
                           ILogger<CreateModel> logger)
        {
            _matrizService = matrizService;
            _referenciaService = referenciaService;
            _uapService = uapService;
            _celulaTipoService = celulaTipoService;
            _celulaService = celulaService;
            _toastNotification = toastNotification;
            _logger = logger;
        }

        [BindProperty]
        public Matriz Matriz { get; set; }

        public void OnGet()
        {
            ViewData["CelulaId"] = new SelectList(_celulaService.GetAllFromCache(), "Id", "Nome");
            ViewData["UAPId"] = new SelectList(_uapService.GetAllFromCache(), "Id", "Nome");
            ViewData["ReferenciaId"] = new SelectList(_referenciaService.GetAllFromCache(), "Id", "Nome");
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                ViewData["CelulaId"] = new SelectList(_celulaService.GetAllFromCache(), "Id", "Nome");
                ViewData["UAPId"] = new SelectList(_uapService.GetAllFromCache(), "Id", "Nome");
                ViewData["ReferenciaId"] = new SelectList(_referenciaService.GetAllFromCache(), "Id", "Nome");

                _toastNotification.AddErrorToastMessage("Falha ao criar Matriz. Verifique os dados novamente.");

                return Page();
            }

            _matrizService.Add(Matriz);

            try
            {
                await _matrizService.SaveChangesAsync();
            }
            catch (DbUpdateException e)
            {
                //This either returns a error string, or null if it can’t handle that error
                _logger.LogError($@"Falha ao Adicionar Referência
                                    Area: Administration
                                    Page: Account/Robotics/Referencias/Create
                                    Error: {e.InnerException}");

                _toastNotification.AddErrorToastMessage($"A Matriz com a Referência {Matriz.Referencia.Nome} já existe");

                return Page();
            }

            _toastNotification.AddSuccessToastMessage("Matriz criada com sucesso.");

            return RedirectToPage("./Index");
        }
    }

Most of my services are usually the same with crud methods

  public interface IUserService
    {
        IQueryable<User> GetAll();
        User GetById(int id);
        void Add(User user);
        void Update(User user);
        int AddAndSave(User user);
        int SaveChanges();
        int UpdateDateAndSave(User user);
        User GetByUsername(string username);
    }

public class UserService : IUserService
{
    private readonly DatabaseContext _context;

    public UserService(DatabaseContext context)
    {
        _context = context;
    }

    public void Add(User user)
    {
        _context.Users.Add(user);
    }

    public int AddAndSave(User user)
    {
        _context.Users.Add(user);
        return _context.SaveChanges();
    }

    public IQueryable<User> GetAll()
    {
        return _context.Users.AsNoTracking();
    }

    public User GetById(int id)
    {
        return _context.Users.Find(id);
    }

    public User GetByUsername(string username)
    {
        return _context.Users
            .Include(u => u.Colaborador)
            .Include(u => u.UserRoles)
            .ThenInclude(ur => ur.Role)
            .AsNoTracking()
            .FirstOrDefault(u => u.Username == username);
    }

    public int SaveChanges()
    {
        return _context.SaveChanges();
    }

    public void Update(User user)
    {
        _context.Users.Update(user);
    }

    public int UpdateDateAndSave(User user)
    {
         user.DataSessao = DateTime.Now;
        _context.Users.Attach(user);
        _context.Entry(user).Property(u => u.DataSessao).IsModified = true;
        return _context.SaveChanges();

    }
}
1
From the docs: Scoped lifetime services (AddScoped) are created once per client request (connection). Transient lifetime services (AddTransient) are created each time they're requested from the service container. What is your actual question?mm8
It's not really possible to assess how that change would impact your entire application without knowing the details of each dependency that is being registered/implemented. But knowing the difference between Scoped vs. Transient lifestyles (based on the previous comments), you should be able to look at your dependencies and determine how to configure their lifestyle appropriately. Maybe providing a specific example with just one of your services would better scope the questiondevNull
Minor quibble, can't you add using Areas.Robotics.Services; to this file, it would make the code a little more readable :)DavidG
It's still not possible for us to help with this example. The key thing that you need to decide is what happens with the dependencies and how they interact with each other. For example, if two dependencies both take a third dependency, does that third item nee to be a distinct object or can it be shared.DavidG

1 Answers

3
votes

how would this impact my application overall if i started using AddScoped for services

We would have to see a service (or, actually, all of them) to be sure.

But most likely it won't matter.

The thing to look out for is the state inside your services. Usually there is no state, and then Scoped or Transient won't matter.

So, do any of your service implementations have fields (other than injected services) ?

When they are currently registered as Transient then they are most likely stateless. And that makes the change to Scoped safe but still unnecessary.

Moving the other way (from Scoped to Transient) would require much more investigation.