Home > Software design >  InvalidOperationException: Unable to resolve service for type 'Data.IRestaurantsData' whil
InvalidOperationException: Unable to resolve service for type 'Data.IRestaurantsData' whil

Time:08-26

I'm following a course on Pluralsight about ASP.NET Core but, when accessing to Restaurant Page I receive the following error:

InvalidOperationException: Unable to resolve service for type 'Data.IRestaurantsData' while attempting to activate 'OdeToFood.Pages.Restaurants.ListModel'.

I saw another post on StackOverflow that suggests moving the singleton in Startup.cs outside from the lambda function. I move it in the position but the error is still there. Can you help me understand the problem?

Restaurant.cs

namespace OdeToFood.core {
   public class Restaurant {
         public int Id { get; set; }
         public string? Name { get; set; }
         public string? Location { get; set; }
         public CuisineType Cuisine { get; set; }
    }
}

IRestaurantData.cs

using OdeToFood.core;

namespace Data {
    public interface IRestaurantsData {
        IEnumerable<Restaurant> GetRestaurantsByName(string name);
    }

    public class InMemoryRestaurantsData : IRestaurantsData {
        public List<Restaurant> restaurants;
        public InMemoryRestaurantsData()
        {
            restaurants = new List<Restaurant>()
            {
                new Restaurant  { Id = 1, Name = "Pizza", Location = "Milano", Cuisine = CuisineType.Italian },
                new Restaurant  { Id = 2, Name = "Rice", Location = "Mexic", Cuisine = CuisineType.Mexican },
                new Restaurant  { Id = 3, Name = "Chicken", Location = "London", Cuisine = CuisineType.Indian},
            };
        }
        public IEnumerable<Restaurant> GetRestaurantsByName(string name = null) {
            return from r in restaurants
                   where string.IsNullOrEmpty(name) || r.Name.StartsWith(name)
                   orderby r.Name
                   select r;
        }
    }
}

List.cs

using Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using OdeToFood.core;

namespace OdeToFood.Pages.Restaurants {
    public class ListModel : PageModel {
        private readonly IConfiguration config;
        private readonly IRestaurantsData restaurantData;
        public string Message { get; set; }
        public IEnumerable<Restaurant> Restaurants;
        public ListModel(IRestaurantsData restaurantsData) {
            this.restaurantData = restaurantsData;
        }
        public void OnGet(string searchTerm) {
            Message = config["Message"];
            Restaurants = restaurantData.GetRestaurantsByName(searchTerm);
        }
    }
}

Startup.cs

using Data;
using Microsoft.AspNetCore.Mvc;

namespace OdeToFood {
    public class Startup {
        public Startup(IConfiguration configuration) {   
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        public IRestaurantsData RestaurantsData { get; set; }
        public InMemoryRestaurantsData InMemoryRestaurantsData { get; set; }

        public void ConfigureServices(IServiceCollection services) {
            services.Configure<CookiePolicyOptions>(options => {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            
            services.AddSingleton<IRestaurantsData, InMemoryRestaurantsData>();

            services.AddRazorPages();
            services.AddControllers();
        }
    }
}

Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment()) {
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

CodePudding user response:

I think this is the source of a lot of confusion. .NET Core 6 changed the default way startup is handled. Right now, your startup class is doing nothing. It looks like your example code came from a course before .NET 6. You have two options.

1: Move the Registration Statement to program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

builder.services.AddSingleton<IRestaurantsData, InMemoryRestaurantsData>();


var app = builder.Build();
if (!app.Environment.IsDevelopment()) {
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

Make sure to move your cookie registration also if you need it.

2: Tell it to use your startup class.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);


var app = builder.Build();
if (!app.Environment.IsDevelopment()) {
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

Make sure to take out the duplicate razor pages registration if you go this route.

Here is an article on it: https://www.infoworld.com/article/3646098/demystifying-the-program-and-startup-classes-in-aspnet-core.html

  • Related