Web Service / Authenticating Proxy .NET and COM interop

G

Guest

Sorry for the repost - MS requested I do this
Hi,
I have a C# Web Service component I call 2 different ways:
- For testing I have a "pure" .NET solution. A C# test harness app
invokes my C# component.
- From the "real" application, a native C++ app, I call the C#
component via COM interop.

My all .NET test harness has a 407 error returned to it from the web
service component when I don't supply credentials for the proxy server.
The real app, using COM interop, results in an underlying connection closed
error that I've seen written about many times Anyone know why the
difference? this is under framework version 1.1.

Is the "underlying connection closed" error really only a defect seen when
you go native to managed as in COM interop?

Also, when I test the COM Interop solution under version 2.0 of framework
with invalid credentials (hoping to get the improved proxy handling) I never
get a response. The application just hangs. I can't even cancel the request.

The above is all implemented as asynchronous using the Begin... and End...
semantics.
Thank you
 
P

Peter Huang [MSFT]

Hi

I think you may try to follow the link below to access a Web Service from
C++.
Walkthrough: Accessing an XML Web Service Using C++
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsent7/html
/vbwlkwalkthroughusingwebservicewithunmanagedcode.asp

The code above will use ATL class CSoapSocketClientT to access the Web
Service.
CSoapSocketClientT Class
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/
vclrfCSoapSocketClientT.asp
============================================================================
================================
This class conforms to ATL Server's SOAP client archetype.

Typically this class is used with SPROXY-generated classes which build up
the SOAP messages for you, but it is possible to use this class
independently in the following way:

Create an instance and pass the location of the XML Web service to the
constructor.

Call SetProxy or SetTimeout if necessary.

Call GetWriteStream and write the SOAP message to that stream.

Call SendRequest to send the SOAP message to the server.

If SendRequest succeeded, call GetReadStream to read the SOAP response.

If SendRequest failed, call GetClientError and GetStatusCode, or look at
m_fault for error information.

Call CleanupClient before returning to Step 3 to send further messages.
============================================================================
================================
Here is C++ code snippet to access webservice.
void AccessService(){
using namespace std;
Service::CService ws;
CComBSTR bstr;
HRESULT hr = ws.HelloWorld(&bstr);
if (SUCCEEDED(hr))
{
CW2A printstr(bstr);
cout<<"C++"<<endl;
cout<<printstr<<endl;
}
else
{
cout<<ws.GetStatusCode()<<endl;
cout<< "An error occurred: "<<hex<<hr<< endl;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
if (SUCCEEDED(CoInitialize(NULL))){
AccessService();
CoUninitialize();
}
return 0;
}

NOTE: we can try to use the ws.GetStatusCode() to get the StatusCode e.g.
401.

If I have any misunderstanding, please feel free to post here.



Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I'm not sure that you understand my problem. This question doesn't concern
the proxy (code) as much as a difference between how the .NET framework runs
the same .NET code via COM interop vs. a pure .NET solution. True I could
have possibly used ATL but we are moving towards .NET.

The difference is only when I need to get past an authenticating proxy
server residing on the network. Using .NET via COM Interop works fine except
for when an authenticating proxy server is in the mix. This is that I have
an issue with - the COM interop solution.

Why would I get different return values from the same .NET code depending if
it's called via COM interop or pure .NET?

To summarize:

Pure .NET solution - NET test harness (with Authenticating proxy server in
the mix) -> NET Web Service Client (framework 1.1) works fine (receive
response with 407 error)

Interop solution - COM Interop (with Authenticating proxy server in the mix)
-> different return (underlying connection closed)

Additionally, under 2.0 framework
COM Interop (with Authenticating proxy in the mix) -> no good (never returns
- async call can't be stopped)

"Peter Huang" said:
Hi

I think you may try to follow the link below to access a Web Service from
C++.
Walkthrough: Accessing an XML Web Service Using C++
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsent7/html
/vbwlkwalkthroughusingwebservicewithunmanagedcode.asp

The code above will use ATL class CSoapSocketClientT to access the Web
Service.
CSoapSocketClientT Class
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/
vclrfCSoapSocketClientT.asp
============================================================================
================================
This class conforms to ATL Server's SOAP client archetype.

Typically this class is used with SPROXY-generated classes which build up
the SOAP messages for you, but it is possible to use this class
independently in the following way:

Create an instance and pass the location of the XML Web service to the
constructor.

Call SetProxy or SetTimeout if necessary.

Call GetWriteStream and write the SOAP message to that stream.

Call SendRequest to send the SOAP message to the server.

If SendRequest succeeded, call GetReadStream to read the SOAP response.

If SendRequest failed, call GetClientError and GetStatusCode, or look at
m_fault for error information.

Call CleanupClient before returning to Step 3 to send further messages.
============================================================================
================================
Here is C++ code snippet to access webservice.
void AccessService(){
using namespace std;
Service::CService ws;
CComBSTR bstr;
HRESULT hr = ws.HelloWorld(&bstr);
if (SUCCEEDED(hr))
{
CW2A printstr(bstr);
cout<<"C++"<<endl;
cout<<printstr<<endl;
}
else
{
cout<<ws.GetStatusCode()<<endl;
cout<< "An error occurred: "<<hex<<hr<< endl;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
if (SUCCEEDED(CoInitialize(NULL))){
AccessService();
CoUninitialize();
}
return 0;
}

NOTE: we can try to use the ws.GetStatusCode() to get the StatusCode e.g.
401.

If I have any misunderstanding, please feel free to post here.



Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
P

Peter Huang [MSFT]

Hi

I am sorry. It seems that I did not understanding your scenario very clear.
From your description, you have two test solutions.
1. pure .NET
NET client --->proxy---->Web Service
You will get 407, which means the proxy need authentication. You did not
have concern with the scenario or you want to know how to make the .NET
client call Web Service successfully without the 407 error.

2. Com Interop
Refer to my last post about how to call Web Service from C++.
If you mean the scenario as below.
C++ client ----> .NET class libray----->proxy----->Web Service

The C++ client called .NET class library via Com Interop.
You want to know why the C++ client did not get the 407 error. If this is
not the case please let me know.
This involved the fact that .NET and COM have their own error handling
mechanism.
Error Handling
http://msdn.microsoft.com/msdnmag/issues/01/08/Interop/

Handling COM Interop Exceptions
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconhandlingcominteropexceptions.asp

HRESULTs and Exceptions
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconHRESULTsExceptions.asp


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Sorry, I think I'm not being clear in my question. Let me give some sample
code where the issue shows:
When the WebService fails with authenticating proxy it throws exception as
follows:
if(ex is System.Net.WebException)
{
..
..
// Get the HttwWebResponse to examine status
System.Net.WebException we = (System.Net.WebException)ex;
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)we.Response;
// called pure .NET always have resp
// When COM client calls resp always null for some reason
// and ex.message says underlying connection is closed
if(resp != null)
{
// this code does not execute for COM clients. resp is always null
serverError = (int)resp.StatusCode; // look for 407 enum
// proxy
authentication required
 
P

Peter Huang [MSFT]

Hi

So far I understand your scenario you are going the second test solution in
my last post.
C++ client ----> .NET class library----->proxy----->Web Service

In the .NET class library, you are using the same code with the .NET test
client.
But in the .NET class library you will not get 407 response. You will just
get a underlying connection is closed¡§error or just hang in .NET 2.0.
If I misunderstood, please feel free to post here.

For this scenario, I think you may try to use netmon tool to see what will
return from the proxy or if it has returned from the proxy.
Microsoft have netmon tool shipped with SMS server.
You may try the netmon tool in the link below.
http://www.netmon.org/tools.htm#Sniffers

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Sorry for taking so long to get back...
Upon further review with Ethereal:
407 is returned in all cases. To summarize in my .NET -> .COM interop
solution the following code will not work since the response is always NULL
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)we.Response;
if(resp != null)
{
serverError = (int)resp.StatusCode;.
}
The same code above works for a .NET -> .NET solution where resp is never
null.

What I realized is in the .NET -> .COM interop solution is that for some
reason the true error condition is instead found in the InnerException. For
this case the outer exception indicates only that the "underlying connection
was closed". So basically same code as above but:
System.Net.WebException we = ex.InnerException as System.Net.WebException;
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)we.Response;
if(resp != null)
{
serverError = (int)resp.StatusCode;
}
Any ideas why I should have to look at InnerException for COM interop?

Also the hanging under .NET 2.0 seems to also happen under .NET 1.1.
However, the issue here seems to be .NET using http 1.1 vs. what my proxy
server is using, which is http 1.0. There seems to be some incompatibility
between versions . This only happens when I supply a userID and an incorrect
password. If I change the property on the HttpWebRequest object returned to
Version10 this seems to take care of this issue. I can also duplicate this
with Internet Explorer going against my proxy if I configure IE to use HTTP
1.1 for proxy authentication.

Thanks
 
P

Peter Huang [MSFT]

Hi

First I think we need to confirm what is your scenario with Com Interop
solution.
C++ client ----> .NET class library----->proxy----->Web Service

If it is the problem at the above one, then the problem occurred in .NET
class library----->proxy----->Web Service should did not be related with
Com interop.
Becaused the problem is all occurred in the .NET library called web service.

If I misunderstand, please correct me.
If you want to handle exception across Com interop layer.

I htink you may try to have a look at the information below about how to
handle exception between .NET and COM via Com inerop wrap.
This involved the fact that .NET and COM have their own error handling
mechanism.
Error Handling
http://msdn.microsoft.com/msdnmag/issues/01/08/Interop/

Handling COM Interop Exceptions
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconhandlingcominteropexceptions.asp

HRESULTs and Exceptions
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconHRESULTsExceptions.asp




Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Peter,
Both articles are good, but this isn't what I'm trying to solve.

The issue seems to be with .NET library and only happens under the scenario
I described. I am having no issues returning error information from COM
(please see earlier postings). From watching in the debugger I can see the
problem is that the .NET library exception contains different information to
return to COM (different from the pure .NET solution). As I just discovered,
when calling the .NET library from COM I must look at the innerexception
information. I can change my library to additionaly check the
innterexception and return this to my COM client, and this is probably what
I'll end up doing.

Before doing so, I am trying to understand why the same .NET code behaves
differently depending on client that is calling the library. The only
difference I see is that in one case a C++ unmanaged client calls via COM
interop, and in the other case a .NET managed client calls the code.
 
P

Peter Huang [MSFT]

Hi

Here I assumed that you have gone the way below.
C++--->.NET Library--->proxy---->WebService

In this way, if there is 407 returned from proxy to the .NET Library, the
try catch block in the .NET Library will generate the exception which is
different from the way below.
..NET client --->proxy----> WebService.

The code in the .NET client and .NET Library are of the same.
e.g.
try
{
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}

In the two scenario, the Debug Writeline will output differently.

If so can you provide a simple reproduce sample for us to make further test?

Thanks!

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top