Как динамически изменять URL-адрес в пользовательском поведении WCF
класс определяется следующим образом:
public class BizTalkRESTTransmitHandler : IClientMessageInspector
Я метод с этой подписью:
public object BeforeSendRequest(ref Message request, IClientChannel channel)
поэтому я думаю, что мне нужно манипулировать объектом канала.
причина в том, что это используется в BizTalk 2010 SendPort для поддержки JSON. Я пробовал это до сих пор:
if (channel.RemoteAddress.Uri.AbsoluteUri == "http://api-stage2.mypartner.com/rest/events/2/"
|| channel.RemoteAddress.Uri.AbsoluteUri == "http://api.mypartner.com/rest/events/2/")
{
//TODO - "boxout" will become a variable obtained by parsing the message
Uri newUri = new Uri(channel.RemoteAddress.Uri.AbsoluteUri + "boxout");
channel.RemoteAddress.Uri = newUri;
}
выше дает ошибку компиляции: "система.Средство servicemodel.Адрес endpointaddress.Uri "не может быть назначен - он готов только" RemoteAddress, кажется, только для чтения.
я ссылался на эти вопросы, но они не используют объект канала. назначьте URL-адрес Url-адресу.AbsoluteUri in ASP.NET, и WCF изменить адрес конечной точки во время выполнения Но они, похоже, не имеют дело с объектом канала.
обновление 1: я попробовал следующий:
//try create new channel to change URL
WebHttpBinding myBinding = new WebHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress(newURL);
ChannelFactory<IClientChannel> myChannelFactory = new ChannelFactory<IClientChannel>(myBinding, myEndpoint); //Change to you WCF interface
IClientChannel myNewChannel = myChannelFactory.CreateChannel();
channel = myNewChannel; //replace the channel parm passed to us
но это дало эту ошибку: Система.InvalidOperationException: попытка получить тип контракта для IClientChannel, но этот тип не является ServiceContract, ни наследует ли он ServiceContract.
3 ответов
IClientMessageInspector
Не правильно манипулировать канал, вы должны использовать IEndpointBehavior
вместо:
С MSDN
реализует методы, которые могут использоваться для расширения поведения во время выполнения конечная точка в службе или клиентском приложении.
вот простой пример:
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
Uri endpointAddress = endpoint.Address.Uri;
string address = endpointAddress.ToString();
if (address == "http://api-stage2.mypartner.com/rest/events/2/"
|| address == "http://api.mypartner.com/rest/events/2/")
{
//TODO - "boxout" will become a variable obtained by parsing the message
Uri newUri = new Uri(address + "boxout");
ServiceHostBase host = endpointDispatcher.ChannelDispatcher.Host;
ChannelDispatcher newDispatcher = this.CreateChannelDispatcher(host, endpoint, newUri);
host.ChannelDispatchers.Add(newDispatcher);
}
}
здесь вы можете прочитать отличный пост Карлоса Фигейры о IEndpointBehavior
:
https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/04/wcf-extensibility-iendpointbehavior/
Другой альтернативой является реализация простой маршрутизации с WCF, вот ссылка с примером: маршрутизация url-адресов службы WCF REST на основе параметров запроса
надеюсь, что это помогает.
через интерфейс IEndpointBehavior, у вас будет доступ к ApplyClientBehavior метод, который предоставляет ServiceEndPoint экземпляра. Теперь вы можете изменить значение адреса, определив новый экземпляр EndpointAddress.
public class MyCustomEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, System.ServiceModel.Dispatcher.ClientRuntime behavior)
{
serviceEndpoint.Address = new System.ServiceModel.EndpointAddress("http://mynewaddress.com");
}
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint serviceEndpoint)
{
}
}
Я, возможно, немного опоздал, но мотыга это немного помогает.
недавно у меня была аналогичная цель (также связанная с biztalk), где мне нужно было изменить url-адрес на основе некоторого значения, отправленного в сообщении. Я попытался использовать метод ApplyDispatchBehavior, но он никогда не вызывался, а также я не мог видеть, как получить доступ к сообщению отсюда, поэтому я начал искать метод BeforeSendRequest (в классе Inspector).
вот что я придумал:
object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
var queryDictionary = HttpUtility.ParseQueryString(request.Headers.To.Query);
string parameterValue = queryDictionary[this.BehaviourConfiguration.QueryParameter];
//Only change parameter value if it exists
if (parameterValue != null)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
//Necessary in order to read the message without having WCF throwing and error saying
//the messas was already read
var reqAux = buffer.CreateMessage();
//For some reason the message comes in binary inside tags <Binary>MESSAGE</Binary>
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(reqAux.ToString().Replace("<Binary>", "").Replace("</Binary>", ""))))
{
ms.Position = 0;
string val = ExtractNodeValueByXPath(ms, this.BehaviourConfiguration.FieldXpath);
queryDictionary.Set(this.BehaviourConfiguration.QueryParameter, DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" +
this.BehaviourConfiguration.Message + (string.IsNullOrWhiteSpace(val) ? string.Empty : "_" + val) + ".xml");
UriBuilder ub = new UriBuilder(request.Headers.To);
ub.Query = queryDictionary.ToString();
request.Headers.To = ub.Uri;
}
}
return null;
}
Так, Я обнаружил это, возясь с request.Headers.To
Я мог бы изменить конечную точку.
у меня было несколько проблем с получением содержимого сообщения и большинства примеров в интернете (показывающих использование MessageBuffer.CreateNavigator или сообщение.GetBody, который всегда бросал expcetion я не мог обойти) не дал бы мне сообщение biztalk, а сообщение soap?... не уверен, но у него был заголовок узла, тело и внутри тела была строка base64, которая не была моей biztalk сообщение.
кроме того, как вы можете видеть в Convert.FromBase64String(reqAux.ToString().Replace("<Binary>", "").Replace("</Binary>", ""))
, Я должен был сделать это уродливое заменяет. Я не знаю, почему это происходит в base64, возможно, в какой-то конфигурации WCF? но, сделав это, я смогу найти свою ценность.
примечание: Я не полностью протестировал это, но до сих пор это работало для моих примеров.
кстати, любая идея о том, что я могу переключить свой MemoryStream, чтобы он стал более потоковым решением?