tag:support.appharbor.com,2010-11-23:/discussions/problems/83648-odata-web-api-2-patch-not-workingAppHarbor: Discussion 2016-07-24T21:17:45Ztag:support.appharbor.com,2010-11-23:Comment/403415742016-07-18T21:30:40Z2016-07-18T21:30:40ZOData Web API 2 PATCH not working<div><p>Not exactly fixed because I still don't know what was telling
the client to change ports, but I forced the client back into the
right port during header insertion</p>
<p>I feel dirty T_T</p></div>lvmcastrotag:support.appharbor.com,2010-11-23:Comment/403415742016-07-18T21:37:01Z2016-07-18T21:37:01ZOData Web API 2 PATCH not working<div><p>Hi,</p>
<p>Sounds like the problem is that the wrong URL is being used --
the app isn't listening publicly on other ports than 80 and
443.</p>
<p>What do you mean by forcing the client back during header
insertion?</p>
<p>Best,<br>
Rune</p></div>runetag:support.appharbor.com,2010-11-23:Comment/403415742016-07-19T19:58:52Z2016-07-19T19:58:52ZOData Web API 2 PATCH not working<div><p>I asked in StackOverflow, <a href="http://stackoverflow.com/questions/38467377/does-microsoft-odata-client-change-the-service-port-on-patch-requests">
http://stackoverflow.com/questions/38467377/does-microsoft-odata-cl...</a></p>
<p>it includes the answer to your question</p></div>lvmcastrotag:support.appharbor.com,2010-11-23:Comment/403415742016-07-20T01:56:48Z2016-07-20T01:56:48ZOData Web API 2 PATCH not working<div><p>Hi,</p>
<p>Ah ok, makes sense -- the reason you're getting a URL with the
port number is simply that the application runs on a unique,
dedicated port. The load balancer listens to requests on default
ports and acts as a reverse proxy to the private IP and port for
your worker.</p>
<p>The protocol (http/https) can be determined from the
<code>X-Forwarded-Proto</code> header. You can <a href="https://gist.github.com/runesoerensen/921bf766b76d7573fcd4">find
an example of using it here</a>, and a couple of workarounds for
generating public URLs <a href="https://support.appharbor.com/kb/getting-started/workaround-for-generating-absolute-urls-without-port-number">
in this KB article</a>.</p>
<p>However, I don't entirely understand why you need to do this
when making requests <em>from</em> the application -- based on your
Stack Overflow post it appears that you have to modify the port
prior to making a request. Is the application making a request to
itself or what is the workflow/use case for this?</p>
<p>Best,<br>
Rune</p></div>runetag:support.appharbor.com,2010-11-23:Comment/403415742016-07-20T19:03:59Z2016-07-20T19:03:59ZOData Web API 2 PATCH not working<div><p>Hi Rune,</p>
<p>Thanks for looking into it, I edited the SO question to try and
explain the workflow.</p>
<p>Do you still think it's the load balancer telling my desktop
application "don't send your request to me, send them over there
instead"?</p></div>lvmcastrotag:support.appharbor.com,2010-11-23:Comment/403415742016-07-23T07:53:59Z2016-07-23T07:53:59ZOData Web API 2 PATCH not working<div><p>Hi,</p>
<p>Nope I never thought that the load balancer was telling your app
to send requests elsewhere :-)</p>
<p>I tried this for myself and I can see that the problem indeed is
that the server is giving the client the wrong URL. It seems that
OData/WebAPI doesn't support the <code>X-Forwarded-Proto</code>
header out of the box. That causes issues since the OData client
software doesn't continue to use the URL you specify when setting
up the OData context -- it reads the metadata, which will contain
the wrong scheme, hostname and port.</p>
<p>The solution to this can be found in the article I linked to
earlier. In particular, you need to take two step to make sure that
the OData base URL returned in the service metadata is
accurate:</p>
<ol>
<li>Set the <code>aspnet:UseHostHeaderForRequestUrl</code>
appSetting to <code>true</code>. You can simply add this as an
configuration variable for your AppHarbor app so it'll be injected
when deploying the app. This will ensure that IIS respects the
<code>Host</code> header rather than building a URL based on the
server's IP address.<br></li>
<li>Make sure the OData service respects the
<code>X-Forwarded-Proto</code> header and sets the scheme and port
when generating URLs.</li>
</ol>
<p>There's a sample in the KB article I linked to earlier which
shows a solution for Owin. Sounds like you're usign WebAPI so
here's a quick example of a handler implementation that'll work
with that:</p>
<pre>
<code>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);
}
}</code>
</pre>
<p>Also remember to register the handler in your WebApi
configuration. Something like this should work:</p>
<pre>
<code>public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new ForwardedProtocolHeadersHandler());
// Other WebApi configuration
}
}</code>
</pre>
<p>I hope this helps!</p>
<p>Best,<br>
Rune</p></div>runetag:support.appharbor.com,2010-11-23:Comment/403415742016-07-24T12:27:11Z2016-07-24T12:27:11ZOData Web API 2 PATCH not working<div><p>Hi Rune,</p>
<p>Implemented it and It works, thanks a bunch.</p>
<p>So... before, the webservice was telling the client to use the
uri and port the server uses when communicate with the load
balancer and now the 1st step makes the webserver send no port info
so it defaults to default and the second step makes the webservice
send the correct uri and port?</p>
<p>I'll put reading up on X-Forwarded-Proto header and
DelegatingHandler on my todo list T_T</p></div>lvmcastrotag:support.appharbor.com,2010-11-23:Comment/403415742016-07-24T21:17:16Z2016-07-24T21:17:45ZOData Web API 2 PATCH not working<div><p>Hi,</p>
<p>Yes pretty much -- actually the first step is just there to
ensure that the ASP.NET service to use the value of the
<code>HOST</code> header rather than the IP address (e.g.
`example.apphb.com rather than. I'm not sure whether this is
necessary for your use case, but it seemed like it may be based on
the Stack Overflow thread (which had the IP and port in the error
message).</p>
<p>The 2nd step involving the <code>X-Forwarded-Proto</code> header
is responsible for setting the proper protocol scheme (https/http)
and uses this to set the port to the corresponding standard port
values (443/80).</p>
<p>In the end this is a more elegant solution -- it fixes the root
cause rather than being a workaround on the client side.</p>
<p>Support for these types of headers (in particular,
<code>X-Forwarded-Proto</code> and <code>X-Forwarded-For</code>)
has been lacking in .NET libraries, but fortunately newer versions
of ASP.NET Core, MVC, OWin etc have better support for it.</p>
<p>Best,<br>
Rune</p></div>rune