3

My client code makes call to an API and I'm trying to get the returned ETag value from the response headers. If I use Fiddler I can see the response contains the ETag header and if I make API call using Postman I can see the ETag header, but no matter what approach I take to try and retrieve the headers in my code all I get returned is a null.

Essentially the API call is;

// create request object
var request = new HttpRequestMessage(HttpMethod.Get, url);
// add authorization header
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", await GetBearerToken());
// send request
HttpResponseMessage response = await _client.SendAsync(request);

Fiddler Response Header showing Etag

The Postman response is;

Postman response headers

I've spent hours searching and trying examples from web, but no matter what I try I can't get the the ETag header.

Using the example code below I do get the first 2 headers as shown in the Postman response headers returned but not the ETag header / value.

String allResponseHeaders = Enumerable
    .Empty<(String name, String value)>()
    .Concat(
    response.Headers
    .SelectMany(kvp => kvp.Value
    .Select(v => (name: kvp.Key, value: v))
    ))
    .Concat(
    response.Content.Headers
    .SelectMany(kvp => kvp.Value
    .Select(v => (name: kvp.Key, value: v))
    ))
   .Aggregate(
   seed: new StringBuilder(),
   func: (sb, pair) => sb.Append(pair.name).Append(": ").Append(pair.value).AppendLine(),
   resultSelector: sb => sb.ToString()
   );

I'm using Visual Studio, Blazor and aspnetcore 5.0 and I'm looking to generate an PWA with IndexDB and use ETag's to reduce data downloads.

Any help on how to get to the Etag header will be much appreciated...

gunr2171
  • 16,104
  • 25
  • 61
  • 88
SteveW
  • 43
  • 1
  • 6

3 Answers3

6

I had similar issue like other people. Actually we have github issue and great discussion that was open on this issue. I just want to share like with other people that are maybe stuck at same point and visit stack overflow.

Link for issue (closed):

https://github.com/dotnet/runtime/issues/42179

Quote from discussion "Your CORS policy needs to specify what headers are exposed. If you would like the client to read all headers, you can specify it as so"

Example(Server side):

services.AddCors(options =>
{
    options.AddPolicy("Open", builder => builder
        .AllowAnyOrigin()
        .AllowAnyHeader()
        .AllowAnyMethod()
        .WithExposedHeaders("*")); // this is the important part!
});
gunr2171
  • 16,104
  • 25
  • 61
  • 88
Dino Lozina
  • 61
  • 1
  • 3
  • Dino, Thanks very much for this update, I had just about given up on getting eTag working with Blazor WASM. However, I simply added the .WithExposedHeaders("*") as you showed and that got the eTag header being returned. I still have the question of why Postman was getting the eTag header without that setting in the API Server and the Blazor WASM was not, but that can be for another day.... Again thanks.... – SteveW Mar 19 '21 at 23:23
  • I had the same issue @SteveW thanks for the question, and yet Fiddler returned it. Maybe web application servers/frameworks are more stricter. It comes down to this which helped me understand it. https://stackoverflow.com/questions/28107459/in-the-http-cors-spec-whats-the-difference-between-allow-headers-and-expose-he – User101 Mar 13 '23 at 14:05
  • @SteveW running the requests side by side, It looks like the .WithExposedHeaders("*") sends an extra response header 'access-control-expose-headers: *'. My guess is that because the wasm runtime HttpClient is a wrapper around native script web requests, it's beholden to the same header visibility rules as listed here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers – Mike Aug 10 '23 at 01:59
1

I created very simple console app and used that to GET data from API, I can see that the ETag value is being returned in the response but can't seem to simply extract the value in code, using response.Headers.Etag.

using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace SimpleAPIClient
{

    class Program
    {
        private static readonly HttpClient client = new HttpClient();

        static async Task Main(string[] args)
        {

            var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44338/api/headers/3");
            request.Headers.Authorization = new AuthenticationHeaderValue("bearer", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBjb250cmEtc29mdC5jb20iLCJqdGkiOiI4NjgyMmQ1YS1iNTQ3LTRlMjItYmQ3NS0wNDlkZmE5MTMzZmUiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjVkODExZmY1LTgyY2QtNDY2NC05ODkzLTZmNGRjMDU0YzFmNSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE2MDgzNTU0MTEsImlzcyI6ImNvbnRyYS1zb2Z0LmNvbSIsImF1ZCI6ImNvbnRyYS1zb2Z0LmNvbSJ9.w_CSstMZkFFn0DcMlcPNNm_Nr0idzHPo6I2hRjEUglQ");
            HttpResponseMessage response = await client.SendAsync(request);

            var etag = response.Headers.ETag;

            int i = 0;
        }

    }
}

VS Breakpoint shows ETag data

I believe the issue is due to the project being a Blazor Web Assembly project, if I create simple .net core project then the following code works;

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiO");
Task<HttpResponseMessage> s = client.GetAsync("https://localhost:44338/api/headers/3");
HttpResponseMessage nresponse2 = await s;
var etag2 = nresponse2.Headers.FirstOrDefault(i => i.Key == "ETag").Value.FirstOrDefault();

However the same code in Blazor does not.

SteveW
  • 43
  • 1
  • 6
0

On the response message object, you can access the ETag header directly.

// create request object
var request = new HttpRequestMessage(HttpMethod.Get, url);
// add authorization header
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", await GetBearerToken());
// send request
HttpResponseMessage response = await _client.SendAsync(request);

//read the response headers. The ETag is already a "known" header and is easily accessible via a property
EntityTagHeaderValue etagHeader = response.Headers.ETag;

Just the benno
  • 2,306
  • 8
  • 12
  • 1
    Thanks for the response, I had tried similar options and I've now tried your code, but value returned is still null. I just made a simple console app using restsharp and .net 4.7.2 and could see all the headers, so going to create simple aspnetcore console app to see if httpclient works, will try version 3.1 and 5.0 – SteveW Dec 22 '20 at 01:26