Compartir a través de


Creación de un objeto de servicio funcional y multiproceso (POS para documentación del SDK de .NET v1.14)

En las secciones anteriores se proporcionan ejemplos y guías para iniciar el proyecto, entre las que se incluyen:

  • Creación de una plantilla sencilla.
  • Implementar una clase de objeto de servicio que pueda ser compilada y vista por la aplicación de ejemplo Point Of Service a través de PosExplorer.
  • Implementación de una clase auxiliar de subprocesos.

En este ejemplo se combinan todos estos pasos para crear una clase de objeto de servicio MSR en funcionamiento y multiproceso. En realidad, este ejemplo no lee de ningún dispositivo de hardware. Simplemente envía datos de prueba a través del sistema. Sin embargo, muestra cómo agregar código específico al objeto de servicio.

Para personalizar este código para el objeto de servicio

  1. Modifique el PosAssembly atributo en AssemblyInfo.cs para que contenga el nombre de la organización.

  2. Asegúrese de que el nombre del espacio de nombres sea adecuado para la organización y el objeto de servicio.

  3. Modifique el ServiceObject atributo para que contenga el tipo, el nombre, la descripción y el número de versión del objeto de servicio que está creando.

  4. Agregue un HardwareId atributo para asociar este objeto de servicio con un dispositivo Plug and Play o un intervalo de dispositivos.

  5. Incluya la clase ThreadHelper presentada en Introducción a los subprocesos del Lector de objetos de servicio. Para ello, pegue el código en el archivo de código fuente o compilelo como un archivo de código fuente independiente en el proyecto. Asegúrese de que la clase ThreadHelper está en un espacio de nombres accesible.

  6. Implemente los miembros necesarios en función de la clase Base utilizada por el objeto de servicio y la funcionalidad que desee admitir. Este ejemplo es un objeto de servicio MSR funcional con muy poca funcionalidad.

Requisitos

Para compilar este ejemplo, el proyecto debe tener las referencias correctas y los atributos globales. Si aún no ha creado un POS en funcionamiento para el objeto de servicio de .NET, revise las secciones Ejemplos de objetos de servicio: Introducción .

Además, también tendrá que incluir el código de la sección anterior, Introduciendo los hilos de lectura del objeto de servicio, en su proyecto.

Demostraciones

La mayoría de los objetos de servicio deben usar un segundo subproceso para supervisar el hardware y notificar a la aplicación varios eventos de datos entrantes. En este ejemplo se muestra una manera de crear un objeto de servicio multiproceso. Se basa en la clase ServiceObjectThreadHelper que se describe en Introducción a los subprocesos del Lector de objetos de servicio para hacerlo.

Para usar la clase auxiliar, una aplicación debe definir una nueva clase que implemente la interfaz ServiceObjectThreadHelper . Esta interfaz incluye tres métodos:

  • ServiceObjectThreadOpen Se llama a este método durante la inicialización del subproceso y se debe usar para inicializar los recursos específicos del hardware.
  • ServiceObjectThreadClose Se llama a este método cuando finaliza el subproceso y se debe usar para liberar los recursos específicos del hardware.
  • ServiceObjectThreadProcedure Se llamará a este método una vez que el subproceso se haya iniciado correctamente y debe realizar un bucle en espera de eventos de hardware y no debe salir hasta que se desencadene el evento ManualEvent adecuado.

Este código se basa en el ejemplo presentado en el tema Creación de un ejemplo de objeto de servicio y agrega las siguientes características:

  • Crea una clase derivada de ServiceObjectThreadHelper.
  • Crea una instancia de una clase MsrThreadingObject . El constructor de esta clase toma un único argumento, una referencia al objeto de servicio.
  • Llama a los métodos del objeto MsrThreadingObject desde el objeto Service Para iniciar y detener el asistente de subprocesos según corresponda.

Example

using System;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
using System.Text;

namespace Samples.ServiceObjects.Advanced.MSR
{
    public class MsrThreadingObject :
            ServiceObjectThreadHelper, IDisposable
    {
        // This is a helper class which will depend on
        // being able to call back into the actual Service
        // Object to pass along data. However, you cannot
        // keep a strong reference to the Service Object,
        // since that will prevent proper disposal, which
        // may create a state in which all hardware resources
        // are not properly released by the SO. Therefore,
        // create a weak reference. From this reference,
        // you can get a temporary strong reference, which
        // you act on and then release.
        WeakReference ServiceObjectReference;

        // The name of the Service Object.
        string ObjectName;

        public MsrThreadingObject(AdvancedSampleMsr so)
        {
            ObjectName = GetType().Name;
            ServiceObjectReference = new WeakReference(so);
        }

        ~MsrThreadingObject()
        {
            Dispose(true);
        }

        private bool IsDisposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                IsDisposed = true;
                base.Dispose(disposing);
            }
        }

        public void Dispose()
        {
            Dispose(false);
        }

        #region Methods of ServiceObjectThreadHelper

        // This will be called during initialization.
        public override void ServiceObjectThreadOpen()
        {
            Logger.Info(ObjectName, "Msr Thread Open");
        }

        // This method will be called during shutdown.
        public override void ServiceObjectThreadClose()
        {
            Logger.Info(ObjectName, "Msr Thread Open");
        }

        public override void ServiceObjectThreadProcedure(
                            AutoResetEvent ThreadStopEvent)
        {
            // Convert a C# string into a sample byte array.
            UTF8Encoding encoder = new UTF8Encoding();

            // Convert sample data to a byte array.
            byte[] MsrData = encoder.GetBytes(
                        "This is MSR test data");

            Logger.Info(ObjectName, "Msr Thread Procedure Entered");

            while (true)
            {
                // When this method is called by the
                // ServiceObjectThreadHelper, it is obligated to
                // exit when the event ThreadStopEvent has been
                // set.

                // Additionally, this method will also wait for
                // hardware events or for a time-out. That should
                // be done here.

                // This example waits for the event to be set
                // or times out after several seconds.

                if (ThreadStopEvent.WaitOne(2000, false))
                {
                    break;
                }

                Logger.Info(ObjectName, "Reader Thread cycling");

                // Try to get a strong reference to the Service
                // Object using the weak reference saved when
                // this helper object was created.
                AdvancedSampleMsr msr =
                    ServiceObjectReference.Target
                    as AdvancedSampleMsr;

                // If this fails, that means the Service
                // Object has already been disposed of. Exit the
                // thread.
                if (msr == null)
                {
                    break;
                }

                // Using the strong reference, you can now make
                // calls back into the Service Object.
                msr.OnCardSwipe(MsrData);
                msr = null;
            }
            #endregion Methods of ServiceObjectThreadHelper
        }

        // Implementation of the Service Object class. This class
        // implements all the methods needed for an MSR Service
        // Object.
        //
        // A Service Object which supports a Plug and Play device
        // should also have a HardwareId attribute here.

        [HardwareId(
                @"HID\Vid_05e0&Pid_038a",
                @"HID\Vid_05e0&Pid_038a")]

        [ServiceObject(
                DeviceType.Msr,
                "AdvancedSampleMsr",
                "Advanced Sample Msr Service Object",
                1,
                9)]
        public class AdvancedSampleMsr : MsrBase
        {
            // String returned for various health checks.
            private string MyHealthText;
            private const string PollingStatistic =
                            "Polling Interval";

            // Create a class with interface methods called from the
            // threading object.
            MsrThreadingObject ReadThread;
            public AdvancedSampleMsr()
            {
                // DevicePath must be set before Open() is called.
                // In the case of Plug and Play hardware, the POS
                // for .NET Base class will set this value.
                DevicePath = "Sample Msr";

                Properties.CapIso = true;
                Properties.CapTransmitSentinels = true;

                Properties.DeviceDescription =
                            "Advanced Sample Msr";

                // Initialize the string to be returned from
                // CheckHealthText().
                MyHealthText = "";
            }

            ~AdvancedSampleMsr()
            {
                // Code added from previous sections to terminate
                // the read thread started by the thread-helper
                // object.
                ReadThread.CloseThread();

                Dispose(false);
            }

            protected override void Dispose(bool disposing)
            {
                try
                {
                    if (disposing)
                    {
                        if (ReadThread != null)
                        {
                            ReadThread.Dispose();
                            ReadThread = null;
                        }
                    }
                }
                finally
                {
                    // Must call base class Dispose.
                    base.Dispose(disposing);
                }
            }

            #region Internal Members
            // This is a private method called from the task
            // interface when a data event occurs in the reader
            // thread.
            internal void OnCardSwipe(byte[] CardData)
            {
                // Simple sample data.
                UTF8Encoding utf8 = new UTF8Encoding();
                byte[] track1Data = utf8.GetBytes(
                                "this is test track 1");
                byte[] track2Data = utf8.GetBytes(
                                "this is test track 2");

                // Call GoodRead(), UnreadableCard, or FailedRead
                // from here.
                GoodRead(
                        track1Data,
                        track2Data,
                        null,
                        null,
                        Microsoft.PointOfService.BaseServiceObjects.CardType.Iso);
            }
            #endregion Internal Members

            #region PosCommon overrides
            //  PosCommon.Open.
            public override void Open()
            {
                // Call base class Open.
                base.Open();

                // Initialize statistic values.

                // Set values for common statistics.
                SetStatisticValue(StatisticManufacturerName,
                                "Microsoft Corporation");
                SetStatisticValue(
                            StatisticManufactureDate, "2004-10-23");
                SetStatisticValue(
                            StatisticModelName, "Msr Simulator");
                SetStatisticValue(
                            StatisticMechanicalRevision, "1.0");
                SetStatisticValue(
                            StatisticInterface, "USB");

                // Create a new manufacturer statistic.
                CreateStatistic(
                            PollingStatistic,
                            false,
                            "milliseconds");

                // Set handlers for statistics stored in hardware.
                // Create a class with interface methods called
                // from the threading object.
                ReadThread = new MsrThreadingObject(this);
            }

            // PosCommon.CheckHealthText.
            public override string CheckHealthText
            {
                get
                {
                    // MsrBasic.VerifyState(mustBeClaimed,
                    // mustBeEnabled).
                    VerifyState(false, false);
                    return MyHealthText;
                }
            }

            //  PosCommon.CheckHealth.
            public override string CheckHealth(
                            HealthCheckLevel
                            level)
            {
                // Verify that device is open, claimed, and enabled.
                VerifyState(true, true);

                // Your code here checks the health of the device and
                // returns a descriptive string.

                // Cache result in the CheckHealthText property.
                MyHealthText = "Ok";
                return MyHealthText;
            }

            //  PosCommon.DirectIO.
            public override DirectIOData DirectIO(
                                int command,
                                int data,
                                object obj)
            {
                return new DirectIOData(data, obj);
            }

            public override bool DeviceEnabled
            {
                get
                {
                    return base.DeviceEnabled;
                }
                set
                {
                    if (value != base.DeviceEnabled)
                    {
                        base.DeviceEnabled = value;

                        if (value == false)
                        {
                            // Stop the reader thread when the
                            // device is disabled.
                            ReadThread.CloseThread();
                        }
                        else
                        {
                            try
                            {
                                // Enabling the device, start the
                                // reader thread.
                                ReadThread.OpenThread();
                            }
                            catch (Exception e)
                            {
                                base.DeviceEnabled = false;

                                if (e is PosControlException)
                                    throw;

                                throw new PosControlException(
                                        "Unable to Enable Device",
                                        ErrorCode.Failure, e);
                            }
                        }
                    }
                }
            }
            #endregion PosCommon overrides.

            #region MsrBasic Overrides

            // MsrBasic.MsrFieldData
            // Once the track data is retrieved, this method is
            // called when the application accesses various data
            // properties in the MsrBasic class. For example,
            // FirstName and AccountNumber.
            protected override MsrFieldData ParseMsrFieldData(
                                    byte[] track1Data,
                                    byte[] track2Data,
                                    byte[] track3Data,
                                    byte[] track4Data,
                                    CardType cardType)
            {
                // MsrFieldData contains the data elements that
                // MsrBasic will return as properties to the
                // application, as they are requested.
                MsrFieldData data = new MsrFieldData();

                // Parse the raw track data and store in fields to
                // be used by the app.
                data.FirstName = "FirstName";
                data.Surname = "LastName";
                data.Title = "Mr.";
                data.AccountNumber = "123412341234";

                return data;
            }

            // MsrBasic.MsrTrackData.
            protected override MsrTrackData ParseMsrTrackData(
                                    byte[] track1Data,
                                    byte[] track2Data,
                                    byte[] track3Data,
                                    byte[] track4Data,
                                    CardType cardType)
            {
                MsrTrackData data = new MsrTrackData();

                // Modify the track data as appropriate for your SO.
                // Remove the sentinel characters from the track data,
                // for example.
                data.Track1Data = (byte[])track1Data.Clone();
                data.Track2Data = (byte[])track2Data.Clone();

                return data;
            }
            #endregion MsrBasic overrides
        }
    }
}

Véase también

Tasks

Otros recursos