Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving .NET user settings takes very long time

In our .NET 4.0 Winforms application, some users (all Win7 x64) recently experienced very long wait times (compared to others) when the application is saving its' settings using this code:

Properties.Settings.Default.Save();
  • Typical durations: 0.5 to 1 seconds
  • Extreme durations: 15 to 20 seconds

The applications settings (scope: User, everything saved in user.config under AppData\Local\\) consist of several custom classes as well as two classes representing printer settings: System.Drawing.Printing.PageSettings and System.Drawing.Printing.PrinterSettings

Using GlowCode profiler on one of those machines, I found the following function to take 17 seconds:

<Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPrinterSettings_x003A__x003A_Write9_PrinterSettings Nodes="1" Visits="1" percent_in_Child="100.00 %" Time_in_Child="17.456" Time="17.456" Avg._Time_in_Child_="17.456" Avg._Time="17.456" Blocks_net="12" Bytes_net="1024" Blocks_gross="1087" Bytes_gross="494146" />

Of which the duration was almost equally split onto three getters (taken from GlowCode viewer):

  • PrinterSettings::get_PaperSizes
  • PrinterSettings::get_PaperSources
  • PrinterSettings::get_PrinterResolutions

Doing some research revealed following pages: https://social.msdn.microsoft.com/Forums/vstudio/en-US/8fd2132a-63e8-498e-ab27-d95cdb45ba87/printersettings-are-very-slow and http://www.pcreview.co.uk/forums/papersources-and-papersizes-really-slow-some-systems-t3660593.html, quote:

On some systems, particularly Vista x64 systems, it takes forever (5 to 15 seconds if compiled for x64, 10-20 seconds if compiled for x86) to enumerate either the papersources or papersizes collection of a printersettings object.

Using a small test app just saving PrinterSettings revealed a saving time around 3.5 seconds on one of those "slow" machines, while the other was quite not impressed with a duration of 0.2 seconds which corresponds to my fast development machine.

Any ideas on the reasons and how to improve this?

How can I find the real reasons for these delays?

Edit: Thanks for pointing out that the printer settings are acquired through the driver, this might explain delays on certain machines.

Updating the printer drivers on machines which I cannot access in future wherever this will be installed is not possible.

Also, I won't (I know I know) reduce the PrinterSettings information to be saved just because some people might experience a lag and break backward compatibility eventually ...

Maybe if I try serialization in background (after user has done some printer changes?) it might speed up things ...

like image 659
bettwäsh Avatar asked Nov 18 '14 14:11

bettwäsh


1 Answers

First suggestion:

The calls to retrieve paper sources and paper sizes are being passed through to the driver. Your best bet is going to make sure that the newest version of the driver is installed. It's possible that older versions of the driver (in particular, those from the CD that came in the box) are old and buggy. If you haven't already, hit the manufacture's website, and grab the latest.

Second suggestion

Apart from that, it's going to be a pain, but you could try using the underlying Win32 APIs instead of the CLR counterparts. In this case, you'd call GetPrinter, requesting a PRINTER_INFO_2 struct. Once you have that, you can examine pDevMode to get a DEVMODE struct that has all of the information you're looking for.

This question or this question should be helpful.

Instead of persisting the entire PrinterSettings class instance, only persist individual settings as their base types. Keep it simple -- strings, ints, bools, etc. Clearly the Serializer is requesting communication with the printer, and that's what is introducing the latency. I'm willing to bet that if you grab individual class members and serialize them yourself, you'll see an improvement.

Obviously, this means that when you load settings, you'll need to deserialize all of these settings back into a new PrinterSettings class, and apply them.

EDIT 1, in response to question edit

That's true - you could have the Save() run async in the background. Your only issue would be if the user attempts to end the process (close the app) before the save is complete. You'd have to maintain a bool as to whether a save is occurring (set to false when the callback fires). If the user attempts to exit the app and the bool is true, put up "Please wait while settings are saved..." until the bool goes false.

like image 120
Lynn Crumbling Avatar answered Oct 02 '22 14:10

Lynn Crumbling