【问题标题】:Send binary message in MSMQ在 MSMQ 中发送二进制消息
【发布时间】:2023-03-26 05:37:01
【问题描述】:

在 .NET 服务中,我想在 MSMQ 消息中发送流的内容。我从 WCF 收到一个 Stream 对象(可以是图像、.doc 文件或其他任何东西),我只想将内容放在 MSMQ 中。我尝试将 System.Messaging.Message.BodyStream 属性设置为流对象,但在尝试发送消息时收到“方法不支持”错误。

有没有人有关于如何做到这一点的示例或教程?

我正在寻找这样的东西:

消息合约:

    <MessageContract()> _
   Class UploadStreamMessage
        <MessageHeader()> _
        Public guidCaller As Guid
        <MessageBodyMember()> _
        Public data As Stream
    End Class

然后是WriteToMSMQ方法实现:

   <OperationBehavior(TransactionScopeRequired:=True, Impersonation:=ImpersonationOption.Required)> _
   Public Sub WriteToMSMQ (ByVal stream As IServiceMSMQ.UploadStreamMessage) Implements IServiceMSMQ.WriteToMSMQ 

Using queue As New MessageQueue(NOM_QUEUE)

    Dim msmqMessage As New Message
    msmqMessage = New System.Messaging.Message()
    msmqMessage.Body = stream.data
    queue.Send(msmqMessage, transaction)
    stream.data.Close()

End Using

谢谢!

【问题讨论】:

  • 这是个坏主意。除了 MSMQ 消息有 4MB 的硬大小限制之外,消息队列并不是为这种事情设计的。您应该将数据存储在一个中心位置,并在消息中传递对它的引用。

标签: .net wcf binary stream msmq


【解决方案1】:

这是我使用的电子邮件队列的示例...我认为您需要添加格式化程序。

这里是 DTO:

[Serializable]
public class EmailOut
{
  private readonly string _fromEmail;
  private readonly string _toEmail;
  private readonly string _subject;
  private readonly string _body;
  private readonly string _cc;
  private readonly IList<EmailOutAttachment> _emailOutAttachments;


  public EmailOut(string fromEmail, string toEmail, string subject, string body, string cc, IList<EmailOutAttachment> emailOutAttachments)
{
  _fromEmail = fromEmail;
  _cc = cc;
  _emailOutAttachments = emailOutAttachments;
  _toEmail = toEmail;
  _subject = subject;
  _body = body;
}

public string FromEmail
{
  get { return _fromEmail; }
}

public string ToEmail
{
  get { return _toEmail; }
}

public string Subject
{
  get { return _subject; }
}

public string Body
{
  get { return _body; }
}

public string Cc
{
  get { return _cc; }
}

public IList<EmailOutAttachment> EmailOutAttachments
{
  get { return _emailOutAttachments; }
}

public override string ToString()
{
  return string.Format("FromEmail: {0}, ToEmail: {1}, Subject: {2}, Body: {3}, Cc: {4}", _fromEmail, _toEmail, _subject, _body, _cc);
}
}

[Serializable]
public class EmailOutAttachment
{
private readonly string _name;
private readonly byte[] _bytes;
private readonly int _size;
//Null ok for emailer
private readonly string _mimeEncodingType;

/// <summary>
/// Null ok for mime type.
/// </summary>
/// <param name="name"></param>
/// <param name="bytes"></param>
/// <param name="size"></param>
/// <param name="mimeEncodingType">Null ok for mime type.</param>
public EmailOutAttachment( string name, byte[] bytes, int size, string mimeEncodingType)
{
  _bytes = bytes;
  _name = name;
  _size = size;
  _mimeEncodingType = mimeEncodingType;
}

public byte[] Bytes
{
  get { return _bytes; }
}

public int Size
{
  get { return _size; }
}

public string MimeEncodingType
{
  get { return _mimeEncodingType; }
}

public string Name
{
  get { return _name; }
}

}

这是您需要的扩展。

public static Byte[] GetBytes(this Stream input)
{
  if (null == input || 0 == input.Length)
    return new Byte[0];

  byte[] bytes = new byte[input.Length];
  int numBytesToRead = (int)input.Length;
  int numBytesRead = 0;
  while (numBytesToRead > 0)
  {
    // Read may return anything from 0 to numBytesToRead.
    int n = input.Read(bytes, numBytesRead, numBytesToRead);

    // Break when the end of the file is reached.
    if (n == 0)
      break;

    numBytesRead += n;
    numBytesToRead -= n;
  }
  return bytes;
}

这是发送机制:

  using (Message msg = new Message())
  {
    msg.Body = new EmailOut(from, to, title, body, cc, attachments);
    msg.Recoverable = true;
    msg.Formatter = new BinaryMessageFormatter();
    string queuePath = config.MsmqEmailBox;
    //if this queue doesn't exist we will create it
    //if (!MessageQueue.Exists(queuePath))
    //  MessageQueue.Create(queuePath);
    using (MessageQueue messageQueue = new MessageQueue(queuePath))
    {
      messageQueue.Formatter = new BinaryMessageFormatter();
      messageQueue.Send(msg);
    }
  }

这是它的接收端...

  using (var messageQueue = new MessageQueue(_config.MsmqEmailBox))
    try
    {
      _log.Debug("Retrieving queue");
      messageQueue.Formatter = new BinaryMessageFormatter();
      messageQueue.MessageReadPropertyFilter.SetAll();
      List<Message> allMessages = messageQueue.GetAllMessages().ToList();
      if(0 < allMessages.Count)
        SendEmailNoMsmq.Instance.SendDotNetEmail(_config.DevRecipient,string.Format("Sending queued messages, Count: {0}, Time: {1}",allMessages.Count,DateTime.Now),"MSMQ MAIL SEND", _config, _log);

      foreach (Message message in allMessages)
      {
        EmailOut msg = (EmailOut)message.Body;
        _log.Info(string.Format("Sending email id:{0} to:{1} ", message.Id, msg.ToEmail));
        SendEmailNoMsmq.Instance.SendDotNetEmail(msg, _config, _log);
        messageQueue.ReceiveById(message.Id);
      }
    }
    catch (Exception ex)
    {
      _log.Error("Error ex:" + ex);
      throw;
    }
}

【讨论】:

  • EmailOut 只是一个标记为 Serializable 的普通类。重新阅读您的问题后,我意识到您正在尝试在 WCF 中执行此操作,这与此示例不同,我不知道该答案。但这就是你“手动”的方式。
  • 谢谢!很好的例子。我认为这会很有帮助。
  • 我需要检查的是你的“附件”变量类型,我假设它是二进制数据。正是我要发送的内容。
  • 好的,我添加了整个小猫卡布德尔。
  • 谢谢:-) 那么下面确实是一个字节数组。
【解决方案2】:

MSMQ 不支持流式传输,因为它显式地基于消息并且松耦合。您应该将合同字段声明为byte[] 并在那里收集数据。

【讨论】:

  • +1。此外,传入的流应该被完全读取并转换为这个字节数组。 (只是为了让答案更完整)。
  • 我确实尝试过使用字节数组,并且能够将其发送到队列中。但是,之后我无法正确检索它......我会再试一次。
猜你喜欢
  • 1970-01-01
  • 2010-10-16
  • 2010-12-27
  • 1970-01-01
  • 2020-01-26
  • 2013-06-24
  • 2012-02-12
  • 2023-03-07
  • 1970-01-01
相关资源
最近更新 更多