| Yang 的个人资料Yang's .NET Zone日志列表 | 帮助 |
|
5月30日 I'll move back to Google's BloggerWell, I've decided to move my blogs back to Google's Blogger and wait for Microsoft catching up. The new link is http://yangcao88.blogspot.com/. 5月29日 About Microsoft Management SecretsFrom Microsoft Secrets - by Micchael A Cusumano and Richard W. Selby: Many firms hire or promote people based solely on their managerial skills, not necessarily on how well they can combine their technical knowledge with an understanding of business and strategy. Microsoft puts knowledge of the technology and how to make money with this knowledge first in choosing managers. While this results in a shortage of middle managers with good people management skills, it has served Microsoft well in the highly technical world of developing computer software. At the same time, through new hires and acquisitions, Micorosft continually broadens its existing skill base such as by adding new groups for consumer software and information-highway products and services.
5月11日 Magic 15 with GetProcessesByName on Windows 2000My coworkers and friends, Ronnie Brown and Jerry Dennany, pointed it to me that static method Process.GetProcessesByName may return empty on Windows 2000 if the processName is longer than 15 characters. The appeared reason is that both Windows Task Manager and Performance Monitor on Windows 2000 can only display the first 15 characters of a process. But there are some exceptions to that rule that GetProcessesByName can find some of the processes with the name longer than 15. So what's going on? I opened Reflactor to check out how GetProcessesByName method is implemented in Porcess class. Here is the part in my interest: ProcessInfo info1 = infoArray1[num1]; Obviously on NT platform, the method compares the 1st 15 characters using the process name, and then turns around to compares the full name using process main module's name (without the last ".exe"). The most interesting part is the try/catch block that makes the logic become something like: "as long as the first 15 characters matches, it's still considered match even there is something wrong trying to retrieve the module's name." So I cranked up an app to perform some tests on Windows 2003 and 2000. Here is my coclusions:
For example, if an executable is named "Company.Prodct.App.exe" (the 15th character is "."), the test results are:
Does that mean that on Windows 2000 the process name is only 14 character long? Watch the following test. Now rename the executable to "CompanyProdctApp.exe" (removing the first 2 dots, but still contains 16 characters before the extention. Here we go:
So it seems that on Windows 2000 platform:
4月24日 Comments on Performance of EntLib LoggingFinally I got a chance return to my Blog again. I guess I must be pretty bad on managing my time. I have been following the the comments on EntLib Logging performance vs log4net's, for I intend to use EntLib in our product. Our product has very high requirement to logging performance, especially when debugging trace is turned on. I'm quite familiar with log4net and I really like it, except the part of Remoting Appender that I think needs some refactory. However, log4net has not been updated for almost 2 years and some useful features such as supporting WMI events are not there. That's the reason for me to pay special attention to EntLib Logging. Although there are number blogs about EntLib Logging performance, I was hoping someone on the development team would give an "official" explaination on what is and is not. Here we have Tom Hollander. But to my disappointment, he's wiggling just like a classical programmer that "it works on my machine". What I interpreted from his words was that EntLib wasn't designed with the mind for your solution. If it works, great. If not, sorry, buddy! I have worked with EntLib Data and Configuration application blocks and so far the taste wasn't great. I took quite a chunk of code out of DAB to make it simpler and more efficient. For CAB, I coded quite a lot just to make it work within our solution. 2月24日 Enterprise Library: Configuration Application Block - Something about ConfigurationChangeFileWatcher classIt's really nice to read someone from the development team of Enterprise Library blogs about it, like Scott Densmore. He has several blogs about Configuration Application Block, like this one: "Enterprise Library : Configuration Part 1.1.1 - Storage Provider". They give an easy introduction on how it works, which makes me feel more confortable to work with the product, besides just reading the documentation and over simplified code samples. However, I always think the major difference between a sales person and a developer is the former always tells you what works, the latter, on the other hand, reminds you what doesn't. I'm pretty sure I'm a developer, a die hard kind. It brought to my attention when I saw IConfigurationChangeWatcher interface. I was hoping to read something about the default implementation from the blogs. Unfortunately, I didn't see any. It took me about 15 seconds to figure out what is dirty out there. Here it is: ConfigurationChangeFileWatcher class. It creates a dedicated thread to poll the the configure file, check its LastWriteTime, and fire a ConfigurationChanged event. The default polling interval is set to 15 seconds. This is something shocked me but I'd like to hear the reason that it's implemented this way, without using System.IO.FileSystemWatcher class provided by .NET Framework which in my opinion is a far more scalable solution than polling. If my application has 3 configuration files need to be watched, the last thing I want to see is having 3 dedicated threads sit there doing nothing but polling. In most cases, configure files are rarely changed at runtime and polling is almost always one of the worst waste of system resources. If you really have to poll, use System.Threading.Timer class which uses System.Threading.ThreadPool thread for timing and is much scalable. I also happened to notice that the private DateTime field ConfigurationChangeFileWatcher.lastWriteTime is only used in private thread start method ConfigurationChangeFileWatcher.Poller, which means the field should really be only a local variable to the method. This type of evidences led me doubt how much serious effort Microsoft patterns & practices group has made to refactory their code. Knowing what can and can't do is vital important in today's development world to use someone's solution in your application. You won't have many chances going back and forth on different solutions. Don't wait until your customers wake you up at 3:00 AM and ask you why their production server's CPU has peaked every 15 seconds which has resulted in the functional failure of another application because it sleeps until system has been idle for at least 30 seconds. Don't give me wrong. I am not trying to complain about some bad implementation here. I believe every implementation has its reason behind it and can be improved later on. I just want to mark clearly what's the catch before I jump in. I hope those who know details about EntLib blog more about what doesn't work and why it doesn't. To see something working is way too obvious. However, to figure out its bondary can cost you lots of sleepless nights and beautiful weekends, and bring you painful experience, hopefully not too late. 2月22日 How to Create a Database Object Programmatically in Enterprise Library, Painfully?Thanks to scottden's post at GotDotNet on "Can the configuraton be modified throgh code?", which has saved me a lot of time to dig it out. Here I've corrected errors in his code and posted the complete code sample on how to create a Database object programmatically (without reading configuration files) in Enterprise Library:
using Microsoft.Practices.EnterpriseLibrary.Data;using Microsoft.Practices.EnterpriseLibrary.Configuration;using Microsoft.Practices.EnterpriseLibrary.Data.Configuration;DatabaseSettings settings = new DatabaseSettings(); // This maps to <databaseType> element in data config file DatabaseTypeData type = new DatabaseTypeData("Sql Server", "Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase, Microsoft.Practices.EnterpriseLibrary.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");settings.DatabaseTypes.Add(type); // This maps to <connectionString> element in data config file ConnectionStringData connectionString = new ConnectionStringData("localhost.EntLibQuickStarts");// Followings map to <parameter> elements in data config file ParameterData param = new ParameterData("server", "localhost");connectionString.Parameters.Add(param); param = new ParameterData("database", "EntLibQuickStarts");connectionString.Parameters.Add(param); param = new ParameterData("integrated security", "true");connectionString.Parameters.Add(param); settings.ConnectionStrings.Add(connectionString); // Too bad compiler gets confused InstanceData with System.Diagnostics.InstanceData. It maps to <instance> element in data config file Microsoft.Practices.EnterpriseLibrary.Data.Configuration.InstanceData instance = new Microsoft.Practices.EnterpriseLibrary.Data.Configuration.InstanceData("localhost", "Sql Server", "localhost.EntLibQuickStarts");settings.Instances.Add(instance); ConfigurationDictionary configurations = new ConfigurationDictionary();// This is how to tie DatabaseSettings with ConfigurationDictionary. It maps to <configurationSection name="dataConfiguration"> element in App.config file configurations.Add("dataConfiguration", settings);ConfigurationContext context = ConfigurationManager.CreateContext(configurations); Database database = new DatabaseProviderFactory(context).CreateDatabase("localhost");
Isn't it pathetic to write so many line of code to accomplish what should have been a single function call? Just compare to what's so simply in GotDotNet.ApplicationBlocks.Data:
public static AdoHelper AdoHelper.CreateHelper(string providerAssembly, string providerType)
There should be a similar one in Enterprise Library:
public static Database DatabaseFactory.CreateDatabase( string providerAssembly, string providerType)
Or better:
public static Database Database.CreateDatabase(string providerType, ConnectionString connectionString)
What I really don't understand is why Data Access Application Block is so tightly coupled with Configuration Application Block. I understand it's nice to be able to hook up data configuration file with Database object creation. However, what enables you to do is completely different to what forces you to do. |
|
|