difference in consume WCF service - Console vs Silverlight - c#

Can someone tell my why when I have wcf contract:
[ServiceContract]
public interface IService1
{
[OperationContract]
string TestGetName();
}
and implementation
public string TestGetName()
{
return "Kasia";
}
When I try consume it in Console app I can do just that:
Service1Client client = new Service1Client();
Console.WriteLine((client.TestGetName()));
but in Silverlight I must use that way :
Service1Client clientTest = new Service1Client();
clientTest.TestGetNameCompleted += new EventHandler<TestGetNameCompletedEventArgs>(clientTest_TestGetNameCompleted);
clientTest.TestGetNameAsync();
void clientTest_TestGetNameCompleted(object sender, TestGetNameCompletedEventArgs e)
{
this.dataGridChild.DataContext = e.Result;
}
Why in SL I don't see this first short solution, but only this with Event handlers?
Or better... why in Console app I can choose synchro operation generation and in SL I must use Generate asynchronous operations... :/

A synchronous call would stop the Silverlight UI thread and possibly the executing environment, i.e. the browser. To prevent this, only asynchronous calls are allowed.
Of course this is something unusual at first, but in the long run it is actually helpful to decouple the view and service layer.

Silverlight does not support synchronous calls (which is what you're doing in your console app).
Update: http://forums.silverlight.net/forums/p/34531/104526.aspx "The main point is that it looks like synchronous behaviour was removed on account of not being supported by all browsers."

Related

Error in Web Service ASMX in XAMARIN

I have a problem when calling a web-service(asmx) in Xamarin.forms. My web-service works in Android and I generated it with svcutil.exe, but when I tested it in IOS I got a problem saying:
"Mono touch does not support dynamic proxy code generation"
After searching I found out that I have to use a Silverlight tool called SLSvcutil.exe in order to override the CreateChannel method, and to make it work in IOS. It worked, but I need the methods to be synchronous (not async).
I kept searching how to make a pure synchronous method for my web-service and I found this: Monotouch/WCF: How to consume the wcf service without svcutil
Here is my code:
protected override POService2Soap CreateChannel()
{
return new POService2SoapClientChannel(this);
}
private class POService2SoapClientChannel : ChannelBase<POService2Soap>, POService2Soap
{
public POService2SoapClientChannel(System.ServiceModel.ClientBase<POService2Soap> client) :
base(client)
{
}
public ClientLoginResponse ClientLogin(ClientLoginRequest request)
{
object[] _args = new object[1];
_args[0] = request)
return (ClientLoginResponse)base.Invoke("ClientLogin", _args);
}
I get the interface from the Silverlight-generated code, and I create the LoginResponse class there etc, but the problem comes where i call base.invoke("Client Login",_args).
Basically, the ChannelBase doesn't have an Invoke method, it only has BeginInvoke and EndInvoke. So I get the problem cause there is no Invoke in the ChannelBase class inside ClientBase. How can I invoke this, or does anyone have any better solution for getting synchronous results from the web-service?
P.S. I know why Silverlight has async methods, also I know that it is better to async now, and I also know that web-services (asmx) especially in mobile development are a bit "outdated". But in my case I need it like that.
Thanks in advance.

WCF hosted in WPF and how can i change control in MainWindow UI from wcf?

I write WCF code and hosted in my WPF app.
I write class to switch my MainWindow to show other page in my project
public static class Switcher
{
public static MainWindow pageSwitcher;
public static void Switch(Page newPage)
{
pageSwitcher.Navigate(newPage);
}
}
and I write my wcf service like this:
[ServiceContract]
public interface IAppManager
{
[OperationContract]
void DoWork();
[OperationContract]
void Page1();
[OperationContract]
void Page2();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class AppManager : IAppManager
{
public void DoWork()
{
}
public void Page1()
{
MainWindow.pageSwitcher = new MainWindow();
MainWindow.Switch(new Page1());
}
public void Page2()
{
MainWindow.pageSwitcher = new MainWindow();
MainWindow.Switch(new Page2());
}
}
I want change page remotely from another computer with WCF but it not work
and I trace code the wcf is run and response but do not do anything
how can access to main thread to change ui page or other element?
Your current solution is unusual, but WCF can be hosted in a WPF application. However you should never try to directly manipulate the UI from the WCF service - you'll have cross thread issues to begin with.
What you should consider doing is using messaging via a pub-sub broker (image linked from MSDN):
Something that fits this bill nicely is Prism's EventAggregator. A couple of samples I cherry picked are Simplifying PRISM’s EventAggregator and Prism EventAggregator Sample.
The way you use this is the service registers events and then raises them, the WPF subscribes to those events and processes them. With this you can also specify whether to receive the events on the UI thread or a background thread.
I suggest you start over and this time separate the WCF from your WPF app.
You need to:
1) Separate WCF from WPF - should be in different layers.
2) Use WCF with duplex binding - this way your WCF service will be able to communicate with clients when it needs to.
3) In your WCF callback contract (implemented by the client) - you should prepare a method that will be used to change the local UI mode.
Duplex binding is the perfect solution for your needs.
You can reed about Duplex here
Hope I helped!
Eking.

How to access a service from a GUI

I have a program for collecting files from networked computers and storing them to local directories. This is done hourly, I am looking to make this into a service that will run in the background, BUT have a small app running that makes a systemtray icon, this icon would allow the user to open a GUI where they can modify the location to save the files to and the location to retrieve the files from, as well as do a manual collection of files for a user defined dateTime range. I am curious if the GUI is just a front end and all the 'heavy-lifting' methods are done in the service how can I access those service functions from GUI?
for example if the below was my service(very crude version):
partial class RemoteArchiveService : ServiceBase
{
...
...
string destination;
string retrieveFrom;
List<string> fileNames;
public void ChangeCollectFrom(string filepath){...}
public void ChangeDestinationFolder(string filepath){...}
public void GetFilesAsynchronously(){...}
...
...
}
in the GUI code how could I access the function ChangeCollectionFrom() with a new user input string?
Look into WCF and make your GUI a client that calls into the service. A good place to start would be http://msdn.microsoft.com/en-us/library/ms733069.aspx
WCF will allow you to cleanly and concisely specify the methods that a client will need to access by hosting a WCF service in your existing windows service. For example you could do something like the following:
[ServiceContract(Namespace = "http://Somewhere.StackOverflow.Samples")]
public interface IRemoteArchive
{
[OperationContract]
void ChangeCollectionFrom(string filepath);
}
partial class RemoteArchiveWCFService : IRemoteArchive
{
public void ChangeCollectionFrom(string filepath)
{
// ...
}
}
And then elsewhere in your RemoteArchiveService ( snippet taken from link above )
partial class RemoteArchiveService : ServiceBase
{
// ...
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(RemoteArchiveWCFService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
// ...
}
Nowadays, most of services expose a Web UI for configuration and administration like Oracle, Network-enabled printers, etc., so I recommend you take advantage of Web UI for your purpose and the happy news is that it's not very difficult.
Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .Net and Mono which can help you in this way.
In addition, Build Simple Web UIs with the Nancy Framework is a great article that exactly describes what you want.

How to enable user GUI response in wcf service to trigger duplex callback to client

Maybe I am trying the impossible...
I have created a wpf application to start a wcf service with the following service contract:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IRejectCallback))]
public interface IRejectService
{
[OperationContract(IsOneWay = true)]
void SubmitNewRejectInfo();
[OperationContract(IsOneWay = true)]
void SendRejectCallback();
}
My service behavior:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = true)] //(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = true)]
public class RejectService : IRejectService, IPostRejectEvent
I create my duplex channel and call the SubmitNewRejectInfo service method:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
IRejectService _rejectService = tcpFactory.CreateChannel();
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo();
The SubmitNewRejectInfo method is run on the service side. Normally, I would add my callback method like this:
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Do something here...
callback.RejectCallback();
}
However, when the SubmitNewRejectInfo method is run from the client (using IsOneWay = true), I do not want to callback to the client at that time. I would like to wait for the user to click a button on my WPF GUI which will transmit the signal to callback to the client. ** Is it possible to postpone the callback, or send a callback via a different operation contract? **
How could the client invoke the service via an operation contract method and then receive a callback after user interaction happens on the service side? I saw one duplex example where someone used a reentrant service with Thread.Sleep() as follows:
public void Register()
{
OperationContext ctxt = OperationContext.Current;
IClientCallback callBack = ctxt.GetCallbackChannel<IClientCallback>();
Thread.Sleep(3000);
callBack.TempUpdate(10);
}
In my case, I would need to trigger the callback in the Register method after a user clicks a button on a gui that is hosting the service. Would this be possible? Any ideas?
UPDATE **
I have discovered my main issue:
I make a call from my wcf client to my operation service contract method:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
_tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo();
The wcf service operation is invoked here:
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Throw event to notify MainViewModel that new reject information is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
callback.RejectCallback();
}
The event is fired to notify my MainViewModel that some data has been updated and refresh some properties. Then problem begins... I do not want the callback.RejectCallback(); to fire just yet. I need the user to click a button on my Mainwindow GUI associated to the view model to "authorize" the duplex callback to return a message to the wcf client.
Any ideas how to "pause" the callback long enough for a user to click a button to authorize the duplex callback to deliver a message to the wcf client? Perhaps my OnSubmitNewRejectInfo event can return some event argument before the callback is invoked? Could a new delegate be triggered to return information from my MainViewModel before the callback is invoked?
I hope this describes my problem a little better. Any help is VERY much appreciated.
Update number 2 **
More information... :)
The WCF service was created as a WCF service class library. The WCF client was also created as a WCF service class library. This makes it easy for other applications or class objects to host the service and client. This was done in order for human interaction via a GUI on the service side, and other software interaction on the wcf client side. The WCF service and client are hosted on separate machines.
The WCF service is hosted by a WPF application, and communication is event driven between the two. The service class is created as a singleton in the MainViewModel of the WPF application.
The WCF service class must talk via duplex communication with the wcf client. The client invokes an operation contract to update information in the service, which is displayed on the WPF GUI. After the information is displayed on the GUI, then the user must click a button to invoke the callback to the client indicating that the service has completed it's task.
So, WPF app hosts a wpf service class library. There is communication between the WPF app and service class via events. The service class is consumed by a wcf client via duplex channel communication. The wcf client is also hosted by another class object with a service reference to the wcf service. The client communicates with it's host via events.
WCF CLIENT CODE:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
_tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo(); // This is where I invoke a service operation from my client.
WCF SERVICE CODE:
// This service operation is consumed by the client.
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Create event to notify MainViewModel that new reject info is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
// **** I need something to happen here in order to halt the duplex callback to the client until a human creates a button click event in my MainViewModel, which indicates the duplex callback may be sent back to the client. ****
callback.RejectCallback();
}
Sorry this question has become very detailed. I never should have fallen asleep during my technical writing class in college... :)
Update number 3 **
I tried running the code that degorolls mentioned below. His example code is perfect for my needs!! (Thanks degorolls!) However I get a null reference exception: "Object reference not set to an instance of an object".
First the action executes in this part of degoroll's demo code:
if (pendingNotifications.TryGetValue(rejectInformation, out action))
{
try
{
action(rejectInformation); // This is invoked
Then this part of the demo code is called -> callback.RejectCallback(new RejectCallbackMessage())); :
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Throw event to notify MainViewModel that new reject information is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
pendingNotifications.Add(rejectInformation, info => callback.RejectCallback(new RejectCallbackMessage())); // **** the action returns to callback.RejectCallback here ****
This is where I get my null exception error.
Here is my code to get the callback channel:
IRejectCallback callback
{
get { return OperationContext.Current.GetCallbackChannel<IRejectCallback>(); }
}
My guess is that I am not returning null instead of the original callback channel...
Is there a way I can obtain the correct channel at this point in the code?
If I'm understanding things correctly it seems that the server simply needs to be keep a list of things it is waiting to do. How you implement will be tied closely to the instancing of the server. If you stick with singleton, you can simply hold a map of pending notification in the server class. E.g.:
public class RejectService
{
Dictionary<RejectInformation, Action<RejectInformation>> pendingNotifications = new Dictionary<RejectInformation, Action<RejectInformation>>();
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
pendingNotifications.Add(rejectInformation, info => callback.RejectCallback(info));
}
public void SendRejectCallback(RejectInformation rejectInformation)
{
Action<RejectInformation> action;
if (pendingNotifications.TryGetValue(rejectInformation, out action))
{
acion(rejectInformation);
pendingNotifications.Remove(rejectInformation);
}
}
}
If you want to make this reentrant you may need to think about locks... This is a really simplistic approach but gives a starting point.

C# WCF NetTCPBinding Blocking Application

I have a basic buddylist type application which is a pub/sub deal in WCF. My problem is one or two of the calls are long running and this blocks up the entire server application (gui updates etc).
Here's my code:
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IBuddyListContract))]
public interface IBuddyListPubSubContract
{
[OperationContract]
string GetABunchOfDataZipped(String sessionId); // this can take > 20 seconds
....
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class BuddyListPubSubContract : IBuddyListPubSubContract
{
string GetABunchOfDataZipped(String sessionId)
{
// do some calculations and data retrival
return result;
}
}
So far I have an idea on how to go about it but is there a simpler way?
Idea 1: Have GetABunchOfDataZipped(String sessionId) be a void, when it finishes have another endpoint which on my duplex contract which I hit. I don't like this as ifs a fundamental change in my architecture and if the string is a large block of text over a slow internet connection it will still suffer from the same issue?
My problem is one or two of the calls are long running and this blocks up the entire server application (gui updates etc).
You're not clear on where you're seeing the blocking behavior, but it sounds like it would be on the client side. You should be making your call to your WCF service from a background thread, not the UI thread. Then when you handle the result, you won't be able to interact with your UI elements directly, you will need to use each control's Invoke method.

Categories

Resources