从ASP .NET Core中的任意URL手动实例化Controller实例

时间:2018-12-21 15:17:26

标签: asp.net-core-mvc

我只想通过使用路径和正文来执行ASP.NET Core(2.1)请求。我正在寻找这样的东西:

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

目前,我实际上是通过在服务器端进行HTTP请求来实现的。我想通过不使用HTTP请求执行代码来以尽可能少的开销实现此目标。我担心不必要的HTTP请求会导致高负载的问题。

2 个答案:

答案 0 :(得分:0)

您要达到什么目标?我真的不明白为什么要这样做,我针对我能想到的用例编写了两个解决方案。

  1. 如果您希望整个请求管道都能正常工作,那么最好的方法就是当前正在执行的操作,即向本地主机发出http请求。但您说对了,它比简单的方法调用需要更多的资源。

  2. 如果您只想在控制器中调用方法(控制器动作),则只需重组逻辑并创建一个可以实例化的类,简单的方法调用即可解决您的问题。

答案 1 :(得分:0)

我在这个问题上苦苦挣扎,终于找到了解决方法,here对此进行了解释,但是它仍然有一个问题我仍在尝试解决。

我正在用/ one和/ two的批量请求调用/ three。因此,我希望在/ three运行之前先运行/ one和/ two,并将/ three的响应返回给客户端。

发生的事情是,当代码到达/ two时,我将收到错误消息“由于已发送,无法修改响应”。因此,/ first请求将响应修改为原始请求(即/ 3),我再也无法编写响应了。

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"; }
}

我试图通过将控制器方法更改为异步Task(因此无需返回)并使用Response.WriteAsync手动编写响应来对此进行反击,但这在AspNet内部代码中的某个地方提供了nullreference异常,我还没有找到原因。

[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(...)