I am new to WCF. Is the client connected when the service is instantiated
SampleService client = new SampleService();
Or does it connect and disconnect when a method is called on the client?
client.sampleMethod();
I want to connect to the client and send multiple messages across the same connection. Is this possible?
To answer your second question: the connection is kept open by default.
For the first, and as an clarification to above statement: it depends on the binding. For starters, there is no Connect() method in ClientBase<TChannel> (which a WCF proxy client inherits from), so there'll be no use calling it since that'll throw a compiler error.
A connection to the service is made upon the first call to the service; the constructor does nothing more than bring the client object in a usable state, it does not connect to the service.
It is connected when you use the service. Also you would need to call client.Close() if you would write it like that. We mostly write our service calls like this:
using(var client = new SampleServiceClient()){
client.MethodA();
client.MethodB();
}
So yes you can call multiple methods on one instance of the service. By writing the using statement you make sure that the service is disposed after usage.
Or if you like:
var client = new SampleServiceClient();
client.MethodA();
client.MethodB();
client.Close();
You will need to call the generated proxy it's Connect method.
e.g.
SampleServiceProxy client = new SampleServiceProxy();
client.Connect()
client.SampleMethod()
Related
I've got a WCF server/client setup using named pipes, and my client connects to the host process (already running) as follows:
var pipeFactory = new DuplexChannelFactory<IArbiter>(this, new NetNamedPipeBinding(), new EndpointAddress(new Uri("net.pipe://localhost/IArbiter")));
arbiter = pipeFactory.CreateChannel();
This is fine for the first client connecting, but when the second client connects, a new instance of the IArbiter implementation is created (the arbiter's constructor is called every time a connection happens).
Is there a way to find the "existing" instance of that arbiter at the endpoint address?
Figured it out, just need to set this above my class implementation:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
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.
I'm making a WCF service with netTcpBinding which has a main lobby with multiple chatrooms which the clients can enter. The Lobby class implements ILobby as the service contract.
When a client wishes to enter a room I want to callback the client exposing a new Channel containing the InstanceContext for the room he just entered but after much searching I am doubting that this is possible.
For example on the Service side I might have
class Lobby : ILobby
{
Dictionary<string, Chatroom> rooms;
public void JoinRoom(string roomname)
{
if (rooms[roomname].TryEnter()) {}
}
}
class ChatRoom : IChatRoom
{
public bool TryEnter(string username)
{
ILobbyCallback callback =
OperationContext.Current.GetCallbackChannel<ILobbyCallback>();
// How do I do this next bit?
callback.JoinedRoom(pass some instance context here);
return true;
}
}
On the client side callback method I want
public void JoinedRoom(InstanceContext for the room on the service side)
{
// Create a new WCF proxy using above InstanceContext
// Create a WPF UI for the new room passing the proxy so it can communicate
// with the room class directly without going via the root service
}
Is this possible? What's the best practice for spawning new classes with their own contracts on the service side? Or do I just have to bundle everything into one massive MyService class and handle everything myself?
You cannot pass instance context as parameter to any operation contract. It doesn't make sense because that context has local scope. It is called "instance context" = it is context of current service instance. In duplex scenario both client and server has its own service:
Clients calls server's service through its proxy
Server calls client' service through received callback channel
Server's service instance context has meaning only on the server. It is not clear what you are trying to achieve (except very complex architecture).
If you want to share context on client you can try to pass around the instance context used for the very first proxy you created - I'm not sure if it will work but you can try it
If you want to share service instance context between multiple proxies you must develop your own IInstanceContextProvider and perhaps also your own IInstanceProvider (depending on what you want to achieve), wrap them in behavior and add them to the service. That will put whole complexity of session handling and correct instance releasing under your control (it obviously has its pros and cons).
But is it really needed? When I look at your code I see that one service and one proxy is enough. Also your JoinRoom operation doesn't need to use callback at all, it can be just request response method.
I'm putting together a WCF service using net.tcp and netTcpBinding to get duplex comms with my Silverlight client. I call into the service from the Silverlight app and the service calls out to another server, passing it a callback method in the WCF service class. The remote server calls back several times and each time it does, the WCF service uses the callbackchannel to send the data to the Silverlight client. It all works nicely most of the time.
If the user puts in a big request, I get a TimeoutException after a large number of callbacks have already worked. (Clearly, there's some work to do elsewhere to prevent this but I'd like to robustify the service, first.)
I was expecting to do some kind of 'if (client.ConnectionState == faulted)' check before trying to call back to the Silverlight client but I can't seem to find the object that holds the state of the connection. Is there one? Am I approaching this from the wrong side?
This is my first venture into a service net.tcp and duplex. I just moved house and my WCF bible is still in a box. Somewhere. :-) So, I can't do my usual background reading.
Any pointers would be gratefully received. Here's some bare code in case my description is too soupy:
private IActiveDirectoryClient client;
private AsyncSearchRunner runner;
public void Search(Request request)
{
this.client = OperationContext.Current.GetCallbackChannel<IActiveDirectoryClient>();
runner = new AsyncSearchRunner();
runner.Run(request.SearchRoot, request.SearchFilter, request.PageSize,
System.DirectoryServices.Protocols.SearchScope.Subtree, SendObjects);
}
private void SendObjects(List<DirectoryObject> items)
{
Response response = new Response();
response.DirectoryObjects = items.ToArray();
client.SendResponse(response);
}
Yes, there is a State property that is defined in the ClientBase<> class (all the proxy classes are derived from ClientBase<>).
There are some proxy wrappers out there that handle fault states of the connection and re-establish connections as needed. Google for "wcf proxy wrapper".
You can also home-brew something if you use some kind of ServiceLocator pattern.
From a little bit of reading around, it is my understanding that the only way to detect that a client has connected to my service is through writing my own code. I am using a Singleton service. I would like to display a message every time a client connects to my service that client x with ip xxx has connected. There is no built-in event that is generated? Am I correct?
No, I don't think there's any support in WCF for your requirement.
Not sure what you want to achieve with this, either. Your service class (in your case, just a single instance) really doesn't have any business putting up messages (on screen, I presume) - that really not it's job. The service class is used to handle a request and deliver a response - nothing more.
The ServiceHost class might be more of a candidate for this feature - but again, it's job really is to host the service, spin up the WCF runtime etc. - and it's really not a UI component, either.
What you could possibly do is this
have an Admin UI (a Winforms, console, or WPF app) running on your server alongside your service, providing an admin service to call
define a fast connection between the two services (using e.g. netNamedPipe binding which is perfect for intra-application messaging)
when your "real" service gets a call, the first thing it does is send out a message to the admin UI which can then pick up that message and handle it
That way, you could cleanly separate your real service and it's job (to provide that service) and the Admin UI stuff you want to do and build a cleanly separated system.
I have actually implemented my own connect, disconnect and ping service methods which I manually call from my client once the channel has been created. By using them as a kind of header section in all of my ServiceContract interface definitions (and their implementations, of course), they form an makeshift "base service definition" that only requires a bit of cut-n-paste.
The string-based parameters of connect and disconnect will be used to send client info to the server and return server info and (perhaps a unique connection id) to the client. In addition a set of timing reference points may make its way in also.
Note how SessionMode is required and the individual OperationContract properties IsInitiating and IsTerminating are explicitly specified for each method, the end result being what I would call a "single-session" service in that it defines connect and disconnect as the sole session bookends.
Note also that the ping command will be used as the target of a timer-based "heartbeat" call that tests the service connection state and defeats ALL connection timeouts without a single config file :-)
Note also that I haven't determined my fault-handling structure yet which may very well add a method or more and/or require other kinds of changes.
[ServiceContract( SessionMode = SessionMode.Required )]
public interface IRePropDalSvr {
[OperationContract( IsInitiating=true, IsTerminating=false )]
string connect (string pClientInfo);
[OperationContract( IsInitiating=false, IsTerminating=true, IsOneWay=true )]
void disconnect (string pClientInfo);
// ------------------------------------------------------------------------------------------
[OperationContract( IsInitiating=false, IsTerminating=false )]
string ping (string pInp);
// ------------------------------------------------------------------------------------------
// REST OF ServiceContract DEFINITION GOES HERE
One caveat: while I am currently using this code and its implemention in my service classes, I have not verified the code yet.