The below are few points that we learned during a recent application developed using WinForms and deployed using ClickOnce.
The core functionality of the application was to provide proximity card based attendance system for students in a classroom. For this we were previously using the API provided by HID Global. This caused various dependency issues between Windows operating systems and architectures (32bit vs 64bit), so as part of the refactoring we have removed the dependency and using the PC/SC interface exposed by Windows natively. Of course, this means mucking around a bit in the P/Invoke world (for accessing WinScard.dll related functions), but it provides elegance to the application by eradicating extra baggage of dependency.
From Windows Vista the operating system had a group policy setting where the operating system installed new device driver for every proximity card that was swiped on the card reader. This meant that for every card swipe, the user had to wait for Windows to install the device driver and then go through with the rest of the application logic. As part of our requirements this was not necessary, even so more of a hinderance. We have an internal ERP system which stores the additional identification details for the students and we had to integrate with that ERP for the student attendance marking.
In order to disable the above behaviour of Windows, we needed to disable the SmartCard Plug and Play functionality. The details of this setting is detailed at http://technet.microsoft.com/en-us/library/ff404287(WS.10).aspx. Basically the administrator has to disable the “Turn on Smart Card Plug and Play service” option under Computer Configuration -> Administrative Templates -> Windows Components -> Smart Card
in the group policy.
Apart from normally authenticating the service calls from the client application, we wanted to obscure the actual service call endpoint strings stored in the application settings. In order to achieve this, we made use of protection mechanism provided by System.Configuration.ConfigurationSection.SectionInformation.ProtectSection
function.
We determined that the application was running for the first time using
|
|
and then used the ProtectSection
functionality
|
|
this makes sure that the settings are not stored in plain strings for anybody to view.
Due to various internal reasons and ClickOnce not successfully (reliably checking and updating to newer version) we have used a check and update mechanism for updating the version of the deployed application. Without reinventing the wheel we simply used the same architecture of ClickOnce by using a custom update checking form and providing event handlers to the System.Deployment.Application.ApplicationDeployment
class.
One more advantage of keep the update manual is we can selectively call the update process only when running the application in network deployed mode. So that when doing normal local debugging this doesn’t interfere with the debugging process.
We were facing with the following exception whenever we tried copying any text from a DataGridView control:
``
When researching on this issue, we came across Soumitra Mondal’s blog entry on addressing the same error when invoking the OpenFileDialog in another application. And using the same methodology we used a helper class for invoking the new form objects in STA thread.
|
|
By using the STAShowDialog
we successfully loaded the target form object on a STA thread and avoided the above mentioned exception.
I have blogged about the new System.DirectoryServices.AccountManagement
in a past blog entry. The main requirement was that we needed to authenticate Active Directory users without a separate administrative login credential for connecting to the directory service. This was achieved using a elaborate LDAP DirectoryEntry class with a directory path using ldap protocol and such. With .NET 4.0 we simply use System.DirectoryServices.AccountManagement
for these purposes.
The authentication of student entry needed to be confirmed using audible alerts apart from the visual alerts. We also wanted to make sure that the system’s volume was appropriately set so that we were not playing the sounds on muted systems. For this purpose we used CoreAudioAPI for the major weight lifting and a helper class to address our requirements:
|
|
The final form had few business logic to take care before the application was closed, and to control the exit we had to disable standard close button on the top right of the form. We also wanted the user to be able to minimize the application at will, so we couldn’t simply disable the ControlBox. So, the CreateParams
was overridden to achieve the desired effect as follows:
|
|
tip from http://www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms.
That is it for now, I hope the above tips ends up helpful for someone.
Happy coding!