I am currently trying to learn how to create a WCF service and I am facing an issue.
I have a project lets call it MainProject which is a console application and a second project called SoapServer which is created as a class library.
The MainProject doesn't need to reference the SoapServer but the SoapServer does need to reference stuff from within the MainProject.
However, even though MainProject doesn't need to access SoapServer at the moment it does so that the console application can start the host on the WCF service.
However, this obviously causes a circular dependency as I can't have MainProject refernece SoapServer and visa versa. Is there a way to get a round this.
Below is how I am opening the connection for the WCF Service.
public class SoapServer : ISoapServerInterface
{
public void startSoapServer()
{
Uri baseAddress = new Uri("http://localhost:6525/hello");
using (ServiceHost host = new ServiceHost(typeof(SoapServer), baseAddress))
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.Open();
Console.WriteLine("The service is ready at: {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service");
Console.ReadLine();
host.Close();
}
}
Thanks for any help you can provide.
There shouldn't be much code in hosting application (MainProject). It is responsible only for hosting the service and this is its sole purpose. Don't place commonly-used code there.
Instead create another class library with commonly-used code and create references to it from SoapServer and from MainProject.
Related
I want to be able to use the TopShelf debugging abilities of my service in Visual Studio.
A lot of the examples and documentation out there refer to creating a Windows Console project in Visual Studio first, and then adding TopShelf, OWIN, etc
However, in my case I already have a perfectly good and working Windows Service project called QShipsService.sln, etc... and it uses a simple Connected Service (admittedly to old SOAP legacy services).
Can someone please direct me or provide an example of how to use TopShelf, with an existing non-Console like project?
I found my own solution...
The assumption I made was the default Windows Service project defaulting to wanting to register the program as a service and kick off the OnOpen() and OnClose() methods, once the service is running.
In my case I wanted to re-use an existing service that was based on a Timer(), and it would kick in every 4 hours to call a SOAP call and return some data. What I didn't realise was the ServiceConfigurator was trying to call its own Open() and Close() methods.
So I commented out the OnOpen and OnClose methods and allowed the configurator to call my worker process via Open() method instead, which is what I was meant to have done the first time!
For the noobs out there like me, here is the code...
//using System.ServiceProcess;
using Topshelf;
namespace QShipsService
{
static class Program
{
static void Main(string[] args)
{
HostFactory.Run(
configure =>
{
configure.Service<QShipsService.QshipsService>(
service =>
{
service.ConstructUsing(s => new QShipsService.QshipsService());
service.WhenStarted(s => s.QStart());
service.WhenStopped(s => s.QStop());
});
//Setup Account that window service use to run.
configure.RunAsLocalSystem();
//add details and names about the service
configure.SetServiceName("QshipsService");
configure.SetDisplayName("QshipsService");
configure.SetDescription("QshipsService Windows Service to extract data from the QSHIPS SOAP service. Data is recorded and maintained inside the SPOT's database in POT-DB.");
});
//## USE THIS IF WE'RE NOT USING TOPSHELF !! ##
// //this loads and starts the QshipsService (see QshipsService.cs program)
// ServiceBase[] ServicesToRun;
// ServicesToRun = new ServiceBase[]
// {
// new QShipsService.QshipsService()
// };
// ServiceBase.Run(ServicesToRun);
}
}
}
I'm trying to run a Web API application as a Windows Service using OWIN. However, I get the following message, when trying to start the service:
The [ServiceName] service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.
For some reason my service doesn't understand that it should keep listening to http://localhost:9000
The VS solution consists of two projects: The Web API and the Windows service.
In the Windows service project I have:
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service()
};
ServiceBase.Run(ServicesToRun);
}
}
public partial class Service : ServiceBase
{
private const string _baseAddress = "http://localhost:9000/";
private IDisposable _server = null;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_server = WebApp.Start<Startup>(url: _baseAddress);
}
protected override void OnStop()
{
if (_server != null)
{
_server.Dispose();
}
base.OnStop();
}
}
In OnStart the Startup refers to the Startup class in the Web API project:
public class Startup
{
public void Configuration(IAppBuilder builder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default",
"{controller}/{id}",
new { id = RouteParameter.Optional });
builder.UseWebApi(config);
}
}
(It also contains some configurations for Unity and logging.)
I guess the installer part of the Windows service project is mostly irrelevant, though it could be useful to know that I have:
this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalService;
What I've tried:
To host the Web API using a console application and then host the console application as a Windows Service. But even though I included 'Console.ReadKey()', it simply stopped.
To follow this guide:
OWIN-WebAPI-Service
The weird thing is that I can get his service to work, but when I tried changing my code to match his set-up, I kept getting the same error.
Full source code:
github.com/SabrinaMH/RoundTheClock-Backend/tree/exploring_hosting
When you are getting 'service on Local Computer started and then stopped', generally means there's uncaught exception while starting the service. Take a look at Windows service on Local Computer started and then stopped error, for tips to look for that exception.
Based on what you described, my guess the issue is caused by the Startup class exists on a different project, have you tried to have the startup class within the window service project?
Also, the link from HStackOverflow (https://github.com/danesparza/OWIN-WebAPI-Service), shows a work-around approach to load controllers from different project, or dynamically resolve assembly into the current AppDomain. I guess that's also worth trying.
Hope this helps.
For that example OWIN-WebAPI-Service, you must install Package
Install-Package Microsoft.Owin.Host.HttpListener
[WCF newbie]
I have a basic client-server WCF project.
My Service is "gui"less application, meaning that I created winform application, removed the Form1.cs and the lines that starts the gui.
The service is running ok, I am using servicehost.open..
My problem is that it is "serial" (sync), so after a second the application exists.
How can i keep the application alive and listening to the host ?
I need to halt the process and then to host.close when I want to end it.
Thanks
This is code of service:
class Program
{
public static Uri BaseAddress;
[STAThread]
static void Main(string[] args)
{
string baseAddressStr = "http://localhost:7000/someservice";
BaseAddress = new Uri(baseAddressStr);
using (ServiceHost host = new ServiceHost(typeof(MyClass)BaseAddress))
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.Open();
host.Close();
}
}
}
I don't think you want to host your WCF service in a windowless WinForms app.
If you want it to stay open indefinitely, the way to go is to host the WCF service in a Windows Service. Here you have a basic sample.
The benefits should be obvious:
Can run even if no user is logged in.
Does not require a workaround for keeping the application open.
Additionally, you should consider externalizing your WCF configuration (like the base address, service behavior) to the application configuration file. You don't want to rebuild and redeploy your service each time something (anything) changes in the configuration, which may vary from development, test, acceptance and production environments.
This question is a followon from my previous where I have since discovered that it is not working 100% on my computer: WCF service not running on non-dev machine
I'm working through this example:
http://msdn.microsoft.com/en-us/library/ff649818.aspx
It turns out that the InstallUtil step isn't really working here. I've discovered that if VS2010 has the project open, and you go to add a service reference like in step 8 of the tutorial, VS2010 actually starts up the service host and therefore a reference is created.
Here's how i've debugged so far:
Install the service as per InstallUtil, close down VS2010 solution; then open a completely different solution (TESTWCF) Try and add a service reference and it fails - cannot find at the specified address
Open WCFServiceLibrary1 project again as a separate instance of VS2010. Try and add a service reference to TESTWCF and it fails.
Within WCFServiceLibrary1, attempt step 8 - add a service reference. This causes the service host to start and the service is found.
With service host still running, in TESTWCF I then try and add service and it works.
Close down the service host and try and add reference in TESTWCF and it doesn't work again.
This all seems to be totally independant of the service running or not running as installed by InstallUtil.
I've also verified this through the creation of a new virtual server from scratch and loading things on one by one. And only when VS2010 was installed did it start to work - when I observed above.
Any ideas ?
WCF services can be self-hosted in an application (such as a console or a Windows Forms application)
I think you are over complicating it, you don't have to even install it with InstallUtil.
InstallUtil installs it to run as windows service, and you can make console application which will be serving as WCF service.
You have to import:
System.ServiceModel
System.ServiceModel.Web
System.Web.Services
I think those with web will be needed if you want to use it as web service with get and post.
Then you need to specify contract for client and server.
[ServiceContract(Name = "SomeService", Namespace = "http://some.domain.com/some/someservice",SessionMode=SessionMode.Required)]
public interface ISomeService
{
[OperationContract]
string Execute(string expression);
}
You have contract and now you have to implement it in service. nothing special in there just use this interface.
What is very important is app.config, you have to specify it well for client and for service. In config you have all stuff that points to service.
In client you have to add service as reference, it should find it as in point 8 but only if you have configs ok!
In client just do something in code like that:
using (ChannelFactory<ISomeService> channel = new ChannelFactory<ISomeService>("SomeService"))
{
ISomeService svc = channel.CreateChannel();
svc.Execute("my expression to evaluate by the service");
}
Try to make it easiest possible way without InstallUtil and such, it doesn't have to be windows service to serve stuff over network.
Success ! After like 4 days of effort on this, the MSDN tutorial has a fatal flaw.
In the first step of the tutorial you create a wcf service library and by default it names the service Service1. In step 2.6 of the tutorial you are asked to specify the base address:
net.tcp://localhost:8523/Service1
Step 3 you are asked to create a new windows service, and by default this is also called Service1.
In step 5.2 you are asked to make a reference to System.ServiceModel and to WcfServiceLibrary1.
In step 5.6 you replace the Onstart Method to start the service and, Step 8 shows the final code as being:
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.ServiceModel;
using WcfServiceLibrary1;
namespace WindowsService1
{
public partial class Service1: ServiceBase
{
internal static ServiceHost myServiceHost = null;
public WCFServiceHost1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(Service1));
myServiceHost.Open();
}
protected override void OnStop()
{
if (myServiceHost != null)
{
myServiceHost.Close();
myServiceHost = null;
}
}
}
}
The crucial line of code which is wrong is:
myServiceHost = new ServiceHost(typeof(Service1));
Well it might behave differently in VS2008 or 2005 or maybe it's a config in VS2010 however, my VS2010 interprets Service1 to be that of the containing class ie:
WindowsService1.Service1
Whereas it should in fact be:
WcfServiceLibrary1.Service1
I noticed that 4 days ago but figured I didn't know enough about WCF and I was wrong somehow - esp when it appeared to work 'cause of VS2010 starting it up itself.
When i create a Windows Service for getting information from a Web Application(ASP.NET c#) for scheduling some task in the client machine.
To consume WCF from the web application. I added WCF reference
to Window Service project as a service reference, everything seems fine. It
updated app.config file, added service reference etc.
it was not working. Any idea will be very helpful.
My Code is shown below
string result = string.Empty;
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://test.com/Service.svc/DevicesService");
using (ChannelFactory<IDevicesService> myChannelFactory = new ChannelFactory<IDevicesService>(myBinding, myEndpoint))
{
IDevicesService wcfClient1 = myChannelFactory.CreateChannel();
result = wcfClient1.CheckNetworkConnection(IPLocalHost);
if (!string.IsNullOrEmpty(result) && result.Equals(IPLocalHost))
{
EventLog.WriteEntry("Test connection succeeded");
}
else
{
EventLog.WriteEntry("No live connection currently available");
}
((IClientChannel)wcfClient1).Close();
}
I find it easier, when building a windows service, to build a console application that performs the same work as the service will. I abstract out the actual working code (e.g. your code snippet above) into a separate assembly and then just invoke it from either my service's start method or the console's main method.
If you move your code above into a console application, does it work? If it doesn't, can you step through it and let us know where it fails. And when it fails, what exception information are you seeing?
Let us know and we'll help!