1

I am developing a ComVisible library in .NET which is then called in an old VB6 class. What I basically do in the class is calling a web service, parsing the response and returning an object with necessary data. The web service is designed so that it returns a SoapException if called with wrong parameter(s). Here is a part of my code:

    private static WCFPersonClient _client;
    private static ReplyObject _reply;

    public BFRWebServiceconnector()
    {
        _client = new WCFPersonClient("WSHttpBinding_IWCFPerson");
        _reply = new ReplyObject ();            
    }

    [ComVisible(true)]
    public ReplyObject GetFromBFR(string bestallningsID, string personnr, bool reservNummer = false)
    {
        try
        {
            var response = new XmlDocument();

            //the service operation returns XML but the method in the generated service reference returns a string for some reason               
            var responseStr = _client.GetUserData(orderID, personnr, 3); reason.

            response.LoadXml(responseStr);
            //parse the response and fill the reply object
            .......
        }
        catch (Exception ex)
        {
            _reply.Error = "Error: " + ex.Message;
            if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
        }
        return _reply;
    }

Once I try to call this method from my VB6 code with correct parameters, I get a proper reply. But if I call it with a wrong parameter, I get a -245757 (Object reference was not set to an instance of an object) runtime error in my VB6 program and it seems that it's not caught by the catch clause in my C# code (while I would expect an empty ReplyObject with filled Error field returned by the method).

I have created a test C# project and copied the same method (i.e. I call the same web service from within the .NET platform) and I can confirm that in this case the SoapException is being properly caught.

Is this behavior intentional? Is there a way to catch the SoapException within a ComVisible class (since I really would like to include the error message into my reply object)?

UPD: My VB6 code is following:

Set BFRWSCReply = New ReplyObject
Set BFRWSC = New BFRWebbServiceconnector
Set BFRWSCReply = BFRWSC.GetFromBFR(m_BeställningsID, personnr)

If Not IsNull(BFRWSCReply) Then
    If BFRWSCReply.Error= "" Then
       m_sEfternamn = BFRWSCReply.Efternamn
       //etc i.e. copy fields from the ReplyObject
    Else
       MsgBox BFRWSCReply.Error, vbExclamation
    End If
End If
Azimuth
  • 2,599
  • 4
  • 26
  • 33
  • Maybe `_replay` object is not initialized while error is set in catch clause: `_reply.Error = "Error: " + ex.Message;` – Algirdas Jan 04 '13 at 13:55
  • @algirdas, no, it is initialized, in the constructor. – Azimuth Jan 04 '13 at 14:02
  • What is the runtime error from VB? – D Stanley Jan 04 '13 at 14:23
  • @DStanley it's `-245757 Error 1 - Application-defined or object-defined error : Object reference not set to an instance of an object.` – Azimuth Jan 04 '13 at 14:31
  • Is the `ReplyObject` marked as `ComVisible` as well? – D Stanley Jan 04 '13 at 14:38
  • @DStanley yes, it is `ComVisible` as well. – Azimuth Jan 04 '13 at 14:42
  • Returning global variables is asking for trouble. Be sure to use the debugger, setting it up to allow debugging both VB6 and C# code is covered in this answer: http://stackoverflow.com/a/11975581/17034 – Hans Passant Jan 04 '13 at 15:19
  • @HansPassant unfortunately I cannot debug the program as the web service is only accessible from a test machine via VPN where I got no VisualStudio... – Azimuth Jan 04 '13 at 15:30
  • @Azimuth then my guess about scope is probably wrong since the _data_ for the class is marshaled, the service can do anything it wants with the objects. Are you trying to access a specific property of the `ReplyObject` when the exception occurs? – D Stanley Jan 04 '13 at 15:36
  • @DStanley do you mean in the VB6 code? If so, yes, I check if the `Error` field is empty and if not I try to read other fields of the object. I updated the question with my VB6 code. – Azimuth Jan 04 '13 at 15:43

2 Answers2

0

(this is just a guess and is more fitting for a comment but it's pretty long)

It's possible that the .NET runtime is disposing of the ReplyObject COM object when the BFRWebServiceconnector class goes out of scope, maybe because it is a property of the class and not created within the method?

Try creating the ReplyObject within GetFromBFR instead of making it a property of the class. That also might prevent weird errors from multithreaded access if the COM object is called from different threads.

Also if there's a particular line in the VB program that is throwing the error (after you call GetFromBFR), you could see if the variable is Nothing within VB to try and narrow down the problem.

Like I said, just a guess. Feel free to refute it. :)

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • I will try to create the `ReplyObject` within the method. Somehow I missed this point myself... – Azimuth Jan 04 '13 at 15:31
0

I'm very ashamed that the reason was very very simple... Instead of following:

catch (Exception ex)
    {
        _reply.Error = "Error: " + ex.Message;
        if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
    }

I had actually following code:

catch (Exception ex)
    {
        _reply.Error = "Error: " + ex.Message + "; " + ex.InnerException.Message;
        if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
    }

and it turns out that ex.InnerException was null which caused the NullPointerException...

Azimuth
  • 2,599
  • 4
  • 26
  • 33