如何实例化ASP.net Web服务的SoapMessage?

时间:2016-06-06 18:49:32

标签: c# asp.net web-services mocking asmx

我已经实现了一个ASP.net Web服务SoapExtension,我想对它进行单元测试。麻烦的是我在ProcessMessage()方法中有我要测试的代码,这个方法需要SoapMessage作为参数。

鉴于SoapMessage是一个带有内部构造函数的抽象类,并且我知道的唯一两个派生类(SoapClientMessageSoapServerMessage)是密封的,我如何实例化它?

我唯一的选择是使用TypeMockJustMock等商业模拟工具吗?

1 个答案:

答案 0 :(得分:1)

我能想出的最好的方法是使用反射来实例化密封类并在其内部字段中设置值。

以下是我提出的代码:

    private SoapServerMessage CreateSoapServerMessage(
        SoapMessageStage stage,
        string action,
        SoapHeaderCollection headers)
    {
        var typ = typeof(SoapServerMessage);

        // Create an instance:
        var constructorInfo = typ.GetConstructor(
            BindingFlags.NonPublic | BindingFlags.Instance,
            null, new[] { typeof(SoapServerProtocol) }, null);
        var message = (SoapServerMessage)constructorInfo.Invoke(new object[] { CreateSoapServerProtocol(action) });

        // Set stage:
        var stageField = typ.BaseType.GetField("stage", BindingFlags.NonPublic | BindingFlags.Instance);
        stageField.SetValue(message, stage);

        // Set headers:
        var headersField = typ.BaseType.GetField("headers", BindingFlags.NonPublic | BindingFlags.Instance);
        headersField.SetValue(message, headers);

        return message;
    }

    private SoapServerProtocol CreateSoapServerProtocol(string action)
    {
        var typ = typeof(SoapServerProtocol);

        // Create an instance:
        var constructorInfo = typ.GetConstructor(
            BindingFlags.NonPublic | BindingFlags.Instance,
            null, Type.EmptyTypes, null);
        var protocol = (SoapServerProtocol)constructorInfo.Invoke(null);

        // Set serverMethod:
        var serverMethodField = typ.GetField("serverMethod", BindingFlags.NonPublic | BindingFlags.Instance);
        serverMethodField.SetValue(protocol, CreateSoapServerMethod(action));

        return protocol;
    }

    private SoapServerMethod CreateSoapServerMethod(string action)
    {
        var typ = typeof(SoapServerMethod);

        // Create an instance:
        var method = new SoapServerMethod();

        // Set action:
        var actionField = typ.GetField("action", BindingFlags.NonPublic | BindingFlags.Instance);
        actionField.SetValue(method, action);

        return method;
    }