WCF问题集锦:基础连接已经关闭 接收时发生错误

时间:2022-08-16 20:46:16

今天,进行单元测试时,当执行到第二个测试类时——之前从来没有错误的测试居然报了:基础连接已经关闭 接收时发生错误。想想今天唯一改动的是在测试代码中加了下列两个执行体:

[TestFixtureSetUp]
public void Set()
{
    CommonFuns.SetTime();
}

[TestFixtureTearDown]
public void Restore()
{
    CommonFuns.RestoreTime();
}
其中,Set用来设置系统当前时间为制定值,Restore用来恢复系统时间。

然后,手动一个一个测试类执行过来,都是好的。为了确认问题的确是上述代码执行造成的,把上面代码注销后再次整体执行,没有报错;再次加上代码,整体执行,报错,重复上面两个,都是同一现象。确定问题原因是这段系统时间调整造成的。

想到手动执行就没有问题,猜测可能是因为系统执行过程中,从一个上一个类的恢复时间到下一个类的调整时间,然后又马上调用实际的测试代码,造成服务端(开发环境测试代码与服务端在同一电脑上)代码执行时系统时间错乱,从而造成超时等时间原因,最后关闭连接。因此,决定模拟手动操作,在调整和恢复时间后,加上1秒的延时再执行具体的测试方法。经过测试,问题解决。

系统时间调整代码如下:

using System.Runtime.InteropServices;

namespace VME.UnitTest.Service
{
    public class SystemTimer
    {
        //imports SetLocalTime function from kernel32.dll 
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int SetLocalTime(ref SystemTime lpSystemTime);

        //struct for date/time apis 
        public struct SystemTime
        {
            public short wYear;
            public short wMonth;
            public short wDayOfWeek;
            public short wDay;
            public short wHour;
            public short wMinute;
            public short wSecond;
            public short wMilliseconds;
        }
    }
}

public static void SetTime()
{
    SetTime(0);
}

public static void RestoreTime()
{
    RestoreTime(0);
}

/// <summary>
/// 将时间从15点开始向后拨5小时
/// </summary>
public static void SetTime(int day)
{
    _diffHours = 0;

    if (DateTime.Now.Hour > 15)
    {
        _diffHours = 5;

        // And then set up a structure with the required properties and call the api from code: 
        SystemTimer.SystemTime systNew = new SystemTimer.SystemTime();

        // 设置属性 
        systNew.wDay = Convert.ToInt16(DateTime.Now.AddDays(day).Day);
        systNew.wMonth = Convert.ToInt16(DateTime.Now.Month);
        systNew.wYear = Convert.ToInt16(DateTime.Now.Year);
        systNew.wHour = Convert.ToInt16(DateTime.Now.Hour - _diffHours);
        systNew.wMinute = Convert.ToInt16(DateTime.Now.Minute);
        systNew.wSecond = Convert.ToInt16(DateTime.Now.Second);

        // 调用API,更新系统时间 
        SystemTimer.SetLocalTime(ref systNew);

        Thread.Sleep(1000);
    }
}

/// <summary>
/// 将时间拨回
/// </summary>
public static void RestoreTime(int day)
{
    if (_diffHours > 0)
    {
        // And then set up a structure with the required properties and call the api from code: 
        SystemTimer.SystemTime systNew = new SystemTimer.SystemTime();

        // 设置属性 
        systNew.wDay = Convert.ToInt16(DateTime.Now.AddDays(day).Day);
        systNew.wMonth = Convert.ToInt16(DateTime.Now.Month);
        systNew.wYear = Convert.ToInt16(DateTime.Now.Year);
        systNew.wHour = Convert.ToInt16(DateTime.Now.Hour + _diffHours);
        systNew.wMinute = Convert.ToInt16(DateTime.Now.Minute);
        systNew.wSecond = Convert.ToInt16(DateTime.Now.Second);

        // 调用API,更新系统时间 
        SystemTimer.SetLocalTime(ref systNew);

        _diffHours = 0;

        Thread.Sleep(1000);
    }
}