WCF Winform freezes when opened by server - wcf

I've written a VSTO Outlook Add-In and am trying to open a form in a separate Winform app when the user pushes a button on the Add-In, passing an integer as argument. I'm using WCF Named Pipe Binding. The Add-In is the client and the Winform app is the server. The binding and inter-process communication works fine. However, when the target form opens, it freezes with a spinning cursor. The form otherwise works fine from within the Winform app.
Per the code below, when I call "clsActivity.EditT("", activityID);" within the server method, it opens a form which is properly created and displayed, but then locks up with a spinning cursor and is inaccessible. I've been assuming that there is some element of the servicehost or other WCF process that is uncompleted, but can't identify the issue.
I've spent several days trying to find an answer. As I'm pretty new to WCF, I'm not even sure if I'm asking the right questions. Any assistance would be greatly appreciated. Thanks.
Server
// Service Contract
[ServiceContract(Namespace = "ComsIPC")]
interface ComsIPCContract
{
[OperationContract(IsOneWay = true)]
void OpenActivity(int activityID);
}
// Server Implementation
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class ComsIPCServer : ComsIPCContract
{
public void OpenActivity(int activityID)
{
try
{
clsActivity.EditT("", activityID);
}
catch
{
MessageBox.Show("Error in ComsIPCServer");
}
}
public void CreateComsIPCServerHost()
{
string address = "net.pipe://localhost/coms/IPC";
ServiceHost serviceHost = new ServiceHost(typeof(ComsIPCServer));
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
serviceHost.AddServiceEndpoint(typeof(ComsIPCContract), binding, address);
serviceHost.Open();
}
}
Client
// Service Contract
[ServiceContract(Namespace = "ComsIPC")]
interface ComsIPCContract
{
[OperationContract(IsOneWay = true)]
void OpenActivity(int activityID);
}
public class ComsIPCClient
{
public void OpenActivityInComs(int activityID)
{
string address = "net.pipe://localhost/coms/IPC";
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
EndpointAddress ep = new EndpointAddress(address);
ComsIPCContract channel = ChannelFactory<ComsIPCContract>.CreateChannel(binding, ep);
channel.OpenActivity(activityID);
}
}

Related

WCF oneway exception faults channel

I haven't found a clear answer on this. so if there is already a question about this, my bad.
I have a WCF service that pushes data via a callback method to connected clients. this callback method is oneway. so everytime there is new data I loop over the connected users and push the data.
The problem I have right now is when a client disconnects it throws an error and the channel becomes faulted.
I always thought that oneway didn't care if the message arrives at the destination. So if there's no client, then bad luck. but no exception.
but there is an exception and that exception faults the channel.
Now I've read somewhere that if you enable reliable sessions, that the exception won't fault the channel. Is this true?
How can I prevent that the channel goes into faulted state when an exception happens on a oneway call?
The list of registered and avaiable clients you can store in some resource such as List. Create another interface which exposes Connect/Disconnect methods. Connect is invoked when application starts off and within method client is added to the list. Disconnect in turn is invoked when application shuts down in order to get rid client of list. OnStartup/OnClosing events or their equivalents, depending on what kind of application client is, refer to moment when application is launched and closed. Such a solution ensures that resource stores only users avaiable to be reached.
[ServiceContract]
interface IConnection
{
[OperationContract(IsOneWay = true)]
void Connect();
[OperationContract(IsOneWay = true)]
void Disconnect();
}
[ServiceContract]
interface IServiceCallback
{
[OperationContract(IsOneWay = true)]
void CallbackMethod();
}
[ServiceContract(CallbackContract = typeof(IServiceCallback))]
interface IService
{
[OperationContract]
void DoSth();
}
class YourService : IConnection, IService
{
private static readonly List<IServiceCallback> Clients = new List<IServiceCallback>();
public void Connect()
{
var newClient = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
if (Clients.All(client => client != newClient))
Clients.Add(newClient);
}
public void Disconnect()
{
var client = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
if (Clients.Any(cl => cl == client))
Clients.Remove(client);
}
public void DoSth()
{
foreach(var client in Clients)
client.CallbackMethod();
}
}
At the end expose another endpoint with IConnection so that client can create proxy meant to be used only for connection/disconnection.
EDIT:
I know it has been a while since I posted an answear but I did not find in order to prepare an example. The workaround is to let service's interface derive IConnection and then expose only service as an endpoint. I attach simple example of WCF and WPF app as client. Client's application violates MVVM pattern but in this case it is irrelevant. Download it here.
To add on what Maximus said.
I've implemented this pattern in a class where clients can subscribe to get updates of internal states of a system, so a monitoring client can show graphs and other clients do other stuff like enabling/disabling buttons if some state is active.
It removes faulted channels from the list when they fail. Also all current states are sent when a client connects.
here's the code, hope it helps!
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Publish : IPublish
{
private struct SystemState
{
public string State;
public string ExtraInfo;
}
private static Dictionary<Key<string>, IPublishCallback> mCallbacks = new Dictionary<Key<string>, IPublishCallback>();
private static Dictionary<string, SystemState> mStates = new Dictionary<string, SystemState>();
public void RegisterClient(string name, string system)
{
lock (mCallbacks)
{
IPublishCallback callback = OperationContext.Current.GetCallbackChannel<IPublishCallback>();
Key<string> key = new Key<string>(name, system);
if (!mCallbacks.ContainsKey(key))
{
mCallbacks.Add(key, callback);
}
else
{
mCallbacks[key] = callback;
}
foreach (KeyValuePair<string, SystemState> s in mStates)
{
mCallbacks[key].ServiceCallback(s.Key, s.Value.State, s.Value.ExtraInfo);
}
}
}
public void UnregisterClient(string name)
{
lock (mCallbacks)
{
outer: foreach (var key in mCallbacks.Keys)
{
if (key.Key1 == name)
{
mCallbacks.Remove(key);
goto outer;
}
}
}
}
public void SetState(string system, string state, string extraInfo)
{
lock (mCallbacks)
{
List<Key<string>> toRemove = new List<Key<string>>();
SystemState s = new SystemState() { State = state, ExtraInfo = extraInfo };
SystemState systemState;
if (!mStates.TryGetValue(system, out systemState))
mStates.Add(system, s);
else
mStates[system] = s;
foreach (KeyValuePair<Key<string>, IPublishCallback> callback in mCallbacks)
{
try
{
callback.Value.ServiceCallback(system, state, extraInfo);
}
catch (CommunicationException ex)
{
toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
}
catch
{
toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
}
}
foreach (Key<string> key in toRemove)
mCallbacks.Remove(key);
}
}
}

How do I solve the error in my WCF service and proceed on?

I am currently developing a C# Windows Form Application that I intend to let it interact with a server. The server will receive posting from a mobile application that I have developed and whenever a posting is received, my Windows Form Application should be notified and give me a notification.
E.g. My mobile application sends an message over to my server. Once my server receives the message, my windows form application should display a new notification showing the content of the message received.
I am now starting to develop my WCF Service and this is what I've done so far
[ServiceContract(Namespace = "Posting")]
public interface IPostingService
{
[OperationContract]
void NotifyAboutPosting(Posting post);
}
[DataContract]
public class Posting
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public DateTime PostingTimestamp { get; set; }
}
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost/");
ServiceHost selfHost = new ServiceHost(typeof(Posting), baseAddress);
try
{
// Step 3 of the hosting procedure: Add a service endpoint.
selfHost.AddServiceEndpoint(
typeof(IPostingService),
new WSHttpBinding(),
"Posting");
// Step 4 of the hosting procedure: Enable metadata exchange.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
// Step 5 of the hosting procedure: Start (and then stop) the service.
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
// Close the ServiceHostBase to shutdown the service.
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
}
}
regarding the posting class, what I want to ask is that are the methods inside used to get the information from the server?
and how do I proceed on from here after the service is done. (My winform application has been finished and all thats left is to add in this logic to receive the posting whenever the mobile app sends to the server.
and there seems to be a compilation error of
The contract name '##.IPostingService' could not be found in the list of contracts implemented by the service '##.Posting'.
could anyone help me with this? thanks a million!
Where is your actual implementation? You have contract (IPostingService), data (Posting)... but where's code doing the work? You seem to lack contract implementation:
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
// do something with post here
}
}
And you register actual worker class (not data) when setting up your host:
ServiceHost selfHost = new ServiceHost(typeof(PostingService), baseAddress);
I would suggest checking out these likely culprits:
WCF - Contract Name could not be found in the list of contracts
Discussion on Microsoft forums
Blog post on the issue

How do I program my WCF service in the given scenario?

I am currently developing a C# Windows Form Application that I intend to let it interact with a server. The server will receive posting from a mobile application that I have developed and whenever a posting is received, my Windows Form Application should be notified and give me a notification.
E.g. My mobile application sends an message over to my server. Once my server receives the message, my windows form application should display a new notification showing the content of the message received.
I am now starting to develop the WCF service and has reach the PostingService method and I am unsure of how I am able to continue to program the service to work the way I wan as stated above.
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
// do something with post here
}
}
and after I program the service, how do I test the service by, I dunno? uploading a fake post to see if the services works or whatsoever , meaning a dummy test. thanks !
EDIT
for my main method, the code are as follows ,
Uri baseAddress = new Uri("http://localhost/");
ServiceHost selfHost = new ServiceHost(typeof(IPostingService), baseAddress);
try
{
selfHost.AddServiceEndpoint(typeof(IPostingService),new WSHttpBinding(), "Posting");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
basically I just followed through the tutorial given by MSDN WCF getting started tutorial. not sure if this is really the correct way to do it for the type of implementation that I want.
Well, your WCF service can do anything you want - so what do you really want it to do??
Your posting server gets a new message from a mobile device, and then calls this WCF service class in your Winforms app. What do you want to happen here and now??
One thing to keep in mind: the WCF service class receiving the message and the Winforms app might be running on different threads; if that's the case, you cannot just update e.g. UI elements on your Winforms UI from the service code (you need to use some synchronization methods). But that depends on your exact way of creating and opening the ServiceHost in your Winforms app.
Update: if you put your code to create and initialize your ServiceHost into the main application form (see Service Synchronization Context on CodeIdol for a sample on how to do this), then you could probably just do:
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
MessageBox.Show(post.Title, post.Message,
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
assuming your Posting class has both a .Title and a .Message string property...
1) PostingService assembly (class-library project)
Interface: IPostingService.cs
using System;
using System.ServiceModel;
namespace PostingService
{
[ServiceContract]
public interface IPostingService
{
[OperationContract]
void NotifyAboutPosting(Posting posting);
}
}
Implementation: PostingService.cs
using System;
using System.Windows.Forms;
namespace PostingService
{
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting posting)
{
MessageBox.Show(posting.Message, posting.Title, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
DataContract: Posting.cs
using System;
using System.Runtime.Serialization;
namespace PostingService
{
[DataContract]
public class Posting
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Message { get; set; }
}
}
2) Your Winforms app (Winforms application project)
Must reference the service assembly (since it needs the service contract and the data contract class)
Main Form of your app: Form1.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Windows.Forms;
using PostingService; // your class library from above
namespace WinformsApp
{
public partial class Form1 : Form
{
private ServiceHost _host = null;
public Form1()
{
InitializeComponent();
// IMPORTANT: here you need the **SERVICE IMPLEMENTATION CLASS** in the typeof() (*NOT* the interface!)
_host = new ServiceHost(typeof(PostingService), new Uri("http://localhost:8888/PostingService"));
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
_host.Description.Behaviors.Add(smb);
_host.Open();
label2.Text = "Service up and running (http://localhost:8888/PostingService)";
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
_host.Close();
base.OnFormClosed(e);
}
}
}
3) Run your Winforms app - now that service is up and running and ready to be notified.
4) Launch WCF Test Client (that's what your "posting server" will be doing later on)
4a) File > Add Service - type in http://localhost:8888/PostingService - should find your service
4b) if found: enter some values into the properties for the "Posting" class (an ID, title, message)
4c) Click "Invoke" - your service should now be called, a dialog pop (message box) should pop up with the title and message you've defined
Perhaps WCF callbacks might meet your requirements:
What You Need To Know About One-Way Calls, Callbacks, And Events

WCF web service stops responding after several repeated calls

I have Windows applications that communicate to the logic layer and data layer with a WCF web service.
When the form is opened the connection to the web service is established and the connection is kept alive as long as the form is opened. On closing the from, the connection is closed using Finalize and Dispose on the web service.
After several times opening and closing forms, the service stops responding and I need to reset service which hosted in the IIS to get it working again. Any hints on how to proceed with this issue?
this is my service contract:
[ServiceContract]
public interface ICommandInvoker : IDisposable
{
[OperationContract(IsOneWay = false)]
void Initialize(TypeInfo managerType, UserInfo userInfo, Dictionary<string,string> settingDic);
[OperationContract(IsOneWay = true)]
void Finalize();
[OperationContract(IsOneWay = false, Action="*")]
//[CustomOperationBehavior]
ServerResult Execute(ServerCommand command);
[OperationContract(IsOneWay = false, Name="Execute Serialized")]
string Execute(string command, TypeInfo typeInfo);
[OperationContract(IsOneWay = false, Name = "Execute 2 Non Serialized")]
ServerResult Execute(TypeInfo mangerType, UserInfo userInfo, ServerCommand command);
[OperationContract(IsOneWay = false, Name = "Execute 2 Serialized")]
string Execute(TypeInfo mangerType, UserInfo userInfo, string command, TypeInfo typeInfo);
[OperationContract(IsOneWay = true)]
void BeginExecute(ServerCommand command);
and this is my Service
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class BudgetService : BaseCommandInvoker<BudgetDataContext>, IBudgetService
{
public BudgetService()
{
}
}
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IBudgetService : ICommandInvoker
{
}
Do you have any sample program for this method of use Wcf?
thank you
Could be lots of things!
Is the server returning a timeout? How are you managing your try catch blocks? Are any errors being thrown. I would check if the channel has faulted because an Exception will fault the channel. Your service should be throwing FaultExceptions if something goes wrong.
Impossible to really help ant more without more information.

WCF InstanceContextMode.Multiple issues

So I'm hosting WCF service in a WinForms application. I have the following
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerCall)]
public class Test : ITest
{
public string TestIt(string input)
{
Thread.Sleep(5000);
return "test";
}
}
I'm using Named Pipes and have two instances of another application that act as clients to the above WCF service (running in a WinForms application). I thought based on the ConcurrencyMode setting of Multiple that when Client1 calls the Test Service, Client2 doesn't have to wait till the first call is complete. However, when Client1 calls TestIt, Client2 blocks until the call from Client1 is complete!?!?! Shouldn't it make a new instance each time based on the above settings?
Also, is the best way to keep a WinForms application that is hosting a WCF service responsive is by running the WCF service on a separate thread?
NOTE: Setting [CallbackBehavior(UseSynchronizationContext = false)] on the Test class does not alleviate the problem. The service still only responds to one request at a time.
Sounds like you want to set this
http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.usesynchronizationcontext.aspx
to false. By default, if there is a synchronization context when service.Open() happens, WCF will pick it up and use it. But if you don't want that feature, this flag is how to turn it off.
After digging into this a bit more the only way I was able to get this to work properly was to start the ServiceHost on a separate thread in the WinForms application. If you don't do that setting the ConcurrencyMode and InstanceContextMode attributes does nothing.
I had the same problem.
My class that implemented Callback also contained methods for wcf client, so when I was calling some method from remote service and service was calling Callback method, I was creating a deadlock.
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class AppContext : ICustomerOrderCallback
{
//WCF Proxy client
private CustomerOrderClient _client = null;
public AppContext()
{
InstanceContext context = new InstanceContext(this);
_client = new CustomerOrderClient(context);
_client.Subscribe(); //Remote method for subscribing callback
}
public void SendMessage(string message)
{
//Calling Remote method
_client.SendMessage(message);
}
//....code
//callback method
public void OnMessageReceived(string message)
{
//.....code
}
}
So I created a separate class for callback, added attribute CallBehavior to it and everything worked OK.
public class AppContext
{
private CustomerOrderClient _client = null;
private MyCallbackClass _myCallback = null;
public AppContext()
{
_myCallback = new MyCallbackClass();
InstanceContext context = new InstanceContext(_myCallback);
_client = new CustomerOrderClient(context);
_client.Subscribe();
}
public void SendMessage(string message)
{
_client.SendMessage(message);
}
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallbackClass : ICustomerOrderCallback
{
public void OnMessageReceived(string message)
{
//.....code
}
}