DarioSantarelli.Blog(this);

Archive for October, 2010

[C#] How to programmatically find a COM port by friendly name

Posted by dariosantarelli on October 18, 2010


When using the SerialPort.GetPortNames() method, you are querying the current computer for a list of valid serial port names. For example, you can use this method to determine whether “COM1” and “COM2” are valid serial ports in your computer. The port names are obtained from the system registry (if the registry contains stale or otherwise incorrect data then this method will return incorrect data). The limit of this approach is that you get just an array of port names (e.g. { “COM1”,”COM2” … }) and nothing else! If the com ports are physical, there’s no problem but what about virtual ports connected for example through an USB adapter? Well, you can determine if a port is valid but you don’t know exactly which COM number was assigned to your device. So you need more information! In the system Device Manager, you can see the COM port friendly name under the "Ports (COM & LPT)" heading. This means that the right COM port number can be found by using WMI 🙂
A solution to this need comes from WMI Code Creator tool which allows you to generate VBScript, C#, and VB .NET code that uses WMI to complete a management task such as querying for management data, executing a method from a WMI class, or receiving event notifications using WMI.
A suitable WMI query is “SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0”.
Here is a code example showing how to enumerate the information of the COM ports currently available on your system (including the friendly name of course) by executing the query above.

using System.Management;

internal class ProcessConnection {

   public static ConnectionOptions ProcessConnectionOptions()

   {

     ConnectionOptions options = new ConnectionOptions();

     options.Impersonation = ImpersonationLevel.Impersonate;

     options.Authentication = AuthenticationLevel.Default;

     options.EnablePrivileges = true;

     return options;

   }

 

   public static ManagementScope ConnectionScope(string machineName, ConnectionOptions options, string path)

   {

     ManagementScope connectScope = new ManagementScope();

     connectScope.Path = new ManagementPath(@"\\" + machineName + path);

     connectScope.Options = options;

     connectScope.Connect();

     return connectScope;

   }

}

 

public class COMPortInfo

{

   public string Name { get; set; }

   public string Description { get; set; }

 

   public COMPortInfo() { }     

 

   public static List<COMPortInfo> GetCOMPortsInfo()

   {

     List<COMPortInfo> comPortInfoList = new List<COMPortInfo>();

 

     ConnectionOptions options = ProcessConnection.ProcessConnectionOptions();

     ManagementScope connectionScope = ProcessConnection.ConnectionScope(Environment.MachineName, options, @"\root\CIMV2");

 

     ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");

     ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery);

 

     using (comPortSearcher)

     {

       string caption = null;

       foreach (ManagementObject obj in comPortSearcher.Get())

       {

         if (obj != null)

         {

           object captionObj = obj["Caption"];

           if (captionObj != null)

           {

              caption = captionObj.ToString();

              if (caption.Contains("(COM"))

              {

                COMPortInfo comPortInfo = new COMPortInfo();

                comPortInfo.Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")",

                                                     string.Empty);

                comPortInfo.Description = caption;

                comPortInfoList.Add(comPortInfo);

              }

           }

         }

       }

     } 

     return comPortInfoList;

   }
}

Finally you can easily get the com port list in this way…

foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())

{

  Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));

}

Other solutions?

  • A first alternative is SetupAPI. You can find a complete example here.
  • Secondly, you can try to use DevCon (a Microsoft tool that allows "device management" from the command line): you could use the

    System.Diagnostics.Process class to parse the standard output of the command line “>devcon find =ports”.

Posted in .NET Framework, C# | Tagged: | 35 Comments »

[C#] Byte Array to Hex string

Posted by dariosantarelli on October 16, 2010


There are a lot of ways of converting a byte array to the corresponding hexadecimal string. I usually adopt the BitConverter class in order to optimize the readibility of code, but starting from the .NET Framework 3.0 the same task can be obtained using a single line of code through extensions methods:

[TestMethod]
public void BitConverterVsStringConcatAndExtensionMethod()
{
 
byte[] bytes = new byte[] { 0x00,0xAA,0xB0,0xC8,0x99,0x11,0x01,0x02 … };
 
string expectedResult = "00AAB0C899110102…";
 
 
string result1 = BitConverter.ToString(bytes).Replace("-",string.Empty);
 
 
string result2 = string.Concat(bytes.Select(b => b.ToString("X2")));

 
Assert.AreEqual(expectedResult, result1);
 
Assert.AreEqual(expectedResult, result2);
}

OK no performance issue has been discussed. Aren’t you satisfied? Follow this thread !!! (4 years of discussion :D)

Posted in .NET Framework, C# | Leave a Comment »

[ASP.NET MVC 2] Handling timeouts in asynchronous controllers

Posted by dariosantarelli on October 16, 2010


An important feature of the ASP.NET MVC framework is the possibility of creating asynchronous controllers. As in Asynchronous Pages in ASP.NET 2.0, the aim is to avoid a “thread starvation” in your web application, preventing web clients to receive a bad 503 status code (Server too busy). In fact, when the Web Server receives a request, a thread is taken from the application threadpool mantained by the .NET Framework. In a synchronous scenario, this thread lives (and can’t be reused) until all the operations complete. Well, asynchronous pipeline is better when the logic creates bottlenecks waiting for network-bound or I/O-bound operations. Considering that an asynchronous request takes the same amount of time to process as a synchronous request, minimizing the number of threads waiting for blocking operations is a good practice, particularly appreciated by your Web server when it’s bombarded by hundreds of concurrent requests. Now, have a look to this simple asynchronous controller:

public class CustomersController : AsyncController

{

   [AsyncTimeout(10000)]

   public void ListAsync()

   {

     AsyncManager.OutstandingOperations.Increment();

     Task.Factory.StartNew(() =>

     {

       try { AsyncManager.Parameters["result"] = new MyServiceClient().GetCustomers(); }

       catch (Exception ex) { … }

       finally { AsyncManager.OutstandingOperations.Decrement(); }

     );

   }

 

   public ActionResult ListCompleted(List<Customer> result)

   {

     return View("List", result);

   }

   …

      

   protected override void OnException(ExceptionContext filterContext)

   {

     if (filterContext.Exception is TimeoutException)

     {

       filterContext.Result = RedirectToAction("TryAgainLater");

       filterContext.ExceptionHandled = true;

     }           

     base.OnException(filterContext);

   }   

}

By default, ASP.NET MVC won’t call the ListCompleted method until the AsyncManager associated with the request says that there is no outstanding asynchronous operations. But it’s possible that one or more asynchronous operations might never complete!!! Moreover, if the callback for one of your asynchronous operations throws an exception before it calls the AsyncManager.OutstandingOperations.Decrement() method, the request will keep waiting a decrement until it times out! So, putting the AsyncManager.OutstandingOperations.Decrement() call inside a finally block would be fine :).
The AsyncManager object has a built-in default timeout set to 45 seconds, so if the count of outstanding operations doesn’t reach zero after this long, the framework will throw a System.TimeOutException to abort the request. If you want to set a different timeout you can use the AsyncTimeout filter for specifying a different duration. If you want to allow asynchronous operations to run for an unlimited period, then use the NoAsyncTimeout filter instead.

Finally, we have to say that most applications will have an ASP.NET global exception handler that will deal with timeout exceptions in the same way as other unhandled exceptions. But if you want to treat timeouts in a custom way, providing a different feedback to the user, you can create your own exception filter or you can override the controller’s OnException() method (e.g. to redirect users to a special “Try again later” page).

Posted in ASP.NET | Tagged: , | 1 Comment »