So, I will start this with a disclaimer: the following is merely sample code which shows a hypothetical “how it could be done”, and bypasses much of the internal sanity checks, validations, etc. that the full .NET SDK (C Wrapper) provides. Also, because it involves reflection to obtain private fields, could break any time you upgrade the .NET SDK package.
With that out of the way, here is a very bare-bones helper class which allows a “mostly C#” application to directly invoke the C send multiple API. Note: as we discussed, it assumes that individual IMessage instances are going to be re-used. (I would be curious to hear how you are handling ITopic > references as well.)
class MessageBatchSender: IDisposable
{
IntPtr sessionPtr;
IntPtr messagePtrs;
public MessageBatchSender(ISession session)
{
this.Messages = Enumerable.Repeat(null, 50).Select(_ => session.CreateMessage()).ToArray();
this.messagePtrs = this.Messages.Select(GetPrivateIntPtr).ToArray();
this.Session = session;
this.sessionPtr = this.GetPrivateIntPtr(session);
}
public IMessage Messages { get; }
public ISession Session { get; }
public ReturnCode SendMessages(uint length, out uint messagesSent)
{
return SolClientSessionSendMultipleMsg(this.sessionPtr, this.messagePtrs, length, out messagesSent);
}
// This method could stop working if an SDK upgrade changes the internal implementation
private IntPtr GetPrivateIntPtr(IMessage message)
{
var messageImplType = message.GetType();
var messagePtrField = messageImplType.GetField(“m_opaqueMessagePtr”, BindingFlags.NonPublic | BindingFlags.Instance);
return (IntPtr)messagePtrField.GetValue(message);
}
// This method could stop working if an SDK upgrade changes the internal implementation
private IntPtr GetPrivateIntPtr(ISession session)
{
var sessionImplType = session.GetType();
var sessionPtrField = sessionImplType.GetField(“m_opaque”, BindingFlags.NonPublic | BindingFlags.Instance);
return (IntPtr)sessionPtrField.GetValue(session);
}
p ublic > void Dispose()
{
//TODO: Dispose all those IMessage instances!
}
[DllImport(“libsolclient”, CharSet = CharSet.Ansi, EntryPoint = “solClient_session_sendMultipleMsg”, ExactSpelling = true)]
[SuppressUnmanagedCodeSecurity]
static extern ReturnCode SolClientSessionSendMultipleMsg(IntPtr opaqueSession, [MarshalAs(UnmanagedType.LPArray)] IntPtr opaqueMessages, uint msgArrayLength, out uint numMsgsSent);
}
And it can be used in this manner:
// Create context and session instances
using (var context = ContextFactory.Instance.CreateContext(contextProperties, null))
using (var session = context.CreateSession(sessionProperties, null, null))
{
// Connect to the Solace messaging router
Console.WriteLine($“Connecting as {username}@{vpnname} on {host}…”);
var connectResult = session.Connect();
if (connectResult == ReturnCode.SOLCLIENT_OK)
{
Console.WriteLine(“Session successfully connected.”);
// Create a topic and subscribe to it
using (var publisher = new Helpers.MessageBatchSender(session))
using (var topic = ContextFactory.Instance.CreateTopic(“tutorial/topic”))
{
// This example assumes all messages have the same topic
publisher.Messages[0].Destination = topic;
publisher.Messages[0].BinaryAttachment = Encoding.UTF8.GetBytes(“Msg 1”);
publisher.Messages[1].Destination = topic;
publisher.Messages[1].BinaryAttachment = Encoding.UTF8.GetBytes(“Msg 2”);
publisher.Messages[2].Destination = topic;
publisher.Messages[2].BinaryAttachment = Encoding.UTF8.GetBytes(“Msg 3”);
publisher.Messages[3].Destination = topic;
publisher.Messages[3].BinaryAttachment = Encoding.UTF8.GetBytes(“Msg 4”);
Console.WriteLine(“Publishing messages…”);
var sendResult = publisher.SendMessages(4, out var messagesSent);
if (sendResult == ReturnCode.SOLCLIENT_OK)
{
Console.WriteLine($“Done. Sent {messagesSent} messages.”);
}
else
{
Console.WriteLine($“Publishing failed, return code: {sendResult}”);
}
}
}
else
{
Console.WriteLine($“Error connecting, return code: {connectResult}”);
}
}