在跟踪级别上记录 System.Net 时分配的超时

Allotted timeout while logging System.Net on Trace level

我的程序有问题。我创建了一个使用 NLOG 记录其操作的服务。在这项服务旁边,我创建了一个工具来捕获此日志记录并将其显示给用户。此连接基于 WSDualHTTPBinding。

除了服务的操作之外,我还记录了 [System.Net]、[System.ServiceModel] 和 [System.Windows] 以获得完整的日志报告。

现在我收到 TimeOutException:无法在 00:01:00 的分配超时内传输消息。可靠频道的传输 window 中没有可用的 space。等...

我发现当 System.Net.* 的 LogLevel 设置为 Trace 时会抛出此异常。否则不会抛出异常。

我尝试了多种解决方案,例如增加超时;设置默认连接限制;设置 ServiceBehaviorAttribute 等等。 None 他们为我工作...

有人可以帮我解决这个问题吗?


ConsoleApplication 服务:

class Program
{
    static void Main(string[] args)
    {
        IoC.Kernel.Bind<ILogging>().ToConstant(new Logging());

        try
        {
            //Normal binding
            var binding = new BasicHttpBinding();
            binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

            var host = new ServiceHost(typeof(Contract));
            host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;

            var path = "http://address:port/IContract";
            host.AddServiceEndpoint(typeof(IContract), binding, path);

            host.Open();

            //Duplex binding
            var duplexBinding = new WSDualHttpBinding();
            duplexBinding.Security.Mode = WSDualHttpSecurityMode.Message;
            duplexBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

            var duplexHost = new ServiceHost(typeof(DuplexContract));
            duplexHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;

            var duplexPath = "http://address:port/IDuplexContract";
            duplexHost.AddServiceEndpoint(typeof(IDuplexContract), duplexBinding, duplexPath);

            duplexHost.Open();
            IoC.Kernel.Get<ILogging>().Log("Listening.......");
        }
        catch (Exception ex)
        {
            IoC.Kernel.Get<ILogging>().Log(ex.ToString());
        }
        Console.ReadLine();
    }
}

接口服务:

[ServiceContract]
public interface IContract
{
    [OperationContract]
    void Update(string i);
}

[ServiceContract(CallbackContract = typeof(IDuplexContractCallback), SessionMode = SessionMode.Required)]
public interface IDuplexContract
{
    [OperationContract(IsOneWay = true)]
    void AddListener();
}

public interface IDuplexContractCallback
{
    [OperationContract(IsOneWay = true)]
    void Logger(string obj);
    [OperationContract(IsOneWay = true)]
    void ReceivedCalculate(int i);
}

public interface ILogging
{
    void Log(string message);
    void AddObserver(Action<string> addEventLog);
}

实施服务:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class DuplexContract : IDuplexContract
{
    public void AddListener()
    {
        IoC.Kernel.Get<ILogging>().AddObserver(OperationContext.Current.GetCallbackChannel<IDuplexContractCallback>().Logger);
        IoC.Kernel.Get<ILogging>().Log("Added listener");
    }
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Contract : IContract
{
    public void Update(string i)
    {
        IoC.Kernel.Get<ILogging>().Log(string.Format("Received: {0}", i));
    }
}

public class Logging : ILogging
{
    public Logging()
    {
        if (LogManager.Configuration == null)
        {
            LogManager.Configuration = new LoggingConfiguration();
        }

        Target consoleTarget;
        consoleTarget = LogManager.Configuration.FindTargetByName(nameof(consoleTarget));
        if (consoleTarget == null)
        {
            consoleTarget = new ColoredConsoleTarget()
            {
                Layout = "${longdate} [${logger}] [${level:uppercase=true}]: ${message} ${onexception:inner=${newline} ${exception:format=ToString:maxInnerExceptionLevel=4:innerFormat=ToString:seperator=\r\n}}",
                Name = nameof(consoleTarget),
                UseDefaultRowHighlightingRules = false,
            };
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Fatal"), ConsoleOutputColor.Magenta, ConsoleOutputColor.NoChange));
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Error"), ConsoleOutputColor.Red, ConsoleOutputColor.NoChange));
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Warn"), ConsoleOutputColor.Yellow, ConsoleOutputColor.NoChange));
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Info"), ConsoleOutputColor.White, ConsoleOutputColor.NoChange));
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Debug"), ConsoleOutputColor.Gray, ConsoleOutputColor.NoChange));
            (consoleTarget as ColoredConsoleTarget).RowHighlightingRules.Add(new ConsoleRowHighlightingRule(ConditionParser.ParseExpression("level == LogLevel.Trace"), ConsoleOutputColor.DarkGray, ConsoleOutputColor.NoChange));
            LogManager.Configuration.AddTarget(consoleTarget);
        }

        UpdateRules(consoleTarget);
        LogManager.ReconfigExistingLoggers();
    }

    public void Log(string message)
    {
        LogManager.GetLogger("CustomLogger").Trace(message);
    }

    private void UpdateRules(Target target)
    {
        var rules = LogManager.Configuration.LoggingRules.Where(u => u.Targets.Contains(target)).ToList();
        rules.ForEach(u => LogManager.Configuration.LoggingRules.Remove(u));

        LogManager.Configuration.LoggingRules.Add(new LoggingRule("System.Net.*", LogLevel.Trace, target)); //<-- Throws the exception
        LogManager.Configuration.LoggingRules.Add(new LoggingRule("System.ServiceModel.*", LogLevel.Trace, target));
        LogManager.Configuration.LoggingRules.Add(new LoggingRule("System.Windows.*", LogLevel.Trace, target));
        LogManager.Configuration.LoggingRules.Add(new LoggingRule("CustomLogger", LogLevel.Trace, target));
    }

    public void AddObserver(Action<string> addEventLog)
    {
        Target duplexCallbackTarget;
        duplexCallbackTarget = LogManager.Configuration.FindTargetByName(nameof(DuplexCallbackTarget));
        if (duplexCallbackTarget == null)
        {
            var layout = new XmlLayout();
            duplexCallbackTarget = new DuplexCallbackTarget()
            {
                Name = nameof(DuplexCallbackTarget),
                Layout = layout,
                CallbackAction = addEventLog,
            };
            LogManager.Configuration.AddTarget(duplexCallbackTarget);
        }
        UpdateRules(duplexCallbackTarget);
        LogManager.ReconfigExistingLoggers();
    }
}

[Target("DuplexCallback")]
public class DuplexCallbackTarget : TargetWithLayout
{
    /// <summary>
    /// The callback action from the client event viewer.
    /// </summary>
    public Action<string> CallbackAction { get; set; }

    /// <summary>
    /// Writes the specified log event information.
    /// </summary>
    /// <param name="logEventInfo">The log event information.</param>
    protected override void Write(LogEventInfo logEventInfo)
    {
        try
        {
            CallbackAction(logEventInfo.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

//Ninject
public static class IoC
{
    public static IKernel Kernel = new StandardKernel();
}

实现侦听器:

public class ContractCallback : IDuplexContractCallback
{
    public void Logger(string obj)
    {
        Console.WriteLine(string.Format("Client received: {0}", obj));
    }

    public void ReceivedCalculate(int i)
    {
        Console.WriteLine(string.Format("Client received: {0}", i));
    }
}

ConsoleWindow 侦听器:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Waiting for server to be ready...");
        Console.ReadLine();

        var binding = new WSDualHttpBinding();
        binding.Security.Mode = WSDualHttpSecurityMode.Message;
        binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

        var factory = new DuplexChannelFactory<IDuplexContract>(new InstanceContext(new ContractCallback()), binding, new EndpointAddress("http://address:port/IDuplexContract"));
        var channel = factory.CreateChannel();
        channel.AddListener();
        Console.WriteLine("Listening at server....");
        Console.ReadLine();
    }
}

ConsoleWindow 客户端:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Waiting for server & listener to be ready...");
        Console.ReadLine();

        var binding = new BasicHttpBinding();
        binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

        var factory = new ChannelFactory<IContract>(binding, new EndpointAddress("http://address:port/IContract"));
        var channel = factory.CreateChannel();

        while (true)
        {
            channel.Update(Console.ReadLine());
        }
    }
}

问题是无限循环。这是由 System.Net class 创建的,因为当我调用我的回调函数时,System.Net 命名空间正在使用 http 消息跟踪我对下一个服务器的调用。这被记录并发送到记录器等...