에서 사용자 지정 서버를 만듭니다.그물심
10209 단어 dotnet
사용자 정의 서버를 만들려면 사용자 정의 서버 클래스가 IServer 인터페이스와 그에 상응하는 방법을 실현해야 합니다.구축할 서버는 포트(127.0.0.1:8091)의 localhost에 연결되어 HTTP 요청을 탐지한 다음 HTTP 요청을 응용 프로그램 요청 파이프의 나머지 부분으로 전송합니다.요청을 처리한 후 상응하는 응답을 보냅니다.
먼저 CustomServerExample이라는 콘솔 응용 프로그램 프로젝트를 만듭니다.
프로그램cs는 응용 프로그램의 주요 입구점입니다. 이렇게 해야 합니다.
class Program
{
static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseCustomServer(o => o.ListeningEndpoint = @"127.0.0.1:8091")
.UseStartup<Startup>()
.Build();
}
UseCustom Server 메서드는 사용자 정의 서버가 구현하는 엔트리 포인트입니다.또한 서버를 통해 HTTP 트래픽의 엔드포인트를 수신합니다.UseCustomer Server 메서드를 정의하는 확장 클래스를 만듭니다.
public static class ServerExtensions
{
public static IWebHostBuilder UseCustomServer(this IWebHostBuilder hostBuilder, Action<CustomServerOptions> options)
{
return hostBuilder.ConfigureServices(services =>
{
services.Configure(options);
services.AddSingleton<IServer, CustomServer>();
});
}
}
위의 확장에서, 우리는 IServer 형식의 단례를 등록하여Custom Server 클래스를 등록하여 응용 프로그램 풀에 주입할 수 있도록 합니다.이 모든 작업이 완료되면 이제 Custom Server를 구축할 수 있습니다.
IServer 인터페이스에는 다음과 같은 설명이 있습니다.
//
// Summary:
// Represents a server.
public interface IServer : IDisposable
{
//
// Summary:
// A collection of HTTP features of the server.
IFeatureCollection Features { get; }
//
// Summary:
// Start the server with an application.
//
// Parameters:
// application:
// An instance of Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1.
//
// cancellationToken:
// Indicates if the server startup should be aborted.
//
// Type parameters:
// TContext:
// The context associated with the application.
Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken);
//
// Summary:
// Stop processing requests and shut down the server, gracefully if possible.
//
// Parameters:
// cancellationToken:
// Indicates if the graceful shutdown should be aborted.
Task StopAsync(CancellationToken cancellationToken);
}
Features 속성에는 이 서버에 필요한 HTTP 기능과 StartAsync 및 StopAsync 메서드가 포함되어 있습니다.전자는 서버가 필요한 응용 프로그램의 상하문을 시작할 때 호출되고, 후자는 서버가 정상적으로 닫힐 때 호출된다.Custom Server 클래스는 앞에서 설명한 ServerExtension에서 IServer 유형으로 등록되어 있기 때문에 클래스에서 인터페이스의 모든 서명을 실현합니다.Custom Server는 다음과 같습니다.
public class CustomServer : IServer
{
public CustomServer(IOptions<CustomServerOptions> options)
{
Features.Set<IHttpRequestFeature>(new HttpRequestFeature());
Features.Set<IHttpResponseFeature>(new HttpResponseFeature());
var serverAddressesFeature = new ServerAddressesFeature();
serverAddressesFeature.Addresses.Add(options.Value.ListeningEndpoint);
Features.Set<IServerAddressesFeature>(serverAddressesFeature);
}
public IFeatureCollection Features { get; } = new FeatureCollection();
public void Dispose() { }
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
{
return Task.Run(() =>
{
var listener = new CustomHTTPListener<TContext>(application, Features);
listener.Listen();
});
}
...
}
구조 함수에서, 우리는 요청과 응답 설정 기능을 가지고 있으며, ServerAddresses Feature의 새로운 실례를 시작하여, 주입된 IOOptions에 탐지 단점을 추가한 다음, 이 기능을 IFeature Collection에 추가합니다.Custom Server에는 HTTP 요청과 응답을 처리할 수 있는 서버 스누핑 주소가 있습니다.이제 StartAsync로 이동합니다.
서버가 시작되면 CustomHTTPlistener의 새 인스턴스가 만들어지고 HTTP 요청이 수신됩니다.CustomHTTPlistener의 컨텐트
public class CustomHTTPListener<TContext>
{
private IHttpApplication<TContext> application;
private IFeatureCollection features;
private string uri;
private HttpListener listener;
public CustomHTTPListener(IHttpApplication<TContext> application, IFeatureCollection features)
{
this.application = application;
this.features = features;
uri = features.Get<IServerAddressesFeature>().Addresses.FirstOrDefault();
listener = new HttpListener();
listener.Prefixes.Add(uri);
}
public void Listen()
{
while (true)
{
if (listener.IsListening) return;
ThreadPool.QueueUserWorkItem(async (_) =>
{
listener.Start();
HttpListenerContext ctx = listener.GetContext();
var context = (HostingApplication.Context)(object)application.CreateContext(features);
context.HttpContext = new CustomHttpContext(features, ctx);
await application.ProcessRequestAsync((TContext)(object)context);
context.HttpContext.Response.OnCompleted(null, null);
//listener.Stop();
});
}
}
}
탐지기 구조 함수는 IHTTP 응용 프로그램 Listen 방법에서while 순환에서 탐지기가 탐지 중이면 교체를 종료합니다.우리는 탐청 관리를 돕기 위해 스레드 탱크에 의뢰를 추가했다.그리고 탐지기를 시작하여 탐지기의 상하문을 가져오고 그 기능과 응용 프로그램 기능을 CustomHttpContext에 전달합니다. CustomHttpContext는 HttpRequest와 HttpResponse의 파생을 현재 응용 프로그램 상하문에 주입하기 위한 것입니다.
다음은 out CustomHttpContext의 모양입니다.
public class CustomHttpContext : HttpContext
{
private IFeatureCollection features;
private HttpListenerContext ctx;
private readonly HttpRequest request;
private readonly HttpResponse response;
public CustomHttpContext(IFeatureCollection features, HttpListenerContext ctx)
{
this.Features = features;
Request = new CustomHttpRequest(this, ctx);
Response = new CustomHttpResponse(this, ctx);
}
public override IFeatureCollection Features { get; }
public override HttpRequest Request { get; }
public override HttpResponse Response { get; }
.....
CustomHttpContext는 추상 클래스 HttpContext를 상속합니다. 기본 방법을 실행하고 있습니다.구조 함수에서 CustomHttpRequest와 CustomHttpResponse를 사용하여 각각 요청과 응답 속성에 계승과 재쓰기를 할당합니다.
CustomHttpRequest를 보십시오. 방법과 경로 속성을 설정했습니다. 이 두 속성은 모두 프로그램 파이프라인에서 경로를 정확하게 요청하는 데 필요한 것입니다.
public class CustomHttpRequest : HttpRequest
{
private CustomHttpContext customHttpContext;
public CustomHttpRequest(CustomHttpContext customHttpContext, HttpListenerContext ctx)
{
this.customHttpContext = customHttpContext;
Method = ctx.Request.HttpMethod;
Path = ctx.Request.RawUrl;
}
public override string Method { get; set; }
public override string Scheme { get; set; }
public override bool IsHttps { get; set; }
public override HostString Host { get; set; }
....
다음 CustomHttpResponse에서는 완료되지 않은 메서드를 트리거하고 응답 바디를 읽고 HttpListener 응답 흐름에 추가합니다....
public override Stream Body { get; set; } = new MemoryStream();
public override void OnCompleted(Func<object, Task> callback, object state)
{
if (!Body.CanRead) return;
using (var reader = new StreamReader(Body))
{
HttpListenerResponse response = ctx.Response;
Body.Position = 0;
var text = reader.ReadToEnd();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(text);
response.ContentLength64 = Body.Length;
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Body.Flush();
Body.Dispose();
}
}
...
이 모든 일이 끝난 후에도 우리는 여전히 관건적인 노선 처리 부분이 부족하다.그래서 우리는 초창기 회사를 창립할 것이다.프로그램 파이프에 리셋을 추가합니다. 이것은 루트를 처리하는 데 도움을 줄 것입니다. public void Configure(IApplicationBuilder app)
{
app.MapWhen(c => c.Request.Path == "/foo/bar", config =>
{
config.Run(async (context) =>
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync("This is Foo Bar!");
});
})
.Run(async (context) =>
{
context.Response.StatusCode = 404;
await context.Response.WriteAsync("Not Found");
});
}
이것만 있으면 우리 서버는 운행할 수 있다.우리의 코드를 실행하려면 터미널에서 이런 것이 나오는 것을 보아야 한다.자신의 서버를 기본 서버로 설정할 필요는 없습니다.netcore 기능이 강하고 웹api는 루트, HTTP 요청, 응답 처리 등 기능을 추상화하고 유도합니다.이 글은 엔진 뚜껑 아래에서 발생하는 일을 이해하는 데 도움을 주는 데 목적을 두고 있다.
온전한 코드 라이브러리는 이곳에서 찾을 수 있다https://github.com/omoabobade/CustomServer
Reference
이 문제에 관하여(에서 사용자 지정 서버를 만듭니다.그물심), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/omoabobade/creating-custom-server-in-net-core-3fp2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)