I am trying to add my custom (not WCF) service to my WCF.
It is hosting in Windows Service and in IIS.
I added call
serviceHost = new ServiceHost(typeof(MyService));
...
// ok, works.
When win service stopping it calls
if (serviceHost != null && serviceHost.State != CommunicationState.Closed) serviceHost.Close();
But my custom service still works.
The question is: how to stop my service when host is stopped?
Related
I have a service hosted in a Service Fabric cluster in Azure (not locally) and I'm trying to call a method in it using a console application on my local machine. Using WCF for communication, I have a HTTPS endpoint set up in my application on a specific port, and have configured load balancing rules for the port in the Azure portal. The cluster has 6 nodes and the application is the only one deployed on the cluster.
Have followed the ServiceFabric.WcfCalc on GitHub (link), which works on a local cluster using HTTP endpoints, but can't call a method on the service using HTTPS endpoints once it has been deployed. What do I need to do to get it working? Have tried following the example here but don't know how to configure this for HTTPS with a service on multiple nodes for a console application to access.
Thanks in advance.
EDIT Here's my client code which I am using to call the service method. I pass the fabric:/ URI into the constructor here.
public class Client : ServicePartitionClient<WcfCommunicationClient<IServiceInterface>>, IServiceInterface
{
private static ICommunicationClientFactory<WcfCommunicationClient<IServiceInterface>> communicationClientFactory;
static Client()
{
communicationClientFactory = new WcfCommunicationClientFactory<IServiceInterface>(
clientBinding: new BasicHttpBinding(BasicHttpSecurityMode.Transport));
}
public Client(Uri serviceUri)
: this(serviceUri, ServicePartitionKey.Singleton)
{ }
public Client(
Uri serviceUri,
ServicePartitionKey partitionKey)
: base(
communicationClientFactory,
serviceUri,
partitionKey)
{ }
public Task<bool> ServiceMethod(DataClass data)
{
try
{
//It hangs here
return this.InvokeWithRetry((c) => c.Channel.ServiceMethod(data));
}
catch (Exception)
{
throw;
}
}
}
When debugging my console application on my local machine, the application hangs on the InvokeWithRetry call which calls the method in my service in Service Fabric. The application does not throw any exceptions and does not return to the debugger in Visual Studio.
Make sure you run every service instance /replica with a unique url.
Make sure you call the WebHttpBinding constructor using WebHttpSecurityMode.Transport.
Make sure you register the url using the same port number (443 likely) as in you service manifest endpoint declaration.
Make sure the endpoint is configured as HTTPS.
The warning you see in Service Fabric is telling you that there is already another service registered to listen on port 443 on your nodes. This means that Service Fabric fails to spin up your service (since it throws an exception internally when it is trying to register the URL with http.sys). You can change the port for your service to something else that will not conflict with the existing service, e.g.:
<Resources>
<Endpoint Name="CalculatorEndpoint" Protocol="https" Type="Input" Port="44330" />
</Endpoints>
If you log in to Service Fabric Explorer on https://{cluster_name}.{region}.cloudapp.azure.com:19080 you should be able to see what other applications and services are running there. If you expand services all the way down to node you should be able to see the registered endpoints, including ports, for existing services.
Bonus
You can query the cluster using FabricClient for all registered endpoints
var fabricClient = new FabricClient();
var applicationList = fabricClient.QueryManager.GetApplicationListAsync().GetAwaiter().GetResult();
foreach (var application in applicationList)
{
var serviceList = fabricClient.QueryManager.GetServiceListAsync(application.ApplicationName).GetAwaiter().GetResult();
foreach (var service in serviceList)
{
var partitionListAsync = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).GetAwaiter().GetResult();
foreach (var partition in partitionListAsync)
{
var replicas = fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id).GetAwaiter().GetResult();
foreach (var replica in replicas)
{
if (!string.IsNullOrWhiteSpace(replica.ReplicaAddress))
{
var replicaAddress = JObject.Parse(replica.ReplicaAddress);
foreach (var endpoint in replicaAddress["Endpoints"])
{
var endpointAddress = endpoint.First().Value<string>();
Console.WriteLine($"{service.ServiceName} {endpointAddress} {endpointAddress}");
}
}}}}}
Just run that with the proper FabricClient credentials (if it is a secured cluster) and you should see it listing all endpoints for all services there. That should help you find the one that has an endpoint for :443
I have a Window Service thats hosts wcf:
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof('myservicetype'));
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
serviceHost.AddServiceEndpoint
(typeof('myservicetype'),
binding, ConfigurationManager.AppSettings["myconfig"]
);
serviceHost.Open();
Console.ReadLine();
}
the wcf listen to requests, one of the request is to open notepad on the server,
this doesnt work because the service is running on session 0(no gui...),
how can i fix this?
You can open notepad regardless of what you're using (windows app, service etc) if the identity associated with the service got enough permissions.
You can then use Process.Start("notepad.exe", yourTextFile);
Or just Process.Start(yourTextFile); if notepad is the default program for handling text files.
WCF (winodws service hosting) service uses set of protocols and bindings: http, https, net.tcp, net.pipe.
It uses config file settings.
I want to build demo version of the service.
This demo will use only net.pipe protocol.
How I can restrict service to use only this one?
I can do changes in code , but how and where?
ServiceHost owns collection of ChannelDispatchers in ChannelDispatchers property. You can use ChannelDispatcher.BindingName to figure out name of binding used in your service.
ServiceHost host = new ServiceHost(typeof(SomeService), baseAddress))
//configure service endpoints here
host.Open();
#if DEMO_MODE
foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
{
//binding name includes namespace. Example - http://tempuri.org/:NetNamedPipeBinding
var bindingName = dispatcher.BindingName;
if (!(bindingName.EndsWith("NetNamedPipeBinding") || bindingName.EndsWith("MetadataExchangeHttpBinding")))
throw new ApplicationException("Only netNamedPipeBinding is supported in demo mode");
}
#endif
I have a WCF Service Using MSMQ hosted on IIS. I want to create a windows application which can stop WCF Service from picking MSMQ message. Once I have seen the MSMQ message in the queue I need to click a button and Start the WCF service to pick the message in MSMQ. Code sample would be apperciated.
IIS is not an appropriate container to host a MSMQ client in. This is because when the app pool unloads during times of low traffic the queue client also unloads. This behaviour is automatic and you don't have any control over it.
It would be far better to host your client in a windows service. However, the kind of "consume-on-demand" functionality you require is not easy to achieve and certainly is not supported by the standard bindings.
The best I can suggest is consume the message as soon as it's received and persist it somewhere until the user clicks the button, upon which you do whatever you want as the data in the message is already available.
I was able to solve this problem by applying a workaround. I created another queue in a different machine. Changed the address of the WCF client endpoint address to this queue in config. I created another external application which moved the message from the alternate queue to the actual queue. Thus the behavior of stopping IIS hosted WCF service with MSMQ binding was achieved
Stopping the "Net.Msmq Listener Adapter" Windows service and the "Windows Process Activation Service" will stop the messages from being pulled out of the queue. Starting the services back up will causes the messages to be pulled from the queue again. I'm doing this manually, rather than through another application, but I'd assume you could do it through another application as well. I haven't tested this completely, but something like this would probably work:
Dictionary<string,List<string>> runningDependentServices = new Dictionary<string,List<string>>();
private void StartMsmqBinding()
{
StartService("WAS");
StartService("NetMsmqActivator");
}
private void StopMsmqBinding()
{
StopService("NetMsmqActivator");
StopService("WAS");
}
private void StartService(string serviceName)
{
List<string> previouslyRunningServices = null;
var sc = new ServiceController();
sc.ServiceName = serviceName;
if (runningDependentServices.ContainsKey(serviceName))
{
previouslyRunningServices = runningDependentServices[serviceName];
}
try
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running);
if(previouslyRunningServices != null)
{
previouslyRunningServices.ForEach(a =>
{
var serviceController = new System.ServiceProcess.ServiceController() { ServiceName = a };
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running);
});
}
}
catch (InvalidOperationException)
{
}
}
private void StopService(string serviceName)
{
var sc = new System.ServiceProcess.ServiceController() { ServiceName = serviceName };
runningDependentServices[serviceName] = sc.DependentServices.Where(a => a.Status == System.ServiceProcess.ServiceControllerStatus.Running).Select(a => a.ServiceName).ToList();
if (sc.CanStop)
{
try
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
catch (InvalidOperationException)
{
}
}
}
I'd think a similar approach would work for Net.Tcp binding. You'd probably have to stop the "Net.Tcp Listener Adapter" Windows service (ServiceName: "NetTcpActivator") and the "Windows Process Activation Service" in that case.
How do I host my WCF class library in a console app? I have a WCF service within a class library and I wanted to test the service outside my project with a test app.(I have to do it outside the project)
Create a simple console app, add a reference to your WCF service assembly, and then basically write these few lines:
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Namespace.YourWCFService)))
{
host.Open();
Console.WriteLine("Service host running......");
foreach (ServiceEndpoint sep in host.Description.Endpoints)
{
Console.WriteLine(" endpoint {0} ({1})",
sep.Address, sep.Binding.Name);
}
Console.ReadLine();
host.Close();
}
}
All you do is instatiate a ServiceHost and pass it the type of a service (implementation) class, and then basically call .Open() on it.
The Console.ReadLine() just wait until someone presses ENTER and then terminates the service host.
That's all there is! (of course, you need to specify service address and bindings in a app.config for the service host console app for it to work)
You may create ServiceHost in your console application with your existing service contract (from your class library).
After the service is running, your test project can access your WCF Service as usual.
Consider using the WCF Service Host application: http://msdn.microsoft.com/en-us/library/bb552363.aspx
You can simply point the host to your service class library and configuration file and it will host your service for you.