Создание экземпляра Controller вручную с произвольного URL-адреса в ASP .NET Core - PullRequest
0 голосов
/ 21 декабря 2018

Я хочу выполнить запросы ASP.NET Core (2.1), используя только путь и тело.Я ищу что-то вроде этого:

string path = "/controller/method";
string body = "{}";
ExecuteRoute(path, body); // this calls Controller.Method(body)

В настоящее время я достигаю этого, фактически делая HTTP-запросы на стороне сервера.Я хотел бы достичь этого с минимальными накладными расходами, выполняя код без HTTP-запросов.Я обеспокоен тем, что ненужные запросы HTTP могут вызвать проблемы с высокой нагрузкой.

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Я много боролся с этой проблемой и, наконец, нашел решение, которое объясняется здесь , но у него есть одна проблема, которую я все еще пытаюсь решить.

ЯВызов / три с пакетными запросами на / один и / два.Так что я ожидаю запустить / one и / two до / трех запусков и вернуть клиенту ответ / three.

В результате получается, что когда код получит значение / two, я получу ошибку "Невозможно изменитьответ, потому что он уже отправлен.Таким образом, запрос / first изменяет ответ на исходный запрос (т. Е. / Три), и я больше не могу написать ответ.

public class BatchController : Controller
{
    // inject this to controller via constructor
    IHttpContextFactory contextFactory;

    public async override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        IRouteCollection router = RouteData.Routers.OfType<IRouteCollection>().First();

        // run batched requets one by one
        foreach(...)
        {
            HttpContext context = contextFactory.Create(HttpContext.Features);

            // set request data
            context.Request.Path = path;
            context.Request.Body = body;
            context.Request.Headers = headers;

            var routeContext = new RouteContext(context);
            await router.RouteAsync(routeContext); // get route
            await routeContext.Handler.Invoke(context); // call controller
        }

        // continue
        await next();
    }

    [HttpGet("one")] public string One() { return "one"; }
    [HttpGet("two")] public string Two() { return "two"; }
    [HttpGet("three")] public string Three() { return "three"; }
}

Я попытался противостоять этому путем изменения метода контроллера на асинхронную задачу (таквозврат не требуется) и запись ответа вручную с помощью Response.WriteAsync, но это дает исключения нулевой ссылки где-то во внутреннем коде AspNet, и мне еще предстоит выяснить причину.

[16:12:50 ERR] Connection id "0HLJVLA0U0328", Request id "0HLJVLA0U0328:00000001": An unhandled exception was thrown by the application.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter.<>c__DisplayClass3_0.<OnResourceExecuting>b__0(Object state)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnStartingMayAwait(Stack`1 onStarting)
[16:12:50 ERR] An unhandled exception has occurred while executing the request.
System.ObjectDisposedException: The response has been aborted due to an unhandled application exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter.<>c__DisplayClass3_0.<OnResourceExecuting>b__0(Object state)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnStartingMayAwait(Stack`1 onStarting)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAbortedException()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.ResponseCompression.BodyWrapperStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
   at ... await Response.WriteAsync(...)
0 голосов
/ 03 января 2019

Чего ты пытаешься достичь?Я не вижу смысла, почему вы делаете это так, я пишу два решения для вариантов использования, которые я могу придумать.

  1. Если вы хотите, чтобы весь конвейер запросов работаллучший apparoach - это то, что вы сейчас делаете, это отправка http-запроса к localhost.Но вы правы, что это требует больше ресурсов, чем простой вызов метода.

  2. Если вы просто хотите вызвать метод (действие контроллера) в контроллере, то вам просто нужно реорганизовать логикуи создайте класс, который можно создать, и простой вызов метода решит вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...