1

I am trying to migrate an app to Core 2.0 from a framework project. The problem I am running into Is very Similar to this one, but I am trying to use DI. I created a sample project in line with that problem but using a view model similar to how I am using it in my project. I have been trying to figure out what I'm doing wrong to over a day so hopefully someone on here can help.

In case It's helpful code on github

After doing some Research, I changed the way my application was using my view model based on the comments in this post and started using the Repository Pattern. I updated the git hub example to reflect my changes in case it would help anyone.

ApplicationDbContext.cs

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Gig> Gigs { get; set; }
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }

    public DbSet<gigs2.Models.Gig> Gig { get; set; }
}

GigsController.cs

public class GigsController : Controller
{
    // GET: Gigs
    public ActionResult Index()
    {
        GigsViewModel vm = new GigsViewModel();
        vm.Get();
        return View(vm);
    }
}

I am erroring out on new GigsViewModel(); it says because I need to pass options to the ApplicationDbContext

There is no argument given that corresponds to the required formal parameter 'options' of 'ApplicationDbContext.ApplicationDbContext(DbContextOptions)'

GigsViewModels.cs

 public class GigsViewModel
{
    private ApplicationDbContext _context;

    public GigsViewModel(ApplicationDbContext context) {
        _context = context;

    }
    public List<GigViewModel> Gigs { get; set; }

    public void Get()
    {
        Gigs = _context.Gigs.Select(g => new GigViewModel {
            Id = g.Id,
            Date = g.Date,
            Time = g.Time,
            Venue = g.Venue
        }).ToList();
    }
}

startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-/=?^_`{|}~.@ ";
            options.User.RequireUniqueEmail = false;
            options.Password.RequireDigit = false;
            options.Password.RequiredLength = 4;
            options.Password.RequireDigit = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireLowercase = false;
        })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        services.AddScoped<UserManager<ApplicationUser>, ApplicationUserManager>();
        services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager<ApplicationUser>>();
        services.Configure<Configuration.cofAuthSettings>(Configuration.GetSection("cofAuthSettings"));


        // Add application services.
        services.AddTransient<IEmailSender, EmailSender>();

        services.AddMvc();
    }
  • 1
    I would argue your `GigsViewModel` is no longer a [view model](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) when you ask it to look itself up on a database. In any case, `GigsViewModel` is just a class and yes you can inject a dependency with a DI container. But you are _newing_ the class yourself instead of asking the DI container for an instance. But this is moot -- Just instantiate and return the model yourself. You don't need the DI container to provide an instance for your view model class(es). – Jasen Aug 19 '17 at 20:16

1 Answers1

1

Add a constructor to your GigsController class which accepts an instance of your GigsViewModel. This will allow the IoC container to construct the dependency tree (instead of creating it yourself like you are doing at the moment.

Something like this should work:

private readonly GigsViewModel _gigsViewModel;

public GigsController(GigsViewModel gigsViewModel)
{
    _gigsViewModel = gigsViewModel;
}

// GET: Gigs
public ActionResult Index()
{
    _gigsViewModel.Get();
    return View(_gigsViewModel);
}
Maurits van Beusekom
  • 5,579
  • 3
  • 21
  • 35
  • Well that got me past that but when I test, I now get this error ""InvalidOperationException: Unable to resolve service for type 'gigs2.Models.GigsViewModels.GigsViewModel' while attempting to activate 'gigs2.Controllers.GigsController'." I think it may be related. – justawebguy Aug 19 '17 at 21:20
  • That is because you haven't registered the `GigsViewModel` with the IoC container (in your `startup.cs`). To solve this problem add the following line somewhere in the `ConfigureServices` method: `services.AddScoped();` Note that you'll have to do this for all view model classes you would like the IoC container to resolve (your controllers are added automatically by the framework). – Maurits van Beusekom Aug 20 '17 at 04:21
  • Thanks for the feed back, After doing some more research, because of your comments, I'm looking to update the app a little more to use better practices than it was using. – justawebguy Aug 20 '17 at 19:52
  • This is technically correct but still a horrible design. Inject the DbContect into the controller, then use a proper conversion tool to construct the ViewModel. The Get() should go. – H H Aug 20 '17 at 21:51