Microsoft Point of Service for .NET(POS for .NET)服務物件持續追蹤並更新每個連接裝置的多項統計資料。 統計追蹤是透過類別 DeviceStatistics 完成,該類別包含重設、檢索與更新統計資料的方法,以及用於建立統計、遞增統計數據,以及載入或儲存統計資料至或從 XML 檔案儲存的輔助方法。
POS for .NET 的統計報告支援儲存在硬體或軟體中的統計資料。 軟體統計資料儲存在 XML 統計檔案 \Program Files\Common Files\Microsoft Shared\Point of Service\Statistics\PosDeviceStatistics.xml中,並依系統安裝與設定時決定的全局定義刷新間隔更新。 預設情況下,這個沖洗間隔是 1 秒。 當應用程式認領裝置時,POS for .NET 會從 XML 檔案載入相應的統計資料。
裝置專屬統計管理由 Base 或 Basic 裝置類別介面支援。 繼承自 Base 或 Basic 類別的服務物件通常只需呼叫 IncrementStatistic(遞增指定統計量的值)或 SetStatistic(將一個統計量設為指定值)。 所有其他統計實作皆由 Base 或 Basic 類別介面提供。
DeviceStatistics 類別的主要成員如下:
CapStatisticsReporting 用來識別裝置的統計報告功能。 當 CapStatisticsReporting 設 為 false 時,無法取得該裝置的統計資料。 如果 CapStatisticsReporting 屬 實,則有部分統計資料可用,裝置可能會開始累積各種使用統計數據。 累積並回報的資訊是針對特定裝置的,並透過 RetrieveStatistics 方法檢索。
CapUpdateStatistics 定義了所收集統計數據是否能由應用程式使用 UpdateStatistics 和 ResetStatistics 方法來重置或更新。 此特性僅在 CapStatisticsReporting為真時有效。 如果 CapStatisticsReporting 為 假,則 CapUpdateStatistics 屬性永遠為 假。
只有當 CapStatisticsReporting 和 CapUpdateStatistics 都為真時,才能呼叫 ResetStatistics。 此方法會將一個、部分或全部可重置的裝置統計資料重設為零。 它會將裝置中定義的可重置統計值重置為零。 所有請求的統計資料必須成功重置,此方法才能成功完成。 否則,會透過 Extended ErrorCode 方法拋出錯誤。 此方法始終以同步方式執行。
UpdateStatistics 會將一個、部分或全部可重置的裝置統計值設定為指定的值。 所有要求的統計資料必須成功更新,才能使此方法順利完成。 若某些資料因任何原因無法更新,則會回傳 ErrorCode 事件。 CapStatisticsReporting 和 CapUpdateStatistics 都必須設為 true,才能呼叫此方法。 UpdateStatistics 方法總是同步執行。
RetrieveStatistics 是從裝置擷取所需統計資料。 CapStatisticsReporting 必須 為真 ,才能成功使用此方法。 所有對 RetrieveStatistics 的呼叫至少會回傳以下 XML。
<?xml version='1.0'?> <UPOSStat version="1.10.0" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns="http://www.nrf-arts.org/IXRetail/namespace/" xsi:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace/ UPOSStat.xsd"> <Event> <Parameter> <Name>RequestedStatistic</Name> <Value>1234</Value> </Parameter> </Event> <Equipment> <UnifiedPOSVersion>1.10</UnifiedPOSVersion> <DeviceCategory UPOS="CashDrawer"/> <ManufacturerName>Cashdrawers R Us</ManufacturerName> <ModelName>CD-123</ModelName> <SerialNumber>12345</SerialNumber> <FirmwareRevision>1.0 Rev. B</FirmwareRevision> <Interface>RS232</Interface> <InstallationDate>2000-03-01</InstallationDate> </Equipment> </UPOSStat>若應用程式請求的統計名稱不受裝置支援,則
<Parameter>條目將返回一個空的<Value>。 例如:<Parameter> <Name>RequestedStatistic</Name> <Value></Value> </Parameter>裝置收集的所有製造商特定且未在結構中定義的統計數據,都會以標籤形式回傳
<ManufacturerSpecific>,而非標籤<Parameter>。 例如:<ManufacturerSpecific> <Name>TheAnswer</Name> <Value>42</Value> </ManufacturerSpecific>當應用程式向裝置請求所有統計資料時,裝置會為該裝置類別中每個已定義的統計資料回傳一個
<Parameter>條目。 裝置類別由標籤中version屬性所指定的<UPOSStat>XML 架構版本所定義。 如果裝置沒有記錄任何統計數據,標籤<Value>就會是空的。
POS for .NET 使用處理常式來執行統計資料的讀寫,方式類似於事件的處理方式。 當建立這些統計處理器之一時,會將其分配給特定裝置的統計資料。 當讀取或更新此統計資料時,處理器會呼叫一個代理,該代理能根據需要從裝置讀取或寫入。
統計處理器使用不同類型的代理來執行不同的統計操作。 GetStatistic 代理用來檢索統計值,代理 SetStatistic 則指派統計值。 GetStatistics 代理會將要檢索的統計量名稱作為參數,並回傳代表該統計量值的字串。 SetStatistic 代理會將要變更的統計量名稱及該統計量的值作為參數。 SetStatistic 代理不會回傳任何值。
統計處理程式可指派至統一服務點(UnifiedPOS)規範中定義的任何標準統計資料,但也支援以 CreateStatistic 依服務物件程式碼建立的任何統計資料的自訂處理程序。
Example
以下程式碼範例示範如何啟用、處理及檢索 MSR 裝置的統計資料。
// File FORM1.CS
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
namespace Statistics
{
public partial class SampleStatistics : Form
{
// Indicates whether or not the Service Object has
// been started.
bool ServiceObjectStarted = false;
// The Service Object.
PosCommon so = null;
public SampleStatistics()
{
InitializeComponent();
// Disable the buttons until the SO is loaded successfully.
UpdateControls();
}
public void UpdateControls()
{
btnGenerateStatistics.Enabled = ServiceObjectStarted;
btnRetrieveStatistics.Enabled = ServiceObjectStarted ;
txtStatisticName.Enabled = ServiceObjectStarted;
// The statistic name text box is disabled until the
// Service Object is loaded.
if (ServiceObjectStarted)
{
btnStartSO.Text = "Close SO";
}
else
{
txtStatisticName.Clear();
txtRetrievedStatistics.Clear();
btnStartSO.Text = "Start SO";
}
// The retrieve one statistic button is disabled until
// the user has entered a statistic name.
if (txtStatisticName.TextLength > 0)
{
btnRetrieveStatistic.Enabled = true;
}
else
{
btnRetrieveStatistic.Enabled = false;
}
}
private void StartServiceObject(object sender, EventArgs e)
{
PosExplorer explorer = new PosExplorer(this);
string SOName = "SampleStatistics";
if (ServiceObjectStarted)
{
so.DeviceEnabled = false;
so.Close();
so = null;
ServiceObjectStarted = false;
UpdateControls();
}
else
{
foreach (DeviceInfo d in explorer.GetDevices())
{
if (d.ServiceObjectName == SOName)
{
try
{
// Standard Service Object startup.
so = explorer.CreateInstance(d)
as PosCommon;
so.Open();
so.Claim(0);
so.DeviceEnabled = true;
// Application-specific setup.
ServiceObjectStarted = true;
UpdateControls();
}
catch
{
// Something went wrong starting the SO
MessageBox.Show("The Service Object '" +
SOName + "' failed to load",
"Service Object Error",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
return;
}
break;
}
}
if (so == null)
{
// No Service Object with the
// specified name could be found.
MessageBox.Show("The Service Object '" +
SOName + "' could not be found",
"Service Object Error",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
}
}
private void GenerateStatistics(object sender, EventArgs e)
{
// In this example case, you use this
// property to tell the Service Object to change statistic
// values.
so.DeviceEnabled = true;
// Report status.
txtRetrievedStatistics.Text = "DeviceEnabled called to" +
" to modify statistic values.";
}
private void RetrieveStatistics(object sender, EventArgs e)
{
string statistics;
bool IsXml = true;
try
{
statistics = so.RetrieveStatistics();
}
catch
{
statistics = "No statistics found";
IsXml = false;
}
DisplayStatistics(statistics, IsXml);
}
private void RetrieveOneStatistic(object sender, EventArgs e)
{
string statistics;
bool IsXml = true;
try
{
statistics = so.RetrieveStatistic(
txtStatisticName.Text);
}
catch
{
statistics = "Statistic not found: " +
txtStatisticName.Text;
IsXml = false;
}
DisplayStatistics(statistics, IsXml);
txtStatisticName.Clear();
btnRetrieveStatistic.Enabled = false;
}
private void StatisticSizeChanged(object sender, EventArgs e)
{
if (txtStatisticName.TextLength > 0)
{
btnRetrieveStatistic.Enabled = true;
}
else
{
btnRetrieveStatistic.Enabled = false;
}
}
// When retrieving statistics, POS for .NET returns a block
// of XML (as specified in the UPOS specification). This
// method will make it look readable with white space
// and indenting and then display it in the text box.
private void DisplayStatistics(string inputString, bool isXml)
{
string s = null;
// In case of an exception, you do not have an XML
// string, so just display the error description. Otherwise,
// load the XML string into an XmlDocument object and
// make it look readable.
if (!isXml)
{
s = inputString;
}
if(isXml)
{
// Create new XML document and load the statistics
// XML string.
XmlDocument doc = new XmlDocument();
doc.LoadXml(inputString);
// Create a XmlTextWriter using a MemoryStream and
// tell it to indent the XML output (so that it is
// readable.)
MemoryStream m = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(m, null);
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
// Save the document to the memory stream using the
// XmlWriter.
doc.Save(writer);
// The stream will be encoded as UTF8, so convert the
// buffer into a string.
UTF8Encoding u = new UTF8Encoding();
s = u.GetString(m.GetBuffer());
}
// Write the string to the text box.
txtRetrievedStatistics.Text = s;
}
}
}
// File FORM1.DESIGNER.CS
namespace Statistics
{
partial class SampleStatistics
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartSO = new System.Windows.Forms.Button();
this.btnGenerateStatistics = new System.Windows.Forms.Button();
this.btnRetrieveStatistics = new System.Windows.Forms.Button();
this.txtStatisticName = new System.Windows.Forms.TextBox();
this.txtRetrievedStatistics = new System.Windows.Forms.TextBox();
this.btnRetrieveStatistic = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// btnStartSO
//
this.btnStartSO.Location = new System.Drawing.Point(45, 35);
this.btnStartSO.Name = "btnStartSO";
this.btnStartSO.Size = new System.Drawing.Size(133, 23);
this.btnStartSO.TabIndex = 0;
this.btnStartSO.Text = "Start SO";
this.btnStartSO.UseVisualStyleBackColor = true;
this.btnStartSO.Click += new System.EventHandler(this.StartServiceObject);
//
// btnGenerateStatistics
//
this.btnGenerateStatistics.Location = new System.Drawing.Point(45, 75);
this.btnGenerateStatistics.Name = "btnGenerateStatistics";
this.btnGenerateStatistics.Size = new System.Drawing.Size(133, 23);
this.btnGenerateStatistics.TabIndex = 1;
this.btnGenerateStatistics.Text = "GenerateStatistics";
this.btnGenerateStatistics.UseVisualStyleBackColor = true;
this.btnGenerateStatistics.Click += new System.EventHandler(this.GenerateStatistics);
//
// btnRetrieveStatistics
//
this.btnRetrieveStatistics.Location = new System.Drawing.Point(45, 117);
this.btnRetrieveStatistics.Name = "btnRetrieveStatistics";
this.btnRetrieveStatistics.Size = new System.Drawing.Size(133, 23);
this.btnRetrieveStatistics.TabIndex = 2;
this.btnRetrieveStatistics.Text = "Retrieve Statistics";
this.btnRetrieveStatistics.UseVisualStyleBackColor = true;
this.btnRetrieveStatistics.Click += new System.EventHandler(this.RetrieveStatistics);
//
// txtStatisticName
//
this.txtStatisticName.Location = new System.Drawing.Point(16, 68);
this.txtStatisticName.Name = "txtStatisticName";
this.txtStatisticName.Size = new System.Drawing.Size(205, 20);
this.txtStatisticName.TabIndex = 4;
this.txtStatisticName.TextChanged += new System.EventHandler(this.StatisticSizeChanged);
//
// txtRetrievedStatistics
//
this.txtRetrievedStatistics.BackColor = System.Drawing.Color.White;
this.txtRetrievedStatistics.Location = new System.Drawing.Point(45, 157);
this.txtRetrievedStatistics.Multiline = true;
this.txtRetrievedStatistics.Name = "txtRetrievedStatistics";
this.txtRetrievedStatistics.ReadOnly = true;
this.txtRetrievedStatistics.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtRetrievedStatistics.Size = new System.Drawing.Size(476, 247);
this.txtRetrievedStatistics.TabIndex = 5;
//
// btnRetrieveStatistic
//
this.btnRetrieveStatistic.Location = new System.Drawing.Point(16, 30);
this.btnRetrieveStatistic.Name = "btnRetrieveStatistic";
this.btnRetrieveStatistic.Size = new System.Drawing.Size(133, 23);
this.btnRetrieveStatistic.TabIndex = 6;
this.btnRetrieveStatistic.Text = "Retrieve Statistic";
this.btnRetrieveStatistic.UseVisualStyleBackColor = true;
this.btnRetrieveStatistic.Click += new System.EventHandler(this.RetrieveOneStatistic);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.btnRetrieveStatistic);
this.groupBox1.Controls.Add(this.txtStatisticName);
this.groupBox1.Location = new System.Drawing.Point(219, 35);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(302, 105);
this.groupBox1.TabIndex = 7;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Single Statistic";
//
// SampleStatistics
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.MenuBar;
this.ClientSize = new System.Drawing.Size(565, 439);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.txtRetrievedStatistics);
this.Controls.Add(this.btnRetrieveStatistics);
this.Controls.Add(this.btnGenerateStatistics);
this.Controls.Add(this.btnStartSO);
this.Name = "SampleStatistics";
this.Text = "Form1";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button btnStartSO;
private System.Windows.Forms.Button btnGenerateStatistics;
private System.Windows.Forms.Button btnRetrieveStatistics;
private System.Windows.Forms.TextBox txtStatisticName;
private System.Windows.Forms.TextBox txtRetrievedStatistics;
private System.Windows.Forms.Button btnRetrieveStatistic;
private System.Windows.Forms.GroupBox groupBox1;
}
}
// File STATISTICSSO.CS
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
[assembly: PosAssembly("Service Object Contractors, Inc.")]
namespace SOSamples.Statistics
{
[ServiceObject(DeviceType.Msr,
"SampleStatistics",
"Sample Statistics Service Object",
1,
9)]
public class StatisticsTest : MsrBase
{
// This will be incremented every time DeviceEnabled
// is set so that different sets of demonstration
// statistics can be generated.
int enableCount = 0;
// The name of a custom created statistic used to demonstrate
// custom Statistic handlers.
private const string PollingStatistic = "Polling Interval";
// Statistic used to demonstrate IncrementStatistic.
private const string TestIncrement = "MyIncrementableStat";
// String returned from CheckHealth
private string MyHealthText;
public StatisticsTest()
{
DevicePath = "Sample Statistics";
}
// This is the delegate which will be called for each
// statistic that we have associated with this delegate by
// calling SetStatisticHandler().
//
// Delegates like this should most commonly be used
// to get and set statistics in hardware. The delegate
// allows the POS for .NET statistic subsystem to query
// the value of a statistic in real time, before it is
// returned to the application.
private string GetHardwareInfo(string name)
{
// Add your code to query values from hardware here.
// Very simple demonstration: just return the name
// of the statistic as its value;
return name;
}
// In a typical Service Object implementation, statistics
// will be modified throughout the Service Object code. This
// method demonstrates the methods used to modify statistic
// values.
public void SetDemonstrationStatistics()
{
// IncrementStatistic can be used to easily
// increment a numeric statistic.
IncrementStatistic(TestIncrement);
switch(enableCount)
{
case 0:
SetStatisticValue(StatisticManufacturerName,
"Microsoft Corporation");
break;
case 1:
SetStatisticValue(StatisticManufacturerName,
"Service Control Contractors, Inc.");
break;
case 2:
SetStatisticValue(StatisticManufacturerName,
"Point of Service Controls .com");
break;
}
if (++enableCount == 3 )
{
enableCount = 0;
}
}
#region PosCommon overrides
// Returns the result of the last call to CheckHealth()
public override void Open()
{
base.Open();
// In your implementation of Open(), your Service Object
// code should:
// 1. Initialize statistics.
// 2. Create custom statistics.
// 3. Set statistic handlers for hardware Statistics.
// 1. Initialize statistics
SetStatisticValue(StatisticManufacturerName,
"Microsoft Corporation");
SetStatisticValue(StatisticManufactureDate,
"2004-10-23");
SetStatisticValue(StatisticModelName,
"Statistic Sample");
SetStatisticValue(StatisticMechanicalRevision,
"1.0");
SetStatisticValue(StatisticInterface,
"USB");
// 2a. Create a new statistic to test Increment
// method. No custom handler needed.
CreateStatistic(TestIncrement, false, "blobs");
// 2b. Create a new manufacturer statistic to demonstrate
// custom attributes with StatisticHandlers.
CreateStatistic(PollingStatistic, false,
"milliseconds");
// 3. Set handlers for statistics stored in hardware.
SetStatisticHandlers(PollingStatistic,
new GetStatistic(GetHardwareInfo), null);
SetStatisticHandlers(StatisticSerialNumber,
new GetStatistic(GetHardwareInfo), null);
}
public override bool DeviceEnabled
{
get
{
return base.DeviceEnabled;
}
set
{
// This method will set various statistics to
// demonstrate the statistic APIs. We are going
// to change statistic values every time the device
// is enabled. This operation is just for
// demonstration and would not be found in live code.
SetDemonstrationStatistics();
base.DeviceEnabled = value;
}
}
public override string CheckHealthText
{
get
{
// MsrBasic.VerifyState(musBeClaimed,
// mustBeEnabled). This may throw an exception
VerifyState(false, false);
return MyHealthText;
}
}
public override string CheckHealth(
HealthCheckLevel level)
{
// Verify that device is open, claimed, and enabled.
VerifyState(true, true);
// Your code here:
// check the health of the device and return a
// descriptive string.
// Cache result in the CheckHealthText property.
MyHealthText = "Ok";
return MyHealthText;
}
public override DirectIOData DirectIO(
int command,
int data,
object obj)
{
// Verify that the device is open.
VerifyState(false, false);
return new DirectIOData(data, obj);
}
#endregion PosCommon overrides
#region MsrBasic Overrides
protected override MsrFieldData ParseMsrFieldData(
byte[] track1Data,
byte[] track2Data,
byte[] track3Data,
byte[] track4Data,
CardType cardType)
{
// Your code here:
// Implement this method to parse track data
// into fields which will be returned as
// properties to the application (e.g.,FirstName,
// AccountNumber, etc.)
return new MsrFieldData();
}
protected override MsrTrackData ParseMsrTrackData(
byte[] track1Data,
byte[] track2Data,
byte[] track3Data,
byte[] track4Data,
CardType cardType)
{
// Your code here:
// Implement this method to convert raw track data.
return new MsrTrackData();
}
#endregion MsrBasic Overrides
}
}
編譯程式碼
- 關於建立與編譯服務物件專案的更多資訊,請參閱 服務物件範例:入門指南。