I've got a target in my Xcode project that generate XPCService. Now I wish to implement more functions of different context, so I'd like to add them into different protocol.
I wish that the current xpc service support connections from both protocols.
the default code for single protocol support looks like this :
// Create the delegate for the service.
ServiceDelegate *delegate = [ServiceDelegate new];
// Set up the one NSXPCListener for this service. It will handle all incoming connections.
NSXPCListener *listener = [NSXPCListener serviceListener];
listener.delegate = delegate;
// Resuming the serviceListener starts this service. This method does not return.
[listener resume];
whereas the ServiceDelegate has the following method :
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
and I set the protocol for that connection decisively without option to choose myFirstProtocol
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:#protocol(myFirstProtocol)];
now I have mySecondProtocol as well and I want to choose protocol according to connection attribute that I send on the client side .. I'm looking for some sort of identifier that help me select the right interface.
thanks !
I'm trying out setting interfaces dynamically.
So, something like:
1.let the service export a protocol that has a single method requestInterface(kind: String)
2. let the connecting process call requestInterface with a string specifying what kind of interface it wants
3. at that point change the exportedInterface
Related
I am writing a WCF client/service. The service can perform some long operations so I have added a callback contract IProgressCallback. The system I am developing has to run in all kind of environments so I suspect that I will run into an environment where a callback channel cannot be opened (I might be wrong here).
So to be careful I have defined the operation contract like this.
[ServiceContract()]
interface IContract
{ ... }
[ServiceContract(CallbackContract = typeof(IProgress))]
interface IDuplexContract : IContract
{ ... }
This works great on the server side. I can easily configure the service to use either contract.
The problem however arises on the client side. I have manually defined 2 proxies
public class ContractProxy
: ClientBase<IContract>, IContract
{ ... }
public class DuplexContractProxy
: DuplexClientBase<IDuplexContract>, IDuplexContract
{ ... }
Again both proxies work fine.
Now I have a proxy factory which is responsible for creating the correct proxy. It can easily figure out which proxy to instantiate but my problem arises when I try to return the proxy.
The user needs to get an object back that is at least IContract and ICommunicationObject but I haven't been able to find what to return. I have tried to the following:
IContract CreateProxy(...) // The user lacks access to Open, Abort, Close, etc.
ClientBase<IContract> CreateProxy(...) // DuplexClientBase derives from ClientBase but the generic parameter is different and it isn't covariant so this cannot be done.
// First define a generic interface and then make both proxies implement it.
IProxy<TContract> : TContract, ICommunicationObject // TContract cannot be restricted to an interface so I cannot make IProxy derive from TContract
Currently as a workaround I am simply returning the IContract interface but then everyone using the proxy will have to start by casting it to a ICommunicationObject to open the proxy etc.
Does anyone here have a better way to do this or am I simply being overly worried that duplex communication might not work in some environments?
I am designing a WCF service with callback, but my implementation of the callback function never gets called. And I am confused about the generated service proxy, so please help.
Here is the scenario: in the server side, I defined the service interface IMyService and callback interface IMyServiceCallback, I also implemented the IMyService in the server project. Besides the server project, I surely have another client project, to which I added the service reference in VS. And I implemented the IMyServiceCallback interface on the client side. So here comes the problem: when I am debugging it, the function never goes into my implementation of IMyServiceCallback and of course the desired result never comes out.
And this is I where I got confused: when I added the service reference in the client side, it actually generated three interfaces on the local: IMyService, IMyServiceCallback, and IMyServiceChannel plus the client proxy class. And in my local implementation of IMyServiceCallback, I declared the class to implement the local IMyServiceCallback interface, not the one from service side. Could this be the problem? Why is there two declarations of the interface under different projects(and hence different namespaces)? The reason I implement the client side interface is, if I implemented from the server side interface, it would give the error: "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error" when I tried to call the service. And another confusing part is, on the server side if I declare the callback interface name as IMyCallback, or anything else, instead of IMyServiceCallback, the generated interface on the client side would still be IMyServiceCallback, which is the name of the service interface plus the suffix "Callback". And in this situation I also got the "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error".
I guess there is something that I misunderstood about the "add service reference" and how I should implement the interface(which one to implement). Could anyone help me? Thanks!
Updated:
I somehow fixed the problem. Firstly, the two declarations is fine is desired. The local client will need to implement the local interface, which is generated when adding the service reference. And my problem was that I also defined a DataContract but the generated reference file didn't have it. It could either because I had added the assembly of the service project as reference(somebody said in this case add service reference will not generate the Datacontract) or because I was missing DataMember attribute. But anyway, after I fixed both parts, the function is working now.
When you "Add Service Reference" and generate a proxy, it is totally separate from your service implementation. Remember, you may be consuming a service that you have not written and do not have access to the service source code.
The client code should use the client generated interfaces. If you change your service, you need to regenerate the proxy.
If you find this too messy, and you know you will always control both ends, you can share the service interfaces in a common assembly and generate a proxy class at runtime using DuplexChannelFactory.CreateChannel().
As for your problem, I can only assume you are not registering your callback properly. This is covered here.
if you want publish , you must implement IMyServiceCallback and IMyService together in same project.
if only subscribe , you must implement IMyServiceCallback interface
I fixed the issue when my callback instruction was embedded in a function call.
I learned that placing the callback in just a method that does not return a result works fine.
However, when the callback instruction is placed within a function I ran into timeout issue.
I resolved it by using a backgroundworker thread within the function being invoked:
public static IMyServiceCallback Callback;
.
.
.
TaskStateData taskStateData = GetSomeData();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (se, ev) =>
{
Tuple<OperationContext, TaskStateData> data = ev.Argument as Tuple<OperationContext, TaskStateData>;
var operationContext = data.Item1;
if (operationContext != null)
{
Callback = operationContext.GetCallbackChannel<IMyServiceCallback>();
Callback.OnCallBack();
}
};
Tuple<OperationContext, TaskStateData> payload = new Tuple<OperationContext, TaskStateData>(OperationContext.Current, taskStateData);
backgroundWorker.RunWorkerAsync(payload);
I am using Distributed Objects (DO) in Objective-C. I have a "server" object that I have vended on the network. Other objects on the network have a proxy to my server object and can thus call methods on the server object. However, can I determine any information about the objects that are calling methods on the server object? That is, I have many "client" objects that can call the server and I would like to distinguish these objects. Also, can I determine other attributes about these objects, e.g., host name, unique identifier?
I had a similar problem. I found that a possible way to identify clients is to have them pass some kind of token object through to the server as part of each call. On the server you can do:
NSConnection* clientConnection = [passedTokenObject connectionForProxy];
This will get you a handle on the connection, which will be unique to each client. Whether or not you can get the information you need depends on what Apple allows you to do with that connection object.
In my application, I had clients first do a "registration" call that I used to gather the information I needed about them.
The other thing that might be useful is to become NSConnectionDelegate for the NSConnection that you use to vend your server object. This will give you access to these methods:
- (BOOL)connection:(NSConnection *)parentConnection shouldMakeNewConnection:(NSConnection *)newConnnection {
// You can inspect new connection being established here and maybe glean info about the client
return YES;
}
- (BOOL) connection:(NSConnection *)c handleRequest:(NSDistantObjectRequest*)doReq {
// You get to see every method that is invoked here and can maybe glean info that you need.
// Returning NO means you're just snooping on the call and it will be handled in the normal way.
return NO;
}
The available "tools" aren't very sufficient I have found and I needed to rework my vended API to help provide the information I needed.
I found that the most effective solution to this problem is to explicitly pass a reference to the calling object as, say, the first parameter of the method. That way, the calling object can be easily identified and even called back if necessary. The resulting argument is of type NSDistantObject *.
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.
My app currently has what I'm pretty sure is a bad design, but I'm not sure how I can organize it any better. For example: LoginViewController sends the input text for the username and password to an instance of UserController. UserController sends a request to my server to validate the username and password, via NetworkRequestController which is responsible for dealing with all client-server communications. NetworkRequestController parses the server JSON responses and sends it back to a designated selector on the UserController, which then does all of it's business before informing the view of the result.
Currently, the UserController is instantiated as a local property to the LoginViewController during the LoginViewController's viewDidLoad method - though I feel I would prefer it to be a singleton class. The problem is that I need to set another object (such as LoginViewController) as the delegate on UserController in order to get the login result all the way back to the view with the appropriate selectors.
//LoginViewController sends request to local UserController instance
[userController validateLoginWithDelegate:self
withResult:#selector(loginResult:)
forEmail:email.text
forPassword:password.text];
//UserController asks NetworkRequestController to send login to server
- (void)validateLoginWithDelegate:(id)delegateObj
withResult:(SEL)onResult
forEmail:(NSString *)email
forPassword:(NSString *)password {
if(delegateObj != nil && onResult != nil){
self.delegate = delegateObj;
self.resultSelector = onResult;
}
NSString *url = [NSString stringWithFormat:#"/UserService.cfc?method=Authenticate&email=%#&password=%#&returnFormat=JSON", email, password];
[[NetworkRequestController sharedNetworkRequestController]
requestJSONWithURLString:url
andDelegate:self
onFinished:#selector(onLoginResult:)
onFailed:nil
onOffline:nil
progressView:nil
timeout:30];
}
//NetworkRequestController sends the request to the server and sends the parsed JSON back to UserController
[delegate performSelector:onFinished withObject:parsedJSON];
//UserController does it's business and sends the result to the view
if(delegate != nil && resultSelector != nil){
[delegate performSelector:resultSelector withObject:result];
}
I've only been working with Obj-C and Cocoa a few months and I'm pretty sure this is almost considered good, but I'm more certain there's something I'm missing. Can this be achieved with protocols? Advice?
Delegates are intended for two way communication between objects that serve different roles. Usually one object knows how to do something and the other object, the delegate, knows what to do.
When you have one way communication, notifications are often a better choice. You do not need the formality of a delegate with one way communication.
The two can be used together. For example, UIApplication has a delegate but also sends notifications for many of the delegate calls.
If the UserController is a singleton, then any instance can make requests and it can broadcast a notification of the results to all interested objects.
[NSNotificationCenter defaultCenter] sends notifications within your application.