我有一个简单的WCF服务
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; }
}
}
通过以下实施:
using System;
using System.Threading.Tasks;
using Interface;
namespace ConsoleApplication1
{
public class Service1 : IService1
{
public async Task<A> DoWorkAsync(A a)
{
if (a.B <= 5)
{ // for 5% of calls make an exception
Console.WriteLine("{0} Sleep", DateTime.Now.ToString("hh:mm:ss.fff"));
await Task.Delay(1000);
return a;
}
else
{
Console.WriteLine("{0} No Sleep", DateTime.Now.ToString("hh:mm:ss.fff"));
return a;
}
}
}
}
托管在控制台应用程序中
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();
}
}
}
}
单元测试(使用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;
}
}
}
问题是:当我运行测试时,我得到3个错误(我没想到):
The HTTP request to 'http://localhost:8080/service1' was aborted. This may be due to the local channel being closed while the request was still in progress. If this behavior is not desired, then update your code so that it does not close the channel while request operations are still in progress. ---> System.Net.WebException: The request was aborted: The request was canceled.
为什么会发生这些异常,特别是第二个异常?
更新
似乎设置900ms的超时是一个坏主意,从1300ms超时和1400ms延迟开始,2d错误消失了。这很奇怪,我仍然想知道为什么会这样。
第一个错误是由于WCF&#39;热身&#39; (或者可能是我的实现很糟糕) - 如果你得到一个更大的数字,比如400个请求 - 第一次你运行测试它失败了~290个请求,第二次(如果你真的很快)~140 requets, 3d时间 - 约30次请求,之后如果你非常快地运行测试 - 没有错误。
此外,如果你很好奇 - 尝试大量的请求,比如3000,你也会遇到一些有趣的错误。