首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IHostedService内核中的.NET服务器

IHostedService内核中的.NET服务器
EN

Stack Overflow用户
提问于 2018-09-26 19:13:23
回答 2查看 10.2K关注 0票数 9

我正在尝试构建一个小型的tcp服务器/守护进程,它以asp.net内核为web前端,用于与服务器进行交互。我发现了IHostedService/BackgroundService,它似乎提供了一种将服务器和前端捆绑在一起的低工作量替代方案。

目前,代码基本上是这样的(为了测试目的,回送服务器):

代码语言:javascript
复制
public class Netcat : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8899);
        listener.Start();
        while(!stoppingToken.IsCancellationRequested)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            NetworkStream stream = client.GetStream();

            while (!stoppingToken.IsCancellationRequested)
            {
                byte[] data = new byte[1024];
                int read = await stream.ReadAsync(data, 0, 1024, stoppingToken);

                await stream.WriteAsync(data, 0, read, stoppingToken);
            }
        }
    }
}

并在Startup.cs中初始化如下:

代码语言:javascript
复制
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHostedService<Netcat>();
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

现代Asp.Net核心应用程序和守护进程应该如何协作,是否有一个共同的模式?

如何从Controller与正在运行的服务本身进行交互?

IHostedService甚至可以用于这个目的吗?或者它是一种更好的方法来完全解耦Asp.Net前端和服务/服务器,例如,通过使用某种IPC机制将守护进程和asp.net作为独立进程运行?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-27 09:49:26

现代Asp.Net核心应用程序和守护进程应该如何协作,是否有一个共同的模式?

实际上,目前托管的服务还没有那么强大。所以人们通常使用第三种产品。但是,可以与托管的服务和控制器进行通信。我将以您的代码为例来实现这些目标:

  1. TcpServer能够接收两个命令,这样我们就可以从TcpClient切换托管服务的状态。
  2. WebServer的控制器可以(通过中介)间接调用TcpServer的方法,并将其呈现为html。

将控制器与托管服务结合起来并不是一个好主意。为了从托管服务中调用方法,我们可以引入一个Mediator。中介者不过是一个作为单例的服务(因为它将被宿主服务引用):

代码语言:javascript
复制
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公开他的方法:

代码语言:javascript
复制
public class Netcat : BackgroundService
{
    private IMediator Mediator ;
    public Netcat(IMediator mediator){
        this.Mediator=mediator;
    }

    // method that you want to be invoke from somewhere else
    public string Hello(string status){
        return $"{status}:returned from service";
    }

    // method required by `BackgroundService`
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8899);
        listener.Start();
        while(!stoppingToken.IsCancellationRequested)
        {
            // ...
        }
    }
}

为了允许从NetCat TcpServer控制状态,我使它能够从客户端接收两个命令来切换后台服务的状态:

代码语言:javascript
复制
    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

代码语言:javascript
复制
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();
    }
}
票数 8
EN

Stack Overflow用户

发布于 2018-10-24 09:51:45

我的建议类似于@ is减号

取决于您想要的场景:

  1. 如果您只想从同一个应用程序控制器/页面内部访问该服务:

不要创建TCP侦听器。使用请求的后台队列和处理请求的后台服务,如文档中所解释的那样从代码中调用。

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1#queued-background-tasks

  1. 如果您想通过TCP从其他服务器/客户端等访问服务,以及从托管aspcore应用程序内部访问该服务:

实现单独的处理服务(逻辑服务器),如第1点。您可以注入它并从TCP侦听器后台服务和控制器调用。

  1. 当然,您可以通过HttpClient从同一个应用程序访问自己的服务,但是使用整个TCP堆栈进行内部调用似乎很奇怪。
  2. 如果TCP处理完全独立于web应用程序,则将TCP服务分离为单独的服务器应用程序。关于如何在DotNetCore2.1中创建“纯”服务而不需要asp/kestrel开销,请参见文档
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52524636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档