现代Asp.Net Core应用程序和守护程序之间是否有常见的协作模式?
实际上,目前托管服务并不是很强大。因此,人们通常使用第三方产品。但是,与托管服务和控制器进行通信是可能的。我将使用您的代码作为示例来实现这些目标:
TcpServer
能够从TcpClient
接收两个命令,以便我们可以切换托管服务的状态。
WebServer
的控制器可以通过中介者间接调用TcpServer
的方法,并将其呈现为HTML。
![enter image description here](https://istack.dev59.com/GcKeM.gif)
把控制器和托管服务耦合在一起并不是一个好主意。为了从托管服务中调用方法,我们可以引入一个中介者。中介者只是充当单例服务的服务(因为它将被托管服务引用):
public interface IMediator{
event ExecHandler ExecHandler ;
string Exec1(string status);
string Exec2(int status);
}
public class Mediator: IMediator{
public event ExecHandler ExecHandler ;
public string Exec1(string status)
{
if(this.ExecHandler==null)
return null;
return this.ExecHandler(status);
}
public string Exec2(int status)
{
throw new System.NotImplementedException();
}
}
一个托管服务需要意识到
IMediator
的存在,并以某种方式将其方法暴露给
IMediator
:
public class Netcat : BackgroundService
{
private IMediator Mediator ;
public Netcat(IMediator mediator){
this.Mediator=mediator;
}
public string Hello(string status){
return $"{status}:returned from service";
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
TcpListener listener = new TcpListener(IPAddress.Any, 8899);
listener.Start();
while(!stoppingToken.IsCancellationRequested)
{
}
}
}
为了允许从NetCat的TcpServer控制状态,我使其能够接收来自客户端的两个命令以切换后台服务的状态:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
TcpListener listener = new TcpListener(IPAddress.Any, 8899);
listener.Start();
while(!stoppingToken.IsCancellationRequested)
{
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("a new client connected");
NetworkStream stream = client.GetStream();
while (!stoppingToken.IsCancellationRequested)
{
byte[] data = new byte[1024];
int read = await stream.ReadAsync(data, 0, 1024, stoppingToken);
var cmd= Encoding.UTF8.GetString(data,0,read);
Console.WriteLine($"[+] received : {cmd}");
if(cmd=="attach") {
this.Mediator.ExecHandler+=this.Hello;
Console.WriteLine($"[-] exec : attached");
continue;
}
if(cmd=="detach") {
Console.WriteLine($"[-] exec : detached");
this.Mediator.ExecHandler-=this.Hello;
continue;
}
await stream.WriteAsync(data, 0, read, stoppingToken);
stream.Flush();
}
}
}
如果你想在控制器中调用后台服务的方法,只需注入
IMediator
即可:
public class HomeController : Controller
{
private IMediator Mediator{ get; }
public HomeController(IMediator mediator){
this.Mediator= mediator;
}
public IActionResult About()
{
ViewData["Message"] = this.Mediator.Exec1("hello world from controller")??"nothing from hosted service";
return View();
}
}