【问题标题】:Intercepting and Delegating requests to a custom object/library拦截和委托对自定义对象/库的请求
【发布时间】:2017-02-06 17:57:50
【问题描述】:

在之前的 question 的基础上,我在 middlewareConfigure 方法中拦截传入请求。

public class Startup: IStartup
{
    public Startup(IHostingEnvironment environment)
    {
        // starting apparatus
    }

    public void Configure(IApplicationBuilder app)
    {
        var self = this;
        app.Run(async (context) =>
        {
             await self.Delegate.Service(context);
        });
    }

    public void output(HttpContext context string output) 
    {
          context.Response.WriteAsync(output);
    }

    // other methods

    public IRouter Delegate { get; set; }
}

处理程序

public class Handler: IRouter
{

    public void Service(HttpContext context)
    {
        // shuttles the context to the other parts of the system
        // for processing data
    }

    public void ServiceResult(HttpContext context, object result) 
    {
        // system calls this method, which is then passed back to Startup object.
        Startup.output(context, result);
    }
}
  1. 启动应该将上下文交给处理程序来处理请求。

  2. Handler 然后分派到系统的另一部分,在该部分中根据 URI 处理请求。处理完成后,其他部分将调用 ServerResult。

  3. 基本上,工作流是Startup 将上下文委托给设备,并且设备将上下文与输出结果一起返回。断开连接,输出将发生在另一个函数/闭包/lambda中,但不是同一个中间件。

我被这个中间件阻止了,它迫使我等待并将其定义为异步,关于如何在 asp.net 核心世界中实现上述内容的任何进一步建议。

P.S. 请求拦截可以在任何地方发生,我不必像我的示例那样在中间件中进行。

P.P.S 一个想法可能是 Startup 可以将 lambda 传递给设备,然后一旦请求完成处理,设备就可以调用该设备。


我的尝试:

启动

public void Configure(IApplicationBuilder app)
{
    var self = this;
    app.Run(async (context) =>
    {
        await self.Handler.Handle(new Request(context, new Task(() => { })));
    });
}

public void Result(Request request)
{
    request.Context.Response.WriteAsync(request.Result); // write the result
    request.Task.Start(); // end waiting for the middleware async
}

处理程序

public Task Handle(Request request)
{
    // delegates to helper objects to process the request
    return request.Task;
}

public void Result(Request request)
{
    // helper objects called this function after populating results
    startup.Result(request);
}

【问题讨论】:

  • 假设中间件不会等待内容,这将如何工作? “处理程序”可以在任何随机时刻返回,在任何可能的时刻写入输出并放置在生成的 HTML 中……或者更糟糕的是,它可能会在响应已经发送时尝试写入。 – 如果你有一个不基于任务的异步机制(使用asyncawait)——无论出于何种原因——那么你需要将它转换为一个以正确使用它。
  • 好的,我看到中间件必须等待,因此可以将 lambda 从 Startup 传递到库,库处理并输出数据,然后最终调用此 lambda 以完成序列。请参阅“使用路由中间件”下的配置方法以获取任何想法。 docs.microsoft.com/en-us/aspnet/core/fundamentals/routing
  • 您似乎误解了 lambda 是什么。他们只是匿名代表。请注意,这 不是 JavaScript,并且没有异步事件循环。 – 是的,您可以传递一个 lambda,它会在一切完成后被调用,但这不会使进程神奇地异步。如果你想要异步,你必须明确地做到这一点。
  • 好的,我正在工作,正在重构处理程序以返回任务,将在我取得进展时编辑我的问题。
  • 所以你的问题是你的 Handler 是同步的,但是 app.Run 需要异步委托?

标签: c# asp.net-core


【解决方案1】:

我并不是说最好这样做,但由于您缺乏经验并完成工作 - 您可以使用TaskCompletionSource

public class Handler {        
    private TaskCompletionSource<string> _tcs;
    public Task<string> Start(HttpContext context) {
        _tcs = new TaskCompletionSource<string>();
        // shuttles the context to the other parts of the system
        // for processing data
        return _tcs.Task;
    }

    private void Complete(string output) {
        if (_tcs == null)
            throw new Exception("Task has not been started yet");
        // system calls this method, which is then passed back to Startup object.
        _tcs.SetResult(output);
    }
}


public void Configure(IApplicationBuilder app) {
    app.Run(async (context) => {
        var output = await new Handler().Start(context);
        await context.Response.WriteAsync(output);
    });
}

【讨论】:

  • 感谢@Evk,处理程序没有返回任何输出/结果,处理程序接受请求然后委托请求然后忘记它。只有稍后 辅助对象调用带有结果和任务的处理程序。基本上它是包装ContextTask 的Request 对象,它们被穿梭,但最终返回到Startup 以输出结果。 Startup 对象然后输出结果并调用 Thread.start 来结束中间件的等待。但是,根据您的经验,我想回顾一下微调的方法。
  • 这就是我在示例中所做的。在 Handler.Start 中,您开始处理并忘记。当结果可用时,您调用 Complete 方法将完成任务。您还可以将 TaskCompletionSource 传递给您的设备,它可以自行调用 SetResult。
  • 好的,让我吸收你的答案,请提供 TaskCompletionSource 的任何文档
  • 谷歌“C# TaskCompletionSource”:)
  • 谢谢,我要去。感谢您的耐心和帮助,最终解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 2021-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多