Using WCF to communicate over Windows service and Windows forms applications - c#

Currently, I have 2 solutions in Visual Studio 2017:
A Windows forms application
A Windows service application hosting a WCF service class library (.dll)
And I need to communicate between them, in a cyclic way, as followed by the image below. The numbers represent the order.
The problem is, I'm actually able to communicate between WF and WCF application by using the request-replay operation contract (represented by numbers 1 and 4). But I'm not sure how to acomplhish steps 2 and 3.
Code for WCF interface:
namespace SmithWcfService {
[ServiceContract]
public interface ISmithWcfService {
[OperationContract]
void SendRequest( ); //Operation called by Windows Forms
}
}
Code for WCF interface implementation
namespace SmithWcfService {
public class SmithWcfService : ISmithWcfService {
public void SendRequest( ) {
//Ok, now I need to call Windows service application
}
}
}
Code for Windows service
namespace SmithWindowsService {
static class Program {
static void Main( ) {
ServiceBase[ ] ServicesToRun;
ServicesToRun = new ServiceBase[ ] {
new SmithWindowsService( )
};
ServiceBase.Run( ServicesToRun );
}
}
}
namespace SmithWindowsService {
public partial class SmithWindowsService : ServiceBase {
private ServiceHost host;
public SmithWindowsService( ) {
InitializeComponent( );
}
protected override void OnStart( string[ ] args ) {
host = new ServiceHost( typeof( SmithWcfService.SmithWcfService ) );
host.Open( );
}
}
}

If the windows service hosts your WCF service, you can simply pass anything it needs (callbacks, values, settings) at service start. You could pass a method of the windows service as Func<Input2, Output3> that the WCF service should call.
Without your code it's hard to tell where you need to put it though. Normally, it goes into your custom ServiceHostFactory.
Example of service with callback:
namespace SmithWcfService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SmithWcfService : ISmithWcfService
{
private Func<string, int> callback;
public SmithWcfService(Func<string, int> callback)
{
this.callback = callback;
}
public void SendRequest()
{
//Ok, now I need to call Windows service application:
var output = this.callback("input");
}
}
}
Example of hosting:
namespace SmithWindowsService
{
public partial class SmithWindowsService : ServiceBase
{
private ServiceHost host;
public SmithWindowsService( )
{
InitializeComponent( );
}
protected override void OnStart(string[] args)
{
var instance = new SmithWcfService.SmithWcfService(this.SomeMethodYouWantToCallIn);
host = new ServiceHost(instance, new Uri("your.url.com"));
host.Open( );
}
private int SomeMethodYouWantToCall(string data)
{
// do things...
}
}
}

Related

Self hosted WCF service global object appears to be newly created every time an endpoint is invoked

Following the tutorial here I'm self hosting a WCF service inside of a windows service. My WCF service contains a global object that I update at regular intervals. I want to serialize that object to JSON and return that JSON string via a service endpoint. When I access the endpoint that calls the serialize method on the service, I get what appears to be a brand new instance of the global. The service is set to [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
I'm instantiating in the same way as the tutorial:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyWindowsService: ServiceBase
{public ServiceHost serviceHost = null;
public Service()
{
ServiceName = "MyService";
}
public static void Main()
{
ServiceBase.Run(new MyWindowsService());
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(MyWCFService));
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
And my WCF service looks like this:
public class MyWCFService: IWCFService
{
private myObject = mySerializableObject;
public MyWCFService()
{
myObject = new MySerializableObject();
myObject.Init();
}
public Stream GetJSON()
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(MySerializableObject));
ser.WriteObject(stream, myObject);
string jsonString = Encoding.ASCII.GetString(stream.ToArray());
byte[] resultBytes = Encoding.UTF8.GetBytes(jsonString);
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
return new MemoryStream(resultBytes);
}
}
If I GET the GetJSON endpoint, the string returned is a brand new initialization of the object. If I break on the GetJSON method, myObject shows all newly initialized values. Placing a breakpoint in the MySerializableObject update code shows that the updates are occurring correctly and being saved to the object in memory.
Running the same code in a normal console application works fine. Why the discrepancy? Am I handling the global incorrectly?
Figured it out ... I had a couple of issues going on.
As indicated here, my InstanceContextMode declaration
wasn't decorating the right service, so it was still running in the
default per-call context - hence, a new state object on every connection.
O'Reilly showed me that I wasn't creating my singleton
instance correctly. Side note, when creating a ServiceHost using an instance, you can specify a base URI either explicitly in the constructor or in App.config. That caused me some confusion as many of the examples I ran across passed it in the constructor rather than the config.
Here's my working implementation for posterity:
[ServiceContract(Namespace = "http://my.super.original.namespace")]
public interface IWCFService
{
[OperationContract, WebGet]
Stream GetJSON();
}
//Decorator goes on WCF service, not the Windows service
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyWCFService : IWCFService
{
private StateObject _myStateObject;
public MyWCFService()
{
_myStateObject = new StateObject();
_myStateObject.Init();
}
public Stream GetJSON()
{
.
.
.
return "JSON String Here";
}
}
public class MyWindowsService : ServiceBase
{
public ServiceHost serviceHost = null;
private readonly MyWcfService _wcfSingleton;
public MyWindowsService()
{
ServiceName = "WindowsServiceNameHere";
_wcfSingleton = new MyWCFService();
}
public static void Main()
{
ServiceBase.Run(new MyWindowsService());
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
//load WCF Singleton Instance and open it for connections
serviceHost = new ServiceHost(_wcfSingleton);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}

Connecting C++ Application to WCF Duplex Service

I have a WCF Duplex Service having net.TCP Binding with which two client Applications, lets say Client A and Client B are connected. Client A gets data with respect to Time Tick from some source and notifies the Duplex Service by calling a method which in return passes that data to the Client B by calling back a method to the client B through a call back channel.
Here is the Contract Interface of my WCF Duplex Service:
namespace BroadcastorService
{
[ServiceContract(CallbackContract = typeof(IBroadcastorCallBack))]
public interface IBroadcastorService
{
[OperationContract(IsOneWay = true)]
void RegisterClients(string clientName);
[OperationContract(IsOneWay = true)]
void NotifyServer(EventDataType eventData);
}
public interface IBroadcastorCallBack
{
[OperationContract(IsOneWay = true)]
void BroadCastToClient(EventDataType eventData);
}
[DataContract]
public class EventDataType
{
[DataMember]
public string ClientName { get; set; }
[DataMember]
public string Data { get; set; }
}
}
}
Following is the code of the Service Class which inherits the contract interface:
namespace BroadcastorService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class BroadcastorService : IBroadcastorService
{
private static Dictionary<string, IBroadcastorCallBack> clients = new Dictionary<string, IBroadcastorCallBack>();
private static object locker = new object();
public void NotifyServer(EventDataType eventData)
{
lock(locker)
{
var InactiveClients = new List<string>();
foreach(var client in clients)
{
if(client.Key != eventData.ClientName)
{
try
{
if(client.Key == eventData.symbol)
{
client.Value.BroadCastToClient(eventData);
}
}
catch
{
InactiveClients.Add(client.Key);
}
}
}
if(InactiveClients.Count > 0)
{
foreach(var client in InactiveClients)
{
clients.Remove(client);
}
}
}
}
public void RegisterClients(string clientName)
{
if(clientName != null && clientName != "")
{
try
{
IBroadcastorCallBack callback = OperationContext.Current.GetCallbackChannel<IBroadcastorCallBack>();
lock(locker)
{
if(clients.Keys.Contains(clientName))
{
clients.Remove(clientName);
}
clients.Add(clientName, callback);
}
}
catch(Exception ex)
{
}
}
}
}
}
In the above code, Client B first establishes a callback channel with the Duplex Service by calling the RegisterClients(String ClientName) method. Client A calls NotifyServer(EventDataType eventData) method on each data tick which in return sends eventData to the client B through the callback channel.
Both of my client applications, Client A and Client B are developed on C# and the system is working perfectly fine. However, I would like to have a C++ application to replace Client A, i.e my C++ application is getting data with respect to time tick and I would like to pass the data to the client B by the same process as that of C# Client A application.
Is there any possibility of consuming a WCF service having netTCP binding in a C++ Application and calling NotifyServer(EventDataType eventData) method of the service through the WCF Service's Client object? If yes, then please share it with me.
Thank you!
Maybe you can create a managed C++ library which communicate with the C# library using WCF, and your native C++ library will use this managed lib as proxy.
A managed C++ library is the easy way to communicate a C++ library with C# using WCF.

How to pre-load data in an OWIN self-hosted app

I have a OWIN/Katana self-hosted service app.
One of its functions is to service some data over WebAPI.
In this app I have a class called dataManager, which is responsible for retrieving the data, and passing it onto the API controller, which asked for it.
The data is ultimately served to a mobile platform, so it is very important to cache as much as possible for performance.
Is there a way to pre-load my DataManager at the application startup, and have it pre-execute it's linq queries?
The Application class looks like this:
namespace TaskManager
{
using System;
using Microsoft.Owin.Hosting;
public class TaskManagerApplication
{
protected IDisposable WebApplication;
public void Start()
{
WebApplication = WebApp.Start<WebPipeline>("http://*:8080");
}
public void Stop()
{
WebApplication.Dispose();
}
}
}
The Program class looks like this:
namespace TaskManager
{
using Topshelf;
internal class Program
{
private static int Main()
{
var exitCode = HostFactory.Run(host =>
{
host.Service<TaskManagerApplication>(service =>
{
service.ConstructUsing(() => new TaskManagerApplication());
service.WhenStarted(a => a.Start());
service.WhenStopped(a => a.Stop());
});
host.SetDescription("Task Manager");
host.SetDisplayName("Task Manager");
host.SetServiceName("TaskManager");
host.RunAsNetworkService();
});
return (int) exitCode;
}
}
}
And the data retrieval statement contained within DataManager class look like this:
var rawData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
select data;
What I do is create a public static class in the API library. That's where I modify the HttpConfiguration object. That is also where I define OnStartup() and OnShutdown() methods. I then call these methods in the pipeline class's methods (your WebPipeline class).
For example (in the MyWebApi library, where my controllers and stuff live):
public class Service
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
}
public static void OnStartup()
{
// add any startup logic here, like caching your data
}
public static void OnShutdown()
{
// add any cleanup logic here
}
}
Then in the pipeline class:
public class WebPipeline
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
MyWebApi.Service.Register(config);
MyWebApi.Service.OnStartup();
app.UseWebApi(config);
}
public static void Shutdown()
{
MyWebApi.Service.OnShutdown();
}
}
Now your TaskManagerApplication.Start() will result in the API OnStartup() being called. Then you just have to add a call to WebPipeline.Shutdown() in your TaskManagerApplication.Stop() method.

Saving a cache object when a WCF webservice is ended

I have a simple WCF webservice with 2 methods : one save/updates an obect in the cache and the other one deletes it. How can I save the object when I close the webservice server.
Using CacheItemRemovedCallback doesn't work because the object is removed everytime i update it.
Using Global.asax.cs.Application_End() doesn't work also because the cache is cleared by the time it get here.
Using Dispose() method method doesn't work because it get called every time a call has finished.
[ServiceContract]
public class WebService
{
[OperationContract]
public void Test(string message)
{
List<string> Logs;
Logs = HttpRuntime.Cache.Get("LogMessages") as List<string>;
if (Logs == null)
{
Logs = new List<string>();
Logs.Add(message);
}
else Logs.Add(message);
HttpRuntime.Cache.Insert("LogMessages", Logs, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
}
[OperationContract]
public void WriteToFile()
{
List<string> Logs;
Logs = HttpRuntime.Cache.Get("LogMessages") as List<string>;
if (Logs == null)
{
string filename = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff");
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
//any method of writing the object to disk
HttpRuntime.Cache.Remove("LogMessages");
});
}
}
}
Generally, if you need to do something when a WCF service starts or stops it should be done by extending the ServiceHostFactory.
Check ServiceHost OnClose or OnClosing event to do what your need.
public class DerivedHost : ServiceHost
{
public DerivedHost( Type t, params Uri baseAddresses ) :
base( t, baseAddresses ) {}
protected override void OnClose(System.TimeSpan timeout)
{
...
base.OnClose(timeout);
}
protected override void OnClosing()
{
...
base.OnClosing();
}
}
You can also implement your own instance provider and use the ReleaseInstance method.
public class MyInstanceProviderBehavior : IInstanceProvider
{
...
#region IInstanceProvider Members
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
...
}
#endregion
}
For more information about WCF extensibility, take a look at Carlos Figueira blog.

How to use PRISM within C# windows service applications?

I'm trying to create an windows service application which i would be able to add modules in it as we do in WPF and Silverlight.
This is how i went throw :
public static class Program
{
public static string CurrentAppPath { get; set; }
static void Main()
{
Program.CurrentAppPath = Path.GetDirectoryName(
System.Reflection.Assembly.GetEntryAssembly().Location);
ShellBootstrapper bootstrapper = new ShellBootstrapper();
bootstrapper.Run();
}
}
And for the ShellBootstrapper class :
class ShellBootstrapper : UnityBootstrapper
{
protected override IModuleCatalog CreateModuleCatalog()
{
DirectoryModuleCatalog directoryCatalog =
new DirectoryModuleCatalog() { ModulePath = Program.CurrentAppPath };
return directoryCatalog;
}
protected override System.Windows.DependencyObject CreateShell()
{
return null;
}
public override void Run(bool runWithDefaultConfiguration)
{
base.Run(runWithDefaultConfiguration);
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService(logger)
};
ServiceBase.Run(ServicesToRun);
}
}
Are there any sample out there?
lock at this. you can download there sample as you can see in picture
After download and installing prism(v4), in root directory you have folder named as stock trader. that's what you need! (run desktop version). In section Modules you can Find folder named service.
This is simple, you can call Wcf-service in these method right here.(also you can use wcf method as async-service )

Categories