我的程序有问题。我创建了一个使用 NLOG 记录其操作的服务。在此服务旁边,我创建了一个工具来捕获此日志记录并将其显示给用户。此连接基于 WSDualHTTPBinding。
除了服务的操作之外,我还记录了 [System.Net]、[System.ServiceModel] 和 [System.Windows] 以获取完整的日志报告。
现在我收到 TimeOutException:无法在分配的 00:01:00 超时内传输消息。可靠通道的传输窗口中没有可用的空间。ETC...
我发现当 System.Net.* 的 LogLevel 设置为 Trace 时会引发此异常。否则不会抛出异常。
我尝试了多种解决方案,例如增加超时;设置 DefaultConnectionLimit;设置 ServiceBehaviorAttribute 等等。他们都没有为我工作......
有人可以帮我解决这个问题吗?
控制台应用服务:
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));
}
}
控制台窗口监听器:
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();
}
}
控制台窗口客户端:
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());
}
}
}