Обновление: я был на Build 2013, и Mark Simms посмотрел на это и подтвердил, что HTTP-запрос, выходящий из маршрутизатора, имеет «Тело» в запросе. Он чувствовал, что это вызвано тем, что Get прибыл на SB, а затем упакован для маршрутизации, затем пакет снова управляется как тип Messsage, прежде чем отправить его обратно. Между упаковкой и маршрутизацией свойства остаются в теле запроса, что нарушает протокол для «GET». Все это, однако, живет в рамках MS как в .NET, так и в ServiceBus. Поскольку тело является неизменным (по крайней мере, я не могу найти способ его изменить), единственным способом является дублирование запроса, а затем обновление исходного запроса на выходе.Нарушение протокола - глагол не разрешает тип содержимого
Это небольшая часть приложения маршрутизации, которое принимает HTTP-запрос GET/POST с конечной точки Azure ServiceBus, переносит его через ретрансляционный канал на мою локальную рабочую станцию, где я переписываю URL-адрес и отправляю его на мой местный веб-сервис.
Вот интерфейс - общий, так что он может принимать любой тип вызова на URL контроллер/действие
// The Router, and general concept of how to recieve from the SB and redirect was taken from
// Tony Sneed Blog - which he documented here: http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/
//
[ServiceContract(Namespace = "urn:Twiddler")]
public interface IRoutingService
{
[WebInvoke(UriTemplate = "")]
[OperationContract(AsyncPattern = true, Action = "*", ReplyAction = "*")]
IAsyncResult BeginProcessRequest(Message requestMessage, AsyncCallback asyncCallback, object asyncState);
Message EndProcessRequest(IAsyncResult asyncResult);
}
}
Вот код:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
AddressFilterMode = AddressFilterMode.Any, ValidateMustUnderstand = false)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RoutingService : IRoutingService, IDisposable
{
private IRoutingService _client;
/// <summary>
/// when a message is received from the SB, it arrives here as simply a message -
/// </summary>
/// <param name="requestMessage"></param>
/// <param name="asyncCallback"></param>
/// <param name="asyncState"></param>
/// <returns></returns>
public IAsyncResult BeginProcessRequest(Message requestMessage, AsyncCallback asyncCallback, object asyncState)
{
string RequestMessageAction = requestMessage.Headers.Action;
IAsyncResult asyncResult = null;
//if the full URI for the namespace does not match the one contructed in Twiddler, then pass it through - we have nothing to do with it!
if (requestMessage.Headers.To.AbsoluteUri.Contains(Utilities.ServiceFormBridge.NameSpaceName) && requestMessage.Headers.To.AbsoluteUri.Contains(Utilities.ServiceFormBridge.EndPointName) == false)
return asyncResult;
//as the service bus will accept anything in terms of controllers and actions, we only need alter the DestinationAddress.Authority (host and port)
var RewriteTheURL = requestMessage.Headers.To.AbsoluteUri.Replace(string.Format("http://{0}.servicebus.windows.net/{1}/", ServiceFormBridge.NameSpaceName, ServiceFormBridge.EndPointName), ServiceFormBridge.DestinationWebSite);
Uri DestinationAddress = new Uri(RewriteTheURL);
System.ServiceModel.ChannelFactory<IRoutingService> factory = null;
factory = new ChannelFactory<IRoutingService>(new WebHttpBinding(), DestinationAddress.AbsoluteUri);
WebHeaderCollection httpHeaders = WebOperationContext.Current.IncomingRequest.Headers;
httpHeaders.Remove("Host");
httpHeaders.Add("Host", DestinationAddress.Authority); //give it the new host that we are re-directing to
httpHeaders.Remove("Connection"); //todo: not sure I need this, but without it there is an exception between Keep-Alive and Closed
// Set factory and message address
factory.Endpoint.Address = new EndpointAddress(DestinationAddress);
requestMessage.Headers.To = DestinationAddress;
_client = factory.CreateChannel();
asyncResult = _client.BeginProcessRequest(requestMessage, asyncCallback, asyncState);
return asyncResult;
}
}
На BeginProcessRequest, я получаю исключение: Нарушение протокола: не удается отправить контент-тело с этим глагольным типом
Что я исследовал, и я понимаю, что по запросу GET, в теле запроса ничего не может быть.
Поскольку мой код работает для POST, я могу только предположить, что по какой-то причине в теле есть что-то.
Однако, поскольку исходный запрос был GET из браузера с использованием URL-адреса ServiceBus, я не уверен, почему в теле было что-то.
Итак:
- Я думаю, что я делаю что-то в коде, который вызывает у меня проблема - если это так, я хотел бы знать, что!
- Если во входящем запросе есть что-то, как я могу удалить его, чтобы не получить нарушение?
- Любые другие предложения, улучшения кода?
Итак ... интерфейс определяет только WebInvoke, а не WebGet ... так почему же он позволяет передать запрос GET в службу? Используя такой общий интерфейс, мне нужно обрабатывать GET и POST по-разному? Я не трогаю тело запроса в любом случае ... – codeputer
Причина, по которой GET-запросы получают ретранслирование, заключается в том, что Action и ReplyAction указывают «*», что означает, что все сообщения отправляются сюда. Наличие атрибута WebInvoke на этом интерфейсе тогда меньше! – codeputer