C# 由于关闭本地通道,HTTP请求中止WCF错误
我有一个简单的WCF服务C# 由于关闭本地通道,HTTP请求中止WCF错误,c#,.net,wcf,.net-4.5,channelfactory,C#,.net,Wcf,.net 4.5,Channelfactory,我有一个简单的WCF服务 using System.Runtime.Serialization; using System.ServiceModel; using System.Threading.Tasks; namespace Interface { [ServiceContract] public interface IService1 { [OperationContract] Task<A> DoWorkAsync
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading.Tasks;
namespace Interface
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Task<A> DoWorkAsync(A a);
}
[DataContract]
public class A
{
[DataMember]
public int B { get; set; }
}
}
以及一个单元测试(使用NUnit),它向服务发送一些请求:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Interface;
using NUnit.Framework;
namespace WcfTests
{
[TestFixture]
public class Test
{
public const int NumberOfCalls = 100;
[Test]
public void UseService()
{
var baseAddresses = new Uri("http://localhost:8080/service1");
var binding = new BasicHttpBinding
{
SendTimeout = TimeSpan.FromMilliseconds(900)
};
var endpoint = new EndpointAddress(baseAddresses);
using (var factory = new ChannelFactory<IService1>(binding, endpoint))
{
IService1 client = factory.CreateChannel();
var r = new Random();
try
{
var seed = Enumerable.Range(0, NumberOfCalls)
.Select(i => r.Next(6, 100)).ToList();
Console.WriteLine("Expected to fail: {0}", seed.Count(t => t <= 5));
var tasks = seed.Select(rnd => MakeACall(client, rnd)).ToArray();
Task.WaitAll(tasks);
Console.WriteLine("failed = {0}", tasks.Count(t => !t.Result));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
Console.WriteLine("Program.UseService.finally");
var c = client as IClientChannel;
if (c != null)
{
c.Close();
}
}
}
Console.WriteLine("{0} unique exceptions", UniqueExceptions.Count);
foreach (var uniqueException in UniqueExceptions)
{
Console.WriteLine(uniqueException.Value);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
}
}
public ConcurrentDictionary<string, string> UniqueExceptions = new ConcurrentDictionary<string, string>();
public async Task<bool> MakeACall(IService1 client, int rnd)
{
bool result = true;
var a = new A
{
B = rnd
};
try
{
await client.DoWorkAsync(a);
}
catch (Exception e)
{
var exInfo = e.ToString();
var hasher = SHA256.Create();
var hash = Encoding.UTF8.GetString(hasher.ComputeHash(Encoding.UTF8.GetBytes(exInfo)));
UniqueExceptions.TryAdd(hash, exInfo);
result = false;
}
return result;
}
}
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq;
使用System.Security.Cryptography;
使用System.ServiceModel;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用接口;
使用NUnit.Framework;
命名空间WcfTests
{
[测试夹具]
公开课考试
{
public const int NumberOfCalls=100;
[测试]
公共服务
{
var baseAddresses=新Uri(“http://localhost:8080/service1");
var binding=新的BasicHttpBinding
{
SendTimeout=TimeSpan.From毫秒(900)
};
var端点=新端点地址(基本地址);
使用(var factory=newchannelfactory(绑定,端点))
{
IService1 client=factory.CreateChannel();
var r=新的随机变量();
尝试
{
var seed=可枚举的范围(0,NumberOfCalls)
.Select(i=>r.Next(6100)).ToList();
WriteLine(“预期失败:{0}”,seed.Count(t=>t MakeACall(client,rnd)).ToArray();
Task.WaitAll(任务);
WriteLine(“failed={0}”,tasks.Count(t=>!t.Result));
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
最后
{
WriteLine(“Program.UseService.finally”);
var c=作为IClientChannel的客户端;
如果(c!=null)
{
c、 Close();
}
}
}
WriteLine(“{0}唯一异常”,UniqueExceptions.Count);
foreach(UniqueExceptions中的var uniqueException)
{
Console.WriteLine(uniqueException.Value);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
}
}
public ConcurrentDictionary UniqueExceptions=新建ConcurrentDictionary();
公共异步任务MakeACall(IService1客户端,int rnd)
{
布尔结果=真;
var a=新a
{
B=rnd
};
尝试
{
等待client.doworksync(a);
}
捕获(例外e)
{
var exInfo=e.ToString();
var hasher=SHA256.Create();
var hash=Encoding.UTF8.GetString(hasher.ComputeHash(Encoding.UTF8.GetBytes(exInfo));
TryAdd(散列,exInfo);
结果=假;
}
返回结果;
}
}
}
问题是:当我运行测试时,我得到3个错误(我希望没有错误):
更新: 似乎将超时设置为900ms是个坏主意,从1300ms超时和1400ms延迟开始,2d错误消失了。这很奇怪,我仍然想知道为什么会发生这种情况 第一个错误是由于WCF“预热”(或者可能是因为我的实现很糟糕)-如果您得到一个更大的数字,比如400个请求-第一次运行测试时失败约290个请求,第二次(如果您真的很快)失败约140个请求,3d时间-~30个请求,之后如果您运行测试非常快,则不会出现错误
另外,如果你很好奇-尝试大量的请求,比如3000个,你也会在那里得到一个有趣的错误。我想我不明白你为什么要强制执行这么低的超时阈值?我相信默认的SendTimeout是60秒,大大高于你的900ms-1400ms范围。这个示例主要是教育性的,我是r在WCF和900毫秒范围内搜索async/await只是一种使测试快速失败的方法。但是,对一个响应请求的服务进行web调用需要很多时间……因此我认为WCF没有理由进行故障转移
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var baseAddresses = new Uri("http://localhost:8080/service1");
using (var host = new ServiceHost(typeof (Service1), baseAddresses))
{
var serviceMetadataBehavior = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
MetadataExporter =
{
PolicyVersion = PolicyVersion.Policy15
}
};
host.Description.Behaviors.Add(serviceMetadataBehavior);
host.Open();
Console.WriteLine("Running, press Enter to exit");
Console.ReadLine();
host.Close();
}
}
}
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Interface;
using NUnit.Framework;
namespace WcfTests
{
[TestFixture]
public class Test
{
public const int NumberOfCalls = 100;
[Test]
public void UseService()
{
var baseAddresses = new Uri("http://localhost:8080/service1");
var binding = new BasicHttpBinding
{
SendTimeout = TimeSpan.FromMilliseconds(900)
};
var endpoint = new EndpointAddress(baseAddresses);
using (var factory = new ChannelFactory<IService1>(binding, endpoint))
{
IService1 client = factory.CreateChannel();
var r = new Random();
try
{
var seed = Enumerable.Range(0, NumberOfCalls)
.Select(i => r.Next(6, 100)).ToList();
Console.WriteLine("Expected to fail: {0}", seed.Count(t => t <= 5));
var tasks = seed.Select(rnd => MakeACall(client, rnd)).ToArray();
Task.WaitAll(tasks);
Console.WriteLine("failed = {0}", tasks.Count(t => !t.Result));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
Console.WriteLine("Program.UseService.finally");
var c = client as IClientChannel;
if (c != null)
{
c.Close();
}
}
}
Console.WriteLine("{0} unique exceptions", UniqueExceptions.Count);
foreach (var uniqueException in UniqueExceptions)
{
Console.WriteLine(uniqueException.Value);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
}
}
public ConcurrentDictionary<string, string> UniqueExceptions = new ConcurrentDictionary<string, string>();
public async Task<bool> MakeACall(IService1 client, int rnd)
{
bool result = true;
var a = new A
{
B = rnd
};
try
{
await client.DoWorkAsync(a);
}
catch (Exception e)
{
var exInfo = e.ToString();
var hasher = SHA256.Create();
var hash = Encoding.UTF8.GetString(hasher.ComputeHash(Encoding.UTF8.GetBytes(exInfo)));
UniqueExceptions.TryAdd(hash, exInfo);
result = false;
}
return result;
}
}
}