Skip to content

Instantly share code, notes, and snippets.

@kevinhillinger
Last active February 19, 2019 15:04
Show Gist options
  • Save kevinhillinger/0ddbf242725127d96f08f647afb5c6b2 to your computer and use it in GitHub Desktop.
Save kevinhillinger/0ddbf242725127d96f08f647afb5c6b2 to your computer and use it in GitHub Desktop.
Service Fabric - UDP Service
// sourced: https://stackoverflow.com/questions/35902685/service-fabric-stateless-server-custom-udp-listener
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="UdpServicePkg"
Version="1.0.0"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="UdpServiceType" />
</ServiceTypes>
<!-- Code package is your service executable. -->
<CodePackage Name="Code" Version="1.0.0">
<EntryPoint>
<ExeHost>
<Program>UdpService.exe</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directoy under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="1.0.0" />
<Resources>
<Endpoints>
<!-- This endpoint is used by the communication listener to obtain the port on which to
listen. Please note that if your service is partitioned, this port is shared with
replicas of different partitions that are placed in your code. -->
<Endpoint Name="ServiceEndpoint" Port="5555" />
</Endpoints>
</Resources>
</ServiceManifest>
// sourced: https://stackoverflow.com/questions/35902685/service-fabric-stateless-server-custom-udp-listener
using System;
using System.Diagnostics;
using System.Fabric;
using System.Fabric.Description;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
namespace UdpService
{
public class UdpCommunicationListener : ICommunicationListener, IDisposable
{
private readonly CancellationTokenSource processRequestsCancellation = new CancellationTokenSource();
public int Port { get; set; }
private UdpClient server;
/// <summary>
/// Stops the Server Ungracefully
/// </summary>
public void Abort()
{
this.StopWebServer();
}
/// <summary>
/// Stops the Server Gracefully
/// </summary>
/// <param name="cancellationToken">Cancellation Token</param>
/// <returns>Task for Asynchron usage</returns>
public Task CloseAsync(CancellationToken cancellationToken)
{
this.StopWebServer();
return Task.FromResult(true);
}
/// <summary>
/// Free Resources
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Initializes Configuration
/// </summary>
/// <param name="context">Code Package Activation Context</param>
public void Initialize(ICodePackageActivationContext context)
{
EndpointResourceDescription serviceEndpoint = context.GetEndpoint("ServiceEndpoint");
this.Port = serviceEndpoint.Port;
}
/// <summary>
/// Starts the Server
/// </summary>
/// <param name="cancellationToken">Cancellation Token</param>
/// <returns>Task for Asynchron usage</returns>
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
try
{
this.server = new UdpClient(this.Port);
}
catch (Exception ex)
{
}
ThreadPool.QueueUserWorkItem((state) =>
{
this.MessageHandling(this.processRequestsCancellation.Token);
});
return Task.FromResult("udp://" + FabricRuntime.GetNodeContext().IPAddressOrFQDN + ":" + this.Port);
}
protected void MessageHandling(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, this.Port);
byte[] receivedBytes = this.server.Receive(ref ipEndPoint);
this.server.Send(receivedBytes, receivedBytes.Length, ipEndPoint);
Debug.WriteLine("Received bytes: " + receivedBytes.Length.ToString());
}
}
/// <summary>
/// Receives the specified endpoint.
/// </summary>
/// <param name="endpoint">The endpoint.</param>
/// <returns></returns>
public Task<byte[]> Receive(ref IPEndPoint endpoint)
{
return Task.FromResult(this.server.Receive(ref endpoint));
}
/// <summary>
/// Free Resources and Stop Server
/// </summary>
/// <param name="disposing">Disposing .NET Resources?</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (this.server != null)
{
try
{
this.server.Close();
this.server = null;
}
catch (Exception ex)
{
ServiceEventSource.Current.Message(ex.Message);
}
}
}
}
/// <summary>
/// Stops Server and Free Handles
/// </summary>
private void StopWebServer()
{
this.processRequestsCancellation.Cancel();
this.Dispose();
}
}
}
// sourced: https://stackoverflow.com/questions/35902685/service-fabric-stateless-server-custom-udp-listener
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Fabric;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
namespace UdpService
{
/// <summary>
/// An instance of this class is created for each service instance by the Service Fabric runtime.
/// </summary>
internal sealed class UdpService : StatelessService
{
private UdpCommunicationListener listener;
public UdpService(StatelessServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(initParams =>
{
this.listener = new UdpCommunicationListener();
this.listener.Initialize(initParams.CodePackageActivationContext);
return this.listener;
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment