Using WCF to wrap an existing connected stream - wcf

I have both ends of a bi-directional connected Stream, which I want to do some communication over. The underlying implementation behind the stream isn't important, I want to work at the Stream level...
Rather than implement my own communications protocol for the stream, I want to use all of the existing WCF goodness to wrap the existing stream with with a bi-directional (request/response + callback) WCF communications channel.
My question is, how can I go about doing this...?
UPDATE:
I've gone down the path of implementing a custom transport. I've got this working, but I'm still not totally happy with it...
I've implemented an IDuplexSessionChannel to wrap the stream, along with appropriate IChannelFactory and IChannelListener, and a Binding Element for creating the channel factories. Now, I just pass through the connected stream, and eventually pass these into the transport channel when it is created.
So, I can create the client proxy for accessing the service via the stream as follows:
var callback = new MyCallback();
var instanceContext = new InstanceContext( callback );
var pipeFactory = new DuplexChannelFactory<IMyService>( instanceContext, new StreamBinding(clientStream),
new EndpointAddress("stream://localhost/MyService"));
var serviceProxy = pipeFactory.CreateChannel();
The problem I have is, it seems WCF is set on using a ServiceHost to create the server end of the channel, via a IChannelListener. In my case, I already have a connected stream, and I won't be able to listen for any more incoming connections. I can work around this, but I'd much rather not use a ServiceHost to create the server end of the channel, because I end up with a lot of obscure boilerplate and hacks to make it work.
Questions
I'm looking, therefore, for a better way to take the IDuplexSessionChannels, and wrap these into a Channel proxy at both the server and client ends.
Or maybe a different ServiceHost implementation that doesn't require a IChannelListener.
Really, the problem here is I don't want a single server, multiple client arrangement, I have a 1-1 relationship between my WCF Service and the client. Is there a correct way to instantiate one of these?
To put it yet another way, I want to create the Server-side service instance without using a ServiceHost.
Any suggestions would be appreciated at this stage.

Use a client at both ends. You will need to define your contracts carefully though. If you have ClientA and ClientB at either end of the stream, when ClientA sends a request, ClientB will expect it to look like what it sees as it's defined callback contract and vice versa.

Related

Implementing Callback on WCF DICOM Proxy Service

I am trying to implement a DICOM proxy server using WCF. That it is DICOM isn't really important, except that it forces me to use a particular process for getting image files: Under DICOM, you set up a listener on a well known IPAddress/Port which is registered with an ID (AETITLE) on a server. You then send a query to that server, and at some time in the future (or maybe never) the server sends the image file directly to your listener.
My listener will be a method on the proxy, that will receive the DICOM file.
The proxy will work using WCF, receiving requests from the desktop client. In this case, the desktop client will send a request to the proxy using WCF, for a particular study UID (a GUID for the file from the actual server), I am then happy to have that thread block for a reply from the proxy until the file arrives at the listener, I might also, eventually, use callbacks - but the same problem applies.
So:
Client Proxy DICOM Server
|RegisterListener--------->|
|
|Request(StudyID)------->|
| |Request StudyID---------->|
| |
| |<--------------Send(DICOM)|
|<----------Return(DICOM)|
Is there a pattern or example I can use to implement this? I assume I need to register a pointer (delegate??) to the client making the request, so the proxy knows which client to return the image to when the listener gets the file from the DICOM server? Can I make a dictionary of (StudyUID, List(Of Delegate)) or some similar structure to get this to work (will be List(Of Delegate) as their could be multiple clients requesting the same study)?
Or is it better to just have the proxy thread watch a shared dictionary and wait until that entry is populated with the file? ie: have a shared dictionary of (StudyID, DICOMFile) that is monitored by the clients requesting thread and populated by the proxy listener? This would preclude me from using Async Callbacks though.
Any suggestions welcome. Hopefully this isn't too vague...
I solved this by implementing a nettcp WCF service. The service accepts a DICOM UID from the client and then stores this and the client session in a shared dictionary. It then registers a DICOM listener and queries the PACS server for an image.
Once the image is returned to the listener, the service looks for the UID from the image in the shared dictionary, serializes the image and triggers a callback on the client returning the image.
I still have a couple of issues to iron out, but overall this works effectively.
This tutorial got me started:
http://www.codeproject.com/Articles/596287/Broadcasting-Events-with-a-Duplex-WCF-Service

WCF NetTcpBinding channel caching

We have a service that makes NetTcp calls to other services on different servers. I'm trying to optimize it by caching the ChannelFactories, and by increasing maxOutboundConnectionsPerEndpoint.
I have been using GOOGLE.COM (great website, by the way. Check it out if you haven't heard of them) to try to understand how the channel caching works, and I don't think I have it correct.
Reusing the channel factory - good idea.
Caching channels myself - bad idea. Wcf already does this, as long as all of your channels are created from the same factory. - is that right? If you create a new factory each time, it's not cached?
// factory initialization
var address = "net.tcp://something:8888/testservices";
var factory = new ChannelFactory<ITestService>("configname", new EndpointAddress(address));
// do stuff
var client = factory.CreateChannel(); // you can also pass an address here. how does that effect channel caching?
So that handles the factory stuff. Now, I want to increase maxOutboundConnectionsPerEndpoint, which is achieved via a custom binding. The thing that's not clear there is the GroupName. I can't specify distinct group names in configuration because I'm looking up the URL at runtime. Thus, all channel factories are going to have the same default group name. Are they going to share the same pool, does each factory have it's own?
In the end, I would like to create the custom binding in configuration, then create/cache multiple channel factories as needed, and use them to establish channels. And, I need to increase the maxOutboundConnectionsPerEndpoint per endpoint. I may be calling the same service on 20 different machines, and I want up to 50 cached channels for each. Does the code above achieve that?
Thank you for your help. If there is a link that covers this, please forward. I haven't been able to find it.

WCF is there a way to retrieve the factory associate to a created channel

I'm using WCF to create a connection beween a server app and client app.
Because I'm using NetTcpBinding, I want to keep alive the channel created by:
T proxy = ChannelFactory<T>.CreateChannel();
I bring the proxy instance into my app to communicate with server. At some moment, I renew this proxy, with a different factory. But I want to release resources from the first factory, by disposing it. But I don't wan't to manage factories and keep a reference to.
Is there a way with the proxy instance to retrive the channel associate to dispose it ?
Like ...
var commObj = (ICommunicationObject)proxy;
commObj.Factory.Dispose();
Thanks
Unfortunately, it is not possible, because Channels and Factories are not linked. But I think your approach is not correct. You should keep a reference to the factory and create Channel as needed. Re-using Channel can be a problem in some cases. A channel can be faulted, but the inner factory will still be valid. Creating a factory has a real cost, and some .net 3.5 SP1, factories are internally stored in a static cache.

wcf - transfer context into the headers

I am using wcf 4 and trying to transparently transfer context information between client and server.
I was looking at behaviors and was able to pass things around. My problem is how to flow the context received in the incoming headers to the other services that might be called by a service.
In the service behavior I intercept the the message and read the headers but don't know where to put that data to be accessible to the next service call that the current service might make.
What I am looking for is something like:
public void DoWork()
{
var someId = MyContext.SomeId;
//do something with it here and call another service
using(var proxy = GetProxy<IAnotherService>())
proxy.CallSomeOtherMethodThatShouldGetAccessTo_ MyContextualObject();
}
If I store the headers in thread local storage I might have problems due to thread agility(not sure this happens outside ASP.NET, aka custom service hosts). How would you implement the MyContext in the code above.
I chose the MyContext instead of accessing the headers directly because the initiator of the service call might not be a service in which case the MyContext is backed by HttpContext for example for storage.
In the service behavior I intercept
the the message and read the headers
but don't know where to put that data
to be accessible to the next service
call.
Typically, you don't have any state between calls. Each call is totally autonomous, each call gets a brand new instance of your service class created from scratch. That's the recommended best practice.
If you need to pass that piece of information (language, settings, whatever) to a second, third, fourth call, do so by passing it in their headers, too. Do not start to put state into the WCF server side! WCF services should always be totally autonomous and not retain any state, if at ever possible.
UPDATE: ok, after your comments: what might be of interest to you is the new RoutingService base class that will be shipped with WCF 4. It allows scenarios like you describe - getting a message from the outside and forwarding it to another service somewhere in the background. Google for "WCF4 RoutingService" - you should find a number of articles. I couldn't find antyhing in specific about headers, but I guess those would be transparently transported along.
There's also a two-part article series Building a WCF Router Part 1 (and part 2 here) in MSDN Magazine that accomplishes more or less the same in WCF 3.5 - again, not sure about headers, but maybe that could give you an idea.

ChannelFactory.Close VS IClientChannel.Close

Consider the following code which is typcial of many ChannelFactory examples:
WSHttpBinding myBinding = new WSHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress(
ConfigurationSettings.AppSettings["HelloWorldServiceURL"]);
ChannelFactory<IHelloWorldService> myChannelFactory =
new ChannelFactory<IHelloWorldService>(myBinding, myEndpoint);
IHelloWorldService proxy = myChannelFactory.CreateChannel();
((IClientChannel)proxy).Open();
HelloWorldDataContract dc = proxy.SayHello();
((IClientChannel)proxy).Close();
Note that when proxy.Open() is called, both the the channel's state and the ChannelFactory's state become "Opened". When proxy.Close() is called, the channel's state becomes "closed", but the ChannelFactory's state remains "Opened".
Should one be closing the ChannelFactory as well? I don't seem to see this in many examples. Also, if possible please explain the difference between having a channel open vs having a channel factory open.
Additionally, I am aware of the IDisposable issue, so it probably can be ignored for the sake of this question unless it has direct impact on the answer.
I found the main answer inaccurate so I am responding here.
Obviously Microsoft has made an absolute mess out of Channles and Factories and Clients. Documentation is not also helpful since they seem to be there just to cover up the mess so I had to resort to testing.
With the performance issues regarding non-cached Channels, implementation changed in v3.5 to address these and added caching but that only complicated the issue.
The point is channel in ChannelFactory is in fact not different from the channel used by IClientChannel when you create a channel using ChannelFactory.CreateChannel(). It is all the same pot. Believe me not? Try:
ChannelFactory<IService> factory = new ChannelFactory<IService>();
// ...
IService service = factory.CreateChannel();
factory.Close();
service.DoIt() // Throws object disposed exception
So really, internally it is all the same channel. I personally have started disposing the channel factories and not client channels and have not encountered any issue. I have also tried doing this in a loop with creation of 100000 client channels, and only closing ChannelFactory.
As you know, the ChannelFactory creates the client channel based on configuration. You may want to create multiple client channels from an existing factory (to the same endpoint as that is locked). If you're done using the factory to create channels, there is no reason not to close it.
But, why might you want to keep it open? Here's an interesting article on WCF clients that says:
Checking the value of the
System.ServiceModel.ICommunicationObject.State
property is a race condition and is
not recommended to determine whether
to reuse or close a channel.
Rather than reuse a channel, you might want to simply create a new one with the channel factory. More on the client architecture is here.
Another option is to use the static CreateChannel method:
msdn.microsoft.com/en-us/library/aa344556.aspx
The answer is already here, but it is spread over several comments and answers and not entirely clear, hence my answer.
Should one close the ChannelFactory as well as the Channel?
No. If you want to create multiple Channels from each ChannelFactory, you should dispose of the ChannelFactory, which will dispose all the Channels it created for you.
If you want to create one channel for each (endpoint, binding) pair, you should use this static function: ChannelFactory<ServiceType>.CreateChannel(binding, endpoint) (which avoids the issue as it does not create a second IDisposable), and you should dispose of the channel it returns.
Disposing of both the channelfactory and any of the channels it created will raise an ObjectDisposed exception.