Dependency Injection .NET Core - InvalidOperationException

37,708

Solution 1

public LoginService(LoginHttpService loginHttpService, IOptions<UrlConfigurations> urlConfigurations)
{
    _loginHttpService = loginHttpService;
    _urlConfigurations = urlConfigurations.Value; 
}

Change LoginHttpService in LoginService class constructor to interface ILoginHttpService.

This should work.

Solution 2

In my case, I forget of add context service in Startup.cs:

services.AddDbContext<My_ScaffoldingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyConnectionString")));
Share:
37,708
nick gowdy
Author by

nick gowdy

Updated on September 06, 2021

Comments

  • nick gowdy
    nick gowdy about 2 years

    I'm learning .NET Core, and I'm trying to use IServiceCollection in the startup.cs to resolve my dependencies. I'm injecting a depdency in my controller, and that depency is resolved to a class which also has an injected dependency. Basically I'm getting an InvalidOperationException because it's unable to activate the dependency.

    This is my stacktrace:

    InvalidOperationException: Unable to resolve service for type 'TestApplication.Services.LoginHttpService' while attempting to activate 'TestApplication.Services.LoginService'.
    
        Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet<Type> callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)   
    
        Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet<Type> callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
        Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
        Microsoft.Extensions.DependencyInjection.ServiceProvider.GetResolveCallSite(IService service, ISet<Type> callSiteChain)
        Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
        Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)
        System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd<TKey, TValue, TArg>(ConcurrentDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TArg, TValue> valueFactory, TArg arg)
        Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
        Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
        lambda_method(Closure , IServiceProvider , Object[] )
        Microsoft.AspNetCore.Mvc.Internal.TypeActivatorCache.CreateInstance<TInstance>(IServiceProvider serviceProvider, Type implementationType)
        Microsoft.AspNetCore.Mvc.Controllers.DefaultControllerFactory.CreateController(ControllerContext context)
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeNextResourceFilter>d__22.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeAsync>d__20.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__18.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__18.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware+<ExecuteWithFilter>d__7.MoveNext()
        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()
    

    My startup class with registered dependencies:

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
    
        // Added - uses IOptions<T> for your settings.
        services.AddOptions();
    
        // Added - Confirms that we have a home for our DemoSettings
        services.Configure<UrlConfigurations>(Configuration.GetSection("UrlConfigurations"));
    
        //services.AddSingleton<ITokenProvider, Tokenpro>();
    
        services.AddTransient<ILoginService, LoginService>();
        services.AddSingleton<IHttpService, HttpService>();
        services.AddSingleton<ILoginHttpService, LoginHttpService>();
    
        services.AddSingleton<IUrlConfigurations, UrlConfigurations>();
        services.AddSingleton<IJsonDeserializer, JsonDeserializer>();
        services.AddSingleton<IHttpClientFactory, HttpClientFactory>();
    
        services.AddSingleton<IJsonValidator, JsonValidator>();
    }
    

    I'm going to change the scope (transient, singleton, etc.) to be the correct type as well once the runtime error is resolved.

    My login controller:

    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Options;
    using TestApplication.Configurations;
    using TestApplication.Interfaces.Configurations;
    using TestApplication.Interfaces.Services;
    using TestApplication.Models;
    
    // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
    
    namespace TestApplication.Controllers
    {
        public class LoginController : Controller
        {
            private readonly ILoginService _loginService;
            private readonly IUrlConfigurations _urlConfigurations;
    
            public LoginController(ILoginService loginService, IOptions<UrlConfigurations> urlConfigurations)
            {
                _loginService = loginService;
                _urlConfigurations = urlConfigurations.Value;
            }
    
            public async Task<IActionResult> Index()
            {
                var jsonWebToken = await GetJsonWebToken();
                return View();
            }
    
            private async Task<JwtSecurityToken> GetJsonWebToken()
            {
                // get token - hard-coded for now
                var login = new LoginViewModel { Username = "[email protected]", Password = "marshwall" };
                var jsonWebToken = await _loginService.Login(login);
                return jsonWebToken;
            }
        }
    }
    

    My login service which uses LoginHttpService:

    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Options;
    using Newtonsoft.Json;
    using TestApplication.Configurations;
    using TestApplication.Interfaces.Configurations;
    using TestApplication.Interfaces.Services;
    using TestApplication.Models;
    
    namespace TestApplication.Services
    {
        public class LoginService : ILoginService
        {
            private readonly LoginHttpService _loginHttpService;
            private readonly IUrlConfigurations _urlConfigurations;
    
            public LoginService(LoginHttpService loginHttpService, IOptions<UrlConfigurations> urlConfigurations)
            {
                _loginHttpService = loginHttpService;
                _urlConfigurations = urlConfigurations.Value;
    
            }
    
            public async Task<JwtSecurityToken> Login(LoginViewModel login)
            {
                login.LoginMapper();
                var response = await _loginHttpService.PostLoginAsync(_urlConfigurations.GetToken, login.EncodedLoginDetailsContent);
    
                if (response == null) return null;
    
                var data = await response.Content.ReadAsStringAsync();
                // Deserialize JWT
                var accessToken = JsonConvert.DeserializeObject<UserResponseModel>(data)?.access_token;
    
                if (string.IsNullOrEmpty(accessToken) || !response.IsSuccessStatusCode) return null;
    
                // Cast JWT to correct class
                var securityToken = new JwtSecurityTokenHandler().ReadToken(accessToken) as JwtSecurityToken;
    
                return securityToken;
            }
        }
    }
    

    Does anyone know what I've done wrong in my startup.cs class? I want to resolve TestApplication.Services.LoginHttpService which is used in TestApplication.Services.LoginService.