0 votes
by (140 points)

Hello,

I am trying out Rebex HTTPs for our Compact Framework.Net app. The app makes extensive use of WCF calls using proxies generated by the CF.Net version of svcutil.

I am using the HttpRequestCreator.Register() approach for registering the Rebex library. However, the WCF calls are getting an error inside the HTTPChannelFactory class with an InvalidCastException. The .Net HTTPChannelFactory.GetWebRequest method is expecting the return type of GetWebRequest to be HttpWebRequest. Since Rebex returns a HttpRequest, this is resulting in the casting exception. I am adding the stack trace at the end of this message.

Is there any alternative way of using HttpChannelFactory with Rebex, or plans to add support for this in the future ?

Thanks.

Subha Tarafdar.

Stack Trace returning InvalidCastException: 
at System.ServiceModel.Channels.HttpChannelFactory.GetWebRequest(EndpointAddress to, Uri via, TimeSpan timeout)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.GetWebRequest(EndpointAddress to, Uri via, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.HttpsChannelFactory.HttpsRequestChannel.GetWebRequest(EndpointAddress to, Uri via, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.SendRequest(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message)
at Microsoft.Tools.ServiceModel.CFClientBase`1.getReply(Message msg)
at Microsoft.Tools.ServiceModel.CFClientBase`1._Invoke[TREQUEST,TRESPONSE](CFInvokeInfo info, IsAvailableForSyncingRequest request)
at Microsoft.Tools.ServiceModel.CFClientBase`1.Invoke[TREQUEST,TRESPONSE](CFInvokeInfo info, IsAvailableForSyncingRequest request)
Applies to: Rebex HTTPS
by (73.5k points)
Hi, the problem is already solved. Please see my comment from 2017-05-26:
http://forum.rebex.net/7041/rebex-https-support-for-proxies-using-httpchannelfactory?show=7111#c7111
by (3.9k points)
You are talking about Rebex.Ftp, but this question is related to Rebex.Http.

Please, ask new question and describe your issue.
Are you using Rebex.Ftp in WCF? How?
Attach exception details as well please.
by (73.5k points)
Oh, I was confused by mentioning Rebex.Ftp.

Ok, please download the custom WCF binding implementation from: https://www.rebex.net/getfile/b541b39f9c334407b148786cd6fbdbc4/RebexWcfBinding.zip

Include the classes in your project and use it like this:

    // initialize Rebex WCF binding
    var binding = new Rebex.Samples.WcfBinding();

    // just for testing purposes, skip server's certificate validation
    // Do not use this in production code!
    binding.RequestCreator.Settings.SslAcceptAllCertificates = true;

    // use your WCF service (e.g. GeocodeServiceClient in my case)
    GeocodeServiceClient client = new GeocodeServiceClient(binding,
        new System.ServiceModel.EndpointAddress("https://address/geocodeservice.svc"));
by (3.9k points)
edited by
It seems that the server is closing connection for some reason. please send a communication log in debug level to support@rebex.net for analysis. it cxan be done like this:

binding.RequestCreator.LogWriter = new Rebex.FileLogWriter(@"/log.txt", Rebex.LogLevel.Debug);

1 Answer

0 votes
by (73.5k points)
edited by

UPDATE:

The custom WCF binding implementation discussed below in comments is already available at https://www.rebex.net/getfile/b541b39f9c334407b148786cd6fbdbc4/RebexWcfBinding.zip

You can use it like this:

new MyServiceClient(new WcfBinding(), new EndpointAddress("https://..."))

To configure various properties, use WcfBinding.RequestCreator property.


Original answer:

Hello,

you are right. The problem is caused by impossibility to cast Rebex class HttpRequest into system class HttpWebRequest.

Unfortunately, the HttpWebRequest class on .NET CF has no public or protected constructor, so we cannot derive from it. We can derive only from WebRequest class.

Also the HttpChannelFactory class is written in a way it can use HttpWebRequest class only.

We are not familiar with WCF, but I used to create some Web References. There you get a partial class XyzService, which inherits from System.Web.Services.Protocols.SoapHttpClientProtocol. Using partial keyword, you can simply reimplement some functionality which remains unchanged even when you recreate the web reference.

Try to look at some way to reimplement CFClientBase1.Invoke or CFClientBase1.getReply or RequestChannel.Request or inject your implementation of HttpChannelFactory which doesn't require HttpWebRequest class only or something similar.

For example in my VB.NET project I do similar this way:

Partial Public Class MyService

    Protected Overrides Function GetWriterForMessage(message As SoapClientMessage, bufferSize As Integer) As XmlWriter
        ' inject code for signing the request here
        Return New SigningXmlTextWriter(MyBase.GetWriterForMessage(message, bufferSize))
    End Function

End Class

I implemented SigningXmlTextWriter class to sign the SOAP request message with an X509 certificate.

If you send us your project at support@rebex.net (so we can reproduce the issue) we will look at it and hopefully find a solution to solve this issue.

by (140 points)
Hello,

Thank you for your reply.

As you mentioned, making it work will likely involve replacing the HttpChannelFactory and some related classes. What may make this tricky is that the HttpsChannelFactory is marked as Internal in .Net.

It would have been easier if the Rebex library could return a HttpWebRequest, but I see the problem due to the constructor not being available. Wondering if this can be worked around by using reflection to instantiate the object. Not sure if it would be possible,  just a thought.

I am emailing a small test project that demonstrates the error when calling a publicly available WCF service.

Thanks again for your help regarding this.

- Subha Tarafdar
by (73.5k points)
Thank you for the project. We are able to reproduce the issue. We will share solution here when ready.
by (73.5k points)
I have small progress on this. I found at least one point where to inject my code. When creating `new GeocodeServiceClient(new BasicHttpBinding(...` I used my own class `RebexHttpBinding` derived from `BasicHttpBinding`. That class overrides method `BuildChannelFactory<TChannel>(BindingParameterCollection parameters)`. Using this I am able to redirect calls from system's `HttpsChannelFactory` to my classes. However, implementing the fully functional `Binding` class is more demanding.

If you have experience with using custom `Bindings` this can point you to right direction. I will keep you updated about my progress.
by (140 points)
Thanks for the update, and for looking into this. This approach will probably work. It seems the biggest hurdle would be in implementing the corresponding HttpsChannelFactory class. The class is marked as internal in .Net, so it would pretty much need to be completely  reimplemented.
by (73.5k points)
I Googled for samples of custom IRequestChannel implementations and I found couple of examples:

https://blogs.msdn.microsoft.com/carlosfigueira/2011/07/11/wcf-extensibility-channels/

https://holsson.wordpress.com/2009/10/01/implementing-a-custom-biztalk-adapter-as-a-custom-wcf-channel-part-1-send/

http://www.dotnet-geek.co.uk/index.php/creating-wcf-custom-transport-channel/

Using this, it should be easy to implement custom HttpsBinding. Basically, the most interesting method is:

  public Message Request(Message message, TimeSpan timeout)

Within this method, just use Rebex.Net.WebClient to send/receive the data.

We are just finishing new release, so I have not much time for this, but I will definitely write working example myself and share my code ASAP.
by (73.5k points)
Is it possible for you to use Web Reference proxy instead of WCF proxy?

I tried to add Web Reference for http://dev.virtualearth.net/webservices/v1/metadata/geocodeservice/geocodeservice.wsdl into my test project and it works well with Rebex HTTP (except I am not able to authenticate). This can be quick workaround if you don't need to use specials of WCF.
by (140 points)
Thanks for the suggestion. I will look into whether the WebReference proxies will work with our solution.
by (73.5k points)
I finally completed custom Binding with all necessary features. You can download it from http://www.rebex.net/getfile/b541b39f9c334407b148786cd6fbdbc4/RebexWcfBinding.zip

You can use it like this:

  new MyServiceClient(new WcfBinding(), new EndpointAddress("https://..."))

To configure various properties use WcfBinding.RequestCreator property. Especially, on .NET CF use only for testing purposes:
  binding.RequestCreator.Settings.SslAcceptAllCertificates = true;
by (140 points)
Thanks a lot ! I will try it out and let you know.
by (140 points)
I have tried it out, it is working fine so far. There are some configurations like WCF maximum message size, etc which I will need to look at, but the WCF calls in general are working.
by (73.5k points)
Great. Thank you for letting us know.
...