urig
urig

Reputation: 16831

How to Instantiate ASP.net Web Service's SoapMessage?

I've implemented an ASP.net Web Service SoapExtension and I want to unit test it. Trouble is I have code in the ProcessMessage() method that I want to test and this method expects a SoapMessage as an argument.

Given than SoapMessage is an abstract class with an internal constructor and that the only two derived classes that I know (SoapClientMessage and SoapServerMessage) are sealed, how can I instantiate it?

Is my only option to use commercial mocking tools like TypeMock or JustMock?

Upvotes: 2

Views: 234

Answers (1)

urig
urig

Reputation: 16831

Best I could come up with is using reflection to instantiate the sealed classes and set values in their internal fields.

Here is the code that I came up with:

    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;
    }

Upvotes: 1

Related Questions