2017-09-14 16 views
5

J'ai vu quelques-uns des exemples similaires sur SO à ce sujet, mais je ne connais pas assez la langue pour voir ce que je fais mal. J'ai bricolé une démo pour en savoir plus mais j'ai du mal à ensemencer ma base de données.base de données de base ASP.NET Core 2

Je reçois l'erreur suivante:

InvalidOperationException: Cannot resolve scoped service 'demoApp.Models.AppDbContext' from root provider.

Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, ServiceProvider serviceProvider)

Voici les trois dossiers en question:

Modèles/AppDbContext.cs

public class AppDbContext : DbContext 
{ 
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) 
    { 

    } 
    public DbSet<Product> Products{ get; set; } 
    public DbSet<Category> Categories { get; set; } 
} 

Modèles/DBInitializer.cs

public static class DbInitializer 
{ 
    public static void Seed(IApplicationBuilder applicationBuilder) 
    { 
     //I'm bombing here 
     AppDbContext context = applicationBuilder.ApplicationServices.GetRequiredService<AppDbContext>(); 

     if (!context.Products.Any()) 
     { 
      // Add range of products 
     } 

     context.SaveChanges(); 
    } 

    private static Dictionary<string, Category> _categories; 
    public static Dictionary<string, Category> Categories 
    { 
     get 
     { 
      if (_categories == null) 
      { 
       // Add categories... 
      } 

      return _categories; 
     } 
    } 
} 

Startup.cs

public Startup(IConfiguration configuration) 
{ 
    Configuration = configuration; 
} 

public IConfiguration Configuration { get; } 

public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddTransient<ICategoryRepository, CategoryRepository>(); 
    services.AddTransient<IProductRepository, ProductRepository>(); 

    services.AddDbContext<AppDbContext>(options => 
     options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 

    services.AddMvc(); 
} 

public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
{ 
    if (env.IsDevelopment()) 
    { 
     app.UseDeveloperExceptionPage(); 
     app.UseBrowserLink(); 
     app.UseStatusCodePages(); 

     // Kersplat! 
     DbInitializer.Seed(app); 
    } 
    else ... 

    app.UseStaticFiles(); 
    app.UseMvc(routes => {...}); 
} 

Quelqu'un peut-il aider à expliquer ce que je fais mal et comment remédier à la situation?

Répondre

11

Dans ASP.NET Core 2.0, les modifications suivantes sont recommandées. (L'amorçage dans startup.cs fonctionne pour Core 1.x. Pour 2.0, allez dans Program.cs, modifiez la méthode Main pour faire ce qui suit au démarrage de l'application: Récupère une instance de contexte de base de données du conteneur d'injection de dépendance Appelez la méthode seed , en lui passant le contexte. Éliminer le contexte lorsque la méthode des semences est fait. (Voici un exemple à partir du site Microsoft. https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro)

public static void Main(string[] args) 
{ 
var host = BuildWebHost(args); 

using (var scope = host.Services.CreateScope()) 
{ 
    var services = scope.ServiceProvider; 
    try 
    { 
     var context = services.GetRequiredService<yourDBContext>(); 
     DbInitializer.Seed(context);//<---Do your seeding here 
    } 
    catch (Exception ex) 
    { 
     var logger = services.GetRequiredService<ILogger<Program>>(); 
     logger.LogError(ex, "An error occurred while seeding the database."); 
    } 
} 

host.Run(); 
} 
+0

Pourquoi modifier 'Main'? Y at-il une référence où il est mentionné que cela est préférable? –

+1

I Il le mentionne dans l'article lié juste en dessous du code ci-dessus. "Dans les tutoriels plus anciens, vous pouvez voir un code similaire dans la méthode Configure dans Startup.cs. Nous vous recommandons d'utiliser la méthode Configure uniquement pour configurer le pipeline de requête.Le code de démarrage de l'application appartient à la méthode Main." – palehorse

+0

NB: L'instruction using suivante doit être disponible pour que la méthode CreateScope soit disponible: 'using Microsoft.Extensions.DependencyInjection;'. – JohnLBevan

2

Mise à jour De réponse originale:

Pour .NET Core 2.0, Vérifiez this answer à la place

Réponse d'origine:

Je ne suis pas expert en Core .NET soit, mais pourrait être votre solution.

En DBInitializer.cs

public static void Seed(IApplicationBuilder applicationBuilder) 
    { 
     using (var serviceScope = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>() 
       .CreateScope()) 
     { 
      AppDbContext context = serviceScope.ServiceProvider.GetService<AppDbContext>(); 

      if (!context.Products.Any()) 
      { 
       // Seed Here 
      } 

      context.SaveChanges(); 
     } 
    } 

L'erreur suggère que le contexte devrait être scope.

En outre, si vous ne l'avez pas déjà fait, jetez un oeil à la doc Introduction to Dependency Injection in ASP.NET Core, mais plus précisément, la section Service Lifetimes and Registration Options.

+0

Je rediffusé les migrations, mis à jour la base de données et la base de données semé comme prévu J'apprécie énormément les liens que vous m'avez fournis Merci beaucoup – forcequitIO