解决错误 - 无法解决类型' Serilog.ILogger'

时间:2016-11-20 06:11:14

标签: asp.net-core asp.net-core-mvc serilog

我正在尝试在ASP.NET核心应用程序(.NET框架)中实现SeriLog

以下是我目前执行的步骤 -

1)在Project.json

中添加了以下引用
"Serilog": "2.2.0",
"Serilog.Extensions.Logging": "1.2.0",
"Serilog.Sinks.RollingFile": "2.0.0",
"Serilog.Sinks.File": "3.0.0"

2)将以下行添加到Startup类的构造函数中 -

Log.Logger = new LoggerConfiguration()
           .MinimumLevel.Debug()
           .WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "log-{Date}.txt"))
           .CreateLogger();

3)在启动类的配置方法中添加以下行 -

loggerFactory.AddSerilog();

4)将记录器注入HomeController,如下所示 -

ILogger logger;

    public HomeController(ILogger logger)
    {
        this.logger = logger;
    }

5)在“关于”操作中,尝试记录此类异常 -

public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";

        try
        {
            throw new Exception("Serilog Testing");
        }
        catch (System.Exception ex)
        {
            this.logger.Error(ex.Message);
        }

        return View();
    }

在运行我的应用程序时,我收到以下错误 -

  

System.InvalidOperationException:无法解析类型的服务   ' Serilog.ILogger'在尝试激活时   ' AspNetCore_SeriLog_trial1.Controllers.HomeController&#39 ;.在   Microsoft.Extensions.Internal.ActivatorUtilities.GetService(的IServiceProvider   sp,Type type,Type requiredBy,Boolean isDefaultParameterRequired)
  在lambda_method(Closure,IServiceProvider,Object [])at   Microsoft.AspNetCore.Mvc.Internal.TypeActivatorCache.CreateInstance [TInstance](的IServiceProvider   serviceProvider,类型implementationType)at   Microsoft.AspNetCore.Mvc.Controllers.DefaultControllerActivator.Create(ControllerContext   controllerContext)at   Microsoft.AspNetCore.Mvc.Controllers.DefaultControllerFactory.CreateController(ControllerContext   上下文)   Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__26.MoveNext()

有人可以帮我吗? Serilog缺少任何配置?

6 个答案:

答案 0 :(得分:23)

尝试在控制器中执行以下操作。

    ILogger<HomeController> logger = null;
    public HomeController(ILogger<HomeController> _logger)
    {
        logger = _logger;
    }

答案 1 :(得分:4)

您的控制器中有以下两行?

import importlib
import inspect
from enum import EnumMeta

_readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
               '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
               '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
               '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
               '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
               '__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
               '__basicsize__', '__base__'}


def reset_module(module, inner_modules_also=True):
    """
    This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
    module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
    to be the reloaded-module's
    :param module: The module to reload (module reference, not the name)
    :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
    """

    new_module = importlib.reload(module)

    reset_items = set()

    # For the case when the module is actually a package
    if inner_modules_also:
        submods = {submod for _, submod in inspect.getmembers(module)
                   if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
        for submod in submods:
            reset_module(submod, True)

    _reset_item_recursively(module, new_module, module.__name__, reset_items)


def _reset_item_recursively(item, new_item, module_name, reset_items=None):
    if reset_items is None:
        reset_items = set()

    attr_names = set(dir(item)) - _readonly_attrs

    for sitem_name in attr_names:

        sitem = getattr(item, sitem_name)
        new_sitem = getattr(new_item, sitem_name)

        try:
            # Set the item
            setattr(item, sitem_name, new_sitem)

            try:
                # Will work for classes and functions defined in that module.
                mod_name = sitem.__module__
            except AttributeError:
                mod_name = None

            # If this item was defined within this module, deep-reset
            if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
                    or isinstance(sitem, EnumMeta):  # Deal with enums
                continue

            reset_items.add(id(sitem))
            _reset_item_recursively(sitem, new_sitem, module_name, reset_items)
        except Exception as ex:
            raise Exception(sitem_name) from ex

如果是前一个(using Serilog; using Microsoft.Extensions.Logging; ),则可能是您的问题。

注册服务时,您实际上是在说:“当构造函数要求Microsoft.Extensions.Logging.ILogger时,将它们传递给Serilog实例,因为我正在使用Serilog进行日志记录”,但是随后在您的构造函数中您不是要使用Microsoft.Extensions.Logging.ILogger ,而是要使用 Serilog.ILogger ,而且您的应用程序越来越混乱,因为您尚未定义为using Serilog;注入服务,您已经为Serilog.ILoger定义了一个服务

请记住,您正在实现Microsoft的ILogger接口:您的构造函数不需要知道您正在使用Serilog ...实际上,您不希望这样做!整个要点是,您可以随时将Serilog换成其他记录器,而无需更改代码。

在构造函数中将Microsoft.Extensions.Logging.ILogger更改为using Serilog;,您将请求正确的服务类型

答案 2 :(得分:0)

我收到此问题“尝试激活'Controller_Name'时无法解析'interface_name'类型的服务...。

通过在startup.cs中添加以下行,我已经解决了相同的问题: services.AddScoped();

答案 3 :(得分:0)

您错过了将接口注入控制器构造函数的过程:

ILogger<HomeController> logger = null;

public HomeController(ILogger<HomeController> _logger)
{
    logger = _logger;
}

在Program.cs中,您还必须添加UseSerilog:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .UseSerilog();

答案 4 :(得分:0)

如果您需要使用ILogger(来自Serilog)而不是ILogger<HomeController>(来自Microsoft.Extensions.Logging),则可以在Startup类中注册ILogger

services.AddSingleton(Log.Logger);

答案 5 :(得分:0)

我知道这是一个老问题,但我刚遇到这个问题并找到了不同的解决方案。

我为 Microsoft.Extensions.Logging 切换了 Serilog,但我没有将它从构造函数参数列表中删除。

public HomeController(IIdentityServerInteractionService interaction, IWebHostEnvironment environment, ILogger logger)

一旦我删除了那个参数,错误就消失了。

public HomeController(IIdentityServerInteractionService interaction, IWebHostEnvironment environment)

看起来 OP 试图通过构造函数注入记录器,但应该为该控制器创建一个特定的记录器。你也可以让它static所以there's only 1 creation of the logger for every time this project runs, instead of 1 for every instance of the class.

public class HomeController : Controller
{
    private static readonly ILogger Logger = Log.ForContext<HomeController>();
    ...

    public HomeController(IIdentityServerInteractionService interaction, IWebHostEnvironment environment)
    {
    ...
    }

    ...
}

显然,正在发生的事情是编译器默认给构造函数一个 Microsoft.Extensions.Logging 记录器,而不是尝试匹配构造函数实际期望的 Serilog 记录器,所以这就是错误出现的地方来自。