I am working on an mvc .net application. When I run dotnet build the solution is built normally with no errors. However, when I run the solution to display the api using swagger, it throws a system aggregated exception and the run fails. The exception is being thrown at a certain part in my Program.cs file.
The Program.cs file looks something like this:
using Example.Api.Data;
using Example.Services;
using Example.Services.Interfaces;
using Example.Core;
using Example.Core.Interfaces;
using Example.Core.Repositories;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerUI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddAutoMapper(typeof(StartupBase));
builder.Services.AddControllersWithViews();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddTransient<IApplicantService, ApplicantService>();
builder.Services.AddTransient<IApplicantSurveyChoicesService, ApplicantSurveyChoicesService>();
builder.Services.AddTransient<IApplicantSurveyService, ApplicantSurveyService>();
builder.Services.AddTransient<IChoiceService,ChoiceService>();
//I basically did add transient for everyone of my services
builder.Services.AddSwaggerGen();
var app = builder.Build(); //this is where the exception is being thrown
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
/*app.UseSwagger();
app.UseSwaggerUI();*/
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
options.RoutePrefix = string.Empty;
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
It throws the following exception: 'System.AggregateException' in Microsoft.Extensions.DependencyInjection.dll
Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Example.Services.Interfaces.IApplicantService Lifetime: Transient ImplementationType: Example.Services.ApplicantService': Unable to resolve service for type 'Example.Core.Interfaces.IUnitOfWork' while attempting to activate 'Example.Services.ApplicantService'.)
and the error appears for every single time I call AddTransient
I am fairly new to the dotnet framework and I am still a beginner and would appreciate your help!
The IUnitOfWork file consists of the following:
public interface IUnitOfWork : IDisposable
{
IApplicantRepository Applicants { get; }
IApplicantSurveyChoicesRepository ApplicantSurveyChoices { get; }
IApplicantSurveyRepository ApplicantSurveys { get; }
IChoiceRepository Choices{ get; }
Task<int> CommitAsync();
}
The UnitOfWork class is just an implementation of the interface as such:
public UnitOfWork(DbContext context)
{
this._context = context;
}
public UnitOfWork(DbContext context, DbContext context1, IHostingEnvironment _environment, IHttpContextAccessor httpContextAccessor)
{
this._context = context;
this._environment = _environment;
_httpContextAccessor = httpContextAccessor;
}
public IApplicantRepository Applicants => _applicantRepository = _applicantRepository ?? new ApplicantRepository(_context, Config, _httpContextAccessor);
public IApplicantSurveyChoicesRepository ApplicantSurveyChoices => _applicantsurveychoicesrepository = _applicantsurveychoicesrepository ?? new ApplicantSurveyChoicesRepository(_context, Config, _httpContextAccessor);
public IApplicantSurveyRepository ApplicantSurveys => _applicantsurveysrepository = _applicantsurveysrepository ?? new ApplicantSurveyRepository(_context, Config, _httpContextAccessor);
public IChoiceRepository Choices => _choicerepository = _choicerepository ?? new ChoiceRepository(_context, Config, _httpContextAccessor);
public async Task<int> CommitAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
I believe swagger is running through your controller endpoints and will activate some services while some services remain just registered but not resolved. So in my theory the error will also happen when you use the logic of the ApplicantService.
The error says it can't resolve the implementation of IUnitOfWork while trying to activate ApplicantService. So I would guess, you have missed a registration from the class UnitOfWork, or the interface referenced in the class UnitOfWork. But that would be the place where I would look.
Singelton, Scope and Transient should not have any relevance at this stage.
I figured out the issue. One of my controllers was not properly routed which led to the exception being thrown!
Thank you everyone for your help!
EDIT!
I also added an empty constructor to each of my services so that the DI can inject into them!
Hope this was of any help to anyone!
Related
I am working on an ASP.NET Core MVC application that uses ASP.NET Core identity for role based authorization and I'm facing an issue trying to figure out how to work with the
UserManager class. The app should work as follows:
A coach logs in to the web app through Identity to work with
runner's data (e.g., taking attendance, starting a practice, etc.).
The app should use the UserManager class to loop through all
identity objects (registered users) so that the coach can manipulate
user's data that have the role of Runner (there are currently 4
roles in the database and I am trying to use the UserManager class
to only to select a specific role [Runner]) and then add the objects
to a list for manipulation.
The problem that I am facing is that the UserManager object that I have created is null and after countless hours of googling, I'm not sure how to fix my problem.
On my first attempt, I received a null error and after a bit of research, I attempted to fix the error through dependency injection. The second error I received is "Unable to resolve service type while attempting to activate". I have tried configuring the service an I am currently at a standstill. How exactly do I configure the service? Here is the Controller class in question and also the Program.CS class in question. I've also added two images that can hopefully explain my problem more.
Controller:
[Authorize(Roles = "Master Admin, Coach")]
[Area("Coach")]
public class TakeAttendanceController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly UserManager<ApplicationUser> _userManager; // the UserManager object in question
public TakeAttendanceController(IUnitOfWork unitOfWork, UserManager<ApplicationUser> userManager)
{
_unitOfWork = unitOfWork;
_userManager = userManager;
}
public IActionResult RecordAttendance()
{
var recordAttendanceViewModel = new RecordAttendanceViewModel();
var userClaimsIdentity = (ClaimsIdentity)User.Identity;
var userClaim = userClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier);
if (userClaim != null)
{
recordAttendanceViewModel.UserCoach = _unitOfWork.ApplicationUser.GetById(userClaim.Value);
}
var users = _userManager.GetUsersInRoleAsync("Runner"); // object is null
return View(recordAttendanceViewModel);
}
public IActionResult RecordWorkouts()
{
return View();
}
}
Program.cs file:
using FinalMockIdentityXCountry.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using FinalMockIdentityXCountry.Models.DataLayer.Repositories.IRepository.Interfaces;
using FinalMockIdentityXCountry.Models.DataLayer.Repositories.IRepository.Classes;
using Microsoft.AspNetCore.Identity.UI.Services;
using FinalMockIdentityXCountry.Models.Utilities;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var serverVersion = new MySqlServerVersion(new Version(8, 0, 30)); //current version of mysql - 8.0.30
builder.Services.AddDbContext<XCountryDbContext>(options => options.UseMySql(connectionString, serverVersion));
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<XCountryDbContext>();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddSingleton<IEmailSender, FakeEmailSender>();
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();;
app.UseAuthorization();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
pattern: "{area=Welcome}/{controller=Home}/{action=Index}/{id?}");
app.Run();
The null error
Service error
shouldnt
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
be
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
Or the injected service be
UserManager<IdentityUser>
I am currently working on a project that consists of sub-projects such as WebApp, API, and Client class library. (The project structure is shown below).
Project Solution Structure
Although the project is a web-based project, it uses windows Identity as authentication identity since it is an internal application. I implemented the authorization policy of the WebApp project without any problems by following the steps in the implementation_link.
Now I can control access using DataAnnotation in WebApp (ex. [Authorize(Roles = "Admin"]). If I add Authorization control on the API side, WebApp cannot access this API. This is because of HttpContext.User is null. I found the solution to this problem solution_link. I adapted this solution to the project as below:
ServiceCollectionExtensions.cs in WebApp project:
public static IServiceCollection AddAuraServices(this IServiceCollection serviceCollection, IConfiguration configuration)
{
serviceCollection.AddTransient<IModelDatabaseNamesProvider, StandardCasingModelDatabasesNamesProvider>();
serviceCollection.Configure<RouteOptions>(routeOptions =>
{
routeOptions.ConstraintMap.Add(ModelDatabasesNameConstraint.Name, typeof(ModelDatabasesNameConstraint));
});
serviceCollection.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
serviceCollection.AddScoped<IModelMetadataProvider>(serviceProvider =>
{
var httpContext = serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
var modelName = httpContext.Request.RouteValues["model-name"].ToString();
return new ModelMetadataProvider(modelName);
});
DateOnlyTypeConverter.AddAttributeToType();
serviceCollection.AddHttpClient<UploadRulesClient>("ServerAPI", (httpClient) =>
{
httpClient.BaseAddress = new Uri(configuration["AuraApiClient:BaseAddress"]);
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
serviceCollection.AddHttpClient<ScenarioZipFilesClient>("ServerAPI",(httpClient) =>
{
httpClient.BaseAddress = new Uri(configuration["AuraApiClient:BaseAddress"]);
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
serviceCollection.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("ServerAPI"));
var jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
ClientJsonResponse.Configure(jsonSerializerOptions);
serviceCollection.AddSingleton(jsonSerializerOptions);
serviceCollection.AddAuraDropzoneConfig(configuration);
return serviceCollection;
}
Startup.cs of WebApp:
public class Startup
{
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)
{
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
services.AddAuthorization();
services.AddControllersWithViews();
//services.AddRazorPages();
services.AddAuraServices(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "model-database", pattern: "{model-name:modeldatabasename}/{controller=ZipFiles}/{action=Index}/{id?}");
endpoints.MapControllerRoute(name: "default", pattern: "", new { controller = "Home", action = "Index" });
//endpoints.MapRazorPages();
});
}
}
But this time I am getting No service for Type Error. How can I solve this problem? Where do you think I am going wrong? Thanks
Edit:
As you can see BaseAddressAuthorizationMessageHandler is in namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication. It is supposed to be used with Blazor WebAssembly apps and it attaches the access token to the authentication header of HttpClient requests. BaseAddressAuthorizationMessageHandler depends on other services like IAccessTokenProvider which is responsible to return the access token. For example in web assembly IAccessTokenProvider default implementation retrieves the access token from browser session storage.
If you want to attach access tokens to your http requests your should probably implement your own DelegatingHandler instead of BaseAddressAuthorizationMessageHandler.
Old answer:
You have to register BaseAddressAuthorizationMessageHandler:
serviceCollection.AddTransient<BaseAddressAuthorizationMessageHandler>();
I am trying to identify the issue I am facing here with my middleware injection. I have added an 'Audit' trail to my application by forwarding requests via HttpContext to my SQL Server DB which then can be viewed by admins in my application under my Events Controller/View.
My StartUp.cs is as follows:
using AWS_Service_Catalog.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.EntityFrameworkCore.SqlServer;
using Microsoft.EntityFrameworkCore;
using AWS_Service_Catalog.Models;
using AWS_Service_Catalog.Data;
using AWS_Service_Catalog.Middleware;
namespace AWS_Service_Catalog
{
public class Startup
{
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)
{
services.AddDistributedMemoryCache();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
// Handling SameSite cookie according to https://learn.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
options.HandleSameSiteCookieCompatibility();
});
services.AddOptions();
//Adds authentication/authorization via Microsoft Azure AD
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '))
.AddDownstreamWebApi("AWSServiceCatalogAPI", Configuration.GetSection("DownstreamApi:Scopes"))
.AddInMemoryTokenCaches();
services.AddApiService(Configuration);
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
services.AddRazorPages();
services.AddDbContext<EventLogContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MicrosoftSQLServer")));
//Configuring appsettings section AzureAd, into IOptions
services.AddOptions();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//Production Exception Handler ex: API connection failed will trigger exception routed to /Home/Error
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//Handles User Error: 401, 403, 404, etc. Errors caught must land Application side. Errors occured in API with return 500 and be routed via Exception Handler
app.UseStatusCodePagesWithReExecute("/Home/Error", "?status={0}");
app.UseHttpException();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
//Must include Authentication/Authorization under routing
app.UseAuthentication();
app.UseAuthorization();
app.UseEventLogCaptureMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Server}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
My EventLogCaptureMiddleware class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Identity.Web;
using AWS_Service_Catalog.Models;
using AWS_Service_Catalog.Data;
namespace AWS_Service_Catalog.Middleware
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class EventLogCaptureMiddleware
{
private readonly RequestDelegate _next;
private readonly EventLogContext _context;
public EventLogCaptureMiddleware(RequestDelegate next, EventLogContext context)
{
_next = next;
_context = context;
}
public Task Invoke(HttpContext httpContext)
{
string role;
try
{
role = httpContext.User.Claims.ToArray()[5].Value;
}
catch
{
role = null;
}
var eventLogModel = new EventLogViewModel
{
Timestamp = DateTime.Now,
Role = role,
Method = httpContext.Request.Method,
Upn = httpContext.User.Identity.Name,
Resource = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.Path}{httpContext.Request.QueryString}"
};
_context.Add(eventLogModel);
var tasks = new Task[] { _context.SaveChangesAsync() };
Task.WaitAll(tasks);
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class EventLogCaptureMiddlewareExtensions
{
public static IApplicationBuilder UseEventLogCaptureMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<EventLogCaptureMiddleware>();
}
}
}
I am failing to understand the exact error or the cause. I have looked at this question posted: Cannot resolve scoped service from root provider .Net Core 2
Some elaboration would be wonderful. I can't identify how to resolve this issue until I know what it is. What is interesting to me, this error only occurs when I run my application in IIS Express. Otherwise there seems to be no issue.
Thoughts?
I'm creating a wep api and this is the current structure:
API - The Web API (.net core web api project)
DAL - DbContext and Entities (.net core class library)
DTO - Data Transfert Objects - The classes I send to the client without sensible data (.net core class library)
REPO - Contains de Interfaces and Repositories (.net core class library)
For information I had everything on the same project and decided to split into multiple class libraries.
What I've done until now:
Added the references beetween each project
Update usings
Changed namespaces names to the correct ones
Solution as 0 errors
I think that my problem is related to dependency injection because when I try to access a controller from postman or from the browser this error happens:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: FootballManager.REPO.ILeagueRepository Lifetime: Scoped ImplementationType: FootballManager.REPO.LeagueRepository': Unable to resolve service for type 'FootballManager.DAL.FootballManagerAPIContext' while attempting to activate 'FootballManager.REPO.LeagueRepository'.
My Startup.cs looks like this:
using FootballManager.REPO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace FootballManager.API
{
public class Startup
{
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)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
});
});
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
services.AddScoped<ILeagueRepository, LeagueRepository>();
services.AddScoped<IMatchRepository, MatchRepository>();
services.AddScoped<IPlayerRepository, PlayerRepository>();
services.AddScoped<IRefereeRepository, RefereeRepository>();
services.AddScoped<ITeamRepository, TeamRepository>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
This is my controller code where I do the injection:
public class LeaguesController : ControllerBase
{
private readonly ILeagueRepository _repo;
public LeaguesController(ILeagueRepository repo)
{
_repo = repo;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<LeagueDto>>> GetLeagues()
{
return await _repo.GetAll();
}
}
For my DbContext connection I did directly on the DAL project like this (I dont think that the problem is here):
public partial class FootballManagerAPIContext : DbContext
{
public FootballManagerAPIContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Server =.\SQLEXPRESS; Database = FootballManagerAPI; Trusted_Connection = True;");
}
}
}
After hours on the web and stackoverflow I still can't find any working solution...
How can I solve this error and why I'm having this? Thank you.
You never instantiate your DbContext - the error is very explicit about that;
Unable to resolve service for type 'FootballManager.DAL.FootballManagerAPIContext'
You also need to register the DbContext you need in the startup including configuration
I cant add comments to you question so I leave this here:
Maybe its a stupid question but, maybe you forgot it:
Does LeagueRepository inherit from ILeagueRepository?
I think this will help you.
Check out this video in which i explain how to implement dependency injection using autofac.
https://studio.youtube.com/video/XvklkAj7qPg/edit
Also i sugest that you should use disposable database connection, connect and disconnect in every method. So do not use dependency injection for db context.
Check if you registered the db context.
services.AddDbContext(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
In the services configuration i can't see it.
Thanks,
Liviu
Well, I have created an application to start on ASP net core 3.1 from scratch, I have created an API application and I have already created some layers to have better control on my application, However, when I created my object with its interface and registered them in the startup file on this way:
services.AddScoped<IMySpaceService, MySpaceService>();
I have gotten this error when I run the application:
Unhandled exception. System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: MySpaceService.Services.Interfaces.IMySpaceService Lifetime: Scoped ImplementationType:
this is my code:
public class MySpaceService: IMySpaceService
{
private IMySpaceRepository _mySpaceRepository;
public MySpaceService(IMySpaceRepository mySpaceRepository)
{
_mySpaceRepository = mySpaceRepository;
}
public IList<MySpaceDto> getSpaces()
{
List<MySpaceDto> spaces = new List<MySpaceDto>();
var data = _mySpaceRepository.getSpaces();
foreach (var item in data)
{
SpaceDto spaceDto = new SpaceDto();
spaceDto.Identification = item.Identification;
spaceDto.Name = item.Name;
spaces.Add(spaceDto);
}
return spaces;
}
}
My startup code:
public class Startup
{
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)
{
services.AddControllers();
services.AddScoped<IMySpaceService, MySpaceService>();
services.AddScoped<IMySpaceRepository, MySpaceRepository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Any Ideas about it?.
Your MySpaceService has only one constructor with parameter IMySpaceRepository. You need to register your repository as well:
services.AddScoped<IMySpaceRepository, MySpaceRepository>();
services.AddScoped<IMySpaceService, MySpaceService>();
Well, definitely the problem was that I had not registered yet a dependency, however, the dependency that I hadn't registered was "Dbcontext" and I am calling it from my repository class on the constructor. Therefore, I have to say that your comments helped me to solve my problem because finally, it was a problem with the dependency that didn't register.
I had to do this on my startup file:
services.AddDbContext<ExampleContext>(
options => options.UseMySql("Server=localhost;port=3306;Database=exampleDB;User=UserRegistered;Password=*******", mySqlOptions => mySqlOptions
.ServerVersion(new ServerVersion(new Version(8, 0, 18), ServerType.MySql))));