My question is pretty simple, but I got lost somehow.
I have a project including ClientProject and ServerProject (WCF service application) contains my Service class and its interface.
The service runs method with few iterations.
All I need to do is to show on GUI the service's number of iteration on real time,
so that the user will be able to be aware to service activity state while running.
I've seen examples of declaring a delegate ServerEventHandler on service,
and registration to that event on client side.
For example:
ServiceProject:
public delegate void ServerEventHandler(object sender, EventArgs e);
public event ServerEventHandler ServerEvent; <br/><br/>
ClientProject:
public Client(Server s)
{
s.ServerEvent += new Server.ServerEventHandler(Subscribe);
}
But I can not figure out how can I implement it on my WCF project, since my client and server are separated projects so that the only way I can get my ServiceProject values on my ClientProject is through its ServiceReference.
I can't understand how can the client have the service instance, and how can it access the ServerEvent property through it.
What am I missing?
Do I have to mention anything on my contract? Or is there any other way to implement it?
I'd be thankful If you'll be able to help me..
you can implement WSDualHttpBinding which allows you to define callback contract
WCF comes with async variance for each operation..you can call async operation on Callback Operation so server process will keep running....Even callback will have DataContract so just create DataContract class which will hold all values which you want to show in UI..Imagine callback as Service exposed by client so that Server can notify client by calling appropriate operation.
Related
I have a web service called S
My client have a web service called C
My client send a request to my web service (web service S)
Web service S will send a response to client ( C )
After that, my service (S) will create 1 invoice message and send it to client web service (C)
Client web service return result to my web service (S)
How to implement it?
As I understand, you want to return a response to client app, but still continue with some processing.
There are a few possibilities here:
Start a new thread in 2., that will create the invoice and send it to client WS. This however can be error-prone - your web service might die or be shut down in the middle of creating the invoice and client WS will never know.
Use something like hangfire to schedule invoice creation. Hangfire stores scheduled tasks in DB, so it will be eventually executed, even in case of failure. This does not require additional configuration other than setting up the backend db. Processing happens in the same hosting process of your Service.
Use a ServiceBus or MSMQ - the idea is simmilar as with Hangfire - you send a message (saying like "create invoice with parameters X") to the Bus, the Bus makes sure the message gets delivered to anyone that listens for it. Then you register a listener that would handle that kind of message and create the invoice. This would require more work, since you have to choose the Service Bus engine, take a moment to understand it, install, configure, etc.
This is a good case for a domain event. I don't know what the first request is - perhaps placing an order?
When the order is placed then you would raise an event indicating that an order was placed. The event could contain either some information about the order or a reference (id) that can be used to retrieve it. Then other listeners would respond accordingly.
One benefit is that it keeps different parts of your application decoupled. For example, the class that submits an order doesn't need to know that there's going to be an invoice. It just raises an event indicating that an order has been placed and then goes on its way.
That becomes even more important if you want to have multiple behaviors when an order is placed. Perhaps you also want to send an email confirming that your received the order. Now you can add that additional behavior as an event listener with no modification to the code that places the order.
Also, your application could grow so that perhaps there's another service for placing orders. (I'm running with "placing orders" although I don't know what the specific event is.) You don't want multiple points in your application that follow all of the post-ordering steps. If those steps change then you'd have to modify code in all of those places. Instead you just raise the event.
Here's a popular article that describes the concept well. There are numerous implementations of an event bus. Here's one.
In pseudocode, you could now have a few event handlers, each of which is completely decoupled from your ordering code.
The event itself is raised immediately after the order is submitted.
var order = SubmitOrder(info);
eventBus.Raise(new OrderSubmitEvent(order));
Then you have some event handlers which are registered to respond to that event.
public class SendInvoiceOrderEventHandler : IEventHandler<OrderSubmitEVent>
{
public void HandleEvent(OrderSubmitEvent e)
{
//e contains details about the order. Send an invoice request
}
}
public class SendConfirmationOrderEventHandler : IEventHandler<OrderSubmitEVent>
{
public void HandleEvent(OrderSubmitEvent e)
{
//send an email confirmation
}
}
I am using WCF service and self hosting it as not everything is contained within the service itself (some external events are happening outside of the service):
WCF Service and I am self hosting it in a C# Console App. When WCF clients conncet they call the Login function, and I (try!) to store their callback via GetCallbackChannel
3rd party DLL which calls my console back via a delegate on a different thread from the library
On this console callback I then call in to the WCF service who pool which is then passed on to the WCF service who then broadcasts to all connected clients via a callback contract.
All is fine with the client connecting, calling Login, and I save the callback interface object.
However when I access the code from my service, i find it is an entirely new object and my _endPointMap is empty (despite me storing it in the Login method which is called by the client):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService, IEndpointNotifier
{
public readonly TwoWayDictionary<string, IClientCallback> _endpointMap = new TwoWayDictionary<string, IClientCallback>();
// called by WCF client when they click the login button - it works
public void Login(string username)
{
var callback = OperationContext
.Current
.GetCallbackChannel<IClientCallback>();
_endpointMap.AddOrUpdate(username, callback);
list.Add(username);
}
// called by the WCF self-host console app
public void IEndpointNotifier.Notify(string info, string username)
{
// at this point my list _endpointMap is empty despite
// having received a Login previously and adding to the
// list. so i am unable to call my clients back!!
_endPointMap.Count(); // is 0 at this point?!!
}
}
My main console app starts up the service fine also as below:
static void Main(string[] args)
{
var service = new Service();
var host = new ServiceHost(service);
// between the above line and the task below calling
// service.Notify I click a number of times on client
// which calls the Login method
Task.Run(() =>
{
for (var i = 0; i < 3; i++)
{
Thread.Sleep(10000);
// at this point, service seems like a new object?!
// any data saved in the list member will be lost,
// and will only see the single entry from time of
// construction
service.Notify("hi","bob");
}
});
Console.ReadLine();
}
Questions please
The object seems totally different to the one that was modified in a previous operation (on login from client) - is there any way to tell what service object I am actually looking at (equivalent to the old C++ days and looking at the address pointer for this)?
The singleton attribute seems to be ignored [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] Any ideas what I am doing wrong (why the internal list variable keeps getting reset)?
The WCF service cannot be self contained. How does one achieve communication between WCF self-hosted app and the WCF service according to best practice or is this abusing WCF and what is was designed for (when considering scopes etc)?
I set the breakpoint in the constructor with some dummy values. That breakpoint is only ever hit the first time when i construct it. When i go in to the object via the service.Notify method although the object seems new (members are empty) the constructor breakpoint is not hit - how so?
I have hosted the 3rd party app behind a static global member variable that I control. So I am responsible for all communication and state and cleanup between the 3rd party lib and the normal wcf calls. I am responsible for thread lifetimes for the 3rd party app. If I create them I have to close them. Holding references in my own lists.
It is like it is a separate app but they just happen to be in the same process space. All communication to and from the 3rd party app is controlled by me formally.
You will probably need a thread that looks for completed or abandoned 3rd party objects after usage to kill them your self outside of normal wcf msg processing.
This lets the wcf part be a normal threaded (thread pool) concept with no special declarations.
side note:
I would take out the loop and make it two lines in your simple model.
service.Notify("hi")
Console.ReadLine();
This will expose your object lifetime details instead hiding them for 3 seconds.
I found why the values were not being saved... my WCF client proxy was connecting to the VS WCF Service Host and not my host in the code!
I noticed this when I saw the WCF Service Host running in the service bar tray.
I disabled WCF Service Host starting up for the WCF .svc service by right clicking on the WCF Project -> Properties -> WCF Options -> unticked Start WCF Service Host when debugging another project in the same solution
I have a web service that I want to call from one of my asp.net classes.
I can call my web service successfully.But now I need to call this service asynchronously. I need to call it and NOT wait for the service to complete execution. I don't need to process a response from the service and don't need to verify if the service executed successfully. All I want is to be able to call the service and be free to do other things.
You need to consume web service asynchronously.
Goto and check
AddServiceReference -> Advance -> generate asynchronous operations.
after this async callback events will be available to you for every method
Suppose you have ABC method in you service when you will consume it by as sync these methods will be available to you in your application
1>ABC (fire and wait for output)
2>ABCAsync(fire and forget)
3>ABC callback event(get fired <if ABCAsync is called> when data available in your application)
One way to implement a fire-and-forget approach is to use the IsOneWay property on the OperationContract attribute, like this:
[OperationContract(IsOneWay=true)]
public void SomeMethod(string someValue);
When set to true, the operation won't return a message. Note that methods marked as one-way cannot have return types or ref or out parameters (which makes sense). It also should not be confused with asynchronous calls, because it's not the same thing (in fact, a one-way call can block on the client if it takes a while to get a connection, for example).
See OperationContractAttribute.IsOneWay Property for more information.
Have you tried this:?
http://msdn.microsoft.com/en-us/library/bb885132(v=vs.110).aspx
this is another way to do it, check it out.
I'm implementing an alert type system within my company LAN using WCF callbacks. It has a subscribe mechanism etc. I've used this tutorial as a starting point but I changed the binding to NetTcpBinding instead of wsDualHttpBinding and I'm self hosting in a Windows service.
That's working quite nicely but I have a question. Most of my clients do not need callback. They are various desktop applications that only need to send a one way alert to the server which will be passed on to those clients running the callback enabled "Notify" application and subscribed to that type of alert.
I might be concerned about nothing here but since my WCF service implements callback, all the clients need to implement a callback object whether they need callback or not. It would seem like a more tidy solution if the one way clients communicated with a service that does not do callback.
So ... I created another endpoint without callback in my WCF Service. It just has a simple one way method call. That works but my problem is that I can't quite figure out how to pass the received message to the callback enabled service.
My Windows Service has something like this:
internal static ServiceHost myNotifyHost;
internal static ServiceHost mySendingHost;
protected override void OnStart(string[] args)
{
// service with callback
myNotifyHost = new ServiceHost(typeof(NotifyService));
myNotifyHost.Open();
// service without callback
mySendingHost = new ServiceHost(typeof(SendingService));
mySendingHost.Open();
}
In my SendingService method that is called by the sendonly client, I thought I'd be able to do this:
var notify = (NotifyService)WindowsService.myNotifyHost.SingletonInstance;
notify.SendMessage("Message text");
SendMessage() sends the callback messages out to subscribed clients. Unfortunately, myNotifyHost.SingletonInstance is always null even when there is a client connected and waiting for callback. I guess I'm misunderstanding what that property means. NortifyService has these attributes
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
Is there a way that I can communicate between the two services? Should I give up and this and just stick to the one service and just live with implementing the meaningless callback class in those clients that don't need it. At this point it's not a big deal. It's more to do with my understanding of WCF.
Thanks
Try this,
public class NotifyService
{
public static NotifyService DefaultInstace;
public NotifyService()
{
DefaultInstace = this;
}
///.....SNIP......
}
What is the best possible way to share a single instance of a WCF Service (the SoapClient class) across multiple instances of an application (WPF)?
I need to do this because I need to enable duplex communications with callbacks, so i need to "register the application" to the the service so that other users using the application will get notified whenever a new user logs in.
Btw the below is striked out because I have confirmed that for the notifications to work, the registrants need to register to the same wcf service instance...thus now I need a way to share this instance
I am currently developing an application and I need some way to inform the users that are currently using the application whenever someone logs in the application.
I have tried using the WCF Duplex thing, but and I can't get it to work...and I think the reason behind it is because notifications and subscriptions need to occur to the same instance of the WCF Service.
But since this application will be deployed on multiple users' pcs, I cannot share only one instance of this wcf service eh? (or can I ?)
Is there a way to share a common instance of a wcf service (the SoapClient) for all the users? Or am I going about this the wrong way?
Currently I'm accessing the WCF Service through a class library via a public property that sends a new isntance of the wcf service every time it is accessed, and I think that that is the reason on why the notifications are not working on multiple instances of the application.
The following are the methods (in the class library) that the client application (a wpf app) uses to gain access to the service methods:
public static MusicRepo_DBAccess_ServiceClient GetService(object instanceContext)
{
return new MusicRepo_DBAccess_ServiceClient(new InstanceContext(instanceContext), dualBinding, endpointAddress);
}
public static MusicRepo_DBAccess_ServiceClient GetService()
{
return new MusicRepo_DBAccess_ServiceClient(new InstanceContext(new WSGateway()), dualBinding, endpointAddress);
}
In the main application window, I am then getting a new instance from the above overloaded method passing in this as the instanceContext parameter and the Open it to wait for the notifications but I am never notified when another user logs in from another instance of the application.
This is how I am notifying the registrars (excerpt) in the service login method:
if (!_callbackList.Contains(newUser))
{
_callbackList.Add(newUser);
}
_callbackList.ForEach(c => c.NotifyNewUserOnline(loggedInUser));
The solution was simple. All I needed was to change InstanceContextMode to Single:
[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single)]