Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I need to write a service in C# that will always run on a PC even if no one is logged in. I need to write a c# winform application that will auto-run when a user logs in and allows the user to interact with the service.My proposed solution is to build a WCF server into the service and write a WCF client into the winform application. This will then allow interaction between the Winform application and the service. Is this the best/easiest method?
Yes - WCF is probably the simplest solution to communication between the WinForms client and the Service back-end.
Your main alternatives would be:
1. TCP sockets (lower-level and would likely require a lot more boilerplate code).
2. Messaging middleware like MSMQ/ActiveMQ NMS (involves adding more third-party libraries)
If you go with WCF, there are a few gotchas/recommendations from my experience:
Instead of handling WCF requests synchronously in the server, handle them asynchronously (if you code is thread-safe), or handle them via a single background processing queue (if your code is not thread-safe). This helps avoid issues with timeouts (which can cause WCF to fault), as well as issues where the WCF requests get triggered at the same time from multiple threads.
Don't forget that you will likely need a WCF interface in the client as well as the server. This is needed if you want the server to be able to send any kind of async communication back to the client.
You can set up a pub/sub mechanism with WCF but it's a bit tricky. Here is a code example:
Interface
//Server interface
[ServiceContract(CallbackContract = typeof(IGUIService))]
public interface IServerService
{
[OperationContract(IsOneWay = true)]
void Subscribe();
[OperationContract(IsOneWay = true)]
void Unsubscribe();
...
}
//Client interface
[ServiceContract]
public interface IGUIService
{
[OperationContract(IsOneWay = true)]
void MessageCallback(string Message);
}
The client will need to call Subscribe() when it starts, and Unsubscribe() when it shuts down. The corresponding server code to handle this is:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class ServerService : IServerService
{
internal event SettingsUpdatedHandler SettingsUpdated;
internal delegate void SettingsUpdatedHandler(ServerService adminPort, EventArgs e);
private static List<IGUIService> Clients = new List<IGUIService>();
public void Subscribe()
{
IGUIService callback = OperationContext.Current.GetCallbackChannel<IGUIService>();
if(!Clients.Contains(callback))
Clients.Add(callback);
}
public void Unsubscribe()
{
IGUIService callback = OperationContext.Current.GetCallbackChannel<IGUIService>();
if (Clients.Contains(callback))
Clients.Remove(callback);
}
}
Then to send a message from the server to all connected clients:
internal void SendMessage(string message)
{
for(int i=Clients.Count - 1; i >= 0; i--)
{
IGUIService callback = Clients[i];
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
callback.MessageCallback(message);
else
Clients.RemoveAt(i);
}
}
If you want you can use also web api.But note if use web api you can use transaction.
But both web api and wcf is good.
WCF server: hosted in a Windows Service in server.
WCF Client: Winform application. And put the shortcut of the program in the folder "C:\Documents and Settings[username]\Start Menu\Programs\Startup" (Windows XP). program will be run automatically when user is login.
Do you need to maintain state in the service? If not then can you not just host in IIS or self host a wcf, web api or even service stack service. Also is the service going to be utilised by more than one client? Does the persistence store access need to live in another process, if not then "in process" would be just fine too, without the overhead of all the service related stuff.
What you have, are two processes that need to communicate with each other. One of the processes happens to be a Windows services, while the other is a Windows application. This is a classic problem of interprocess communication. There is a number of available solutions, probably the most popular being:
WCF, already mentioned by you. Your Windows service implements a host for WCF services and the app communicates with the exposed service. Here's a good example how to implement this.
Named Pipes, old and preferred by many. Look here and here for some examples.
Other, more exotic examples:
Custom TCP ports
Win32 RPC. You can use .NET wrapper like this library.
MSMQ
File system. One process writes to a defined location, where the other listens to. You can write simple messages understood by both sides, or even whole objects using serializtion.
Database. Variation of the point 4, using a third process providing database functionality.
Given that WCF is quite mature technology with a sufficient performance, built with .NET and reasonably easy to implement, this seems like a natural choice.
Related
I will be deploying my first application based on WCF and would like to know the best way to deploy. Here is my architecture. Please see the attached image.
We have a WCF written using 4.0 framework and has 3 methods. A front end ASP.NET website (www.site.com) calls the WCF to save data as well as read data. In figure method1 is saving to data and method2 and 3 are for reading the data from SQL server 2008 R2 database.
In my ASP.Net webstie...
I am calling the Method1 and closing the connection...like this..
ServiceClient client = new ServiceClient();
client.Method1(data to be saved)
client.close();
I am calling method 2 and 3 as follows
ServiceClient client = new ServiceClient();
dropDown1list.datasource = client.Method2()
dropDown2list.datasource = client.Method3()
client.close();
Multiple users could be using the website at the same time to submit the data. Considering this architecture..what would be the best way to deploy the WCF so that it could handle multiple users at same time?. I read the article http://www.codeproject.com/Articles/89858/WCF-Concurrency-Single-Multiple-and-Reentrant-and and http://www.codeproject.com/Articles/86007/ways-to-do-WCF-instance-management-Per-call-Per.
I now believe I need to have my WCF service as
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple , InstanceContextMode = InstanceContextMode.PerCall )]
public class Service : IService
{
public bool Method1(data to be saved)
{
}
public List<string> Method2()
{
}
public List<string> Method2()
{
}
}
Am I right ?. Any suggestions ?.
Just answered a similar question yesterday. Based on your description and the picture, I don't see a need to change your architecture. If you're using one of the main WCF bindings (webHttpBinding, wsHttpBinding or BasicHTTPBinding), the service you deploy should easily be able handle dozens of concurrent users, all saving and reading at the same time.
Each client request will generate its own connection and web service objects, each of which can communicate concurrently with your database, whether that request is to read data or write data. When the response is sent back to the client, your WCF service will destroy the objects and clean up the memory for you as long as you're not doing something strange.
I've spent the last two years working on WCF web services on and industrial scale. Lately I've been working on a load testing / benchmarking project that spins up hundreds of concurrent users, each of which is slamming our WCF test server with XML artifacts that get loaded into the database. We've managed to load up to 160 packages (about 110kb - each per client) per second. WCF is not perfect, but it's quick, clean and scales really well.
My experience has been that your database will be your bottleneck, not your WCF web service. If your client wants to scale this archtecture up to an Amazon size web service, then you bring in an F5 load balancer and scale it up that way.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
i am new in wcf service. still reading books to acquire knowledge. my company has many offices in our city but one head office. my company has one static IP. my company plan to host a wcf service in HQ server which can be reach by static IP over the internet and other office is connected each other by VPN. our company want me to develop a wcf service which will be using to handle company data among all the pc of HQ and also among all the pc of other offices. also people can outside will be able to connect to that wcf service.
company want that when any one try to connect to our service from HQ office then HQ lan will be used to connect to that service.
when any one try to connect to our service from our other offices then WAN or VPN connection will be used.
when any one try to connect to our service from other place or home then connection will be made through internet.
i am new in WCF so not being able to think how to design this kind of service with WCF which will be hosted in our HQ server which has static IP.
so guide me is there any tweak requited in coding or in config file where we specify various bindings.
i guess that we need to specify various binding in service config file. so just guide me how do i design or write the config file for service end which can be requested over the LAN, VPN and as well as internet. if possible give me a sample copy of config file for service end. thanks
We are working on a large project right now which I believe is similar to what you are working on. We have many users who will be accessing this app from their desktop PC's as well as their mobile devices. I designed a service layer that is very flexible that delivers optimal performance depending on if the user is local or remote (note that VPN = local).
I cannot give you every detail due to lack of space but here are the big pieces:
Create three Visual studio projects (or one solution with three projects): 1) Your app, 2) A service project (.dll), 3) A WCF project.
Your service project is where the action is.
In your service project, create an interface called something like IMyServices (this is standard WCF stuff):
[ServiceContract]
public interface IMyServices : IDisposable
{
[OperationContract]
IEnumerable<Allocation> GetAllocations();
}
Next, add a class like what you see below. I call it ServiceRouter because if the user is remote, it routes the request to WCF but if the user is local it just gets data using ADO over the LAN. Note that this class implments IMyServices.
public class ServiceRouter : IMyServices
{
private readonly string ServiceURI;
/// <summary>
/// Routes data requests over the LAN if the client is connected locally or over a WCF service if the client is remote. Use this constructor to route data requests over the LAN.
/// </summary>
/// http://msdn.microsoft.com/en-us/library/ms735103.aspx
///
public ServiceRouter()
{
ServiceURI = null;
}
/// <summary>
/// Routes data requests over the LAN if the client is connected locally or over a WCF service if the client is remote.
/// </summary>
/// <param name="serviceURI">Fully qualified URI of a WCF server if the user is remote. Pass null if the user authenticated on the LAN (including using VPN)</param>
/// http://msdn.microsoft.com/en-us/library/ms735103.aspx
///
public ServiceRouter(string serviceURI)
{
ServiceURI = serviceURI;
}
public IEnumerable<Allocation> GetAllocations()
{
IMyServices client = GetClient();
var result = client.GetAllocations().ToList();
CloseClient(client);
return result;
}
#region WCFClient
private IMyServices GetClient()
{
IMyServices _client;
if (string.IsNullOrEmpty(ServiceURI))
_client = new MYServices();
else
{
_client = ChannelFactory<IMyServices>.CreateChannel(new BasicHttpBinding(), new EndpointAddress(ServiceURI));
((ICommunicationObject)_client).Open();
}
return _client;
}
private void CloseClient(IMyServices client)
{
ICommunicationObject wcfClient = client as ICommunicationObject;
if (wcfClient != null)
{
if (wcfClient.State == CommunicationState.Faulted)
wcfClient.Abort();
else
wcfClient.Close();
}
else
((IDisposable)client).Dispose();
}
#endregion
}
Next, in your service project, create a class for your services that implements IMyServices like this:
internal partial class MyServices : IMyServices
{
public IEnumerable<Allocation> GetAllocations()
{
// access your db here
}
Now here is how you you expose your services using WCF. You will need to configure your web.config and you will need to reference the .dll file from your service project.
In your WCF project add a WCF service like what you see below. Note this class inherits from ServiceRouter, which implements IMyService. The code below is the ONLY code in the WCF project! All this code does is create an instance of your ServiceRouter, passing it a null uri which tells it to get its data over the LAN. Your WCF server and you DB server need to be able to communicate over the LAN for this to work of course.
public class MyWCFService : MyServiceProject.ServiceRouter
{
public MyWCFService() : base()
{
// Since the WCF server is running on the local area network, this class only needs to create an instance of
// the service router in local mode and retrive the requested data. WCF serializes the data and sends it
// back over the wire.
}
}
Here is a fragment of how your web.config might look:
<service name="MyWCFService" behaviorConfiguration="xxx">
<endpoint address="" binding="basicHttpBinding" bindingNamespace="http://blah.com" contract="MyServiceProject.IMyServices">
In your app project, add a reference to your service .dll file. Look at your user's IP address and if it is local, use create instances of ServiceRouter passing null to the constructor. If the user is remote, pass the URI of your wcf server when you create insances of Service router: i.e. ServiceRouter router = new ServiceRouter(myServerName);
LAN vs WAN vs VPN is at a too lower newtork level for WCF. Assuming you use say basicHttpBinding and host your WCF service in IIS that runs in the server in HQ that has a static IP, your internet users will be able to come to your service using the external IP (static IP) or the domain name if there is one. For intranet (LAN, WAN, etc), the users can use the internal IP, which you can get by pinging the server from within your network. Again assuming that the path between the computers where WCF will be consumed and where WCF service runs does not cut across firewalls and stuff, you can use a netTcp binding which can be slightly more performant but not worth the trouble if your organization has lots of red tape to opening ports and stuff if there are firewalls in between. Generally, 80 and 443 are not blocked.
Thats a simple question of network configuration. Your service has one or more endpoints. So simple route the requests from the various networks to that/them.
Your question is a bit "tl;dr" and open-ended but can I suggest you learn the "ABC's" of WCF endpoints: Address, Binding, Contract?
If you'd like to use both HTTP and TCP for a single service endpoint can configure both binding types to the same endpoint.
From the article:
It is important to note is that these three elements are independent.
A contract can support many bindings and a binding can support
many contracts. A service can have many endpoints (contract bound to
address) coexisting and available at the same time. So if you want to
expose your service via HTTP and use SOAP 1.1 for maximum
interoperability, and also want to expose it via TCP using a binary
wire encoding for maximum performance, the two resulting endpoints can
reside side-by-side on top of the very same service.
I am designing a webservice interface for use between a Windows CE device and a PC. The Windows CE device is server and the PC is client.
I have decided to use the gSOAP library to implement the server and I am using .NET/C# for the client. I have followed the approach described here and everything is working well.
My question is about how to best implement an asynchronous callback/event from the server to the client. I can think of two methods:
Continuously polling the server for active events
A blocking method that keeps the connection open until an event occurs
I have currently chosen option 2 and it seems to be working well. I use an asynchronous method in the client and therefore get a callback when the method completes, i.e. when an event occurs on the Windows CE device. I then immediately call the same method again so it is ready for the next event.
Example server method (no error handling):
int ns__WaitForEvent(struct soap* soap, int *eventId)
{
WaitForSingleObject(hMyServerEvent, INFINITE);
*eventId = GetCurrentEventId();
return SOAP_OK;
}
Example client (no error handling):
private void SubscribeToServerEvents()
{
var server = new MyMethods.ServicePortTypeClient(
new BasicHttpBinding(),
new EndpointAddress(myIpAddress));
AsyncCallback cb = this.Callback;
server.BeginWaitForEvent(cb, server);
}
private void Callback(IAsyncResult ar)
{
var server = (MyMethods.ServicePortType)ar.AsyncState;
var result = server.EndWaitForEvent(ar);
// Do stuff with result
}
The server must be multi-threaded for this approach to work, and the number of clients should be limited so the server does not have a large number of threads hanging with blocking methods. In my case none of these issues are a problem - it is simple to setup a multi-threaded server using gSOAP and there will only ever be one client (which I control) attached to each server.
Are there any significant disadvantages to this approach? Can you suggest a better solution?
I suggest to turn the WinCE device into a webclient instead of a webserver and the PC into a server, that will be notified on something happens on the client. It is more natural this approach, you can still use gSoap for a soap client. On the PC you should have a web-server like Apache or IIS installed, or you could make a Windows server that will host an embedded light webserver.
it seems like it should be dead easy, but i couldn't find anything in google on it:
I have a video store server, and it has multiple client applications, installed on users' machines, communicating via (let's say) web services.
When a DVD is returned, I'd like to be able to notify useres that have been waiting for that DVD.
When dealing with a single application, then that's no problem using delegates.
my question is- can this approach work with remote clients as well?
You can use a duplex WCF service for that.
But if it really is a DVD handling service where the user doesn't need to be notified immediately, I would recommend a solution where the users' clients poll the server every say 10 minutes. It is far more simple to implement.
Yes - you can use .NET remoting. See this article for a simple example:
http://www.codeproject.com/KB/IP/remotingandevents.aspx
If you want to have a client application that will provide a delegate that people can wire up to, then yes. You would use .net remoting for that.
I used this example: http://www.codeproject.com/KB/dotnet/DotNetRemotingEventsExpl.aspx
Basically what you are going to do, is to expose a remoting server that publishes a known object. The trick with events, is that the server has to know about the type that the client is wiring the event handlers to. So what you do in that case is that you also provide an abstract class as an event sink.
Basically that class will look something like this:
public abstract class MyEventSinkClass : MarshalByRefObject
{
public abstract void MyAbstractEventHandler(string arg1, string arg2);
public void MyEventHandler(string arg1, string arg2)
{
MyAbstractEventHandler(arg1,arg2);
}
}
Then on the client side they would create a class, and inherit from MyEventSinkClass. They put their logic for handling the event in the override for MyAbstractEventHandler. When they wire up the instance that they are using remoting for, instead of wiring like you normally would, they need to wire to their instance of the class that inherits MyEventSinkClass to the MyEventHandler Method. Then when the event fires, it will eventually call into the overriden method and execute their code.
You can find the details of how to setup a remoting server and client in the link I gave, it isn't difficult.
If you don't want to invent the wheel, Use a Message Queuing tool.
Then, when a dvd is return you post a message on some queue. The users are registering to the queues of the DVDs they are interesting in.
Then the communication is persistent and async. the users are getting notifications even if they are offline (they'll get it once they connect and poll the queue)
This question already has answers here:
check the availability of the WCF Web Service
(4 answers)
Closed 8 years ago.
I will have a client application using a proxy to a WCF Service. This client will be a windows form application doing basicHttpBinding to N number of endpoints at an address.
The problem I want to resolve is that when any windows form application going across the internet to get my web server that must have my web server online will need to know that this particular WCF Service is online. I need an example of how this client on a background thread will be able to do a polling of just "WCF Service.., Are You There?" This way our client application can notify clients before they invest a lot of time in building up work client-side to only be frustrated with the WCF Service being offline.
Again I am looking for a simple way to check for WCF Service "Are You There?"
What this obsession with checking whether those services are there??
Just call the service and as any defensive programming course will teach you, be prepared to handle exceptions.
There's really no benefit in constantly sending "are you there?" requests all over the wire...
Even if you could have something like a Ping() method (that just returns a fixed value or something - your service name or whatever) - that only checks whether your service is reachable - what about the database you need to query to get data from? What about other services your service method depends on? It gets quite messy and very very tricky to figure out a way to check all that - just to see if it's there.
In brief: no, there is no reliable and meaningful way to check whether a given service is "there" and "alive" - just call it ! And be prepared to handle a failure - it will fail at times....
There is no value in checking if a service is alive or not. Absolutely none. Why?
if(serviceIsAlive())
{
callService();
}
else
{
handleFailure()
}
Do you see the problem with this snippet? What happens if between the time you check if the service is alive, and the time you call it, the service goes down? This is a race condition, and a bug waiting to happen. So what you need to do, even if you can check the service condition, is:
if(serviceIsAlive())
{
try
{
callService();
}
catch(CommunicationException)
{
handleFailure();
}
}
else
{
handleFailure();
}
But in this block, the handleFailure() call is in two different places - we've got two different paths to handle the same error condition - which seems like a bad thing. So this can be safely reduced to:
try
{
callService();
}
catch(CommunicationException)
{
handleFailure();
}
If your service is hosted in IIS (or WAS), you can perform a resiliency built-in to the IIS6/7 process model. If an worker process fails, another will be started in its place. How it works? Using Ping to analyse. Its called AppoPool Health Monitoring (described here).