当前位置:网站首页>Dotnet replaces asp Net core's underlying communication is the IPC Library of named pipes
Dotnet replaces asp Net core's underlying communication is the IPC Library of named pipes
2022-07-06 11:02:00 【Dotnet cross platform】
This is a program for native multiprocessing IPC The library of Communications , Top level of this library API Is to use ASP.NET Core Of MVC frame , Its bottom communication is not the traditional way of network , But through dotnetCampus.Ipc Open source projects provide services based on NamedPipeStream Communicate by naming pipes . It is equivalent to replacing ASP.NET Core Bottom communication mode , Change from network to named pipeline . The advantage of this library is that it can be used with very good design ASP.NET Core Of MVC The framework is called as the top level API layer , The bottom communication adopts named pipes that can improve transmission performance , In this way, network communication can be avoided, which greatly reduces the problem of network port occupation and the problem caused by the user's network environment
background
Multi process communication in the machine IPC Different from cross device systems RPC Communication mode , Most of the IPC Communication needs to deal with complex client environment problems . about RPC For communications , Most of the time , The server runs under the full control of the developer . but IPC Communication, whether server or client, may run on the client . However, on the client side , Both the system and other environments are very complex , Especially at home , Magic changed system , Ferocious anti-virus software , These will make IPC Communication was unexpectedly interrupted
Conventional dotnet Systematic IPC There are many means , There are also many top-level frameworks for development , Such as .NET Remoting and WCF etc. . But in moving to dotnet core when , Due to the change of the underlying runtime mechanism , For example, transparent proxy no longer supports class objects, but only supports interface behavior changes , let .NET Remoting From the mechanism is not supported . To facilitate the migration of applications to dotnet core On the frame , May adopt dotnet campus The organization is based on the friendliest MIT Protocol open source dotnetCampus.Ipc Open source library for multi process communication in the machine
this dotnetCampus.Ipc The bottom layer of the open source library can communicate based on named pipes , After about 600 Nearly half a year's testing of 10000 devices , It is found that the communication stability in this way is very high . Open source warehouse address :https://github.com/dotnet-campus/dotnetCampus.Ipc
Whether it's RPC still IPC Communications , Its top level is provided for developers API layer , There are two design camps in the mainstream . One is like .NET Remoting The same way to transfer class objects , This method can greatly hide RPC or IPC The details of the , The object that calls the remote process is the same as calling the native process . The other camp is the protagonist of this article , Such as ASP.NET Core Of MVC Pattern , Pass through route with parameters , Mode for controller processing , The excellent design of this method has been ASP.NET Core Proved , This article will not say more
By default , So wonderful ASP.NET Core Of MVC Layer framework is a way that only provides network transmission . However, in the weird client environment , There will be endless network communication problems , If the port is occupied , Special software prevents internet access and so on . Give Way ASP.NET Core From the way of Internet , Replace with the way of naming pipes , It can greatly improve the stability of the client
Praise again ASP.NET Core Excellent design , stay ASP.NET Core in , Each module is clearly layered , This also makes replacement ASP.NET Core Inside “ Communication transmission ”( Actually, the original intention is IServer layer ) This job is very simple
When using ASP.NET Core As IPC When the top-level call of , The way of communication at this time must be Server side - client In the form of . The server can be replaced ASP.NET Core Of “ Communication transmission ” by dotnetCampus.Ipc Named pipeline based transmission . The client ? Yes ASP.NET Core Come on , The most expected behavior of the client is through HttpClient To initiate the call . just dotnet The default under HttpClient It supports the injection of specific message transmission implementation , By way of dotnetCampus.Ipc Encapsulated in the HttpClient Message transmission for HttpMessageHandler You can let the client go dotnetCampus.Ipc The transmission of . So encapsulated , Equivalent to the Server and client The underlying transport , All in dotnetCampus.Ipc Intralaminar , The layering diagram is as follows , adopt dotnetCampus.Ipc Maintain stable transmission to hide specific IPC details , The business side can completely reuse the original knowledge , There is no need to introduce extra IPC knowledge
act as IPC The business code of the server and the client in the will be compared with ASP.NET Core and HttpClient docking . and ASP.NET Core and HttpClient And dotnetCampus.Ipc Layer docking , All the cross process communication logic is dotnetCampus.Ipc Completed in this floor , from dotnetCampus.Ipc The layer remains stable IPC transmission . Let's see how to use this method to develop applications
Usage method
The next step is to use PipeMvcServerDemo and PipeMvcClientDemo These two example projects demonstrate how to use ASP.NET Core Of MVC Layer frame plus named pipe NamedPipeStream Do cross process communication of multiple processes in the machine for communication transmission IPC The way
By convention , stay dotnet Before using the library on the application of the system , Through the first NuGet Installation . In terms of business, it is artificially divided into two projects: service side and business side , Installed separately for the server dotnetCampus.Ipc.PipeMvcServer library , And for clients dotnetCampus.Ipc.PipeMvcClient library
New PipeMvcServerDemo and PipeMvcClientDemo These two are based on .NET 6 All the example projects are based on WPF Project template creation , In terms of business, the two projects, which are artificially divided into service side and business side, are actually running in the same computer , Just for the convenience of narration , Forced the PipeMvcServerDemo It is called a server project , take PipeMvcClientDemo Called client project
Server side
First from PipeMvcServerDemo The server project starts to write , Upon completion of installation dotnetCampus.Ipc.PipeMvcServer After the library , In order to use ASP.NET Core Of MVC frame , It needs to be here WPF Initialize in the application ASP.NET Core frame
Initialization logic , And pure on the server ASP.NET Core There is only a little difference between service applications , That is, during initialization , Need to call UsePipeIpcServer Extension method , Inject IPC Replace the default ASP.NET Core Of “ Communication transmission ”(IServer) layer . The code is as follows
using dotnetCampus.Ipc.PipeMvcServer;
private static void RunMvc(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// The following sentence is the key logic
builder.WebHost.UsePipeIpcServer("PipeMvcServerDemo");
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
}
call UsePipeIpcServer Extension method , Need to add using dotnetCampus.Ipc.PipeMvcServer;
Namespace . stay UsePipeIpcServer Method needs to pass in a parameter , This parameter is used to turn on IPC The service name used by the service , That is, the name of the named pipe . The string of the service name must be unique and not repeated on the current machine , It is recommended to adopt the naming method of attributes to name them . thereafter , The code of the client can use this service name to connect to the server
Just add UsePipeIpcServer The extension method can complete the service side IPC All configurations of
client
After completing the configuration of the server , You can start the configuration logic of the client , The client only needs to know the service name of the server , That is, as in the above example "PipeMvcServerDemo"
character string , You can establish communication with the server . In the design of this library , It can be considered that the service name of the server is different from the traditional C/S The server address of the end application is the same , At least you need to know the address of the server to connect
In any code on the client , May adopt IpcPipeMvcClientProvider Provided CreateIpcMvcClientAsync Static method passes in the service name , Get one that can communicate with the server HttpClient object , As the following code
using dotnetCampus.Ipc.PipeMvcClient;
HttpClient ipcPipeMvcClient = await IpcPipeMvcClientProvider.CreateIpcMvcClientAsync("PipeMvcServerDemo");
I got the above code ipcPipeMvcClient
Objects can be the same as traditional logic , Carry out the request logic of the server , The example shown in the following article . You can see the configuration logic of the client , Only during initialization , obtain HttpClient The logic is different
As the code demonstrated above , You can see , Whether it's the client or the server , The initialization code is all in one sentence , There is not much detail logic , Convenient start
call
Now let's start to demonstrate the examples of server and client invocation . To enable the client to call the corresponding service content of the client , You need to create the corresponding service logic on the server first . The following will demonstrate GET and POST Method and the corresponding route and parameter call method
On the server PipeMvcServerDemo Add a FooController controller , The code is as follows
[Route("api/[controller]")]
[ApiController]
public class FooController : ControllerBase
{
public FooController(ILogger<FooController> logger)
{
Logger = logger;
}
public ILogger<FooController> Logger { get; }
}
stay FooController add to Get Method , The code is as follows
[HttpGet]
public IActionResult Get()
{
Logger.LogInformation("FooController_Get");
return Ok(DateTime.Now.ToString());
}
according to ASP.NET Core Knowledge of routing , It can be passed on the client api/Foo
Access the above Get Method . Next, write the logic of the client , First on the client XAML Add buttons on the interface , The code is as follows
<Button x:Name="GetFooButton" Margin="10,10,10,10" Click="GetFooButton_Click">Get</Button>
stay GetFooButton_Click
Method inside , Use what you get in advance HttpClient To communicate , The code is as follows
using System.Net.Http;
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Log($"Start create PipeMvcClient.");
var ipcPipeMvcClient = await IpcPipeMvcClientProvider.CreateIpcMvcClientAsync("PipeMvcServerDemo");
_ipcPipeMvcClient = ipcPipeMvcClient;
Log($"Finish create PipeMvcClient.");
}
private HttpClient? _ipcPipeMvcClient;
private async void GetFooButton_Click(object sender, RoutedEventArgs e)
{
if (_ipcPipeMvcClient is null)
{
return;
}
Log($"[Request][Get] IpcPipeMvcServer://api/Foo");
var response = await _ipcPipeMvcClient.GetStringAsync("api/Foo");
Log($"[Response][Get] IpcPipeMvcServer://api/Foo {response}");
}
The above Log Method will output the log to the interface TextBlock Control
The above code passes await _ipcPipeMvcClient.GetStringAsync("api/Foo");
Access to the server Get Method , The operation effect is as follows
As can be seen above , The client successfully called the server , Get the return value from the server
The next example is in GET Request with parameters , Such as realizing the function of remote calling computing services , Send two on the client int Count the value added to the server for calculation . The code of the server is as follows
public class FooController : ControllerBase
{
[HttpGet("Add")]
public IActionResult Add(int a, int b)
{
Logger.LogInformation($"FooController_Add a={a};b={b}");
return Ok(a + b);
}
}
The client is in XAML The code of the corresponding button added to the interface is omitted , The calling method code in the button event is as follows
private async void GetFooWithArgumentButton_Click(object sender, RoutedEventArgs e)
{
Log($"[Request][Get] IpcPipeMvcServer://api/Foo/Add");
var response = await _ipcPipeMvcClient.GetStringAsync("api/Foo/Add?a=1&b=1");
Log($"[Response][Get] IpcPipeMvcServer://api/Foo/Add {response}");
}
The operation effect is as follows
You can see that the client successfully called the server to perform the calculation , Got the return value
From the above example, we can see , Even if the bottom layer is replaced with IPC Communications , For the upper business code , Call the logic of the server , There is still no new IPC knowledge , All right. HttpClient Call to
Next is POST Called code , The service side in FooController On the class to add Post Method , add HttpPostAttribute characteristic , The code is as follows
[HttpPost]
public IActionResult Post()
{
Logger.LogInformation("FooController_Post");
return Ok($"POST {DateTime.Now}");
}
Client writing PostFooButton Button , Add the following code to the button click event to request the server
private async void PostFooButton_Click(object sender, RoutedEventArgs e)
{
Log($"[Request][Post] IpcPipeMvcServer://api/Foo");
var response = await _ipcPipeMvcClient.PostAsync("api/Foo", new StringContent(""));
var m = await response.Content.ReadAsStringAsync();
Log($"[Response][Post] IpcPipeMvcServer://api/Foo {response.StatusCode} {m}");
}
The operation effect is shown below
As shown in the figure above, you can see the successful adoption of the client POST Method requests to the server
Next, we will use POST Method requests the server with parameters , The server handles the parameters requested by the client and executes the actual business logic , The code of the server is still on FooController In class
[HttpPost("PostFoo")]
public IActionResult PostFooContent(FooContent foo)
{
Logger.LogInformation($"FooController_PostFooContent Foo1={foo.Foo1};Foo2={foo.Foo2 ?? "<NULL>"}");
return Ok($"PostFooContent Foo1={foo.Foo1};Foo2={foo.Foo2 ?? "<NULL>"}");
}
The above code adopts FooContent As a parameter , The types are defined as follows
public class FooContent
{
public string? Foo1 { set; get; }
public string? Foo2 { set; get; }
}
The client code is as follows , In order to give more details , I will not use PostAsJsonAsync Method , It's created first FooContent object , take FooContent Object serialization to json character string , Again POST request
private async void PostFooWithArgumentButton_Click(object sender, RoutedEventArgs e)
{
Log($"[Request][Post] IpcPipeMvcServer://api/Foo");
var json = JsonSerializer.Serialize(new FooContent
{
Foo1 = "Foo PostFooWithArgumentButton",
Foo2 = null,
});
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _ipcPipeMvcClient.PostAsync("api/Foo/PostFoo", content);
var m = await response.Content.ReadAsStringAsync();
Log($"[Response][Post] IpcPipeMvcServer://api/Foo/PostFoo {response.StatusCode} {m}");
}
The operation effect is shown below
Pictured above , The client successfully will FooContent Parameters are passed to the server
That's all GET and POST Example , It's almost invisible, plus IPC Front back pair ASP.NET Core The difference between application calls , In addition to requiring the use of specific HttpClient Beyond the object , The other logic is the same . The above example project , You can get it at the end of this article
For example, pay attention to the implementation principle of this library , Please read on
principle
Start from the client side , Used in the client HttpClient Is injected into use IPC Bottom frame communication IpcNamedPipeClientHandler object , this IpcNamedPipeClientHandler Object is an inheritance HttpMessageHandler Object of type
stay IpcNamedPipeClientHandler Rewrote HttpMessageHandler Type of SendAsync Method , It can be used by all HttpClient Sent request , Get into IpcNamedPipeClientHandler The logic of . In this way , The request will be serialized , Pass the request dotnetCampus.Ipc Send to server , Re pass dotnetCampus.Ipc Message request mechanism provided , Wait for the return value of the server for this request . After receiving the return value from the server , Encapsulation becomes HttpResponseMessage Return value , Connect this return value to HttpClient Mechanism framework , To implement the call HttpClient The request sent is through dotnetCampus.Ipc Layer transmission rather than network . Get into dotnetCampus.Ipc Layer is designed as peer layer , For clients , Get into dotnetCampus.Ipc The first floor is to go to ASP.NET Core Of MVC Or other frameworks don't need attention . For clients , Just know to enter dotnetCampus.Ipc The request of the layer , You can wait for requests asynchronously , Detailed logic does not need attention
Here are IpcNamedPipeClientHandler Implementation code
class IpcNamedPipeClientHandler : HttpMessageHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Serialize request message , Prepared by IPC Layer send
var message = HttpMessageSerializer.Serialize(request);
// establish IPC News Tag Content , this Tag Content is only used for debugging and logging
var ipcMessageTag = request.RequestUri?.ToString() ?? request.Method.ToString();
// stay dotnetCampus.Ipc layer , use P2P Model , There is no specific server and client
// however P2P The model can simulate C/S Model , Just let one end (Peer) Serve as a server , The other end can act as a client
// stay dotnetCampus.Ipc garage , use PeerProxy Indicates an end
// The end here represents IPC One end of the , Most of the time, it can be regarded as a process
// Following ServerProxy Is to act as a service end , Will be initialized and created within this framework
// adopt PeerProxy send out IPC request , At this time IPC The request will be PipeMvcServer Handle
// stay PipeMvcServer Inside , Will pass through ASP.NET Core MVC Scheduling at the framework layer , Distribute to the corresponding controller for processing
// After the controller processing is completed , Will be made by MVC The framework layer gives the output of the controller to PipeMvcServer layer
// stay PipeMvcServer After the layer receives the output of the controller , Will pass through IPC frame , Return the output to PipeMvcClient End
// When PipeMvcClient After receiving the output return value , Following await The method will return
var response = await ServerProxy.GetResponseAsync(new IpcMessage(ipcMessageTag, message));
// take IPC The returned message is deserialized as HttpResponseMessage For access to HttpClient frame
return HttpMessageSerializer.DeserializeToResponse(response.Body);
}
private PeerProxy ServerProxy { get; }
// Ignore other codes
}
This is why the client needs to pass IpcPipeMvcClientProvider Of CreateIpcMvcClientAsync Get HttpClient Why . stay CreateIpcMvcClientAsync Method , Not only do you need to create HttpClient object , You also need to try to connect to the server first . Although from HttpClient On the design of , You should connect to the server only when you make a request , But because this is IPC Communications , And to solve IPC Multi process resource competition of initialization logic , The current version is used to obtain HttpClient That is, before making a specific request , Connect server
/// <summary>
/// Call to client MVC Of Ipc Functions of services
/// </summary>
public static class IpcPipeMvcClientProvider
{
/// <summary>
/// Get access to Mvc Of Ipc The object of service
/// </summary>
/// <param name="ipcPipeMvcServerName"> other party Ipc service name </param>
/// <param name="clientIpcProvider"> Optional , Used for Ipc Connected local service . If not, or empty , A new Ipc Connection service </param>
/// <returns></returns>
public static async Task<HttpClient> CreateIpcMvcClientAsync(string ipcPipeMvcServerName, IpcProvider? clientIpcProvider = null)
{
if (clientIpcProvider == null)
{
clientIpcProvider = new IpcProvider();
clientIpcProvider.StartServer();
}
var peer = await clientIpcProvider.GetAndConnectToPeerAsync(ipcPipeMvcServerName);
return new HttpClient(new IpcNamedPipeClientHandler(peer, clientIpcProvider))
{
BaseAddress = new Uri(IpcPipeMvcContext.BaseAddressUrl),
};
}
}
stay dotnetCampus.Ipc Layers are made of P2P It's designed in this way , Therefore, the client also needs to create its own IpcProvider object . The client can optionally pass in the existing IpcProvider Object reuse , as HttpClient Reuse logic . But create IpcProvider The object is very cheap , It won't take much resources , Whether reuse or not has little impact on performance . But it supports incoming IpcProvider It is more convenient for developers to IpcProvider Customization logic , For example, inject your own array pool and logs
The above is the logic of the client . About how to serialize request messages, etc , These are the details , No matter what method is used , You just need to be able to compare requests and responses to binary byte Array can be serialized and deserialized . Please get the source code at the end of this article for details
The logic of the server is relatively complex , On the server side dotnetCampus.Ipc After the layer receives the request from the client , The server will build a virtual access request , This access request will pass Inherit IServer Interface IpcServer object , stay ASP.NET Core Initiate a request within the framework , adopt MVC After processing, the framework layer returns the response to IpcServer Give it to dotnetCampus.Ipc Layer transfer to the client
stay IpcServer Object's startup function , That is to say StartAsync In the function , Will synchronize initialization IpcPipeMvcServerCore object . stay IpcPipeMvcServerCore Object will be initialized and created dotnetCampus.Ipc Layer communication mechanism . The code is as follows
public class IpcServer : IServer
{
public IpcServer(IServiceProvider services, IFeatureCollection featureCollection, IOptions<IpcServerOptions> optionsAccessor)
{
// Ignore code
var ipcCore = Services.GetRequiredService<IpcPipeMvcServerCore>();
IpcPipeMvcServerCore = ipcCore;
}
Task IServer.StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
{
// Ignore code
IpcPipeMvcServerCore.Start();
}
private IpcPipeMvcServerCore IpcPipeMvcServerCore { get; }
// Ignore code
}
and IpcPipeMvcServerCore and IpcServer Objects are calling builder.WebHost.UsePipeIpcServer(xxx);
Injected , As the following code
public static class WebHostBuilderExtensions
{
/// <summary>
/// Enables the <see cref="IpcServer" /> service. Enable named pipes IPC service
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/>.</param>
/// <param name="ipcPipeName"> Set up Ipc The pipeline name of the service </param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public static IWebHostBuilder UsePipeIpcServer(this IWebHostBuilder builder, string ipcPipeName)
{
return builder.ConfigureServices(services =>
{
// Ignore code
services.AddSingleton<IServer, IpcServer>();
services.AddSingleton<IpcPipeMvcServerCore>(s => new IpcPipeMvcServerCore(s, ipcPipeName));
});
}
}
rely on ASP.NET Core The mechanism of , It will start on the host , call IServer Of StartAsync Method . adopt IpcServer Of StartAsync Method start up IpcPipeMvcServerCore The logic of
stay IpcPipeMvcServerCore in , Will initialize IpcProvider service . there IpcProvider Service is dotnetCampus.Ipc The external interface of the provided service , adopt IpcProvider You can talk to dotnetCampus.Ipc Other layers Peer To communicate . The same initialization happens on the client IpcProvider service , adopt ipcPipeName
The pipeline name can associate the client and server
class IpcPipeMvcServerCore
{
public IpcPipeMvcServerCore(IServiceProvider serviceProvider, string? ipcServerName)
{
ipcServerName ??= "IpcPipeMvcServer" + Guid.NewGuid().ToString("N");
IpcServer = new IpcProvider(ipcServerName, new IpcConfiguration()
{
DefaultIpcRequestHandler = new DelegateIpcRequestHandler(async context =>
{
// Core code
})
});
}
public void Start() => IpcServer.StartServer();
public IpcProvider IpcServer { set; get; }
}
stay dotnetCampus.Ipc Layer provides a request response framework , You can pass in DefaultIpcRequestHandler Object is used to receive requests sent by other ends , Return to the other party after processing . The core of the above code is DelegateIpcRequestHandler Processing logic , stay context Read the request information of the client in , Deserialize to HttpRequestMessage object , Enter... Through internal logic ASP.NET Core layer , Re pass MVC The framework gets the return value of the request , Encapsulate the return value as IpcResponseMessageResult Return to the client
IpcServer = new IpcProvider(ipcServerName, new IpcConfiguration()
{
DefaultIpcRequestHandler = new DelegateIpcRequestHandler(async context =>
{
// Deserialize the request to HttpRequestMessage object
// Used to pass in to ASP.NET Core layer
System.Net.Http.HttpRequestMessage? requestMessage = HttpMessageSerializer.DeserializeToRequest(context.IpcBufferMessage.Body);
// Create a virtual request , Enter into ASP.NET Core In frame
var server = (IpcServer) serviceProvider.GetRequiredService<IServer>();
var clientHandler = (ClientHandler) server.CreateHandler();
var response = await clientHandler.SendInnerAsync(requestMessage, CancellationToken.None);
// The returned value obtained is serialized as IpcResponseMessageResult Put in dotnetCampus.Ipc Layer is used to return to the client
var responseByteList = HttpMessageSerializer.Serialize(response);
return new IpcResponseMessageResult(new IpcMessage($"[Response][{requestMessage.Method}] {requestMessage.RequestUri}", responseByteList));
})
});
Create a virtual request , Get into ASP.NET Core The logic in the framework is the most complex part of the server . stay IpcServer Of CreateHandler Method inside , Will be created ClientHandler object . this ClientHandler Objects are used to build virtual requests , It is equivalent to initiating a request in the current process rather than through the network layer , The code is as follows
public class IpcServer : IServer
{
/// <summary>
/// Creates a custom <see cref="HttpMessageHandler" /> for processing HTTP requests/responses with the test server.
/// </summary>
public HttpMessageHandler CreateHandler()
{
// Ignore code
return new ClientHandler(BaseAddress, Application) { AllowSynchronousIO = AllowSynchronousIO, PreserveExecutionContext = PreserveExecutionContext };
}
}
It is also inheritance HttpMessageHandler Of ClientHandler in , Also rewrite the SendInnerAsync Method , This method will be responsible for creating HttpContextBuilder object , from HttpContextBuilder Make specific calls ASP.NET Core Layer logic
public async Task<HttpResponseMessage> SendInnerAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// establish HttpContextBuilder object
var contextBuilder = new HttpContextBuilder(_application, AllowSynchronousIO, PreserveExecutionContext);
var requestContent = request.Content;
if (requestContent != null)
{
// The following is right HttpContextBuilder Initialization logic of
// Read content from the request HttpContent into a pipe in a background task. This will allow the request
// delegate to start before the request HttpContent is complete. A background task allows duplex streaming scenarios.
contextBuilder.SendRequestStream(async writer =>
{
// Ignore initialization logic
});
}
contextBuilder.Configure((context, reader) =>
{
// Ignore initialization logic
});
// Ignore other codes
// Perform the actual call ASP.NET Core Framework logic
var httpContext = await contextBuilder.SendAsync(cancellationToken);
// establish HttpResponseMessage Object is used to return
var response = new HttpResponseMessage();
// The following is right HttpResponseMessage Initialization logic of , from httpContext Get the return value in
response.StatusCode = (HttpStatusCode) httpContext.Response.StatusCode;
response.ReasonPhrase = httpContext.Features.Get<IHttpResponseFeature>()!.ReasonPhrase;
response.RequestMessage = request;
response.Version = request.Version;
response.Content = new StreamContent(httpContext.Response.Body);
// Ignore other codes
return response;
}
stay HttpContextBuilder in , Will be in SendAsync Call in logic ApplicationWrapper Of ProcessRequestAsync Method to call ASP.NET Core Within the framework . there ApplicationWrapper It's right Microsoft.AspNetCore.Hosting.HostingApplication
Encapsulation , Because of this HostingApplication Types are not public . The above types of definition logic , Are existing https://github.com/dotnet/aspnetcore Open source repository code
The request is initiated through the current process rather than through the logic of the network layer , Actually in ASP.NET Core There is a default implementation in the open source repository . That is written for unit testing TestHost Mechanism
stay TestHost In the mechanism , Developers can open it in unit tests ASP.NET Core host , But you don't need to listen to any network ports , All tests on this host have passed TestHost The mechanism enters the simulated request initiation in the process . For business code , Most of the time, you don't need to pay attention to the originator of the request , Therefore, we can use TestHost Easy to test business code , Or test the calling logic on the integration test . Use TestHost You can make unit testing or integration testing do not need to pay attention to network monitoring , Prevent testing wrong Services , Convenient in CI Add test logic
Just the code of this mechanism is also what this library needs , By copying https://github.com/dotnet/aspnetcore About open source warehouse TestHost Mechanism code , Can be used to realize IpcServer The logic of
Also like on IpcServer Of CreateHandler Code comments on functions , This is the original TestHost The code of the corresponding function in
Equivalent to the TestHost Add another layer to the mechanism , This layer is based on dotnetCampus.Ipc Layer for communication , adopt TestHost Layer create virtual request , Get into ASP.NET Core frame
In order to facilitate developers to access , Also to prevent developers from accessing dotnetCampus.Ipc Layer of IpcNamedPipeStreamMvcServer after , Re access TestHost Conflicts in unit testing , This warehouse has changed all from https://github.com/dotnet/aspnetcore About open source warehouse TestHost Namespace of the mechanism code of , Rename the entry calling function and type . Add... To each copy of the file // Copy From: https://github.com/dotnet/aspnetcore
Notes
Code
All the code in this article is in https://github.com/dotnet-campus/dotnetCampus.Ipc In the open source warehouse , Welcome to visit
Reference documents
HttpRequestMessage C# (CSharp) Code example - HotExamples
c# - How to send a Post body in the HttpClient request in Windows Phone 8? - Stack Overflow
HttpRequestOptions Class (System.Net.Http)
c# - Serialize and deserialize HttpRequestMessage objects - Stack Overflow
Byte Rot: Serialising request and response in ASP.NET Web API
Efficient post calls with HttpClient and JSON.NET
c# - NamedPipe with ASP.Net - Stack Overflow
wcf - Using "named pipes" in ASP.NET HttpModule - Stack Overflow
边栏推荐
- CSDN问答标签技能树(五) —— 云原生技能树
- Mysql24 index data structure
- [recommended by bloggers] C WinForm regularly sends email (with source code)
- A brief introduction to the microservice technology stack, the introduction and use of Eureka and ribbon
- Global and Chinese market of operational amplifier 2022-2028: Research Report on technology, participants, trends, market size and share
- Timestamp with implicit default value is deprecated error in MySQL 5.6
- Breadth first search rotten orange
- Postman Interface Association
- MySQL19-Linux下MySQL的安装与使用
- [BMZCTF-pwn] 11-pwn111111
猜你喜欢
MySQL21-用戶與權限管理
CSDN blog summary (I) -- a simple first edition implementation
Valentine's Day is coming, are you still worried about eating dog food? Teach you to make a confession wall hand in hand. Express your love to the person you want
【博主推荐】SSM框架的后台管理系统(附源码)
Windows cannot start the MySQL service (located on the local computer) error 1067 the process terminated unexpectedly
API learning of OpenGL (2002) smooth flat of glsl
[recommended by bloggers] background management system of SSM framework (with source code)
安装numpy问题总结
MySQL22-逻辑架构
Mysql33 multi version concurrency control
随机推荐
MySQL master-slave replication, read-write separation
Mysql25 index creation and design principles
安装numpy问题总结
导入 SQL 时出现 Invalid default value for ‘create_time‘ 报错解决方法
Copy constructor template and copy assignment operator template
Leetcode 461 Hamming distance
【博主推荐】C#生成好看的二维码(附源码)
Moteur de stockage mysql23
Ansible practical Series III_ Task common commands
Mysql33 multi version concurrency control
Deoldify项目问题——OMP:Error#15:Initializing libiomp5md.dll,but found libiomp5md.dll already initialized.
1. Mx6u learning notes (VII): bare metal development (4) -- master frequency and clock configuration
[Li Kou 387] the first unique character in the string
MySQL20-MySQL的数据目录
How to change php INI file supports PDO abstraction layer
@Controller, @service, @repository, @component differences
Why is MySQL still slow to query when indexing is used?
CSDN博文摘要(一) —— 一个简单的初版实现
Kubernetes - problems and Solutions
MySQL21-用户与权限管理