Hi everybody,

today I want to describe how you can use SignalR and javascript in Acumatica. I will describe following functionality:
1. User 1 opens sales order SO006768
2. User 2 opens sales order SO006768
3. User 1 modifies Sales order, and clicks on Save button
4. User 2 gets following notification:

One of the ways to achieve that, is to use SignalR and a bit of jQuery.
In order to achieve that, following steps are needed:
1. Create interface, which will be a backbone of functionality:
public interface ISalesOrderNotify
{
Task<string> OrderWasChanged(string refNbr);
}
2. Create class, which will bound interface implementation to SignalR of Acumatica:
public class SOOrderHub : Hub<ISalesOrderNotify>
{
public async Task<string> Notify(string refNbr)
{
await Clients.Others.OrderWasChanged(refNbr);
return await Clients.Caller.OrderWasChanged(refNbr);
}
}
What I want to specifically highlight, is inheritance from the class Hub, which bounds SignalR with Interface and particular implementation.
3. Inform Acumatica framework about such connection:
public class ServiceRegistration : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<SOOrderHub>().ExternallyOwned();
}
}
4. And finally, explain in graph or graph extension, how steps 1 - 3 will be used:
public class SOOrderentryExt : PXGraphExtension<SOOrderEntry>
{
public static bool IsActive() => true;
[InjectDependency]
internal IConnectionManager SignalRConnectionManager { get; set; }
public override void Initialize()
{
base.Initialize();
var hubContext = GlobalHost.ConnectionManager.GetHubContext<SOOrderHub>();
}
[PXOverride]
public void Persist(Action basePersist)
{
basePersist();
var currentOrder = Base.CurrentDocument.Current.RefNbr;
var cnt = SignalRConnectionManager.GetHubContext<SOOrderHub>();
cnt.Clients.All.OrderWasChanged(currentOrder);
}
}
5. In your aspx.cs mention, that you want to have SignalR and jquery:
protected void Page_Init(object sender, EventArgs e)
{
Master.PopupWidth = 950;
Master.PopupHeight = 600;
// panel = (PXFormView)this.PanelAddSiteStatus.FindControl("formSitesStatus");
this.ClientScript.RegisterClientScriptInclude(this.GetType(), "jq", VirtualPathUtility.ToAbsolute("~/Scripts/jquery-3.1.1.min.js"));
this.ClientScript.RegisterClientScriptInclude(this.GetType(), "jqsr", VirtualPathUtility.ToAbsolute("~/Scripts/jquery.signalR-2.2.1.min.js"));
this.ClientScript.RegisterClientScriptInclude(this.GetType(), "hb", VirtualPathUtility.ToAbsolute("~/signalr/hubs"));
}
6. In your aspx describe a bit of javascript logic:
<script type="text/javascript">
var hubProxy = $.connection.sOOrderHub;
hubProxy.connection.start()
.done(function () {
console.log("hub proxy started");
}
);
hubProxy.on(
"OrderWasChanged", function(refNbr) {
var value = $("#ctl00_phF_form_t0_edOrderNbr_text").val();
if (value === refNbr) {
alert("Sales Order:" + refNbr + " was modified");
}
}
);
</script>
Summary
With usage of such technique, you'll be able to connect your C# part to js in a bit more invisible way, and add a bit more interactivity. Couple of additional details I'll add later on my youtube video.