Ich versuche, den Content-Type
-Header eines HttpClient
-Objekts gemäß den Anforderungen einer von mir aufgerufenen API festzulegen.
Ich habe versucht, den Content-Type
wie folgt einzustellen:
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://example.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
// ...
}
Ich kann den Header Accept
hinzufügen, aber wenn ich versuche, Content-Type
hinzuzufügen, wird die folgende Ausnahme ausgelöst:
Name des falsch verwendeten Headers. Stellen Sie sicher, dass Anforderungsheader mit
HttpRequestMessage
, Antwortheader mitHttpResponseMessage
und Inhaltsheader mitHttpContent
Objekten verwendet werden.
Wie kann ich den Content-Type
-Header in einer HttpClient
-Anforderung festlegen?
Der Inhaltstyp ist eine Kopfzeile des Inhalts und nicht der Anforderung, weshalb dies fehlschlägt. AddWithoutValidation
, wie von Robert Levy vorgeschlagen, funktioniert möglicherweise, aber Sie können den Inhaltstyp auch festlegen, wenn Sie den Anforderungsinhalt selbst erstellen (beachten Sie, dass das Code-Snippet "application/json" an zwei Stellen für die Überschriften "Accept" und "Content-Type" hinzufügt ):
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
Encoding.UTF8,
"application/json");//CONTENT-TYPE header
client.SendAsync(request)
.ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
});
Für diejenigen, die Johns Kommentar zur Carlos-Lösung nicht gesehen haben ...
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
Wenn Ihnen eine kleine Bibliotheksabhängigkeit nichts ausmacht, macht Flurl.Http [Offenlegung: Ich bin der Autor] dies sehr einfach. Die PostJsonAsync
-Methode sorgt sowohl für die Serialisierung des Inhalts als auch für das Setzen des content-type
-Headers, und ReceiveJson
deserialisiert die Antwort. Wenn der accept
-Header benötigt wird, müssen Sie dies selbst festlegen, aber Flurl bietet auch eine ziemlich saubere Möglichkeit, dies zu tun:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
Flurl verwendet HttpClient und Json.NET unter der Haube, und es ist eine PCL, so dass es auf einer Vielzahl von Plattformen funktioniert.
PM> Install-Package Flurl.Http
versuchen Sie TryAddWithoutValidation zu verwenden
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
.Net versucht, Sie zur Einhaltung bestimmter Standards zu zwingen, nämlich, dass der Header _Content-Type
_ nur für Anforderungen angegeben werden kann, die Inhalt haben (z. B. POST
, PUT
usw.). Wie bereits von anderen angegeben, erfolgt das Festlegen des Headers _Content-Type
_ daher bevorzugt über die Eigenschaft HttpContent.Headers.ContentType
.
Vor diesem Hintergrund muss für bestimmte APIs (wie die LiquidFiles Api , Stand 19.12.2016) der _Content-Type
_ -Header für eine GET
-Anforderung festgelegt werden. .Net erlaubt es nicht, diesen Header für die Anfrage selbst festzulegen - selbst wenn TryAddWithoutValidation
verwendet wird. Darüber hinaus können Sie für die Anforderung kein Content
angeben, selbst wenn es eine Länge von Null hat. Der einzige Weg, wie ich das umgehen konnte, bestand darin, auf Reflexion zurückzugreifen. Der Code (falls er von anderen benötigt wird) ist
_var field = typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
?? typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (field != null)
{
var invalidFields = (HashSet<string>)field.GetValue(null);
invalidFields.Remove("Content-Type");
}
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");
_
Bearbeiten:
Wie in den Kommentaren erwähnt, hat dieses Feld in verschiedenen Versionen der DLL unterschiedliche Namen. Im Quellcode auf GitHub heißt das Feld derzeit _s_invalidHeaders
_. Das Beispiel wurde geändert, um dies auf Vorschlag von @David Thompson zu berücksichtigen.
Einige zusätzliche Informationen zu .NET Core (nach dem Lesen des Postings von erdomke zum Festlegen eines privaten Felds, um den Inhaltstyp für eine Anfrage ohne Inhalt bereitzustellen) ...
Nach dem Debuggen meines Codes kann ich das private Feld, das über Reflection festgelegt werden soll, nicht sehen. Daher dachte ich, ich würde versuchen, das Problem erneut zu erstellen.
Ich habe den folgenden Code mit .Net 4.6 ausprobiert:
HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl");
httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
Task<HttpResponseMessage> response = client.SendAsync(httpRequest); //I know I should have used async/await here!
var result = response.Result;
Und wie erwartet erhalte ich eine aggregierte Ausnahme mit dem Inhalt "Cannot send a content-body with this verb-type."
Wenn ich jedoch das Gleiche mit .NET Core (1.1) mache - Ich bekomme keine Ausnahme. Meine Anfrage wurde von meiner Serveranwendung sehr zufrieden beantwortet und der Inhaltstyp wurde abgeholt .
Das hat mich positiv überrascht und ich hoffe es hilft jemandem!
Rufen Sie AddWithoutValidation
anstelle von Add
auf (siehe dieser MSDN-Link ).
Alternativ schätze ich, dass die von Ihnen verwendete API dies nur für POST - oder PUT-Anforderungen (keine normalen GET-Anforderungen) benötigt. Wenn Sie in diesem Fall HttpClient.PostAsync
aufrufen und ein HttpContent
übergeben, legen Sie dies für die Headers
-Eigenschaft dieses HttpContent
-Objekts fest.
var content = new JsonContent();
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true"));
Es ist alles was Sie brauchen.
Mit der Verwendung von Newtonsoft.Json, wenn Sie einen Inhalt als JSON-Zeichenfolge benötigen.
public class JsonContent : HttpContent
{
private readonly MemoryStream _stream = new MemoryStream();
~JsonContent()
{
_stream.Dispose();
}
public JsonContent(object value)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var jw = new JsonTextWriter(new StreamWriter(contexStream)) { Formatting = Formatting.Indented })
{
var serializer = new JsonSerializer();
serializer.Serialize(jw, value);
jw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
private JsonContent(string content)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var sw = new StreamWriter(contexStream))
{
sw.Write(content);
sw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _stream.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = _stream.Length;
return true;
}
public static HttpContent FromFile(string filepath)
{
var content = File.ReadAllText(filepath);
return new JsonContent(content);
}
public string ToJsonString()
{
return Encoding.ASCII.GetString(_stream.GetBuffer(), 0, _stream.GetBuffer().Length).Trim();
}
}
Ok, es ist nicht HTTPClient, aber wenn Sie es verwenden können, ist WebClient ganz einfach:
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Accept", "application/json");
client.Headers.Add("Content-Type", "application/json; charset=utf-8");
client.DownloadString(...);
}
charset
habenIch hatte einen ganz besonderen Fall, in dem der Dienstanbieter Zeichensatz nicht akzeptierte und sich weigerte, die Unterstruktur zu ändern, um dies zuzulassen. es wird immer den Zeichensatz setzen ...
Heute war ich am Rande, um das Subsystem zu ändern, als ich von HttpClient auf etwas gestoßen bin. Warum sollte ich nicht die Reflektion verwenden, um den "Zeichensatz" zu leeren? ... und bevor ich es überhaupt probiere, habe ich festgestellt, dass ich es nach der Initialisierung ändern kann. Hier erfahren Sie, wie Sie den genauen "application/json" -Header ohne "; charset = utf-8" festlegen können.
var jsonRequest = JsonSerializeObject(req, options); // Custom function that parse object to string
var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
stringContent.Headers.ContentType.CharSet = null;
return stringContent;
Hinweis: Der folgende null
-Wert funktioniert nicht und hängt "; charset = utf-8" an
return new StringContent(jsonRequest, null, "application/json");
Sie können dies verwenden, es wird funktionieren!
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get,"URL");
msg.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.SendAsync(msg);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
Ich finde es am einfachsten und verständlichsten auf folgende Weise:
async Task SendPostRequest()
{
HttpClient client = new HttpClient();
var requestContent = new StringContent(<content>);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(<url>, requestContent);
var responseString = await response.Content.ReadAsStringAsync();
}
...
SendPostRequest().Wait();
Du musst es so machen:
HttpContent httpContent = new StringContent(@"{ the json string }");
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = client.PostAsync(@"{url}", httpContent).Result;