Еще один подход к возврату значения из асинхронной функции - передать объект, который сохранит результат от асинхронной функции.
Вот пример того же:
var async = require("async");
// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
// some asynchronous operation
$.ajax({
url: '...',
success: function(response) {
result.response = response;
_callback();
}
});
});
async.parallel(asyncTasks, function(){
// result is available after performing asynchronous operation
console.log(result)
console.log('Done');
});
Я использую объект result
для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.
Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.
Тип содержимого - это заголовок содержимого, а не запроса, поэтому это не работает. AddWithoutValidation
, как предложил Роберт Леви, может работать, но вы также можете установить тип содержимого при создании самого содержимого запроса (обратите внимание, что фрагмент кода добавляет «application / json» в двух местах - для заголовков Accept и Content-Type):
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);
});
var content = new HttpContent();
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"));
Это все, что вам нужно.
Для тех, кто не видел комментария Джонса к решению carlos ...
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
.Net пытается заставить вас подчиняться определенным стандартам, а именно, что заголовок Content-Type
может быть указан только в запросах, имеющих контент (например, POST
, PUT
и т. д.). Поэтому, как указывали другие, предпочтительный способ установки заголовка Content-Type
- через свойство HttpContent.Headers.ContentType
.
С учетом сказанного некоторые API (такие как LiquidFiles Api , начиная с 2016-12-19) требует установки заголовка Content-Type
для запроса GET
. .Net не позволит устанавливать этот заголовок на самом запросе - даже используя TryAddWithoutValidation
. Кроме того, вы не можете указать Content
для запроса - даже если он имеет нулевую длину. Единственный способ, которым я мог бы обойти это, - прибегнуть к размышлениям. Код (в случае, если ему это еще нужно)
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");
Редактировать:
Как отмечено в комментариях, это поле имеет разные имена в разных версиях dll. В исходном коде на GitHub поле в настоящее время называется s_invalidHeaders
. Пример был изменен для учета этого в предположении @David Thompson.
Дополнительная информация о .NET Core (после прочтения сообщения erdomke о настройке приватного поля для предоставления контента для запроса, который не имеет содержимого) ...
После отладки моего кода , Я не вижу, как частное поле устанавливается через отражение - поэтому я решил попробовать эту проблему.
Я пробовал следующий код, используя .Net 4.6:
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;
И, как и ожидалось, я получаю агрегатное исключение с контентом "Cannot send a content-body with this verb-type."
Однако, если я делаю то же самое с .NET Core (1.1) - я не получаю исключения , Моя просьба была удовлетворительно удовлетворена моим серверным приложением, и тип контента был поднят.
Я был приятно удивлен этим, и я надеюсь, что это кому-то поможет!
Вызовите AddWithoutValidation
вместо Add
(см. эту ссылку MSDN ).
В качестве альтернативы, я предполагаю, что API, который вы используете, действительно требует только этого для POST или PUT (не обычные запросы GET). В этом случае, когда вы вызываете HttpClient.PostAsync
и передаете в HttpContent
, установите это в свойстве Headers
этого объекта HttpContent
.
попытайтесь использовать TryAddWithoutValidation
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
Если вы не возражаете против небольшой зависимости от библиотеки, Flurl.Http [раскрытие: я автор] делает этот uber-простой. Его метод PostJsonAsync
выполняет как сериализацию содержимого, так и установку заголовка content-type
, а ReceiveJson
десериализует ответ. Если требуется заголовок accept
, вам нужно будет установить это самостоятельно, но Flurl также предоставляет довольно чистый способ:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
Flurl использует HttpClient и Json.NET под капотом, и это PCL, поэтому он будет работать на разных платформах.
PM> Install-Package Flurl.Http
Хорошо, это не HTTPClient, но если вы можете его использовать, WebClient довольно легко:
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(...);
}