กรอบการทำงานสำหรับการสร้างและใช้บริการข้ามแพลตฟอร์มใน .Net Standard
ข้ามแพลตฟอร์ม ดูเพล็กซ์ ปรับขนาดได้ กำหนดค่าได้ และขยายได้
Xeeny เป็นเฟรมเวิร์กสำหรับการสร้างและใช้บริการบนอุปกรณ์และเซิร์ฟเวอร์ที่รองรับมาตรฐาน .net
ด้วย Xeeny คุณสามารถโฮสต์และใช้บริการได้ทุกที่ที่มาตรฐาน .net สามารถทำงานได้ (เช่น Xamarin android, Windows Server, ...) เป็น Cross Platform, Duplex, Multiple Transports, Asynchronous, Typed Proxies, กำหนดค่าได้ และขยายได้
Install-Package Xeeny
For extensions:
Install-Package Xeeny.Http
Install-Package Xeeny.Extentions.Loggers
Install-Package Xeeny.Serialization.JsonSerializer
Install-Package Xeeny.Serialization.ProtobufSerializer
คุณสมบัติปัจจุบัน:
กำลังมา:
public interface IService
{
Task < string > Echo ( string message ) ;
}
public class Service : IService
{
public Task < string > Echo ( string message )
{
return Task . FromResult ( message ) ;
}
}
ServiceHost
โดยใช้ ServiceHostBuilder<TService>
โดยที่การใช้งานบริการAddXXXServer
var tcpAddress = "tcp://myhost:9999/myservice" ;
var httpAddress = "http://myhost/myservice" ;
var host = new ServiceHostBuilder < Service > ( InstanceMode . PerCall )
. AddTcpServer ( tcpAddress )
. AddWebSocketServer ( httpAddress ) ;
await host . Open ( ) ;
ConnctionBuilder<T>
var tcpAddress = "tcp://myhost/myservice" ;
var client = await new ConnectionBuilder < IService > ( )
. WithTcpTransport ( tcpAddress )
. CreateConnection ( ) ;
var msg = await client . Echo ( "Hellow World!" ) ;
public interface ICallback
{
Task OnCallback ( string serverMessage ) ;
}
OperationContext.Current.GetCallback<T>
public Service : IService
{
public Task < string > Join ( string name )
{
CallBackAfter ( TimeSpan . FromSeconds ( 3 ) ) ;
return Task . FromResult ( "You joined" ) ;
}
async void CallBackAfter ( TimeSpan delay )
{
var client = OperationContext . Current . GetCallback < ICallback > ( ) ;
await Task . Delay ( ( int ) delay . TotalMilliseconds ) ;
await client . OnCallBack ( "This is a server callback" ) ;
}
}
WithCallback<T>
กับตัวสร้าง var host = new ServiceHostBuilder < Service > ( InstanceMode . Single )
. WithCallback < ICallback > ( )
. AddTcpServer ( address )
. CreateHost ( ) ;
await host . Open ( ) ;
public class Callback : ICallback
{
public void OnServerUpdates ( string msg )
{
Console . WriteLine ( $ "Received callback msg: { msg } " ) ;
}
}
DuplexConnectionBuilder
เพื่อสร้างไคลเอ็นต์ duplex โปรดทราบว่าเป็นคลาสทั่วไป อาร์กิวเมนต์ทั่วไปตัวแรกคือสัญญาบริการ ในขณะที่อีกอันคือการใช้งานการโทรกลับไม่ใช่อินเทอร์เฟซสัญญา ดังนั้นตัวสร้างจึงรู้ว่าจะสร้างอินสแตนซ์ประเภทใดเมื่อคำขอโทรกลับ ได้รับ. var address = "tcp://myhost/myservice" ;
var client = await new DuplexConnectionBuilder < IService , Callback > ( InstanceMode . Single )
. WithTcpTransport ( address )
. CreateConnection ( ) ;
await client . Join ( "My Name" ) ;
Xeeny กำหนดสามโหมดสำหรับการสร้างอินสแตนซ์บริการ
คุณกำหนดโหมดอินสแตนซ์บริการโดยใช้ InstanceMode
enum เมื่อสร้าง ServiceHost
var host = new ServiceHostBuilder < Service > ( InstanceMode . PerCall )
.. .
. CreateHost ( ) ;
await host . Open ( ) ;
เมื่อคุณสร้างการเชื่อมต่อแบบดูเพล็กซ์ คุณจะส่งประเภทการโทรกลับและ InstanceMode ไปยัง DuplexConnectionBuilder
InstanceMode
ทำหน้าที่ในลักษณะเดียวกันกับบริการเมื่อสร้าง ServiceHost
ServiceHostBuilder
มีโอเวอร์โหลดหนึ่งตัวที่รับอินสแตนซ์ของประเภทบริการ ซึ่งช่วยให้คุณสร้างอินสแตนซ์และส่งต่อไปยังตัวสร้าง ผลลัพธ์คือ InstanceMode.Single
โดยใช้อ็อบเจ็กต์ที่คุณส่งผ่านServiceHostBuilder
DuplextConnectionBuilder
รับอินสแตนซ์ของประเภทการโทรกลับเพื่อให้คุณสามารถสร้างซิงเกิลตันได้ด้วยตัวเองPerCall
และ PerConnection
ถูกสร้างขึ้นโดยเฟรมเวิร์ก คุณยังคงสามารถเริ่มต้นอินสแตนซ์เหล่านั้นได้หลังจากถูกสร้างขึ้นและก่อนที่จะดำเนินการวิธีการใดๆ โดยการฟังเหตุการณ์: ServiceHost<TService>.ServiceInstanceCreated
event และ DuplextConnectionBuilder<TContract, TCallback>.CallbackInstanceCreated
host . ServiceInstanceCreated += service =>
{
service . MyProperty = "Something" ;
}
.. .
var builder = new DuplexConnectionBuilder < IService , Callback > ( InstanceMode . PerConnection )
. WithTcpTransport ( tcpAddress ) ;
builder . CallbackInstanceCreated += callback =>
{
callback .. .
}
var client = builder . CreateConnection ( ) ;
Operation
ที่ส่งผ่าน IsOneWay = true ในสัญญา (อินเทอร์เฟซ) public interface IService
{
[ Operation ( IsOneWay = true ) ]
void FireAndForget ( string message ) ;
}
เมื่อคุณมีเมธอดโอเวอร์โหลดในอินเทอร์เฟซเดียว (หรือลายเซ็นเมธอดที่คล้ายกันในอินเทอร์เฟซหลัก) คุณต้องแยกแยะเมธอดเหล่านั้นโดยใช้แอตทริบิวต์ Operation
โดยการตั้งค่าคุณสมบัติ Name
สิ่งนี้ใช้กับทั้งสัญญาบริการและสัญญาติดต่อกลับ
public interface IOtherService
{
[ Operation ( Name = "AnotherEcho" ) ]
Task < string > Echo ( string message ) ;
}
public interface IService : IOhterService
{
Task < string > Echo ( string message ) ;
}
class Service : IService , IOtherService
{
public Task < string > Echo ( string message )
{
return Task . FromResult ( $ "Echo: { message } " ) ;
}
Task < string > IOtherService . Echo ( string message )
{
return Task . FromResult ( $ "This is the other Echo: { message } " ) ;
}
}
คุณจะต้องเข้าถึงการเชื่อมต่อพื้นฐานเพื่อจัดการ เช่น การตรวจสอบสถานะ ฟังเหตุการณ์ หรือจัดการด้วยตนเอง (ปิดหรือเปิด) การเชื่อมต่อถูกเปิดเผยผ่านอินเทอร์เฟซ IConnection
ซึ่งมีฟังก์ชันการทำงานเหล่านี้:
State
: สถานะการเชื่อมต่อ: Connecting
, Connected
, Closing
, Closed
StateChanged
: เหตุการณ์เกิดขึ้นเมื่อสถานะการเชื่อมต่อเปลี่ยนแปลงConnect()
: เชื่อมต่อกับที่อยู่ระยะไกลClose()
: ปิดการเชื่อมต่อSessionEnded
: เหตุการณ์เกิดขึ้นเมื่อการเชื่อมต่อกำลังปิด ( State
เปลี่ยนเป็นการ Closing
)Dispose()
: กำจัดการเชื่อมต่อConnectionId
: Guid ระบุการเชื่อมต่อแต่ละรายการ (สำหรับตอนนี้ Id บนเซิร์ฟเวอร์และไคลเอนต์ไม่ตรงกัน)ConnectionName
: ชื่อการเชื่อมต่อที่เป็นมิตรเพื่อการดีบักและการวิเคราะห์บันทึกที่ง่ายขึ้นOperationContext.Current.GetConnection()
ที่จุดเริ่มต้นของวิธีการของคุณและก่อนที่วิธีการบริการจะสร้างเธรดใหม่OperationContext.Current.GetConnection()
แต่ส่วนใหญ่แล้วจะเกิดจากการเรียก OperationContext.Current.GetCallback<TCallback>
อินสแตนซ์ที่ส่งคืนคืออินสแตนซ์ที่ปล่อยออกมาขณะรันไทม์และใช้สัญญาการโทรกลับของคุณ (กำหนดไว้ในพารามิเตอร์ทั่วไป TCallback
) ประเภทที่สร้างขึ้นอัตโนมัตินี้ใช้ IConnection
เช่นกัน ดังนั้นเมื่อใดก็ตามที่คุณต้องการเข้าถึงฟังก์ชันการเชื่อมต่อของช่องทาง challback เพียงแค่ส่งไปที่ IConnection
public class ChatService : IChatService
{
ConcurrentDictionary < string , ICallback > _clients = new ConcurrentDictionary < string , ICallback > ( ) ;
ICallback GetCaller ( ) => OperationContext . Current . GetCallback < ICallback > ( ) ;
public void Join ( string id )
{
var caller = GetCaller ( ) ;
_clients . AddOrUpdate ( id , caller , ( k , v ) => caller ) ;
( ( IConnection ) caller ) . SessionEnded += s =>
{
_clients . TryRemove ( id , out ICallback _ ) ;
} ;
}
}
ไคลเอนต์คืออินสแตนซ์ของประเภทที่สร้างขึ้นอัตโนมัติซึ่งจะถูกส่งออกมาที่รันไทม์และใช้อินเทอร์เฟซสัญญาบริการของคุณ เมื่อรวมกับสัญญาแล้วประเภทที่ปล่อยออกมาจะใช้ IConnection
ซึ่งหมายความว่าคุณสามารถส่งไคลเอนต์ใด ๆ (ดูเพล็กซ์หรือไม่ก็ได้) ไปยัง IConnection
var client = await new ConnectionBuilder < IService > ( )
. WithTcpTransport ( address )
. CreateConnection ( ) ;
var connection = ( IConnection ) client ;
connection . StateChanged += c => Console . WriteLine ( c . State ) ;
connection . Close ( )
CreateConnection
รับพารามิเตอร์ทางเลือกหนึ่งประเภทบูลีนซึ่งเป็น true
ตามค่าเริ่มต้น การตั้งค่าสถานะนี้ระบุว่าการเชื่อมต่อที่สร้างขึ้นจะเชื่อมต่อกับเซิร์ฟเวอร์หรือไม่ โดยค่าเริ่มต้นทุกครั้งที่เรียกว่า CreateConnection
การเชื่อมต่อที่สร้างขึ้นจะเชื่อมต่อโดยอัตโนมัติ บางครั้งคุณต้องการสร้างการเชื่อมต่อและต้องการเชื่อมต่อในภายหลัง โดยคุณจะต้องส่งค่า false
ไปยังเมธอด CreateConnection
จากนั้นจึงเปิดการเชื่อมต่อด้วยตนเองเมื่อคุณต้องการ var client = await new ConnectionBuilder < IService > ( )
. WithTcpTransport ( address )
. CreateConnection ( false ) ;
var connection = ( IConnection ) client ;
.. .
await connection . Connect ( ) ;
ผู้สร้างทั้งหมดเปิดเผยตัวเลือกการเชื่อมต่อเมื่อคุณเพิ่มเซิร์ฟเวอร์หรือการขนส่ง ตัวเลือกคือ:
Timeout
: ตั้งค่าการหมดเวลาการเชื่อมต่อ ( ค่าเริ่มต้น 30 วินาที )ReceiveTiemout
: เป็นการหมดเวลาระยะไกลที่ไม่ได้ใช้งาน ( ค่าเริ่มต้นของเซิร์ฟเวอร์: 10 นาที ค่าเริ่มต้นของไคลเอ็นต์: Infinity )KeepAliveInterval
: รักษาช่วงเวลาส่ง Ping ให้คงอยู่ ( ค่าเริ่มต้น 30 วินาที )KeepAliveRetries
: จำนวนการลองใหม่ก่อนที่จะตัดสินใจว่าการเชื่อมต่อปิดอยู่ ( ค่าเริ่มต้นคือลองใหม่ 10 ครั้ง )SendBufferSize
: ขนาดบัฟเฟอร์การส่ง ( ค่าเริ่มต้น 4096 ไบต์ = 4 KB )ReceiveBufferSize
: ขนาดบัฟเฟอร์การรับ ( ค่าเริ่มต้น 4096 ไบต์ = 4 KB )MaxMessageSize
: ขนาดสูงสุดของข้อความ ( ค่าเริ่มต้น 1000000 ไบต์ = 1 MB )ConnectionNameFormatter
: มอบหมายให้ตั้งค่าหรือจัดรูปแบบ ConnectionName
( ค่าเริ่มต้นคือ null ) (ดูการบันทึก)SecuritySettings
: การตั้งค่า SSL ( ค่าเริ่มต้นคือ null ) (ดูความปลอดภัย)คุณได้รับการดำเนินการกำหนดค่าตัวเลือกเหล่านี้บนเซิร์ฟเวอร์เมื่อคุณเรียก AddXXXServer:
var host = new ServiceHostBuilder < ChatService > ( InstanceMode . Single )
. WithCallback < ICallback > ( )
. AddTcpServer ( address , options =>
{
options . Timeout = TimeSpan . FromSeconds ( 10 ) ;
} )
. WithConsoleLogger ( )
. CreateHost ( ) ;
await host . Open ( ) ;
ในฝั่งไคลเอ็นต์ คุณจะได้รับเมื่อโทร WithXXXTransport
var client = await new DuplexConnectionBuilder < IChatService , MyCallback > ( new MyCallback ( ) )
. WithTcpTransport ( address , options =>
{
options . KeepAliveInterval = TimeSpan . FromSeconds ( 5 ) ;
} )
. WithConsoleLogger ( )
. CreateConnection ( ) ;
เมื่อคุณตั้งค่า Timeout
และคำขอไม่เสร็จสมบูรณ์ในช่วงเวลานั้น การเชื่อมต่อจะถูกปิด และคุณต้องสร้างไคลเอนต์ใหม่ หากมีการตั้งค่า Timeout
บนฝั่งเซิร์ฟเวอร์ซึ่งจะกำหนดการหมดเวลาการโทรกลับและการเชื่อมต่อจะถูกปิดเมื่อการโทรกลับไม่สมบูรณ์ในช่วงเวลานั้น โปรดจำไว้ว่าการโทรกลับเป็นการดำเนินการทางเดียวและการดำเนินการทางเดียวทั้งหมดจะเสร็จสมบูรณ์เมื่ออีกฝ่ายได้รับข้อความและก่อนที่วิธีระยะไกลจะถูกดำเนินการ
ReceiveTimeout
คือ " Idle Remote Timeout " หากคุณตั้งค่าไว้บนเซิร์ฟเวอร์ มันจะกำหนดการหมดเวลาสำหรับเซิร์ฟเวอร์เพื่อปิดไคลเอนต์ที่ไม่ได้ใช้งานซึ่งเป็นไคลเอนต์ที่ไม่ได้ส่งคำขอหรือข้อความ KeepAlive ใด ๆ ในช่วงเวลานั้น
ReceiveTimeout
บนไคลเอนต์ถูกตั้งค่าเป็น Infinity ตามค่าเริ่มต้น หากคุณตั้งค่าบนไคลเอนต์ดูเพล็กซ์ คุณกำลังสั่งให้ไคลเอนต์ละเว้นการโทรกลับที่ไม่ได้มาในช่วงเวลานั้น ซึ่งเป็นสถานการณ์แปลก ๆ แต่ก็ยังเป็นไปได้หากคุณเลือกที่จะทำเช่นนั้น .
ReceiveBufferSize
คือขนาดของบัฟเฟอร์การรับ การตั้งค่าเป็นค่าต่ำจะไม่ส่งผลต่อความสามารถในการรับข้อความขนาดใหญ่ แต่ถ้าขนาดนั้นเล็กมากเมื่อเทียบกับข้อความที่จะรับ ก็จะแนะนำการดำเนินการ IO มากขึ้น คุณควรปล่อยให้ค่าเริ่มต้นอยู่ที่จุดเริ่มต้นหากจำเป็นให้ทำการทดสอบโหลดและวิเคราะห์เพื่อค้นหาขนาดที่ทำงานได้ดีและตรงบริเวณ
SendBufferSize
คือขนาดของบัฟเฟอร์การส่ง การตั้งค่าเป็นค่าต่ำจะไม่ส่งผลต่อความสามารถในการส่งข้อความขนาดใหญ่ แต่ถ้าขนาดนั้นเล็กมากเมื่อเปรียบเทียบกับข้อความที่จะส่ง ก็จะแนะนำการดำเนินการ IO มากขึ้น คุณควรปล่อยให้ค่าเริ่มต้นอยู่ที่จุดเริ่มต้น หากจำเป็นให้ทำการทดสอบโหลดและวิเคราะห์เพื่อค้นหาขนาดที่ทำงานได้ดีและใช้หน่วยความจำน้อยลง
ReceiveBufferSize
ของผู้รับควรเท่ากับ SendBufferSize
ของผู้ส่ง เนื่องจากการขนส่งบางอย่างเช่น UDP จะทำงานได้ไม่ดีหากทั้งสองขนาดนี้ไม่เท่ากัน สำหรับตอนนี้ Xeeny จะไม่ตรวจสอบขนาดบัฟเฟอร์ แต่ในอนาคต ฉันกำลังแก้ไขโปรโตคอลเพื่อรวมการตรวจสอบนี้ในระหว่างการประมวลผล Connect
MaxMessageSize
คือจำนวนไบต์สูงสุดที่อนุญาตให้รับได้ ค่านี้ไม่เกี่ยวข้องกับบัฟเฟอร์ ดังนั้นจึงไม่ส่งผลต่อหน่วยความจำหรือประสิทธิภาพ ค่านี้มีความสำคัญสำหรับการตรวจสอบไคลเอนต์ของคุณและป้องกันข้อความขนาดใหญ่จากไคลเอนต์ Xeeny ใช้โปรโตคอลคำนำหน้าขนาด ดังนั้นเมื่อข้อความมาถึงมันจะถูกบัฟเฟอร์บนบัฟเฟอร์ขนาด ReceiveBufferSize
ซึ่งจะต้องเล็กกว่า MaxMessageSize
มาก หลังจากที่ข้อความมาถึง ส่วนหัวของขนาดถูกอ่าน ถ้าขนาดใหญ่กว่า MaxMessageSize
ข้อความจะถูกปฏิเสธและการเชื่อมต่อจะถูกปิด
Xeeny ใช้ข้อความ Keep-alive ของตัวเอง เนื่องจากการขนส่งบางประเภทไม่ได้มีกลไก Keep-alive ในตัว ข้อความเหล่านี้มีขนาด 5 ไบต์จากไคลเอ็นต์ไปยังเซิร์ฟเวอร์เท่านั้น ช่วงเวลา KeepAliveInterval
คือ 30 วินาทีตามค่าเริ่มต้น เมื่อคุณตั้งค่าไว้บนไคลเอนต์ ไคลเอนต์จะส่งข้อความ ping หากไม่สามารถส่งสิ่งใดได้สำเร็จในช่วง KeepAliveInterval
ครั้งล่าสุด
คุณต้องตั้ง KeepAliveInterval
ให้น้อยกว่า ReceiveTimeout
ของเซิร์ฟเวอร์ อย่างน้อย 1/2 หรือ 1/3 ของ ReceiveTimeout
ของเซิร์ฟเวอร์ เนื่องจากเซิร์ฟเวอร์จะหมดเวลาและปิดการเชื่อมต่อหากไม่ได้รับสิ่งใดๆ ในระหว่างที่เป็น ReceiveTimeout
KeepAliveRetries
คือจำนวนข้อความ Keep-alive ที่ล้มเหลว เมื่อถึงไคลเอ็นต์จะตัดสินใจว่าการเชื่อมต่อขาดและปิด
การตั้งค่า KeepAliveInterval
หรือ KeepAliveRetries
บนเซิร์ฟเวอร์ไม่มีผลใดๆ
เพื่อให้ Xeeny สามารถรวบรวมพารามิเตอร์เมธอดและส่งคืนประเภทบนเส้นลวดได้ จำเป็นต้องทำให้อนุกรมพารามิเตอร์เหล่านั้น มีซีเรียลไลเซอร์สามตัวที่ได้รับการสนับสนุนในกรอบงานแล้ว
MessagePackSerializer
: การทำให้ซีเรียลไลซ์ MessagePack ดำเนินการโดย MsgPack.Cli หรือไม่ มันเป็นซีเรียลไลเซอร์เริ่มต้นเนื่องจากข้อมูลที่ซีเรียลไลซ์มีขนาดเล็กและการนำไปใช้งานสำหรับ .net ในไลบรารีที่กำหนดนั้นรวดเร็วJsonSerializer
: Json serializer ใช้งานโดย NewtonsoftProtobufSerializer
: ProtoBuffers serializer ของ Google ใช้งานโดย Protobuf-net คุณสามารถเลือกซีเรียลไลเซอร์โดยใช้ผู้สร้างได้โดยการเรียก WithXXXSerializer
เพียงตรวจสอบให้แน่ใจว่าประเภทของคุณสามารถซีเรียลไลซ์ได้โดยใช้ซีเรียลไลเซอร์ที่เลือก
var host = new ServiceHostBuilder < ChatService > ( InstanceMode . Single )
. WithCallback < ICallback > ( )
. WithProtobufSerializer ( )
. CreateHost ( ) ;
await host . Open ( ) ;
WithSerializer(ISerializer serializer)
Xeeny ใช้ TLS 1.2 (บน TCP เท่านั้นในตอนนี้) คุณต้องเพิ่ม X509Certificate
ไปยังเซิร์ฟเวอร์
var host = new ServiceHostBuilder < Service > ( .. . )
. AddTcpServer ( tcpAddress , options =>
{
options . SecuritySettings = SecuritySettings . CreateForServer ( x509Certificate2 ) ;
} )
.. .
และบนไคลเอนต์คุณต้องผ่าน Certificate Name
:
await new ConnectionBuilder < IService > ( )
. WithTcpTransport ( tcpAddress , options =>
{
options . SecuritySettings = SecuritySettings . CreateForClient ( certificateName ) ;
} )
.. .
หากคุณต้องการตรวจสอบใบรับรองระยะไกล คุณสามารถส่งตัวแทนเสริม RemoteCertificateValidationCallback
ไปยัง SecuritySettings.CreateForClient
Xeeny ใช้ระบบการบันทึกแบบเดียวกับที่พบใน Asp.Net Core
หากต้องการใช้ตัวบันทึกให้เพิ่มแพ็คเกจ nuget ของตัวบันทึก จากนั้นโทร WithXXXLogger
ซึ่งคุณสามารถส่ง LogLevel
คุณอาจต้องการตั้งชื่อการเชื่อมต่อเพื่อให้มองเห็นได้ง่ายเมื่อทำการดีบั๊กหรือวิเคราะห์บันทึก คุณสามารถทำได้โดยการตั้งค่าการมอบหมายฟังก์ชัน ConnectionNameFormatter
ในตัวเลือกที่ส่งผ่าน IConnection.ConnectionId
เป็นพารามิเตอร์ และการส่งคืนจะถูกกำหนดให้กับ IConnection.ConnectionName
var client1 = await new DuplexConnectionBuilder < IChatService , Callback > ( callback1 )
. WithTcpTransport ( address , options =>
{
options . ConnectionNameFormatter = id => $ "First-Connection ( { id } )" ;
} )
. WithConsoleLogger ( LogLevel . Trace )
. CreateConnection ( ) ;
Xeeny ถูกสร้างขึ้นเพื่อให้มีประสิทธิภาพสูงและไม่ซิงค์กัน การมีสัญญาแบบอะซิงก์ทำให้เฟรมเวิร์กเป็นแบบอะซิงก์โดยสมบูรณ์ พยายามให้การดำเนินการของคุณส่งคืน Task
หรือ Task<T>
แทนที่จะเป็น void
หรือ T
วิธีนี้จะบันทึกเธรดพิเศษหนึ่งเธรดที่จะรอซ็อกเก็ตอะซิงก์ที่จำเป็นให้ดำเนินการให้เสร็จสิ้น ในกรณีที่การดำเนินการของคุณไม่ซิงก์กัน
ค่าใช้จ่ายใน Xeeny คือเมื่อจำเป็นต้องปล่อยประเภท "ใหม่" ณ รันไทม์ มันทำเช่นนั้นเมื่อคุณสร้าง ServiceHost<TService>
(การเรียก ServiceHostBuilder<TService>.CreateHost()
) แต่สิ่งนั้นจะเกิดขึ้นหนึ่งครั้งต่อประเภท ดังนั้นเมื่อ xeeny ปล่อยโฮสต์แรกของประเภทที่กำหนดซึ่งสร้างโฮสต์ประเภทนั้นเพิ่มขึ้นก็ไม่มีปัญหาด้านประสิทธิภาพ อย่างไรก็ตาม โดยปกติแล้ว นี่จะเป็นการเริ่มต้นแอปพลิเคชันของคุณ
อีกที่ที่ประเภทการเปล่งแสงเกิดขึ้นคือเมื่อคุณสร้างไคลเอนต์แรกของสัญญาหรือประเภทการติดต่อกลับที่กำหนด (การเรียก CreateConnection
) เมื่อพร็อกซีประเภทแรกนั้นเป็นตัวปล่อย ไคลเอนต์ถัดไปจะถูกสร้างขึ้นโดยไม่มีค่าใช้จ่าย (โปรดทราบว่าคุณยังคงสร้างซ็อกเก็ตใหม่และการเชื่อมต่อใหม่ เว้นแต่คุณจะส่งค่า false
ไปที่ CreateConnection
)
การเรียก OperationContext.Current.GetCallback<T>
ยังปล่อยประเภทรันไทม์ เช่นเดียวกับการปล่อยอื่น ๆ ทั้งหมดที่อยู่เหนือประเภทที่ปล่อยออกมานั้นจะถูกแคชไว้ และโอเวอร์เฮดจะเกิดขึ้นเมื่อมีการโทรครั้งแรกเท่านั้น คุณสามารถเรียกวิธีนี้ได้มากเท่าที่คุณต้องการ แต่คุณควรแคชการคืนสินค้าไว้ดีกว่า
คุณสามารถรับฟีเจอร์กรอบงาน Xeeny ทั้งหมดด้านบนเพื่อทำงานกับการขนส่งที่คุณกำหนดเองได้ (สมมติว่าคุณต้องการให้อยู่หลังอุปกรณ์ Bluetooth)
XeenyListener
ServiceHostBuilder<T>.AddCustomServer()
IXeenyTransportFactory
ConnectionBuilder<T>.WithCustomTransport()
หากคุณต้องการมีโปรโตคอลเป็นของตัวเองตั้งแต่เริ่มต้น คุณจะต้องใช้การเชื่อมต่อ การจัดเฟรมข้อความ การทำงานพร้อมกัน การบัฟเฟอร์ การหมดเวลา การรักษาการทำงาน ฯลฯ ของคุณเอง
IListener
ServiceHostBuilder<T>.AddCustomServer()
ITransportFactory
ConnectionBuilder<T>.WithCustomTransport()