2013-03-06 2 views
1

Обновление: я был на 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, я не уверен, почему в теле было что-то.

Итак:

  1. Я думаю, что я делаю что-то в коде, который вызывает у меня проблема - если это так, я хотел бы знать, что!
  2. Если во входящем запросе есть что-то, как я могу удалить его, чтобы не получить нарушение?
  3. Любые другие предложения, улучшения кода?
+0

Итак ... интерфейс определяет только WebInvoke, а не WebGet ... так почему же он позволяет передать запрос GET в службу? Используя такой общий интерфейс, мне нужно обрабатывать GET и POST по-разному? Я не трогаю тело запроса в любом случае ... – codeputer

+0

Причина, по которой GET-запросы получают ретранслирование, заключается в том, что Action и ReplyAction указывают «*», что означает, что все сообщения отправляются сюда. Наличие атрибута WebInvoke на этом интерфейсе тогда меньше! – codeputer

ответ

0

Размещение этого атрибута на операции, [WebInvoke (UriTemplate = "")], поддерживает POST по умолчанию, но вы можете передать параметр, определяющий другие глаголы, такие как PUT, DELETE и т.д. Тем не менее, GET является поддерживается другим атрибутом [WebGet]. Я бы предложил добавить дополнительные операции к маршрутизатору, один с WebGet, и другие с помощью WebInvoke и различные HTTP-глаголы.

+0

Итак, почему запрос get получает метод? Должно ли это не просто упасть на конечную точку? – codeputer

+0

Кроме того, поскольку это просто передача запроса, почему ошибка? Тип контента - null, действие GET, поэтому почему нарушение? – codeputer

+0

Tony - см. Мой комментарий выше - WebInvoke/WebGet бессмысленны здесь, потому что Action и ReplyAction оба установлены в "*", а тип возврата - Message. Это означает, что ВСЕ сообщения направляются на этот интерфейс. – codeputer

Смежные вопросы