Xeeny
Framework For Building And Consuming Services In .Net Standard
Install / Use
/learn @MhAllan/XeenyREADME

Framework For Building And Consuming Cross Platform Services In .Net Standard.
Cross Platform, Duplex, Scalable, Configurable, and Extendable
Table Of Content
- What Is Xeeny
- Nuget
- Features
- Terminology
- Get Started
- Duplex and Callback
- Instance Lifetime
- Operations
- Managing The Connection
- Serialization
- Security
- Logging
- Transports
- Performance
- Extend Xeeny
- Samples
What is Xeeny
Xeeny is framework for building and consuming services on devices and servers that support .net standard.
With Xeeny you can host and consume services anywhere .net standard is able to work (e.g Xamarin android, Windows Server, ...). It is Cross Platform, Duplex, Multiple Transports, Asynchronous, Typed Proxies, Configurable, and Extendable
Nuget
Install-Package Xeeny
For extensions:
Install-Package Xeeny.Http
Install-Package Xeeny.Extentions.Loggers
Install-Package Xeeny.Serialization.JsonSerializer
Install-Package Xeeny.Serialization.ProtobufSerializer
Features
Current Features:
- Building and consuming services in .Net Standard
- Multiple Transports, You can mix transports
- Duplex connections
- Typed proxies
- Asynchronous, Scalable, and Lightweight
- Extendable, you can have your custom transport (e.g Behind bluetooth), custom protocol, and custom serialization
Comming:
- Integrating AspNetCore (Logger is done, next is DI, Kestrel, and Middleware)
- Streaming
- UDP transport
- P2P Framework
Terminology
- Contract: A shared interface between the Service and Client
- Service Contract: The interface that is referenced by the client to call remotely, and actually implemented on the server
- Callback Contract: The interface that is referenced by the service to call remotely, and actually implemented on the client
- Operation: Any method in a Contract is called Operation
Get Started
- Define service contract (an interface) shared between your client and server
public interface IService
{
Task<string> Echo(string message);
}
Server Side
- Create the service that implements the contract, services without interfaces won't expose methods to clients
public class Service : IService
{
public Task<string> Echo(string message)
{
return Task.FromResult(message);
}
}
- Create
ServiceHostusingServiceHostBuilder<TService>where <TService> is the service implementation - Add Servers to the host using
AddXXXServermethods - Open the host
var tcpAddress = "tcp://myhost:9999/myservice";
var httpAddress = "http://myhost/myservice";
var host = new ServiceHostBuilder<Service>(InstanceMode.PerCall)
.AddTcpServer(tcpAddress)
.AddWebSocketServer(httpAddress);
await host.Open();
Client Side
- Create client connection connection using
ConnctionBuilder<T>
var tcpAddress = "tcp://myhost/myservice";
var client = await new ConnectionBuilder<IService>()
.WithTcpTransport(tcpAddress)
.CreateConnection();
- Once the connection is created it is connected and now you can call the service remotely
var msg = await client.Echo("Hellow World!");
Duplex and Callback
- First define a callback contract (an interface) shared between your service and client to handle the callback
public interface ICallback
{
Task OnCallback(string serverMessage);
}
- Callback contract methods must return void or Task as the server always invoke them as OneWay operations
Duplex Service
- In your service, optain the typed callback channel using
OperationContext.Current.GetCallback<T>
public Service : IService
{
public Task<string> Join(string name)
{
CallBackAfter(TimeSpan.FromSeconds(3));
return Task.FromResult("You joined");
}
async void CallBackAfter(TimeSpan delay)
{
var client = OperationContext.Current.GetCallback<ICallback>();
await Task.Delay((int)delay.TotalMilliseconds);
await client.OnCallBack("This is a server callback");
}
}
- Call
WithCallback<T>on the builder
var host = new ServiceHostBuilder<Service>(InstanceMode.Single)
.WithCallback<ICallback>()
.AddTcpServer(address)
.CreateHost();
await host.Open();
- For Duplex connections you will usually have your services PerConnection or Singleton *
Duplex Client
- Implement your callback contract in the client side
public class Callback : ICallback
{
public void OnServerUpdates(string msg)
{
Console.WriteLine($"Received callback msg: {msg}");
}
}
- Use
DuplexConnectionBuilderto create the duplex client, note that it is generic class, the first generic argument is the service contract, while the other one is the callback implementation not the contract interface, so the builder knows what type to instantiate when the callback request is received.
var address = "tcp://myhost/myservice";
var client = await new DuplexConnectionBuilder<IService, Callback>(InstanceMode.Single)
.WithTcpTransport(address)
.CreateConnection();
await client.Join("My Name");
Instance Lifetime
Service Instance Lifetime
Xeeny defines three modes for creating service instances
- PerCall: A PerCall mode instructs the framework to create one instance of the service object for every client request, That is anytime any client invokes a method on the service a new instance is going to handle that request. Once the method is execute the instance is going to be collect by GC like any other out of scope objects.
- PerConnection: A PerConnection mode istructs the framework to create one instance of the service object for each client. That is every time a proxy is connected there is one instance for that client is created, This instance will last as long as the connection between the client and server is open. Once the connection is closed (Or dropped by the network) the instance is removed and becomes available for GC to collect.
- Single: A Singleton instance mode means that there is one instance of the service handles all requests from all clients, This is the typical chat room example. The instance will be removed when the host is closed.
You define the service instance mode using the InstanceMode enum when creating the ServiceHost
var host = new ServiceHostBuilder<Service>(InstanceMode.PerCall)
...
.CreateHost();
await host.Open();
Callback Instance Lifetime
When you create duplex connection you pass the callback type and InstanceMode to the DuplexConnectionBuilder. The InstanceMode acts the same way it does for the service when creating ServiceHost
- PerCall: Every callback from the service will be handled in new instance, the instance is subject to collection by GC once the callback method is done.
- PerConnection: All callbacks from the service to a connection created by that builder will have one instance to handle them, all callbacks to another connection created by that builder will have another callback instance, these instances are subject to collection by GC when the connection is closed or dropped by the network
- Single: All callbacks from the service to any connection created by that builder will be handeled by one instance.
Initializing Created Instances
ServiceHostBuilderconstructor has one overload that takes instance of the service type, This allows you to create the instance and pass it to the builder, the result isInstanceMode.Singleusing the object you passed- Similar to
ServiceHostBuilder, theDuplextConnectionBuildertakes an instance of the callback type allowing you to create the singleton yourself - Instances that are
PerCallandPerConnectionare created by the framework, you still can initialize them after being constructed and before executing any method by listening to the events:ServiceHost<TService>.ServiceInstanceCreatedevent andDuplextConnectionBuilder<TContract, TCallback>.CallbackInstanceCreated - Once AspNetCore Dependency System (IServiceCollection and IServiceResolver) are used you will be able to have easy DI.
host.ServiceInstanceCreated += service =>
{
service.MyProperty = "Something";
}
...
var builder = new DuplexConnectionBuilder<IService, Callback>(InstanceMode.PerConnection)
.WithTcpTransport(tcpAddress);
builder.CallbackInstanceCreated += callback =>
{
callback...
}
var client = builder.CreateConnection();
Operations
- Two Way Operations: Methods by default are two way, even methods that return void or Task are two way methods. A two way method means that the method waits the service to finish executing the operation before it returns.
- One Way Operations: One way operations return when the server receives the m
Related Skills
node-connect
340.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.2kCommit, push, and open a PR
