Microsoft.OData.Client меняет порт службы в запросах PATCH?

Поэтому я работал на стороне клиента, извлекая записи odata V4 с помощью автоматически сгенерированного контейнера Microsoft.OData.Client, все шло отлично

Когда я подумал, мне нужно патчить запись, ничего страшного, я просто

_container.SaveChanges(SaveChangesOptions.None);

и он начал терпеть неудачу с

"Попытка подключения не удалась, потому что подключенная сторона не ответила должным образом через некоторое время, или не удалось установить соединение, так как подключенный хост не смог ответить 176.34.122.158:15737"

В клиенте что-то еще не известно, что меняло порт с 443 на 15737 и меняло схему URI на обычный http

Visual Studio IIS Express использует порты, отличные от 80 и 443, и проблема появилась только тогда, когда я начал указывать клиенту на развернутую службу в AppHarbor, поэтому я подозреваю, что это изменение в портах происходит только тогда, когда контейнер был установлен с URI с портом по умолчанию, но Мне нужно сделать дальнейшее тестирование.

Если вы, читая это, имеете какое-либо представление о том, что может вызвать изменение URI в контейнере, я хотел бы знать.

Грязный грязный способ исправить симптомы:

при добавлении токена аутентификации в заголовок принудительно верните URI в нужный порт

public static void OnBuildingRequest(object sender, BuildingRequestEventArgs e)
    {
        e.Headers.Add("Authorization", "Bearer " + Properties.Settings.Default.ODataToken);

        if (e.RequestUri.IsDefaultPort == false)
        {
            UriBuilder ub = new UriBuilder(e.RequestUri);
            ub.Scheme = Uri.UriSchemeHttps;
            ub.Port = 443;
            e.RequestUri = ub.Uri;
        }
    }

да, токен хранится в свойствах, которые я обещаю, что я буду в порядке и зашифрую его позже... возможно:P

Редактировать 20/7

Вспомогательный персонал в Appharbour любезно поинтересовался и попросил дать некоторые разъяснения, так что теперь, теперь на 100% больше каракулей:

Архитектура:

Сервер: XXXX.apphb.com (SQL + Entity Framework (Модель) + WEB API 2 OData V4 (Контроллер))

Клиент: настольный клиент (WPF с использованием Microsoft.Odata.Client, с прокси, созданными с помощью OData v4 Client Code Generator)

Сервер <--- HTTPS с аутентификацией токена ---> Клиент

Рабочий процесс (на стороне клиента):

Аутентифицировать -> ПОЛУЧИТЬ -> ПАТЧ

Создать контейнер при создании страницы WPF:

public partial class PageLibrary : Page
{
    Uri _uri;
    Default.Container _container;
    List<BookScore> _bookscores;

    public PageLibrary()
    {
        InitializeComponent();
        _uri = new Uri(Properties.Settings.Default.ServerMetadataUri);  //<-- https://XXXXXX.apphb.com/Metadata/
        _container = new Default.Container(_uri);
        _container.BuildingRequest += (sender, e) => Authentication.OnBuildingRequest(sender, e); 
    }

Пользователь запрашивает BookScores, вызывая:

_bookscores = (_container.BookScores).ToList();

Клиент готовит запрос на отправку GET, BuildingRequestEventArgs e указывает на порт по умолчанию

e.RequestUri.Port = 443

Пользователь изменяет значение и сохраняет:

private void Save_Click(object sender, RoutedEventArgs e)
    {
        foreach (var bookscore in _bookscores)
        {
            _container.UpdateObject(bookscore);
        }
        _container.SaveChanges(SaveChangesOptions.None);
    } 

Все еще указывает на правый порт

_container.BookScores.RequestUri.Port = 443

Клиент готовит запрос на отправку PATCH (обратите внимание, что аргумент теперь переносит другой порт)

e.RequestUri.Port = 15747

1 ответ

Согласно поддержке AppHarbor:

проблема действительно в том, что сервер дает клиенту неправильный URL. Кажется, что OData/WebAPI не поддерживает заголовок X-Forwarded-Proto из коробки. Это вызывает проблемы, поскольку клиентское программное обеспечение OData не продолжает использовать URL-адрес, указанный вами при настройке контекста OData, - он считывает метаданные, которые будут содержать неправильную схему, имя хоста и порт

public class ForwardedProtocolHeadersHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    var forwardedProtocolHeader = request.Headers.FirstOrDefault(x =>
        string.Equals(x.Key, "X-Forwarded-Proto", StringComparison.InvariantCultureIgnoreCase));

    if (!string.IsNullOrEmpty(forwardedProtocolHeader.Key))
    {
        var isHttps = string.Equals(forwardedProtocolHeader.Value.Single(), Uri.UriSchemeHttps, StringComparison.InvariantCultureIgnoreCase);

        var urlBuilder = new UriBuilder(request.RequestUri)
        {
            Scheme = isHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp,
            Port = isHttps ? 443 : 80,
        };

        request.RequestUri = urlBuilder.Uri;
    }

    return base.SendAsync(request, cancellationToken);
}
}

полное объяснение:

https://support.appharbor.com/discussions/problems/83648-odata-web-api-2-patch-not-working

Другие вопросы по тегам