dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.14k stars 4.71k forks source link

System.InvalidOperationException: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects. #33039

Closed HASSEN-MEDDEB-ATOS closed 4 years ago

HASSEN-MEDDEB-ATOS commented 4 years ago

Hello,

I have migarted my project from .NET Framework to .NET Core, and when i call WS i get error

System.InvalidOperationException: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects. at System.Net.Http.Headers.HttpHeaders.GetHeaderDescriptor(String name) at System.Net.Http.Headers.HttpHeaders.Add(String name, String value)



Cordially
HASSEN-MEDDEB-ATOS commented 4 years ago

@davidsh any suggestion please

davidsh commented 4 years ago

@davidsh David Shulman FTE any suggestion please

//request.Headers.Remove("Content-Type");

Entity body related headers such as 'Content-Type', 'Content-Length' should be added to the Content.Headers collection of HttpRequestMessage. That assumes that you are also adding an HttpContent object as well since you are trying to probably post some content.

request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");
HASSEN-MEDDEB-ATOS commented 4 years ago

Thank you for your repsonse i get now this error :/

System.NullReferenceException: Object reference not set to an instance of an object.
   at VSMP_Contracts.CTR_WS_Connection.CustomDelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in C:\Git\VSMP_Data_Integration\VSMP_Data_Integration\VSMP_Contracts_Import\CTR_WS_Connection.cs:line 154
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

Cordailly

HASSEN-MEDDEB-ATOS commented 4 years ago
using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);

                    request.Headers.Add("Authorization", string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\",signature=\"{2}\"", _applicationId, "hmac-sha1", Url_Encoded_Signature));

                    //var invalidHeaders = (HashSet<string>)typeof(HttpHeaders).GetField("invalidHeaders", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request.Headers);
                    //invalidHeaders.Remove("Content-Type");
                    //request.Headers.Remove("Content-Type");
                    request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");
                    request.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
HASSEN-MEDDEB-ATOS commented 4 years ago

@davidsh Can you invetigate please

HASSEN-MEDDEB-ATOS commented 4 years ago

System.NullReferenceException: Object reference not set to an instance of an object, when i used request.Content.Headers.Remove("Content-Type");


using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Content.Headers.Remove("Content-Type");
                    request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");
                    request.Content.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
stephentoub commented 4 years ago

You need to set Content to something. The null ref is from your method trying to call something off of the Content property, which will return null until you set it to something non-null.

davidsh commented 4 years ago

@HASSEN-MEDDEB-ATOS

Why do you want to set the 'Content-Type' header at all?

If you are trying to control the HTTP response body encoding, then you should set the 'Accept-Encoding' header instead.

HASSEN-MEDDEB-ATOS commented 4 years ago

thnaks for all response but still same error,

using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Content.Headers.Add("Accept", "application/json");
                    request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");
                    request.Content.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
            }`
stephentoub commented 4 years ago

still same error

Where are you setting request.Content?

HASSEN-MEDDEB-ATOS commented 4 years ago

request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8"); request.Content.Headers.TryAddWithoutValidation("Date", utcFormattedDate);

stephentoub commented 4 years ago

No, where are you actually setting the Content property, e.g.

request.Content = something;

? If you don't do that, it will return null.

HASSEN-MEDDEB-ATOS commented 4 years ago

https://docs.microsoft.com/fr-fr/aspnet/web-api/overview/advanced/http-message-handlers but accroding to this article we don't need to initialize request.Content ?

HASSEN-MEDDEB-ATOS commented 4 years ago

My code work well using .NET Framework

HASSEN-MEDDEB-ATOS commented 4 years ago

https://docs.microsoft.com/fr-fr/dotnet/api/system.net.http.delegatinghandler.sendasync?view=netframework-4.8

davidsh commented 4 years ago

but according to this article we don't need to initialize request.Content ?

You must create a .Content object if you plan on adding content related headers to the request object like 'Content-Type'.

Also, you didn't answer my question here about why you want to use 'Content-Type' header at all.

HASSEN-MEDDEB-ATOS commented 4 years ago

i used Content_Type to specifies to the server what data it should expect

davidsh commented 4 years ago

i used Content_Type to specifies to the server what data it should expect

Ok. That implies you are sending data to the server? So, where is the data that you're sending? You usually create an HttpRequestMessage with the .Content property set to an object. But where is that code? Currently, .Content is null. So, that means you aren't sending any data (no request body).

HASSEN-MEDDEB-ATOS commented 4 years ago

No in this case i need to get Data from server

HASSEN-MEDDEB-ATOS commented 4 years ago
 request.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
                using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Headers.Remove("Content-Type");
                    request.Headers.Add("Content-Type", "application/json;charset=UTF-8");
                    request.Headers.Add("Content-Encoding", "identity");
                    request.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
HASSEN-MEDDEB-ATOS commented 4 years ago
public async static Task<List<Contract>> GetContracts(string URL, string startDate, string EndDate)
        {
            List<Contract> ListContrats = new List<Contract>();                                 //liste allant contenir des pages de contrats (ou des objets "Contract")           
            int startIndex = 0;
            int NbContracts = 0;
            try
            {
                CustomDelegatingHandler customDelegatingHandler = new CustomDelegatingHandler();

                HttpClient client = HttpClientFactory.Create(customDelegatingHandler);
                var watch = System.Diagnostics.Stopwatch.StartNew();

                string urlAppelWS = URL + "&startDate=" + startDate + "&endDate=" + EndDate + "&count=100";

                while (!string.IsNullOrEmpty(urlAppelWS)) //appel du web service en boucle (pour le parcours de la pagination) jusqu'à ce que l'on ait plus de page suivante
                {
                    LogHelper.Writer("" + urlAppelWS);

                    HttpResponseMessage response = await client.GetAsync(urlAppelWS);
                    LogHelper.Writer("" + response);

                    if (response.StatusCode != HttpStatusCode.OK)
                        throw new Exception();

                    string responsedata = await response.Content.ReadAsStringAsync();

                    Contract Contrats = JsonConvert.DeserializeObject<Contract>(responsedata);
                    if (Contrats.results.Length == 0)
                    {
                        break;
                    }
                    ListContrats.Add(Contrats);        //ajout de la réponse en page de contrats dans la liste
                    urlAppelWS = string.IsNullOrEmpty(Contrats.nextResults) ? string.Empty : URL + Contrats.nextResults.Split('?')[1];
                    Console.WriteLine("Nouvelle page de contrats : {0} contrats", Contrats.results.Length);
                    NbContracts += Contrats.results.Length;
                }
                watch.Stop();
                var elapsedMs = watch.ElapsedMilliseconds;
                LogHelper.Writer(string.Format("Temps d'extraction des contrats depuis le web service : {0} ms soit {1} s", elapsedMs, elapsedMs / 1000));

                if (NbContracts != 0)
                    LogHelper.Writer(string.Format("{0} contrats extrais répartis sur {1} pages", NbContracts, startIndex));
            }
            catch (NullReferenceException ex)
            {
                LogHelper.Writer("Erreur (référence nulle) lors de l'import des contrats depuis le web service, message de l'erreur : " + Environment.NewLine + ex.ToString());
                throw ex;
            }
            catch (Exception ex)
            {
                LogHelper.Writer("Erreur lors de l'import des contrats depuis le web service, message de l'erreur : " + ListContrats.Count + Environment.NewLine + ex.ToString());
                throw ex;
            }
            return ListContrats;
        }
davidsh commented 4 years ago

If you need to set 'Content-Type', you should set it on your request.Content.Headers object. However, looking at your code, you probably already are setting it?

request.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");

No in this case i need to get Data from server

This statement tells me you want to control the data that the server sends to the client. So, you should be setting the 'Accept-Encoding' header on the HttpRequestMessage instead. That tells a server what kind of response body data to send back to the client.

HASSEN-MEDDEB-ATOS commented 4 years ago
 request.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
                using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");
                    request.Content.Headers.Add("Content-Encoding", "identity");
                    request.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
            }
HASSEN-MEDDEB-ATOS commented 4 years ago

system.Exception: Exception of type 'System.Exception' was thrown. at VSMP_Contracts.CTR_WS_Connection.GetContracts(String URL, String startDate, String EndDate)

HASSEN-MEDDEB-ATOS commented 4 years ago

Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects. at System.Net.Http.Headers.HttpHeaders.GetHeaderDescriptor(String name) at System.Net.Http.Headers.HttpHeaders.Add(String name, String value)

  request.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
                using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    request.Headers.Add("Authorization", string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\",signature=\"{2}\"", _applicationId, "hmac-sha1", Url_Encoded_Signature));

                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Content.Headers.Add("Accept-Encoding", "gzip");
                    request.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;
davidsh commented 4 years ago

request.Content.Headers.Add("Accept-Encoding", "gzip");

If you want to use 'Accept-Encoding', that header goes into the main request.Headers collection.

HASSEN-MEDDEB-ATOS commented 4 years ago

system.Exception: Exception of type 'System.Exception' was thrown. at VSMP_Contracts.CTR_WS_Connection.GetContracts(String URL, String startDate, String EndDate)

HASSEN-MEDDEB-ATOS commented 4 years ago

Can you came skype please for 2 minutes please

HASSEN-MEDDEB-ATOS commented 4 years ago

i have modified my code like this

request.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
                using (HMACSHA1 hmac = new HMACSHA1(_secretKeyUTF8))
                {
                    byte[] Datebytes = Encoding.UTF8.GetBytes(Date);
                    byte[] hashedValue = hmac.ComputeHash(Datebytes);
                    string Signature = Convert.ToBase64String(hashedValue);
                    string Url_Encoded_Signature = UpperCaseUrlEncode(Signature);
                    request.Headers.Add("Authorization", string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\",signature=\"{2}\"", _applicationId, "hmac-sha1", Url_Encoded_Signature));

                    var field = typeof(HttpRequestHeaders).GetField("invalidHeaders",BindingFlags.NonPublic | BindingFlags.Static)?? typeof(HttpRequestHeaders).GetField("s_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Static);
                    if (field != null)
                    {
                        var invalidFields = (HashSet<string>)field.GetValue(null);
                        invalidFields.Remove("Content-Type");
                    }
                    request.Headers.Add("Accept-Encoding", "gzip");
                    request.Content.Headers.TryAddWithoutValidation("Date", utcFormattedDate);
                }
                response = await base.SendAsync(request, cancellationToken);
                return response;

i get new error,Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: . Path '', line 0, position 0. at Newtonsoft.Json.JsonTextReader.ParseValue() at Newtonsoft.Json.JsonReader.ReadAndMoveToContent() at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)

HASSEN-MEDDEB-ATOS commented 4 years ago
                string responsedata = await response.Content.ReadAsStringAsync();
HASSEN-MEDDEB-ATOS commented 4 years ago

my request return this messge below Method: GET, RequestUri: 'https://www.test.com/mediation/v1/recette/vsmp/contracts?&startDate=2019-08-01T08:52:13Z&endDate=2020-03-02T20:28:12Z&count=100', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Authorization: Signature keyId="**",algorithm="hmac-sha1",signature="****" Accept-Encoding: gzip Content-Type: application/json; charset=UTF-8 } 02/03/2020 21:28:13 | StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Mon, 02 Mar 2020 20:28:12 GMT Server: Apache Posc_transaction_id: 2cee38a2-56f3-45f4-99ac-65403f57786c Vary: Accept-Encoding X-Hub-Project: LaPosteSpring X-Ratelimit-Limit: 0 X-Ratelimit-Remaining: 0 X-Ratelimit-Reset: 0 Via: 1.1 www.test.com Transfer-Encoding: chunked Content-Encoding: gzip Content-Type: application/json; charset=UTF-8 }

HASSEN-MEDDEB-ATOS commented 4 years ago

I have finally find solution, i don't need to use request.Headers.Add("Accept-Encoding", "gzip");

 request.Content.Headers.Remove("Content-Type");
                    //request.Headers.Add("Accept-Encoding", "gzip");
                    request.Content.Headers.Add("Content-Type", "application/json;charset=UTF-8");

                    request.Content.Headers.TryAddWithoutValidation("Date", utcFormattedDate);`

Thanks for all response @davidsh @stephentoub