Невозможно выполнить http-запрос асинхронно в ClearScript V8

Я пытаюсь сделать HTTP-запрос и получить ответ в ClearScript V8 в моем контроллере C#. Когда я запускаю функцию синхронно, она работает нормально. Но я хотел бы запустить его асинхронно, чтобы воспользоваться преимуществами неблокирующих вызовов. Однако, когда я пытаюсь это сделать, я просто получаю нулевой ответ. Я создал пару вспомогательных классов для получения HTTP-клиента и добавил их в движок ClearScript. И как уже говорилось, работа в режиме синхронизации работает отлично. Но когда (попытка) запуститься в асинхронном режиме, он просто возвращает значение null. Я вообще правильно об этом думаю? Возможно ли это вообще? Или мы заперты из-за ограничений ClearScript? Любая помощь приветствуется. Ниже мой контроллер тестовой заглушки:

public class Javascript : Controller
{
    public async Task<IActionResult> Index()
    {
        var hostVariables = new HostVariables();
        V8ScriptEngine engine = new V8ScriptEngine();
        engine.DocumentSettings.AccessFlags = DocumentAccessFlags.None;
        engine.AddHostType(typeof(Console));
        using (HttpClient client = new HttpClient())
        {
            var request = new Request(client);
            engine.AddHostObject("hostVariables", hostVariables);
            engine.AddHostObject("request", request);
            engine.Execute(new DocumentInfo() { Category = ModuleCategory.Standard }, @"
                hostVariables.syncResponse = request.get(""https://www.google.com"").responseText;
                hostVariables.asyncResponse = (await request.getAsync(""https://www.google.com"")).responseText;
            ");
        }

        //hostVariables.syncResponse contains the Google website html
        //hostVariables.asyncResponse is null

        return View();
    }
}
public class HostVariables
{
    public string syncResponse { get; set; }
    public string asyncResponse { get; set; }
}
//HELPER CLASSES TO GIVE CLEARSCRIPT THE ABILITY TO PERFORM HTTP REQUESTS
public class Request
{
    private HttpClient _client;
    public Request(HttpClient client)
    {
        _client = client;
    }
    //ASYNC AND SYNC MODE ARE EXACTLY THE SAME, EXCEPT FOR THE SYNC/ASYNC METHODS
    public Response get(string url)
    {
        var response = new Response();
        var getResponse = _client.GetAsync(url).Result;
        var encoding = ASCIIEncoding.ASCII;
        response.statusCode = (int)getResponse.StatusCode;
        if (getResponse.Content != null)
            response.responseText = getResponse.Content.ReadAsStringAsync().Result;
        if (getResponse.Headers != null)
            response.responseHeaders = getResponse.Headers.Select(x => new ResponseHeader() { key = x.Key, value = x.Value.ToArray() }).ToArray();
        return response;
    }
    public async Task<Response> getAsync(string url)
    {
        var response = new Response();
        var getResponse = await _client.GetAsync(url);
        var encoding = ASCIIEncoding.ASCII;
        response.statusCode = (int)getResponse.StatusCode;
        if (getResponse.Content != null)
            response.responseText = await getResponse.Content.ReadAsStringAsync();
        if (getResponse.Headers != null)
            response.responseHeaders = getResponse.Headers.Select(x => new ResponseHeader() { key = x.Key, value = x.Value.ToArray() }).ToArray();
        return response;
    }
}
public class Response
{
    public string? responseText;
    public ResponseHeader[]? responseHeaders;
    public int? statusCode;
}
public class ResponseHeader
{
    public string? key;
    public string[]? value;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С вашим образцом есть две проблемы.

Во-первых, чтобы разрешить коду JavaScript выполнять задачи await .NET желаемым образом, используйте V8ScriptEngineFlags.EnableTaskPromiseConversion.

Во-вторых, вам необходимо await код JavaScript так же, как и await метод .NET async. В противном случае вы просто запускаете операцию и возобновляете Index выполнение до ее завершения.

Вот рабочий Index:

public async Task<IActionResult> Index() {
    var hostVariables = new HostVariables();
    using var engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableTaskPromiseConversion);
    using var client = new HttpClient();
    var request = new Request(client);
    engine.AddHostObject("hostVariables", hostVariables);
    engine.AddHostObject("request", request);
    await (Task)engine.Evaluate(new DocumentInfo() { Category = ModuleCategory.Standard }, @"
        hostVariables.syncResponse = request.get(""https://www.google.com"").responseText;
        hostVariables.asyncResponse = (await request.getAsync(""https://www.google.com"")).responseText;
    ");
    return Content(hostVariables.asyncResponse);
}

Кстати, если вам нужно повторно выполнить код JavaScript, вы можете обернуть его в функцию async вместо модуля:

dynamic func = engine.Evaluate(@"(async function () {
    hostVariables.syncResponse = request.get(""https://www.google.com"").responseText;
    hostVariables.asyncResponse = (await request.getAsync(""https://www.google.com"")).responseText;
})");
await func();

Обратите внимание, что func становится недействительным, когда engine удаляется.

Спасибо за это @BitCortex. Это именно то, что мне было нужно. Это ново для меня.

Matt Spinks 27.08.2024 04:14

Еще один вопрос @BitCortext: есть ли причина, по которой вы используете «engine.Evaluate» вместо «engine.Execute»?

Matt Spinks 27.08.2024 04:15

Другие вопросы по теме