How to send/write and receive/read (BIDI) TCP/IP Data from Blazor
Product JSPrintManager for Blazor Published 05/21/2026 Updated 05/21/2026 Author Neodynamic
Overview
JSPrintManager for Blazor supports Bidirectional (BIDI) TCP/IP Communication from Blazor allowing you to Send/Write & Receive/Read data strings to any IP Address and Port reachable from the client system.
In this walkthrough, you'll learn how to Send/Write & Receive/Read data strings from Blazor through any IP Address and Port reachable from the client machine. This solution works with any popular browser like Chrome, Firefox, IE/Edge & Safari on Windows, Linux, Raspberry Pi and Mac systems!
Follow up these steps
- Be sure you install in your dev machine JSPrintManager (JSPM) (Available for Windows, Linux, Raspberry Pi & Mac)
This small app must be installed on each client that will print from your website! - In your Blazor project...
- Add a NuGet reference to the JSPrintManager Razor Component
- Add the JSPrintManager service...
- Add the following statement at the top of your
StartuporProgramfile
using Neodynamic.Blazor;- For Blazor Server
Add the following line in theStartup's ConfigureServicesmethod
services.AddJSPrintManager();For .NET 8+ you must use Interactive Server components and render mode, so add these settings:
builder.Services.AddRazorComponents() .AddInteractiveServerComponents();app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() - For Blazor WebAssembly
Add the following line in theProgram's Mainmethod
builder.Services.AddJSPrintManager();
- For Blazor Server
- Add the following statement at the top of your
- Add the following statement in the
_Imports.razorfile
@using Neodynamic.Blazor - Add a new Razor Page and copy/paste the following code. Please read the source code comments to understand the printing logic!
For .NET 8+ Blazor Server you must use Interactive Server render mode, so add these settings:
@page "/" @rendermode InteractiveServer @inject JSPrintManager JSPrintManager@page "/" @inject JSPrintManager JSPrintManager @using System @using System.Text <div> <strong>JSPM </strong><span>WebSocket Status </span> @if (JSPrintManager.Status == JSPMWSStatus.Open) { <span class="badge badge-success"> <i class="fa fa-check" /> Open </span> } else if (JSPrintManager.Status == JSPMWSStatus.Closed) { <span class="badge badge-danger"> <i class="fa fa-exclamation-circle" /> Closed! </span> <div> <strong>JSPrintManager (JSPM) App</strong> is not installed or not running! <a href="https://neodynamic.com/downloads/jspm" target="_blank">Download JSPM Client App...</a> </div> } else if (JSPrintManager.Status == JSPMWSStatus.Blocked) { <span class="badge badge-warning"> <i class="fa fa-times-circle" /> This Website is Blocked! </span> } else if (JSPrintManager.Status == JSPMWSStatus.WaitingForUserResponse) { <span class="badge badge-warning"> <i class="fa fa-user-circle" /> Waiting for user response... </span> } </div> @if (JSPrintManager.Status == JSPMWSStatus.Open) { <div class="row"> <div class="col-md-12"> <h2 class="text-center"> BIDI TCP/IP Comm </h2> <hr /> </div> </div> <div class="row"> <div class="col-md-12"> <EditForm Model="@MyTcpComm"> <div class="form-group"> <div class="row"> <div class="col-md-2"> <label>IP Address:</label> <InputText @bind-Value="MyTcpComm.Address" class="form-control form-control-sm" /> </div> <div class="col-md-2"> <label>Port:</label> <InputNumber @bind-Value="MyTcpComm.Port" class="form-control form-control-sm" /> </div> </div> <br /><br /> <div class="row"> <div class="col-md-2"> <button class="btn btn-success btn-lg" @onclick="DoTcpBidi"> Start BIDI Comm... </button> </div> <div class="col-md-2"> <button class="btn btn-danger btn-lg" @onclick="StopTcpBidi"> Stop </button> </div> </div> <br /><br /> <div class="row"> <div class="col-md-12"> <br /> <strong>Data to Send:</strong> <div class="input-group mb-3"> <InputText @bind-Value="dataToSend" class="form-control form-control-sm" /> <div class="input-group-append"> <button class="btn btn-info" @onclick="DoSendData"> Send... </button> </div> </div> </div> </div> <br /><br /> <div class="row"> <div class="col-md-12"> <div class="text-center"> Tcp Comm BIDI Messages<br /> <textarea class="terminal" readOnly @bind="Messages" rows="10" cols="100" /> </div> </div> </div> </div> </EditForm> </div> </div> } @code { protected override void OnAfterRender(bool firstRender) { if (firstRender) { JSPrintManager.OnStatusChanged += () => { StateHasChanged(); }; // Start WebSocket comm JSPrintManager.Start(); } base.OnAfterRender(firstRender); } protected override void OnInitialized() { JSPrintManager.OnError += () => { var error = JSPrintManager.LastErrorMessage; }; base.OnInitialized(); } private string Messages { get { return MessagesBuffer.ToString(); } set { MessagesBuffer.Clear(); MessagesBuffer.Append(value); } } private StringBuilder MessagesBuffer = new StringBuilder(); private string dataToSend; // The TcpComm info obj private TcpComm MyTcpComm { get; set; } = new(); private void DoTcpBidi() { // handle TCP Comm messages JSPrintManager.OnTcpCommEvent += () => { var evt = JSPrintManager.TcpCommEventCache[JSPrintManager.TcpCommEventCache.Count - 1]; switch (evt.Type) { case TcpCommEventType.Close: MessagesBuffer.Append("COMM CLOSE" + Environment.NewLine); break; case TcpCommEventType.Error: MessagesBuffer.Append("COMM ERROR: " + evt.Data + Environment.NewLine); break; case TcpCommEventType.Open: MessagesBuffer.Append("COMM OPEN" + Environment.NewLine); break; case TcpCommEventType.DataReceived: MessagesBuffer.Append("<< " + evt.Data); break; case TcpCommEventType.DataSent: MessagesBuffer.Append(">> " + evt.Data); break; } StateHasChanged(); }; // Start BIDI TCP Comm... JSPrintManager.OpenTcpComm(MyTcpComm); } private void StopTcpBidi() { // Stop BIDI TCP Comm... JSPrintManager.CloseTcpComm(MyTcpComm); } private void DoSendData() { // Send data through BIDI TCP Comm... if (string.IsNullOrWhiteSpace(dataToSend) == false) { MyTcpComm.DataToSend = dataToSend; JSPrintManager.SendDataTcpComm(MyTcpComm); } } }
- That's it! Run your website and play with it.