メッセージキューエラー:メッセージを読み取ることができるフォーマッタが見つかりません

StackOverflow https://stackoverflow.com/questions/655276

  •  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);

その行がないと、あらゆる種類のアクセスできないエラーを受け取り、コンピューター管理画面からキューを参照することさえできませんでした。ちなみにそれがあなたに起こり、あなたがあなただけにアクセスできないキューを殺す方法を疑問に思っているなら:

  1. サービスの停止<!> quot; Message Queueing <!> quot;
  2. 後藤<!> quot; C:\ Windows \ System32 \ msmq \ storage \ lqs <!> quot;
  3. 各ファイルをメモ帳で開き、キュー名を探します(最も変更されたファイルである可能性が高い)
  4. そのファイルを削除してメッセージングサービスを再起動します

キューメッセージアイテムの基本クラスを作成し、[シリアル化可能]としてマークします。 アプリケーションのロード時に、次のようなものを使用して、すべてのメッセージタイプのリストをキャッシュします。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top