Five years ago, we decided to utilize Microsoft’s Point Of Service for .NET (POS for .NET) in our point of sale (POS) to integrate with the various peripherals used by POS systems. Simply put, POS for .NET enables developers to utilize receipt printers, cash drawers, barcode scanners, magnetic stripe readers (MSR), line displays (and many other peripherals) within their .NET applications. Back then, the .NET framework was at version 2.0. Obviously, many things have changed since then with the advent of .NET 3.0, 3.5 and, more recently, 4.0. However, the latest version of POS for .NET’s is v1.12 and it was released in 2008.

Being forward-thinking as we are, we structured our point of sale as a web application from day one, to enable future deployment scenarios (being browser-based means we can easily use our point of sale on the iPad or any other hot hardware platform) and code-reuse within our e-commerce application and FranchiseBlast. However, this made it a bit harder on us to integrate with the peripherals as we weren’t using them in the traditional context of a desktop application (especially access Windows printers from a server-side web application). However, we solved those issues many years ago and have continued to evolve the solution ever since.

Fast forward to 2011: POS for .NET has not been refreshed in three years, we’ve moved to 64-bit machines and .NET 4.0. This blog post is a collection of tips & tricks for issues commonly faced by .NET developers working with POS for .NET in 2011.

Common Control Objects – don’t forget about them!

This is just a reminder, as this was true back in 2006 too. You’d typically expect to be able to install the peripheral’s driver and then utilize it within your .NET application. However, you also need to install intermediary Common Control Objects.  I always end up downloading the CCOs from here.  I always forget the proper order and sometimes run into trouble because of this and end up having to uninstall and reinstall half a dozen times until it works (… pleasant…). I believe this is the installation order I use (you may need to reboot between each step).

  1. Install Epson OPOS ADK
  2. Install other drivers (scanners, etc.)
  3. Install the Common Control Objects
  4. Define logical device names (LDN) using Epson OPOS
  5. Install POS for .NET 

 

POS for .NET doesn’t work in 64-bit

Long story short, due to the legacy hardware it supports, POS for .NET only works in 32-bit. If you’re running an app on a 64-bit machine, it will fail with a cryptic error message or will simply be unable to find your peripherals. Example:

System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {CCB90102-B81E-11D2-AB74-0040054C3719} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

You can still use the peripherals on 64-bit operating systems, but you will need to compile your desktop application as 32-bit (Right click on your project –> Build –> Platform target: x86). You even need to do this with the example application that comes with POS for .NET (in C:\Program Files (x86)\Microsoft Point Of Service\SDK\Samples\Sample Application) if you want to use it.

You’ll probably run into the same issues with all the .NET test applications supplied by the device manufacturers. Unless you can manage to find an updated sample, you’ll have to work your magic with a decompiler. In addition to probably being illegal, it is a pain and a half. Therefore, you’re better off using the test application that comes with POS for .NET.

As for web applications, you need to force IIS to run your application in a 32-bit application pool.

POS for .NET doesn’t work in .NET 4.0

Another bad surprise is migrating your application to .NET 4.0 and then realizing the POS hardware stops working. Long story short, you’ll get this error:

This method explicitly uses CAS policy, which has been obsoleted by the .NET Framework. In order to enable CAS policy for compatibility reasons, please use the NetFx40_LegacySecurityPolicy configuration switch. Please see http://go.microsoft.com/fwlink/?LinkID=155570

The error message is fairly self-explanatory. Microsoft stopped supporting '”Code Access Security”, which is internally used by POS for .NET. You can either turn on a configuration option that re-enables the legacy CAS model or wait for Microsoft to release a new version of POS for .NET.  We’ve been told not to hold our breath, so the configuration option is the preferred flag. 

If you’re creating a desktop application, the solution is in the error message – more details here.  Add this to your app.config:

<configuration>
   <runtime>
      <NetFx40_LegacySecurityPolicy enabled="true"/>
   </runtime>
</configuration>

 

If you’re creating a web application, the flag is a bit different. Add this to your web.config:

<configuration>
    <system.web>
      <trust legacyCasModel="true"/>
   </system.web>
</configuration>

POS for .NET doesn’t work with ASP.NET MVC / dynamic data/operations

The above flag will cause your legacy code to run properly on .NET 4.0 but it does have a side-effect. You will not be able to use some of the newer .NET framework features such as the dynamic keyword. Not only can you not use it explicitly within your own code, but ASP.NET MVC 3 uses it internally within the ViewBag.

Dynamic operations can only be performed in homogenous AppDomain.

Thus, you have to choose between POS for .NET or ASP.NET MVC 3, unless you load up your POS objects in another AppDomain. Here’s some sample code to help you do that.

You need to be able to create another AppDomain and specify that this AppDomain should use the NetFx40_LegacySecurityPolicy option, even if your current AppDomain doesn’t have this flag enabled.

   1:  var curr = AppDomain.CurrentDomain.SetupInformation;
   2:  var info = new AppDomainSetup()
   3:  {
   4:      ApplicationBase = curr.ApplicationBase,
   5:      LoaderOptimization = curr.LoaderOptimization,
   6:      ConfigurationFile = curr.ConfigurationFile,
   7:  };
   8:  info.SetCompatibilitySwitches(new[] { "NetFx40_LegacySecurityPolicy" });
   9:   
  10:  return AppDomain.CreateDomain("POS Hardware AppDomain", null , info);

 

You can then use this AppDomain to create your POS peripherals. All our peripherals extend our own custom PosHardware base class with a few standard methods such as FindAndOpenDevice(), so we use the following code. For testing purposes, we created a configuration option (IsHardwareLibInSameAppDomain) to toggle between loading in the current AppDomain versus a separate one.

   1:  private T Build<T>(string id) where T : PosHardware, new()
   2:  {
   3:      T hardware = null;
   4:      if (IsHardwareLibInSameAppDomain)
   5:          hardware = new T();
   6:      else
   7:          hardware = (T)OtherAppDomain.CreateInstanceFromAndUnwrap(Assembly.GetAssembly(typeof(T)).Location, typeof(T).FullName);
   8:   
   9:      if (!string.IsNullOrEmpty(id))
  10:          hardware.DeviceName = id;
  11:      hardware.FindAndOpenDevice();
  12:      return hardware;
  13:  }

 

Also, don’t forget to mark your classes as Serializable and MarshalByRefObject.

   1:  [Serializable]
   2:  public abstract class PosHardware : MarshalByRefObject

 

Working with objects in other AppDomains is a pain.  Any object that you pass between the two app domains (such as parameters to functions or return values) must be marked as Serializable and extend MarshalByRefObject if you wish to avoid surprises.  If you marshal by value instead, you will be working on read-only copies of (which may or may not be desirable, depending on your context.)

Conclusion

It only took three years without a new release before POS for .NET started being a pain to work with – unless you stick with past technologies. With the advice provided here, however, you should be able to move forward without issue. Did you discover any other gotchas with POS for .NET?