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 (обратите внимание, что аргумент теперь переносит другой порт)
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