0
votes

So I am trying to implement my IoC that linked my DBContext class as a Dependency Injection as a ServiceProvider.

I am getting this error when it comes to starting my ASP Core app So my question is; What am i doing wrong, i tried googling it but i can't really find a solution that way. I tried asking some of the more elite programmers on my campus but they haven ot specifically worked with ASPnet Core so they don't know if it's because of my casting or because of ASPnet Core

Application startup exception: System.InvalidCastException: Unable to cast object of type 'Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope' to type 'Microsoft.Extensions.DependencyInjection.ServiceProvider'. at Spackk.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider) in F:\Developement\SpackkMVC\Spackk\Spackk\Startup.cs:line 44 --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder app) at Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder builder) at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6] Application startup exception System.InvalidCastException: Unable to cast object of type 'Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope' to type 'Microsoft.Extensions.DependencyInjection.ServiceProvider'. at Spackk.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider) in F:\Developement\SpackkMVC\Spackk\Spackk\Startup.cs:line 44 --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder app) at Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.b__0(IApplicationBuilder builder) at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

This is how the code looks in Startup

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace Spackk
{
    public class Startup
    {
        private readonly string UserGuid = Guid.NewGuid().ToString();
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }


        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //add ApplicationDbContext to DI
            services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer("Server=.;Database=SpackkDB;Trusted_Connection;MultipleActiveResultSets=true"));
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
        {

            //Store isntance of the DI Service provider so our application can access iot anywhere
            IocContainer.Provider = (ServiceProvider)serviceProvider;
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

This is where the the class where the error is happening;

For context i will also provide the IoC/IoCContainer/ApplicationDbContext and the model;

using System.ComponentModel.DataAnnotations;

namespace Spackk.Models
{
    public class UserModel
    {
        [Key]
        public string Id { get; set; }
        [Required]
        [MaxLength(255)]
        [Display(Name = "UserName")]
        public string Username { get; set; }
        [Required]
        [MaxLength(255)]
        [Display(Name = "DisplayName")]
        public string DisplayName { get; set; }
        [Required]
        [MaxLength(255)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
        [Required]
        [MaxLength(255)]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }
}

ApplicationDbContext

using Microsoft.EntityFrameworkCore;
using Spackk.Models;
using System;
using System.Linq;

namespace Spackk
{
    public class ApplicationDbContext : DbContext
    {
        public string Id { get; set; } = Guid.NewGuid().ToString("N");
        public DbSet<UserModel> Users { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="options"></param>
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder mBuilder)
        {
            base.OnModelCreating(mBuilder);

            mBuilder.Entity<UserModel>().HasIndex(a => a.DisplayName);
        }
    }
}

IoC/IoCContainer

using Microsoft.Extensions.DependencyInjection;

namespace Spackk
{
    public class IoC
    {

        /// <summary>
        /// The scoped instance of the <see cref="ApplicationDbContext()"/>
        /// </summary>
        public static ApplicationDbContext ApplicationDbContext => IocContainer.Provider.GetService<ApplicationDbContext>();
    }
    /// <summary>
    /// the dependenc injection container making use of the built in .Net Core service provider
    /// </summary>
    public class IocContainer
    {
        /// <summary>
        /// the service provider for the is application
        /// </summary>
        public static ServiceProvider Provider { get; set; }
    }
}
1
This approach in the tutorial is shown to make you understand how the ApplicationDbContext works and what you can do with it. He never says this is the preferred way of doing this and it is not. Using dependency injection is much better. Additionally, I got the same error, then concluded that they probably changed something and it is actually not that important since no one should ever use it this way anyways. - M. Azyoksul

1 Answers

4
votes

Well, the error is explicit and it's fairly obviously failing on this line:

IocContainer.Provider = (ServiceProvider)serviceProvider;

serviceProvider there is an instance of ServiceProviderEngineScope, which cannot be cast to ServiceProvider. Just because they both implement IServiceProvider doesn't mean that you can cast from one to the other implementation.

However, this entire thing is just wrong. Like WRONG. I wish I could put more emphasis on that. Imagine a 20-ft billboard with flashing LEDs in bright neon red. Either use DI or don't, but it's completely wrong to just stuff some static class with some dependency-injected object and then expect to be able to just use that wherever you like.