#wcf #binary-serialization #msmqintegrationbinding
#wcf #двоичная сериализация #msmqintegrationbinding
Вопрос:
У меня есть служба Windows WCF, которая извлекает сообщения MSMQ. Похоже, что SubmitPurchaseOrderInMessage не вызывается, и я не вижу никаких сообщений в очереди. Код показан ниже.
Класс WCF:
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
[ServiceKnownType(typeof(MyOrder))]
public void SubmitPurchaseOrderInMessage(MsmqMessage<MyOrder> ordermsg)
{
MyOrder po = (MyOrder)ordermsg.Body;
Console.WriteLine("Processing id:{0}, name:{1} ", po.ID, po.Name);
}
public static void Main()
{
//init queue
if (!MessageQueue.Exists(Constants.QUEUE_PATH)) MessageQueue.Create(Constants.QUEUE_PATH, true);
//init wcf host via code
Uri baseUri = new Uri("http://localhost:7878/msmqsvc");
using (ServiceHost host = new ServiceHost(typeof(OrderProcessorService),baseUri))
{
//add metadata behavior
ServiceMetadataBehavior smb = new ServiceMetadataBehavior(){ HttpGetEnabled=true};
host.Description.Behaviors.Add(smb);
//add service endpoint
MsmqIntegrationBinding binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
binding.SerializationFormat = MsmqMessageSerializationFormat.Binary;
host.AddServiceEndpoint(typeof(ClassLib.IOrderProcessor), binding, "msmq.formatname:DIRECT=OS:" Constants.QUEUE_PATH);
host.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
host.Close();
}
}
}
Контракт интерфейса:
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[ServiceKnownType(typeof(MyOrder))]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true, Action = "*")]
void SubmitPurchaseOrderInMessage(MsmqMessage<MyOrder> msg);
}
Параметры массива могут быть любого динамического сериализуемого типа, который может быть передан клиентом. Я думаю, что проблема связана с этим параметром. Если я удалю этот параметр и атрибут serializable, а также привязку.SerializationFormat в клиенте, тогда все работает нормально.
Сериализуемый класс:
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[Serializable]
public class MyOrder
{
[DataMember]
public string ID;
[DataMember]
public string Name;
[DataMember]
public object[] Parameters;
}
[Serializable]
public class Transaction
{
public int Amount { get; set; }
}
Клиент :
class Program
{
static void Main(string[] args)
{
try
{
Run();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void Run()
{
MsmqIntegrationBinding binding = new MsmqIntegrationBinding();
binding.Security.Mode = MsmqIntegrationSecurityMode.None;
binding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None;
binding.Security.Transport.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None;
binding.SerializationFormat = MsmqMessageSerializationFormat.Binary;
EndpointAddress address = new EndpointAddress("msmq.formatname:DIRECT=OS:" Constants.QUEUE_PATH);
ChannelFactory<ClassLib.IOrderProcessor> channelFactory = new ChannelFactory<ClassLib.IOrderProcessor>(binding, address);
try
{
ClassLib.IOrderProcessor channel = channelFactory.CreateChannel();
MyOrder order = new MyOrder();
order.ID = DateTime.Now.Ticks.ToString();
order.Name = "Order_" order.ID;
order.Parameters = new object[] { new Transaction { Amount = 108 }, new Transaction { Amount = 100 } };
MsmqMessage<MyOrder> ordermsg = new MsmqMessage<MyOrder>(order);
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
channel.SubmitPurchaseOrderInMessage(ordermsg);
scope.Complete();
}
Console.WriteLine("Order has been submitted:{0}", ordermsg);
}
catch(Exception ex)
{
}
finally
{
channelFactory.Close();
}
}
}
Комментарии:
1. msdn.microsoft.com/en-us/library/ms733025 (v = против 110).aspx
Ответ №1:
Вот некоторые вещи, которые нужно проверить:
-
Проверьте отсутствие сообщений во временной исходящей очереди на стороне клиента. Если в этой очереди есть сообщения, это указывает на то, что сообщение не может быть передано по сети. Поскольку ваши очереди являются транзакционными, это может означать конфигурацию MSDTC (ссылка также поддерживает 2012).
-
Проверьте, нет ли сообщений в транзакционной очереди мертвых писем на стороне службы. Если есть, это указывает на проблему с доставкой сообщения в очередь обслуживания. Вероятно, проблема с разрешениями. Для учетной записи службы требуется получить сообщение и просмотреть сообщение в своей очереди, для учетной записи клиента требуется отправить сообщение, получить разрешения и получить свойства в очереди назначения.
-
Включите ведение журнала msmq в журнале событий Windows. Это регистрирует все связанные с MSMQ действия в поле. На стороне службы для успешной передачи вы должны увидеть в журнале 2 события: сообщение пришло по сети, и сообщение с идентификатором было помещено в очередь.
Комментарии:
1. Ошибка, которую я получил: «Не удается найти сборку ‘WCFClientApp'» Проблема решается (на данный момент) путем перемещения класса транзакции в библиотеку, где определен MyOrder. Но это не решает мою проблему, поскольку объекты в параметрах (поле выше) передаются от клиента (сборка WCFClientApp).
2. ДА. Но не могли бы вы, пожалуйста, дать некоторое представление о проблеме выше (о динамическом типе)
3. Почему вы передаете массив нетипизированных объектов? Это очень необычно.
4. клиент хочет сохранить на диск любые данные транзакции, которые ему не удается сохранить (он вызовет webservice для сохранения). Другое приложение получит это сообщение о сбое, попробуйте сохранить данные еще раз. Теперь на этот раз второе приложение создаст динамический прокси-сервер и вызовет метод с помощью отражения. Итак, задача состоит в том, как сохранить эти параметры (для отправки), поскольку это может быть любой объект, а также как получить эти параметры.