ASP.NET 依赖注入激活器实用程序错误

问题描述 投票:0回答:1

问题是:

处理请求时发生未处理的异常。
InvalidOperationException:尝试激活“CineMagic.Controllers.HomeController”时无法解析类型“CineMagicAPI.Controllers.PopularMoviesController”的服务。
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ThrowHelperUnableToResolveService(类型类型,类型requiredBy)

CineMagicAPI> Movies.cs:

public class Movies
{
    public bool adult { get; set; }
    public string backdrop_path { get; set; }
    public List<int> genre_ids { get; set; }
    public int id { get; set; }
    public string original_language { get; set; }
    public string original_title { get; set; }
    public string overview { get; set; }
    public decimal popularity { get; set; }
    public string poster_path { get; set; }
    public DateTime release_date { get; set; }
    public string title { get; set; }
    public bool video { get; set; }
    public decimal vote_average { get; set; }
    public int vote_count { get; set; }
}

CineMagicAPI>PopularMoviesController.cs

using Microsoft.AspNetCore.Mvc;
using CineMagicAPI.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

namespace CineMagicAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class PopularMoviesController : ControllerBase
    {
        private readonly IHttpClientFactory _clientFactory;

        private readonly PopularMoviesController _popularMoviesService;

        private const string TMDB_API_KEY = "30b4c1980f6c33f5036366f3c4def27b"; //tmdb'ye kayıt olunup key alındı.

        public PopularMoviesController(IHttpClientFactory clientFactory, PopularMoviesController popularMoviesService)
        {
            _clientFactory = clientFactory;
            _popularMoviesService = popularMoviesService;
        } 

        [HttpGet]
        public async Task<List<Movies>> GetPopularMoviesAsync()
        {

            List<Movies> popularMovies = new List<Movies>();
            string endpoint = $"https://api.themoviedb.org/3/movie/popular?api_key={TMDB_API_KEY}";
            var client = _clientFactory.CreateClient();
            HttpResponseMessage response = await client.GetAsync(endpoint);
            if (response.IsSuccessStatusCode)
            {
                string json = await response.Content.ReadAsStringAsync();
                var data = JsonSerializer.Deserialize<TMDbResponse>(json);
                popularMovies = data?.results;
            }

            return popularMovies;
        }
    }
    public class TMDbResponse
    {
        public List<Movies> results { get; set; }
    }
}

CineMagic> HomeController.cs

using CineMagic.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using CineMagicAPI.Controllers;

namespace CineMagic.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly PopularMoviesController _popularMoviesService;

        public HomeController(ILogger<HomeController> logger, PopularMoviesController popularMoviesService)
        {
            _logger = logger;
            _popularMoviesService = popularMoviesService;
        }

        public async Task<IActionResult> Index()
        {
            List<Movies> popularMovies = await _popularMoviesService.GetPopularMoviesAsync();
            return View(popularMovies);
        }
     
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

CineMagic>Program.cs

using CineMagicAPI.Controllers;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

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.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

我想使用从 TMDB API 收到的密钥在我的主页上显示热门电影。我有索引 html 页面,但在此之前我收到错误。如何修复我上面分享的错误?

c# asp.net dependency-injection
1个回答
0
投票

您正在尝试将一个控制器注入另一个控制器,但在默认配置中,控制器未在 DI 容器中注册。 MVC 自己创建控制器(不通过 DI 容器请求它们),并且仅从 DI 容器请求其依赖项。这需要注册这些依赖项,但同样,控制器未注册(默认情况下)。

快速解决方法是添加以下注册:

builder.Services.AddControllersWithViews()
    .AddControllersAsServices();

尽管这将允许将

PopularMoviesController
注入到您的
HomeController
中,但它可能仍然无法按预期工作。这是否有效取决于您是否使用 MVC 为
PopularMoviesController
初始化的请求特定状态。此状态仅在 MVC 作为根对象创建/解析时才会初始化,但在将其注入另一个对象时不会初始化。考虑到您发布的代码,目前这可能会起作用,但如果您对 PopularMoviesController 进行更改,将来可能很容易崩溃。
所以更好的解决办法是防止控制器相互依赖。相反,从 

PopularMoviesController

中提取共享逻辑并将其放入新类中。将该类注册到 DI 容器中,并将其作为依赖项注入到

PopularMoviesController
HomeController
例如:

[ApiController] [Route("[controller]")] public class PopularMoviesController : ControllerBase { private readonly PopularMoviesController _service; public PopularMoviesController(IPopularMoviesService service) { _service = service; } [HttpGet] public async Task<List<Movies>> GetPopularMoviesAsync() { var movies = await _service.GetPopularMoviesAsync(); return movies; } } public class HomeController : Controller { private readonly IPopularMoviesService _service; public HomeController(IPopularMoviesService service) { _service = service; } public async Task<IActionResult> Index() { var movies = await _service.GetPopularMoviesAsync(); return View(movies); } ... }

来自 
PopularMoviesController

的逻辑现在隐藏在

IPopularMoviesService
后面,
PopularMoviesController
HomeController
都依赖于此。这个
IPopularMoviesService
需要实现,如下所示:
public interface IPopularMoviesService
{
    Task<List<Movies>> GetPopularMoviesAsync();
}

public class PopularMoviesService : IPopularMoviesService
{
    private const string TMDB_API_KEY = "{your api key}";   
    private readonly IHttpClientFactory _clientFactory;

    public PopularMoviesController(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    } 
    
    public async Task<List<Movies>> GetPopularMoviesAsync()
    {
        List<Movies> popularMovies = new List<Movies>();
        var endpoint = $"https://api.themoviedb.org/3/movie/popular?api_key={TMDB_API_KEY}";
        // IMPORTANT: Do make sure HttpClient is disposed of.
        using (var client = _clientFactory.CreateClient())
        {
            HttpResponseMessage response = await client.GetAsync(endpoint);
            if (response.IsSuccessStatusCode)
            {
                string json = await response.Content.ReadAsStringAsync();
                var data = JsonSerializer.Deserialize<TMDbResponse>(json);
                popularMovies = data?.results;
            }

            return popularMovies;
        }
    }    
}

这引入了一个新的 
PopularMoviesService

类和

IPopularMoviesService
接口,它们必须在 DI 容器中注册,如下所示:
builder.Services
    .AddTransient<IPopularMoviesService, PopularMoviesService>();

© www.soinside.com 2019 - 2024. All rights reserved.