メッセージキューエラー:メッセージを読み取ることができるフォーマッタが見つかりません
-
19-08-2019 - |
質問
次のようにC#のメッセージキューにメッセージを書き込みます。
queue.Send(new Message("message"));
次のようにメッセージを読み込もうとしています:
Messages messages = queue.GetAllMessages();
foreach(Message m in messages)
{
String message = m.Body;
//do something with string
}
ただし、次のようなエラーメッセージが表示されます:<!> quot;このメッセージを読み取ることができるフォーマッタが見つかりません。<!> quot;
何が間違っているのですか?
解決
各メッセージにフォーマッターを追加することで問題を解決しました。キューにフォーマッターを追加しても機能しませんでした。
Messages messages = queue.GetAllMessages();
foreach(Message m in messages)
{
m.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
String message = m.Body;
//do something with string
}
他のヒント
または使用できます
message.Formatter =
new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) });
次のように、本文ではなくメッセージの本文ストリームを読むことができます。
StreamReader sr = new StreamReader(m.BodyStream);
string messageBody = "";
while (sr.Peek() >= 0)
{
messageBody += sr.ReadLine();
}
Message recoverableMessage = new Message();
recoverableMessage.Body = "Sample Recoverable Message";
recoverableMessage.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib" });
MessageQueue myQueue = new MessageQueue(@".\private$\teste");
キューもフォーマッタに設定する必要があります。
myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
シリアル化は、MessageクラスのBodyプロパティにアクセスするときにのみ行われるようです。メッセージに正しいFormatterを設定した後にBodyプロパティにアクセスする限り、正常に機能します。
各メッセージにフォーマッターを作成したくない場合は、キューにフォーマッターを設定し、各メッセージに(Bodyプロパティにアクセスする前に)キューのフォーマッターからFormatterプロパティを設定できます。
_queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData } );
var msg = _qeueu.Receive();
msg.Formatter = _queue.Formatter;
var myObject = (MyClass) msg.Body;
ここで誰もが解決策を提供するのに素晴らしい仕事をしており、自分でこの問題との戦いを終えたところで、自分の2cを投げ入れて、思いついた解決策をうまく見せたいと思いました。
まず、キューが作成されたら、そのようにアクセス許可を開くようにします(アプリケーションのコンテキストでキューのセキュリティを気にしません...これは計算による決定です):
queue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Set);
その行がないと、あらゆる種類のアクセスできないエラーを受け取り、コンピューター管理画面からキューを参照することさえできませんでした。ちなみにそれがあなたに起こり、あなたがあなただけにアクセスできないキューを殺す方法を疑問に思っているなら:
- サービスの停止<!> quot; Message Queueing <!> quot;
- 後藤<!> quot; C:\ Windows \ System32 \ msmq \ storage \ lqs <!> quot;
- 各ファイルをメモ帳で開き、キュー名を探します(最も変更されたファイルである可能性が高い)
- そのファイルを削除してメッセージングサービスを再起動します
キューメッセージアイテムの基本クラスを作成し、[シリアル化可能]としてマークします。 アプリケーションのロード時に、次のようなものを使用して、すべてのメッセージタイプのリストをキャッシュします。
var types = typeof(QueueItemBase).Assembly
.GetTypes()
.Where(t => typeof(QueueItemBase).IsAssignableFrom(t) && t.IsAbstract == false)
.ToArray();
...
// Create and cache a message formatter instance
_messageFormatter = new XmlMessageFormatter(types);
これで、メッセージの受信を開始する準備ができました。私の最初の本能はメッセージをポーリングすることでしたが、APIはそのように動作することを本当に好みません。そこで、バックグラウンドスレッドを作成し、キューでブロックメソッドReceiveを呼び出して、メッセージが利用可能になると戻ります。そこからメッセージのデコードは次のように簡単です:
var message = queue.Receive();
if (message == null)
continue;
// Tell the message about our formatter containing all our message types before we
// try and deserialise
message.Formatter = _messageFormatter;
var item = message.Body as QueueItemBase;
これで、適切に実装された、タイプセーフなMSMQ統合を取得するために必要なすべてのことになるはずです!
これにより、リモートマシンからプライベートキューを読み取ることができました。
MessageQueue queue = new MessageQueue(@"FormatName:Direct=OS:MACHINENAME\private$\MyQueueName", QueueAccessMode.Peek);
Message msg = queue.Peek();
StreamReader sr = new StreamReader(msg.BodyStream);
string messageBody = sr.ReadToEnd();
これは非常にうまく機能します:
static readonly XmlMessageFormatter f = new XmlMessageFormatter(new Type[] { typeof(String) });
private void Client()
{
var messageQueue = new MessageQueue(@".\Private$\SomeTestName");
foreach (Message message in messageQueue.GetAllMessages())
{
message.Formatter = f;
Console.WriteLine(message.Body);
}
messageQueue.Purge();
}
フォーマッタを追加すると問題が解決しました:
public void ReceiveAsync<T>(MqReceived<T> mqReceived)
{
try
{
receiveEventHandler = (source, args) =>
{
var queue = (MessageQueue)source;
using (Message msg = queue.EndPeek(args.AsyncResult))
{
XmlMessageFormatter formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
msg.Formatter = formatter;
queue.ReceiveById(msg.Id);
T tMsg = (T)msg.Body;
mqReceived(tMsg);
}
queue.BeginPeek();
};
messageQueu.PeekCompleted += receiveEventHandler;
messageQueu.BeginPeek();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
githubでサンプルコードとmsmqライブラリを確認できます。 https://github.com/beyazc/MsmqInt