EncoreBilisim.VisionSecurity
2.1.0
dotnet add package EncoreBilisim.VisionSecurity --version 2.1.0
NuGet\Install-Package EncoreBilisim.VisionSecurity -Version 2.1.0
<PackageReference Include="EncoreBilisim.VisionSecurity" Version="2.1.0" />
<PackageVersion Include="EncoreBilisim.VisionSecurity" Version="2.1.0" />
<PackageReference Include="EncoreBilisim.VisionSecurity" />
paket add EncoreBilisim.VisionSecurity --version 2.1.0
#r "nuget: EncoreBilisim.VisionSecurity, 2.1.0"
#:package EncoreBilisim.VisionSecurity@2.1.0
#addin nuget:?package=EncoreBilisim.VisionSecurity&version=2.1.0
#tool nuget:?package=EncoreBilisim.VisionSecurity&version=2.1.0
Encore Vision Security
Client library for the SaiGroups Vision Security API (.NET 8, trim/AOT compatible). One process = one self-checkout lane.
dotnet add package EncoreBilisim.VisionSecurity
Setup
For a POS integration, use VisionSecurityRuntime and its Session. A POS has its own
lifecycle, often learns the lane at run time, and must keep selling when the configuration is
bad. The runtime supports all three. For an app on the Generic Host, the DI path registers the
same parts.
Recommended for a POS: VisionSecurityRuntime
using Encore.VisionSecurity.Runtime;
var created = VisionSecurityRuntime.TryCreate(options, loggerFactory); // never throws
if (created.TryGetError(out var error)) { /* log it; the POS keeps selling */ }
else if (created.TryGetValue(out var runtime))
{
runtime.StartFeed(new MyAlertHandler(runtime.Session, runtime.MediaResolver), new MyNotificationHandler());
// ...
await runtime.DisposeAsync(); // stops the feed, sends pending events, releases HTTP
}
Create the runtime when the lane is known (for example, after the POS database loads). If the lane or the address changes, dispose the runtime and create a new one.
With the Generic Host (DI)
using Encore.VisionSecurity.Common.Configuration;
using Encore.VisionSecurity.Common.Primitives;
services
.AddVisionSecurity(options =>
{
options.BaseAddress = new Uri("http://vision-security.store.local:8080");
options.Lane = Lane.Parse(3);
options.StoreNumber = StoreNumber.Parse("1042"); // optional
})
.AddEventQueue() // POS -> AI, ordered, non-blocking
.AddFeed<MyAlertHandler, MyNotificationHandler>(); // AI -> POS, polled in the background
.AddEventQueue() also registers IVisionSecuritySession. AddVisionSecurity also registers
IAlertMediaResolver.
Which entry point
| You are… | Use |
|---|---|
| sending POS flow events (tx-start, scan, scan-info, ui-state, tx-end, …) | IVisionSecuritySession — the queue guarantees, plus the open TxId, an automatic tx-start, a tx-end guard and a ui-state repeat filter |
| sending single events and keeping the state yourself | IVisionSecurityEventQueue — synchronous, keeps wire order, never blocks the POS thread, stamps Ts at enqueue |
| answering alerts / notifications from the AI | IAlertHandler / INotificationHandler, started with runtime.StartFeed or registered with .AddFeed<,>(); the feed sends the feedback for you |
| calling one endpoint and awaiting its result (tools, diagnostics, tests) | IVisionSecurityClient — async, returns VisionSecurityResult<T> |
Sending events
using Encore.VisionSecurity.Contracts;
using Encore.VisionSecurity.Session;
session.Start(txId); // every call returns immediately
session.Scan(txId, Barcode.Parse("8690504010012"), ScanType.Product, ScanMode.Regular, mobileScan: false);
session.ScanInfo(txId, Barcode.Parse("8690504010012"), "Milk 1L", 32.50m, quantity: 1, weight: 0m, voided: false, scanType: ScanInfoScanType.Product);
session.UiState(UiState.Payment);
session.End(EndType.Complete); // closes the open transaction
The session keeps one open transaction per lane:
ScanandScanInfosend a tx-start first if the transaction is not open.- If transaction A is open and B starts, the session sends tx-end VOID for A and logs a warning.
End,Operator,UiStateandWeightScaleInforeturnFailureif no transaction is open.UiStatedoes not send the same state two times in a row.
Do not send events through the queue and the session for the same lane.
The return value is the enqueue result: Failure(ValidationError) means the request was
invalid (rejected immediately), the queue is full, or the queue is stopped. Send outcomes are
reported through ILogger<VisionSecurityEventQueue> and the encore.visionsecurity.eventqueue.*
metrics. The queue is in-memory: pending events are lost if the process dies.
TxId is yours to supply. Derive it from the POS receipt identity, so that logs on both sides
correlate.
Handling alerts
public sealed class MyAlertHandler(IVisionSecuritySession session, IAlertMediaResolver media) : IAlertHandler
{
public async Task<VisionSecurityResult<AlertFeedbackType>> HandleAsync(AlertResponse alert, CancellationToken ct)
{
if (!session.IsOpen(alert.TxId)) // the sale ended; your policy decides
return VisionSecurityResult<AlertFeedbackType>.Success(AlertFeedbackType.For(alert.PresentationType, AlertOutcome.NotShown));
var image = media.ResolveAsync(alert, ct); // gif or gifUrl -> bytes, with size and time limits
AlertOutcome outcome = await ShowOnScreenAsync(alert, image, ct);
return VisionSecurityResult<AlertFeedbackType>.Success(AlertFeedbackType.For(alert.PresentationType, outcome));
}
}
AlertFeedbackType.For maps the screen outcome (Rescan, NoAction, TimedOut, NotShown)
to the contract value. NUDGE_* values are used only for SOFT_NUDGE. NO_FEEDBACK is used only
for NotShown.
Never throw from a handler; return a Failure instead. The feed still sends NO_FEEDBACK
if a handler fails, so the AI side never waits on a lost alert.
Errors
Nothing throws after construction. Every operation returns VisionSecurityResult /
VisionSecurityResult<T>; inspect with TryGetValue / TryGetError, or compose with
Match / Map / Bind. Error kinds:
ApiError (4xx/5xx), TransportError, TimeoutError, ParseError, ValidationError,
UnknownEnumError, CancelledError, HandlerError.
Full documentation (architecture, configuration, feed flows, domain rules, library
invariants) lives in the repository: README.md, docs/kurallar.md, docs/invariants.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Options (>= 8.0.2)
- Polly.Core (>= 8.4.0 && < 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.