I'm trying to create a WCF callback service with netTcpBinding. When I try to call a method of the service I get following exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll
Additional information: The InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType 'Client.WCFService.IHostFunctionsCallback'.
I've added a service reference instead of using SvcUtil.exe
I've searched the internet for fixing this problem, but I haven't found a solution yet.
Here's my implementation:
IHostFunctions.cs (Part of HostLibrary)
using System.ServiceModel;
namespace HostLibrary
{
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IHostFunctions
{
[OperationContract]
void OpenSession();
}
}
ICallback.cs (Part of HostLibrary)
using System.ServiceModel;
namespace HostLibrary
{
public interface ICallback
{
[OperationContract]
void OnCallback();
}
}
HostFunctions.cs (Part of HostLibrary)
using System;
using System.ServiceModel;
using System.Timers;
namespace HostLibrary
{
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class HostFunctions : IHostFunctions
{
#region Implementation of IHostFunctions
public static ICallback Callback;
public static Timer Timer;
public void OpenSession()
{
Console.WriteLine("> Session opened at {0}", DateTime.Now);
Callback = OperationContext.Current.GetCallbackChannel<ICallback>();
Timer = new Timer(1000);
Timer.Elapsed += OnTimerElapsed;
Timer.Enabled = true;
}
void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
Callback.OnCallback();
}
#endregion
}
}
Callback.cs (Part of Client)
using System;
using HostLibrary;
namespace Client
{
public class Callback : ICallback
{
#region Implementation of ICallback
public void OnCallback()
{
Console.WriteLine("> Received callback at {0}", DateTime.Now);
}
#endregion
}
}
Program.cs of the service
using System;
using System.ServiceModel;
using HostLibrary;
namespace WCF_TCP_Callbacks
{
internal static class Program
{
private static void Main(string[] args)
{
using (var sh = new ServiceHost(typeof (HostFunctions)))
{
sh.Open();
Console.WriteLine("Service started.");
Console.ReadLine();
Console.WriteLine("Stopping service...");
sh.Close();
}
}
}
}
Program.cs of the client
using System;
using System.Globalization;
using System.ServiceModel;
using System.Threading;
using Client.WCFService;
namespace Client
{
internal class Program
{
private static void Main(string[] args)
{
var callback = new Callback();
using (var proxy = new HostFunctionsClient(new InstanceContext(callback)))
{
proxy.OpenSession();
}
Console.ReadLine();
}
}
}
The code is from http://adamprescott.net/2012/08/15/a-simple-wcf-service-callback-example/ but with netTcpBinding.
by default WCF will attempt to dispatch using an available SynchronizationContext. The problem with this callback is the UI thread is already blocked in an outbound call. SO for the call to dispatch we need to tell WCF not to use the SynchronizationContext – again using the CallbackBehavior attribute:
[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant, UseSynchronizationContext=false)]
public class Callback : ICallback
{
....
}
for further detail look this link http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b891610a-6b78-4b54-b9a6-4ec81c82b7c0.aspx
and one more post describe it further
http://stefanoricciardi.com/2009/08/28/file-transfer-with-wcp/
I fixed that problem by simply renaming the class ICallback to IHostFunctionsCallback.
I still don't know why this works now as I didn't use IHostFunctionsCallback before.
I know post is old :
What is really the name of your callback Class?
the code you posted says this:
Callback : ICallback
The Error Message says this:
CallbackContractType 'Client.WCFService.IHostFunctionsCallback'
So is the Callback as per your code above, or is it really defined as:
Client.WCFService.IHostFunctionsCallback
I would say you have decorated an attribute reference to the callback channel incorrectly, or inherited from the wrong callback. Search your project to make sure you named everything correctly.
EDIT
As to why the fix worked and what happened:
I answered for the case of others.It may be if you were in a team environment that someone changed the name of the Callback class interface from so generic to something more understandable - in WCF that is what your userobject is - it is the contract. You may have used Visual Studio to generate your Client or Service at one point. which can also foul things up, which is what it looks like to me as the naming convention follows IService[Callback].
Related
I'm working through two tutorials to create a super simple WCF web service and Silverlight app.
Buiding a Service
Accessing a Service from Silverlight
Everything was going fine. I created my service:
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace TestOnline.Web.Data
{
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataService
{
[OperationContract]
public String TestService()
{
return "Service Worked!";
}
}
}
I added it as a service reference, then tried to create an instance but I'm getting the error "Cannot create an instance of the abstract class or interface" on the line "proxy = new DataService();"
I pretty much followed the steps of the tutorial exactly, I'm unsure what I've missed. I've certainly not seen many Service examples with constructors, and the reference code is auto-generated - so I don't want to go adding them manually to that.
Does anyone know of a solution/what I've done wrong? Thanks
using System.ServiceModel;
using TestOnline.ServiceReference1;
namespace TestOnline
{
public partial class MainPage : UserControl
{
DataService proxy;
public MainPage()
{
InitializeComponent();
proxy = new DataService();
}
private void TestServiceButton_Click(object sender, RoutedEventArgs e)
{
//call service and get response
}
}
}
You should be creating an instance of the generated proxy client class.
It'll be named DataServiceClient() if it's been added correctly.
I was following the example (Aggressive old mode) given in:
http://docs.castleproject.org/Default.aspx?Page=Startable-Facility&NS=Windsor&AspxAutoDetectCookieSupport=1
Here is my full source code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Castle.Facilities.Startable;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
namespace Test
{
public interface IStartable
{
void Start();
void Stop();
}
public class Startable : IStartable
{
public Startable()
{
Console.WriteLine("Created!");
}
public void Start()
{
Console.WriteLine("Started!");
}
public void Stop()
{
Console.WriteLine("Stopped!");
}
}
[TestFixture]
public class StartableFacilityContainerTest
{
[Test]
public void TestOperation()
{
IKernel container = new DefaultKernel();
container.AddFacility<StartableFacility>();
container.Register(Component.For<Startable>());
Console.WriteLine("Registered!");
container.Dispose();
Console.WriteLine("Released!");
}
}
}
However when I run it, I get:
Registered!
Released!
when I expect to get (as given in the example):
Created!
Started!
Registered!
Stopped!
Released!
Basically my Startable did not start.
This is tested in .Net 4.0 and Castle Windsor 3.0
What did I do wrong?
I'm using Installers. This helped me:
container.AddFacility<StartableFacility>(f => f.DeferredTryStart());
try
container.Register(Component.For<Startable>()
.StartUsingMethod(s => s.Start)
.StopUsingMethod(s => s.Stop);
The problem is you have created and implemented your own IStartable interface instead of just implementing the Castle.Core.IStartable
I have an ASP.NET 3.5 app consuming a C# WCF in an intranet.
The service executes three commands sequentially taking 2-3 mins each. I'd like to keep the user updated with the command that is running, for example, refreshing a label.
I'm not an expert on this matter so I'd like to know what is the best way to do this.
Thanks,
Ps. The service and the client are hosted in the same server using IIS 7.5.
EDIT
Well, I've been working on this for the past two days .. I'm not an expert :)
I'm following Eric's suggestion, use of WSHttpDualBinding and a callback function.
So, I was able to build a service using duplex binding and define a callback function, however I can't define the callback function on the client side, can you please shed some light on this.
namespace WCF_DuplexContracts
{
[DataContract]
public class Command
{
[DataMember]
public int Id;
[DataMember]
public string Comments;
}
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))]
public interface ICommandService
{
[OperationContract]
string ExecuteAllCommands(Command command);
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void MyCallbackFunction(string callbackValue);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CommandService : ICommandService
{
public string ExecuteAllCommands(Command command)
{
CmdOne();
//How call my callback function here to update the client??
CmdTwo();
//How call my callback function here to update the client??
CmdThree();
//How call my callback function here to update the client??
return "all commands have finished!";
}
private void CmdOne()
{
Thread.Sleep(1);
}
private void CmdTwo()
{
Thread.Sleep(2);
}
private void CmdThree()
{
Thread.Sleep(3);
}
}
}
EDIT 2
This the client implementation,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Client.DuplexServiceReference;
using System.ServiceModel;
namespace Client
{
class Program
{
public class Callback : ICommandServiceCallback
{
public void MyCallbackFunction(string callbackValue)
{
Console.WriteLine(callbackValue);
}
}
static void Main(string[] args)
{
InstanceContext ins = new InstanceContext(new Callback());
CommandServiceClient client = new CommandServiceClient(ins);
Command command = new Command();
command.Comments = "this a test";
command.Id = 5;
string Result = client.ExecuteAllCommands(command);
Console.WriteLine(Result);
}
}
}
And the result:
C:\>client
cmdOne is running
cmdTwo is running
cmdThree is running
all commands have finished!
Use a duplex binding and update status in a callback.
EDIT*
You need to get a reference to the callback channel
public string ExecuteAllCommands(Command command)
{
var callback = OperationContext.Current.GetCallbackChannel<ICallbacks>();
CmdOne();
//How call my callback function here to update the client??
callback.MyCallbackFunctio("cmdOne done");
CmdTwo();
callback.MyCallbackFunctio("cmdTwo done");
//How call my callback function here to update the client??
CmdThree();
callback.MyCallbackFunctio("cmdThree done");
//How call my callback function here to update the client??
return "all commands have finished!";
}
You'll prolly want the service method to be void as to not time out
I would create a couple of operations. One to start the lengthy command, and another to get the status. If you have one operation that waits for the command to complete, you run into the problem of timeouts and have no way to figure out progress.
I have a WCF service (VS 2010, .Net 4.0) hosted as a Windows service.
What I want to do is this: I want a method which is in the service to be executed when the service is started.
I am not sure how you have used Windows Service to host your WCF service(s) but I would expect something like #SSamra described.
Anyway, below the line wherever you do .Open(); to open your service, you could initialize your wcf proxy and call your method.
Say your proxy is FirstWcfProxy, then you can do something like,
var firstWcfProxy = new FirstWcfProxy();
// or IFirstWcfService firstWcfProxy = new FirstWcfProxy();
firstWcfProxy.YourMethod();
EDIT:
If you want to ensure the method is called as soon as the service is started, initialize your proxy below the line sHost.Open(); and invoke the method there, like I described above
how about
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceProcess;
using System.ServiceModel;
namespace Windows_Service
{
public partial class WCFWindowsService : ServiceBase
{
ServiceHost m_serviceHost;
protected override void OnStart(string[] args)
{
m_serviceHost = new ServiceHost(typeof(FirstWcfService.Service));
m_serviceHost.Open();
}
protected override void OnStop()
{
if (m_serviceHost != null)
{
m_serviceHost.Close();
}
m_serviceHost = null;
}
}
}
I am trying to use ManagementEventWatcher in a service to keep track of when a computer goes in and out of sleep mode. I am new to .NET and C# so I am struggling quite a bit to come up with syntax to make this work.
I have found a blog post that details how he used ManagementEventWatcher to keep track of this status, but he did not post up his entire code. I am trying to go through and make a simple service that creates a .txt log file stating that the computer has been suspended/resumed but am running into problems with the namespaces and types.
Here is the code to the service.cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Management;
namespace SleepNotifierService
{
public class WqlEventQuery : EventQuery { }
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WqlEventQuery query = new WqlEventQuery("Win32_PowerManagementEvent");
_watcher = new ManagementEventWatcher(query);
_watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
_watcher.Start();
}
protected override void OnStop()
{
_watcher.Stop();
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
try
{
int eventType = Convert.ToInt32(e.NewEvent.Properties["EventType"].Value);
switch (eventType)
{
case 4:
Sleep();
break;
case 7:
Resume();
break;
}
}
catch (Exception ex)
{
//Log(ex.Message);
}
}
public void Sleep()
{
}
public void Resume()
{
}
}
}
Again, this is the first time that I am programming with .NET and C# so I apologize for my ignorance.
I am getting namespace errors such as:
The type or namespace name
'ManagementEventWatcher' could not be
found (are you missing a using
directive or an assembly reference?)
Thanks,
Tomek
You need the System.Management namespace, which is included in the code sample provided by you. I believe you need to reference the System.Management library in your project settings. Follow the following steps to do this( I am assuming you are suing Visual Studio):
Go to the Solution Explorer, and expand your project, right click on the References folder/option and select Add References from the context menu. Now select the .Net tab and select the System.Management from the list and click OK.