如何从独立C#程序访问Windows服务中创建的对象?
Absolutely you can access those objects from a standalone C# app—you just need to use inter-process communication (IPC) since the Windows Service runs in its own isolated process space, so you can't directly reach into its memory. Let's walk through the most common, practical ways to do this:
This is a lightweight, reliable option built into Windows, perfect for simple one-way or two-way data transfer between local processes.
Service Side (Windows Service)
Set up a named pipe server to listen for client connections, then serialize your populated objects and send them over the pipe:
using System.IO; using System.IO.Pipes; using System.Text.Json; // Inside your Windows Service's logic public void StartPipeServer() { // Use a unique pipe name to avoid conflicts using var serverStream = new NamedPipeServerStream("MyServiceDataPipe", PipeDirection.InOut); serverStream.WaitForConnection(); // Assume 'populatedObject' is your object from the database var serializedData = JsonSerializer.Serialize(populatedObject); using var writer = new StreamWriter(serverStream); writer.WriteLine(serializedData); writer.Flush(); }
Client Side (Standalone C# App)
Connect to the existing pipe, read the serialized data, and deserialize it back into your object type:
using System.IO; using System.IO.Pipes; using System.Text.Json; // Inside your standalone app public YourObjectType GetDataFromService() { using var clientStream = new NamedPipeClientStream(".", "MyServiceDataPipe", PipeDirection.InOut); clientStream.Connect(5000); // Timeout after 5 seconds using var reader = new StreamReader(clientStream); var serializedData = reader.ReadLine(); return JsonSerializer.Deserialize<YourObjectType>(serializedData); }
Great if you need more advanced features like bidirectional calls, transaction support, or multiple communication protocols.
Step 1: Define a Service Contract
Create a shared interface that both the service and client will use:
using System.ServiceModel; [ServiceContract] public interface IDataRetrievalService { [OperationContract] YourObjectType GetLatestDatabaseObject(); }
Step 2: Host the Service in Your Windows Service
Implement the contract and host it using a named pipe binding (for local communication):
using System.ServiceModel; public class DataRetrievalService : IDataRetrievalService { public YourObjectType GetLatestDatabaseObject() { // Fetch and return your populated object from the database return YourDatabaseHelper.FetchAndPopulateObject(); } } // Inside your Windows Service's OnStart method var serviceHost = new ServiceHost(typeof(DataRetrievalService)); var pipeBinding = new NetNamedPipeBinding(); serviceHost.AddServiceEndpoint( typeof(IDataRetrievalService), pipeBinding, "net.pipe://localhost/MyDataService" ); serviceHost.Open();
Step 3: Call the Service from Your Standalone App
Add a service reference (or use channel factory) to call the service method directly:
using System.ServiceModel; public YourObjectType GetDataFromService() { var binding = new NetNamedPipeBinding(); var endpoint = new EndpointAddress("net.pipe://localhost/MyDataService"); using var factory = new ChannelFactory<IDataRetrievalService>(binding, endpoint); var serviceClient = factory.CreateChannel(); return serviceClient.GetLatestDatabaseObject(); }
Ideal if you want cross-platform support or need efficient serialization (uses Protobuf under the hood).
Step 1: Define a .proto File
Create a proto file to describe your data structure and service methods:
syntax = "proto3"; service DataService { rpc GetLatestObject (EmptyRequest) returns (YourObject); } message EmptyRequest {} message YourObject { string item_name = 1; int32 item_id = 2; // Add all your object properties here }
Step 2: Implement the gRPC Service in Your Windows Service
Generate C# code from the proto file, then implement the service:
using Grpc.Core; public class DataServiceImpl : DataService.DataServiceBase { public override Task<YourObject> GetLatestObject(EmptyRequest request, ServerCallContext context) { var dbObject = YourDatabaseHelper.FetchAndPopulateObject(); // Map your C# object to the gRPC-generated YourObject type return Task.FromResult(new YourObject { ItemName = dbObject.ItemName, ItemId = dbObject.ItemId }); } } // Inside your Windows Service's OnStart method var grpcServer = new Server { Services = { DataService.BindService(new DataServiceImpl()) }, Ports = { new ServerPort("localhost", 50051, ServerCredentials.Insecure) } }; grpcServer.Start();
Step 3: Call the gRPC Service from Your Standalone App
Generate client code from the proto file, then connect and call the service:
using Grpc.Net.Client; public YourObject GetDataFromService() { using var channel = GrpcChannel.ForAddress("http://localhost:50051"); var client = new DataService.DataServiceClient(channel); return client.GetLatestObject(new EmptyRequest()); }
- Serialization Consistency: Make sure both the service and client use the same serialization format (JSON, Protobuf, etc.) and have identical definitions of your object type.
- Permissions: Windows Services often run under restricted accounts—ensure your standalone app has permission to access the IPC endpoint (e.g., set appropriate security for named pipes).
- Thread Safety: If multiple clients connect at once, add concurrency handling in your service to avoid race conditions when accessing database data or shared objects.
内容的提问来源于stack exchange,提问作者user3046756

