Multiple Client binds to SMPP servers
The SmppClient represents a single session to the SMPP server. When you need to bind to multiple SMPP servers or when you need to establish several sessions to a SMPP server, you have to create several instances of SmppClient class and attach event handler methods to all instances.
public class SmppRouterSample
{
private readonly List<SmppClient> _sessions = new List<SmppClient>();
/// <summary>
/// The SMPP sessions
/// </summary>
public IReadOnlyList<SmppClient> Sessions => _sessions;
/// <summary>
/// Add new session with SMPP provider
/// </summary>
/// <param name="endPoint">The endpoint of the SMPP provider.</param>
/// <param name="systemId">The System ID for the Bind command.</param>
/// <param name="password">The Password for the Bind command.</param>
/// <param name="systemType">The type of ESME system</param>
public async Task AddSession(EndPoint endPoint, string systemId, string password, string systemType = null)
{
SmppClient client = new SmppClient();
client.ConnectionRecovery = true;
client.EnquireLinkInterval = TimeSpan.FromSeconds(30);
client.SystemType = systemType;
AttachEvents(client);
await client.RetryUntilConnectedAsync(endPoint, TimeSpan.FromSeconds(5));
BindResp resp = await client.BindAsync(systemId, password);
if (resp.Header.Status != CommandStatus.ESME_ROK)
{
throw new InvalidOperationException($"Cannot bind to {endPoint}. Bind Status: {resp.Header.Status} ");
}
_sessions.Add(client);
}
/// <summary>
/// Send SubmitSm PDU to the selected session
/// </summary>
/// <param name="submitSm">The SUBMIT_SM PDU</param>
/// <param name="sessionSelector">The function to select a SMPP session.</param>
/// <returns></returns>
public Task<SubmitSmResp> SubmitAsync(SubmitSm submitSm, Func<SmppClient,bool> sessionSelector)
{
SmppClient client = Sessions.FirstOrDefault(sessionSelector);
if (client == null)
{
throw new InvalidOperationException("The SMPP session is not found for the message");
}
return client.SubmitAsync(submitSm);
}
/// <summary>
/// Send SubmitSm PDU to the selected session
/// </summary>
/// <param name="builder">The SMS builder</param>
/// <param name="sessionSelector">The function to select a SMPP session.</param>
public Task<SubmitSmResp[]> SubmitAsync(IBuilder<SubmitSm> builder, Func<SmppClient, bool> sessionSelector)
{
SmppClient client = Sessions.FirstOrDefault(sessionSelector);
if (client == null)
{
throw new InvalidOperationException("The SMPP session is not found for the message");
}
return client.SubmitAsync(builder);
}
private void AttachEvents(SmppClient smppClient)
{
smppClient.evDeliverSm += OnDeliverSm;
smppClient.evDataSm += OnDataSm;
smppClient.evUnBind += OnUnbind;
}
private void DetachEvents(SmppClient smppClient)
{
smppClient.evDeliverSm -= OnDeliverSm;
smppClient.evDataSm -= OnDataSm;
smppClient.evUnBind -= OnUnbind;
}
private void OnDataSm(object sender, DataSm data)
{
SmppClient client = (SmppClient)sender;
Console.WriteLine($"DATA_SM received from the session {client.RemoteEndPoint}/{client.SystemID}");
}
private void OnDeliverSm(object sender, DeliverSm deliverSm)
{
SmppClient client = (SmppClient)sender;
if (deliverSm.MessageType == MessageTypes.SMSCDeliveryReceipt)
{
Console.WriteLine($"Delivery Receipt received from the session {client.RemoteEndPoint}/{client.SystemID}");
}
else
{
Console.WriteLine($"Incoming SMS received from the session {client.RemoteEndPoint}/{client.SystemID}");
}
}
private void OnUnbind(object sender, UnBind data)
{
SmppClient client = (SmppClient)sender;
Console.WriteLine($"Unbind the session {client.RemoteEndPoint}/{client.SystemID}");
DetachEvents(client);
_sessions.Remove(client);
}
}
The sample class can be used like this code:
SmppRouterSample router = new SmppRouterSample();
await router.AddSession(new DnsEndPoint("smpp.server.net", 7777), "test", "test");
SubmitSmResp[] resp = await router.SubmitAsync(SMS.ForSubmit().From("SERVICE").To("123456789").Text("my message"), c=>c.SystemID == "test");