Console app client to Service Fabric Stateless Service - c#

I'm learning SF, and am now trying to build a console client to a stateless service.
tried to follow instructions here: https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-connect-and-communicate-with-services
and added this to my StatelessService class
public interface IMyService : IService
{
Task<string> HelloWorldAsync();
}
and a simple implementation
public Task<string> HelloWorldAsync()
{
return Task.FromResult("HELLO FROM SERVICE!");
}
The rest is unchanged.
In my Console app I have
IMyService helloWorldClient = ServiceProxy.Create<IMyService>(
new Uri("fabric:/RestGateway/StatelessGateway1"));
string message = await helloWorldClient.HelloWorldAsync();
The service deployed to my local cluster and seems to work fine (green button) but I get an Exception when calling helloWorldClient.HelloWorldAsync().
Any idea how I can fix this?

Don't forget to add a communication listener to your service like this:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(ServiceRemotingExtensions.CreateServiceRemotingListener(this, Context));
}
Note:
The call to CreateServiceRemotingListener creates a specific communication listener that can be used only from within the cluster. So, when talking from your dev machine to a service running on your dev cluster this will work. You can't talk to services running on different machines like this.
To access your cluster from the outside, you could use ServiceBus, WCF or OWIN for instance. (or something you build yourself)

Related

How should a GRPC Service be hosted?

I have created a GRPC Server in C# using the example given at Link. Now I want to figure out as how should I be hosting this server so that I achieve following:
Should I make this Server a Console application or a a Windows Service. If I make it a windows Service then updating the service will be cumbersome (which is a big negative) and if I make it a console app then updating will simply need shutting down exe. But that comes with the price of closing the same by mistake. Is there any other better way?
With IIS this issue won't b there as I can simply remove the site from LB and stop the website to perform the update but since GRPC won't be a part of IIS, I am not sure what's the way to get this working.
Any references for the better architecture are welcomed.
We can use Microsoft.Extensions.Hosting pacakge to host a .net core console application by using the HostBuilder API to start building gRPC host and setting it up.
In order to run the gRPC service, we first need to start/stop Grpc.Core.Server in a hosted service. A hosted service is basically a piece of code that is run by the host when the host itself is started and the same for when it is stopped. The following code implement a GrpcHostedService to override IHostedService interface:
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Hosting;
namespace Grpc.Host
{
public class GrpcHostedService: IHostedService
{
private Server _server;
public GrpcHostedService(Server server)
{
_server = server;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_server.Start();
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken) => await _server.ShutdownAsync();
}
}
In the Program.cs, use HostBuilder API to start building our grpc host and setting it up:
public class Program
{
public static async Task Main(string[] args)
{
var hostBuilder = new HostBuilder()
// Add configuration, logging, ...
.ConfigureServices((hostContext, services) =>
{
// Better to use Dependency Injection for GreeterImpl
Server server = new Server
{
Services = {Greeter.BindService(new GreeterImpl())},
Ports = {new ServerPort("localhost", 5000, ServerCredentials.Insecure)}
};
services.AddSingleton<Server>(server);
services.AddSingleton<IHostedService, GrpcHostedService>();
});
await hostBuilder.RunConsoleAsync();
}
}
By doing this, the generic host will automatically run StartAsync on our hosted service, which in turn will call StartAsync on the Server instance, essentially start the gRPC server.
When we shut down the host with Control-C, the generic host will automatically call StopAsync on our hosted service, which again will call StopAsync on the Server instance which will do some clean up.
For other configuration in HostBuilder, you can see this blog.
I'm going to add one more option.
With dot net core, you can run this as a Linux Daemon now.
Currently gRPC doesn't support integration with ASP.Net/IIS. You would need to host the server in a console or as a Windows service.
Likely you would want this to be a Windows service to make it easier to keep the server running across reboots or crashes. If you want to easily turn your console application into a Windows service I would recommend using the excellent TopShelf Nuget.
Updating the service can be done as you would a console app.
Stop the Windows service. net stop <service-name}>
Copy the updated assemblies.
Start the Windowsservice net start <service-name>
My company (Shortbar) is building the application server for a hotel management system called HOLMS on gRPC. Our setup is as follows:
HOLMS.Application is a .NET class library (assembly) that does the actual work of the server
HOLMS.Application.ConsoleRunner is a C# console application that hosts HOLMS.Application. The console runner is used by (1) developers for convenience (mentioned in the question) as well as (2) production scenarios running inside a Docker container, where the container runtime (e.g. Amazon ECS) implements job control/scaling. It follows "12 factor app" guidelines, including running itself as a single, standalone, stateless process, fast startup/shutdown, and environment-variable config injection. The system logs to stdout which gets drained however stdout is drained in the prod environment (e.g. Sumo, logstash, etc). This is how our SaaS multi-tenant solution will go into production.
HOLMS.Application.ServiceRunner packages HOLMS.Application into a Windows service, for more traditional, on-premise situations where a customer's IT group will run the service themselves. This package uses the Windows registry for configuration and relies on Windows service job control for startup/shutdown/restarts. It logs to the Windows Event Log.
The ConsoleRunner and ServiceRunner each are only about 200 lines of code; for the most part, they just wrap the Application package, and call into it.
Hope this helps.

Host Web API as Windows Service using OWIN

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

How to Recycle a Self-Hosted WCF Service

I'm hosting a WCF Service in an Azure Woker Role much like this.
I'd like to be able to "recycle" the WCF Service Host on a regular interval. The problem is, I assume the service is running it's own App Domain, and I have no way to poll it for any events, nor can I share any common data between the Worker Role and the WCF Service.
For reference, here's the minimum code to host:
public override void Run()
{
using(var host = new ServiceHost(typeof(MyService))
{
// Configure host here...
host.Open
while(true)
{
Sleep(1000);
}
}
}
I'd like to "restart" the host somehow every 24 hours, but i'm not sure how/what to hook into to accomplish that.
The WCF service is running in-proc to your worker role right (ie. everything is running in WaWorkerHost.exe)? In that case you can either call RoleEnvironment.RequestRecycle, or just let the Run() method exit. Either way will cause WaWorkerHost.exe to gracefully shut down, and then the Azure guest agent will automatically restart everything.

Invoke a method in a Console application that is currently running.

I have a console application I wrote in C# that polls multiple devices, collects some data, and stores the information on a database. The application runs on our web server, and I was wondering how to invoke a method call from the command console (so I can exec a command from php that will be read by the console application, a shell command would work as well).
Anyone got any ideas? I've been floating around 'the google' and have found nothing that will supply my current needs.
Also, i'm not adverse to making changes to the console application if an overhaul is needed there. Please, if your answer is COM Interop, provide a GOOD example of how I would build and call this from PHP / Apache2.
You could create a Service like this:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/magic")]
void MagicMethod();
}
And a service implementation like this:
public class Service : IService
{
public void MagicMethod()
{
//magic here
}
}
to start a HTTP Service it should look like this:
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://127.0.0.1:8080"))
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
ServiceDebugBehavior stp = host.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
host.Open();
This will start a HTTP server on port 8080.
Then you can make a HTTP Get request to 'http://localhost:8080/magic' to invoke the method call.
Perhaps your console app can poll a directory for a certain file, and react to that.
Then your php app will only need to create that file and the console app should notice it and do whatever you want. I'm not really sure what you want to do.
I would look at using WCF. Your C# application would host a WCF service and then your PHP application could call into it, I believe PHP5 comes with a SOAP library which should make this relatively simple. Any other application you write will be able to easily call in to, especially if they're written in .NET.
I imagine COM would work fine, but I like the scalability of WCF, as if you have to end up moving these applications onto separate servers then you wouldn't need to change anything besides a URL.
There's a good example on this blog. If you're using PHP5 it should be a doddle, if you're having to use 4 then it will still be possible but will require just a bit more legwork.

How to host a RESTful C# webservice and test it

I need to create a RESTful webservice in C#. This is what I have right now:
namespace WebService
{
[ServiceContract]
public interface IService
{
[OperationContract(Name="Add")]
[WebGet(UriTemplate = "/")]
int Add();
}
public class Service:IService
{
public int Add()
{
// do some calculations and return result
return res;
}
}
}
Now, my question is How do i host this service at a location say (http://localhost/TestService) and how can i test the service in console application client?
To host the service, WebServiceHost would be a better option. Check out this article http://msdn.microsoft.com/en-us/library/system.servicemodel.web.webservicehost.aspx on its usage.
To test the service in a console application, you can use the HTTPWebRequest/HttpWebResponse classes to make the requests/decipher response. Check out this for the usage http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
For simple requests you could also use fiddler (in the prototyping phase of your project perhaps)
See this answer here to get you started.
All you have to do is run this as a console app having the console run this code in Main method/
RestExample exampleService = new RestExample();
host = new ServiceHost(exampleService);
host.Open();
Be sure to throw in a
Console.WriteLine("Press any key to exit . . . .");
Console.ReadKey(true);
host.Close();
This way your service stays open until you are done.
Keep in mind you don't have to start it up as a rest service to test the implementation of the interface. In the RestExample, you can write unit test against that class to make sure each method performs as designed. Starting it as a console is an option, but to me is more integration testing rather than unit testing.

Categories