.NET Coreを学習していて、startup.csでIServiceCollection
を使用して依存関係を解決しようとしています。コントローラーに依存性を注入していますが、その依存性は、依存性が注入されたクラスに解決されます。基本的に、依存関係をアクティブ化できないため、InvalidOperationException
を取得しています。
これは私のスタックトレースです:
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()
登録された依存関係を持つ私のスタートアップクラス:
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>();
}
ランタイムエラーが解決されたら、スコープ(トランジェント、シングルトンなど)も正しいタイプに変更します。
私のログインコントローラー:
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;
}
}
}
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;
}
}
}
私がstartup.csクラスで何を間違えたのか誰か知っていますか? TestApplication.Services.LoginHttpService
で使用されているTestApplication.Services.LoginService
を解決したい。
public LoginService(LoginHttpService loginHttpService, IOptions<UrlConfigurations> urlConfigurations)
{
_loginHttpService = loginHttpService;
_urlConfigurations = urlConfigurations.Value;
}
LoginHttpService
クラスコンストラクターのLoginService
をインターフェースILoginHttpService
に変更します。
これはうまくいくはずです。
私の場合、Startup.cs
にコンテキストサービスを追加するのを忘れています。
services.AddDbContext<My_ScaffoldingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyConnectionString")));