У меня есть пользовательское приложение интранет, которое не имеет никаких требований совместимости. Мы программно создаем канал NetTcp в дуплексном режиме для передачи сообщений. Мы хотели изменить кодирование сообщения, но не смогли выяснить, как заставить это произойти.
Подход, который мы проявили (неудачно), должен был расширить NetTcpBinding в новый класс под названием LeanTcpBinding следующим образом:
internal class LeanTcpBinding : NetTcpBinding
{
private static readonly ILog _log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection bindingElementCollection = base.CreateBindingElements();
BindingElement encodingElement = bindingElementCollection.FirstOrDefault(
bindingElement => bindingElement is BinaryMessageEncodingBindingElement);
if (encodingElement != null)
{
int index = bindingElementCollection.IndexOf(encodingElement);
bindingElementCollection.RemoveAt(index);
bindingElementCollection.Insert(index, new LeanBinaryMessageEncodingBindingElement());
}
else
{
_log.Warn("Encoding not found");
}
return bindingElementCollection;
}
}
Очевидно, мы пытаемся заменить BinaryMessageEncodingBindingElement по умолчанию нашим собственным. Только для получения запущенного использования LeanBinaryMessageEncodingBindingElement является расширением BinaryMessageEncodingBindingElement следующим образом:
internal class LeanBinaryMessageEncodingBindingElement : MessageEncodingBindingElement
{
private readonly BinaryMessageEncodingBindingElement _bindingElement;
///
/// Initializes a new instance of the class.
///
public LeanBinaryMessageEncodingBindingElement()
{
_bindingElement = new BinaryMessageEncodingBindingElement();
}
///
/// Initializes a new instance of the class.
///
/// The binding element.
public LeanBinaryMessageEncodingBindingElement(BinaryMessageEncodingBindingElement bindingElement)
{
_bindingElement = bindingElement;
}
///
/// Initializes a new instance of the class.
///
/// The element to be cloned.
/// The binding element.
public LeanBinaryMessageEncodingBindingElement(MessageEncodingBindingElement elementToBeCloned, BinaryMessageEncodingBindingElement bindingElement)
: base(elementToBeCloned)
{
_bindingElement = bindingElement;
}
///
/// When overridden in a derived class, returns a copy of the binding element object.
///
///
/// A object that is a deep clone of the original.
///
public override BindingElement Clone()
{
return new LeanBinaryMessageEncodingBindingElement(
(BinaryMessageEncodingBindingElement)_bindingElement.Clone());
}
///
/// When overridden in a derived class, creates a factory for producing message encoders.
///
///
/// The used to produce message encoders.
///
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new LeanBinaryMessageEncoderFactory(_bindingElement.CreateMessageEncoderFactory());
}
///
/// When overridden in a derived class, gets or sets the message version that can be handled by the message encoders produced by the message encoder factory.
///
///
/// The used by the encoders produced by the message encoder factory.
///
public override MessageVersion MessageVersion
{
get { return _bindingElement.MessageVersion; }
set { _bindingElement.MessageVersion = value; }
}
}
Когда я пытаюсь использовать привязку, она делает точно, что я думаю, что она должна сделать..., она заменяет BinaryMessageEncodingBindingElement. Однако я никогда не получаю вызовов к LeanBinaryMessageEncodingBindingElement. CreateMessageEncoderFactory (), даже при том, что сообщениями обмениваются через канал.
У кого-либо есть какие-либо предложения о том, как сделать это правильно?
Кенни Вульф уточнил, чего не хватает, и это задокументировано в записи блога ниже.
Для нетерпеливых проблема в том, что по умолчанию элемент MessageEncoderBindingElement не добавляется к параметрам привязки контекста. В результате, когда транспорт позже отправится на поиски MessageEncoderBindingElement, он не сможет найти тот элемент, который я (или вы) создал, и у него будет "молчаливый" сбой, который я заметил в своей оригинальной заметке.
К сожалению, вам придется переопределить все методы CanBuildXXX и BuildXXX следующим образом, чтобы убедиться, что вы добавляете элемент привязки к параметрам привязки контекста.
public override bool CanBuildChannelFactory(BindingContext context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelFactory();
}
public override bool CanBuildChannelListener(BindingContext context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelListener();
}
public override IChannelFactory BuildChannelFactory(BindingContext context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
context.BindingParameters.Add(this);
return context.BuildInnerChannelFactory();
}
public override IChannelListener BuildChannelListener(BindingContext context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
context.BindingParameters.Add(this);
return context.BuildInnerChannelListener();
}
Попробовали ли вы создать пользовательскую привязку вместо нее из имеющейся конфигурации NetTcpBinding? Что-то вроде этого:
NetTcpBinding binding = new NetTcpBinding(); // get binding from somewhere
var elements = binding.CreateBindingElements();
BindingElementCollection newElements = new BindingElementCollection();
foreach ( var e in elements ) {
if ( e is MessageEncodingBindingElement ) {
newElements.Add(new MyMessageEncodingBindingElement());
} else {
newElements.Add(e);
}
}
CustomBinding cb = new CustomBinding(newElements);