Reputation: 1455
I've created a gRPC server in Visual Studio 2022 Community Preview by selecting the "ASP NET Core gRPC Service" template and .Net 6 Core. I intend to replace four existing .Net Framework Windows services who are all using WCF. So, I'm not looking for an alternative on how to create a Windows service.
The code generated from VS 2022 creates a program.cs (sans comments) that looks like:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run();
Every example I can find does not match this program.cs's contents. Additionally, all the examples include a generated startup.cs file. My project did not create a startup.cs file. All the examples show including the NuGet package Microsoft.Extensions.Hosting.WindowsServices and adding a UseWindowsServices parameter.
Host.CreateDefaultBuilder(args)
.UseWindowsService()
...
I don't have a Host or a CreateDefaultBuilder method. I tried adding the line:
builder.Host.UseWindowsService();
The program compiles and works perfectly when running in VS or the command line. I can see the ports with netstat:
netstat -an | find "6276"
C:\Users\Steve>netstat -an | find "6276"
TCP 127.0.0.1:6276 0.0.0.0:0 LISTENING
TCP [::1]:6276 [::]:0 LISTENING
But when I run it as a Windows Service, it is not listening on the identified port.
netstat -an | find "6276"
C:\Users\Steve>
I tried .Net 6.0 and .Net 7.0 preview 7, checking and unchecking "Do not use top level statements" on the later. No change in the behavior.
So, apparently Visual Studio changed the template output for gRPC and nobody has created a Windows Service with it yet... or at least has not shown how it was done.
Does anyone know how to take the latest gRPC template and create a Windows Service from it?
Upvotes: 5
Views: 6256
Reputation: 5522
Here is an example of the minimal application created by the default template with a few modifications (see code comments)
The project file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />
<!-- Install additional packages -->
<PackageReference Include="Grpc.AspNetCore.Server.Reflection" Version="2.40.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
</ItemGroup>
</Project>
The Program.cs
using GrpcService1.Services;
using Microsoft.Extensions.Hosting.WindowsServices;
// Use WebApplicationOptions to set the ContentRootPath
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService()
? AppContext.BaseDirectory
: default
});
// Set WindowsServiceLifetime
builder.Host.UseWindowsService();
builder.Services.AddGrpc();
// Add reflection services
builder.Services.AddGrpcReflection();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
// Map reflection endpoint
app.MapGrpcReflectionService();
app.Run();
Now open cmd in the project folder and execute
dotnet publish
The publish
command will produce the exe
file (I assume you are working on a Windows machine, otherwise how would you test Windows Service? 😁). On my machine the path to exe
is
"C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe"
Now open cmd as Administrator and run the following command
sc.exe create "GrpcService" binpath="C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe"
Open Services
and start the GrpcService
. Now install and run grpcui tool:
grpcui -plaintext localhost:5000
The grpcui tool will open the UI where you should be able to see the Greeter service
Notes:
WebApplication.CreateBuilder(new WebApplicationOptions())
because without that the service won't start. The Windows Event Viewer shows the error:Description: The process was terminated due to an unhandled exception. Exception Info: System.NotSupportedException: The content root changed from "C:\Windows\system32" to "C:\github\junk\GrpcService1\bin\Debug\net6.0\publish". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.
Found the solution here.
5000
. If you wish to use another port add --urls
argument when creating the servicesc.exe create "GrpcService" binpath="C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe --urls \"http://localhost:6276\""
Upvotes: 11