IServiceProvider in ASP.NET Core

后端 未结 7 1812
被撕碎了的回忆
被撕碎了的回忆 2021-02-02 08:02

I starting to learn changes in ASP.NET 5(vNext) and cannot find how to get IServiceProvider, for example in \"Model\"\'s method

public class Entity 
{
     publ         


        
相关标签:
7条回答
  • 2021-02-02 08:26

    I think the OP is getting confused. Entities should be as “thin” as possible. They should try not to contain logic, and or external references other than navigation properties. Look up some common patterns like repository pattern which helps to abstract your logic away from the entities themselves

    0 讨论(0)
  • 2021-02-02 08:28

    use GetRequiredService instead of GetService, like the example on ASP.NET Core tutorials ( https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql )

    documentation on the method:

    https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_

    using Microsoft.Extensions.DependencyInjection;
    
          using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
    
    0 讨论(0)
  • 2021-02-02 08:28

    Do not use GetService()

    The difference between GetService and GetRequiredService is related with exception.

    GetService() returns null if a service does not exist. GetRequiredService() will throw exception.

    public static class ServiceProviderServiceExtensions
    {
        public static T GetService<T>(this IServiceProvider provider)
        {
            return (T)provider.GetService(typeof(T));
        }
    
        public static T GetRequiredService<T>(this IServiceProvider provider)
        {
            return (T)provider.GetRequiredService(typeof(T));
        }
    }
    
    0 讨论(0)
  • 2021-02-02 08:30

    Generally you want to have the DI do its thing and inject that for you:

    public class Entity 
    {
        private readonly IDataContext dbContext;
    
        // The DI will auto inject this for you
        public class Entity(IDataContext dbContext)
        {
            this.dbContext = dbContext;
        }
    
         public void DoSomething()
         {
             // dbContext is already populated for you
             var something = dbContext.Somethings.First();
         }
    }
    

    However, Entity would have to be automatically instantiated for you... like a Controller or a ViewComponent. If you need to manually instantiate this from a place where this dbContext is not available to you, then you can do this:

    using Microsoft.Extensions.PlatformAbstractions;
    
    public class Entity 
    {
        private readonly IDataContext dbContext;
    
        public class Entity()
        {
            this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider
                                .GetService(typeof(IDataContext));
        }
    
         public void DoSomething()
         {
             var something = dbContext.Somethings.First();
         }
    }
    

    But just to emphasize, this is considered an anti-pattern and should be avoided unless absolutely necessary. And... at the risk of making some pattern people really upset... if all else fails, you can add a static IContainer in a helper class or something and assign it in your StartUp class in the ConfigureServices method: MyHelper.DIContainer = builder.Build(); And this is a really ugly way to do it, but sometimes you just need to get it working.

    0 讨论(0)
  • 2021-02-02 08:31

    Instead of getting your service inline, try injecting it into the constructor.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient(typeof(DataContext));
        }
    }
    
    public class Entity
    {
        private DataContext _context;
    
        public Entity(DataContext context)
        {
            _context = context;
        }
    
        public void DoSomething()
        {
            // use _context here
        }
    }
    

    I also suggest reading up on what AddTransient means, as it will have a significant impact on how your application shares instances of DbContext. This is a pattern called Dependency Injection. It takes a while to get used to, but you will never want to go back once you do.

    0 讨论(0)
  • 2021-02-02 08:35

    I don't think it is a good idea for an entity (or a model) to have access to any service.

    Controllers, on the other hand, do have access to any registered service in their constructors, and you don't have to worry about it.

    public class NotifyController : Controller
    {
        private static IEmailSender emailSender = null;
        protected static ISessionService session = null;
        protected static IMyContext dbContext = null;
        protected static IHostingEnvironment hostingEnvironment = null;
    
        public NotifyController(
                    IEmailSender mailSenderService,
                    IMyContext context,
                    IHostingEnvironment env,
                    ISessionService sessionContext)
        {
            emailSender = mailSenderService;
            dbContext = context;
            hostingEnvironment = env;
            session = sessionContext;
        }
    }
    
    0 讨论(0)
提交回复
热议问题