Monday, October 15, 2007

How to uninstall SQL 2005 if it's missing in Add/Remove Programs


First of all - here is the support KB article.
In my case - I was unable to uninstall SQL 2005 even manually from the command line (ArpWrapper was ceasing to work, displaying some "Registry Enumeration Failed" error and uninstalling components with MsiExec using their GUID's listed in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall just didn't worked).

I was able to do it by uninstalling SQL components manually with Microsoft Windows Install Clean Up utility (do it in order, specified in KB article).



Wednesday, October 10, 2007

How to create WCF service proxy without publishing mex endpoint #2


Important update to my previous article: if your service is defined inside of a namespace - you must specify the namespace using /serviceName option during the 1st step (WSDL and XSD creation).
Updated step #1 example:
svcutil /serviceName:MyNamespace.MyService MyServiceSvc.exe /reference:SomeReference.dll
If you'll miss specification of the namespace - resulting proxy code would be wrong (including even endpoing binding defintion).

Internet Explorer cannot open the Internet site - Operation aborted


I was affected by this issue and it took me some time to figure out what's the reason of it (in my case it was quite tricky). Generally - the reasons causing this error in IE are quite known. (Here are some for your reference :)

In my case it was a completely different story - it was caused by few IE DOM implementation bugs. Consider you have code on the IE client side that parses page body nodes and then removes them:

while (body && body.hasChildNodes()) {
var node = body.firstChild;
// ... app logic
body.removeChild(node);
}


Now consider that body content is created by Response.Write() on the server side (I write down some context in <p>...</p> paragraphs sections).
My application was working as a blaze, but occasionally I was getting "Internet Explorer cannot open the Internet site - Operation aborted" in IE. In Firefox it was never happen.
After some research I narrowed down the reason to the fact that body context is created by Response.Write and then I catched up what the problem was - it was related to the fact that on the server side I was writing body nodes in 4 steps:
1) ‘<p>’
2) app-specific content
3) ‘</p>’
4) Flush() output.

So - sometimes on the client side the code was running while paragraph weren't fully formed (e.g. only starting <p> was written).
In this case body.hasChildNodes() still returns true (IE bug #1) and body.removeChild(node) will cause "operation aborted" (IE bug #2).
As I noted - it's IE-specific and not happens in other browsers.

Fortunatelly - I had Response() bufferring turned off at the server side - o/w above problem would still happen, but with much lower frequency, making it very difficult to track it down.
The solution, as you may guess, is to write whole node at once on the server side...

Wednesday, September 19, 2007

.NET 3.5 Beta 2 - no LINQ performance improvements?


     Today I've got a comment on my post where I compared performance of LINQ vs. DAAB vs. ADO.NET, saying that I should repeat my test with .NET Framework 3.5 beta 2. Indeed there are a lot of posts about performance improvements introduced in it, so I've rushed and repeated my test, compiling it in Microsoft Visual Studio 2008 Beta 2, targeting .NET 3.5 beta 2.
     Not sure that proverb "no news - good news" is correct in this case, but - well - no news. I mean that performance results are absolutely the same - LINQ is about 30% slower than raw ADO.NET (4.28 ms per call for ADO.NET vs. 5.51 ms per call for LINQ). Also, using LINQ rather than ADO.NET makes application much more CPU intensive (something like ~20% of CPU intensity with LINQ vs. ~2% of CPU intensity with ADO.NET - difference of order of magnitude!). You may see screenshots below.

Timing results


CPU Intensity.(First third - ADO, second - DAAB, third - LINQ.)

So it seems to me that there are no significant performance improvements, unless there is something fundamentally wrong with my tests (check code here).

     Yet - I want to develop here something I've mentioned in my previous post. This additional performance cost doesn't mean "don't use LINQ". You'll probably never will get to performance incur of 30% in the real project. In the real life scenario you'll never abuse your DB by shooting thousands of SP calls in a batch, without doing something with results. There is always some business logic around, some DAL, some timings, etc - so the performance costs are never so high and they will be spread around evenly, rather than composed into a performance-loss peak. Also - mind that LINQ greatly improves coding productivity, decreases amount of code and project complexity. This means that developers would spend less timing coding and the costly thing for the project is the developer time. In the very worst case - profile your application to find the bottlenecks of 20:80 rule and use ADO.NET in critical sections of your code. And buy quicker CPU - they are cheap today :) ...

P.S.
     Few links to related articles:


Sunday, August 19, 2007

How to give alias to the SQL Linked Server


There are no problems to add SQL linked server to the specific host running it. But what if you need to give it an alias, rather than use hostname as linked server name?
Here is how to do it:
1) Step 1:
• In SQL Server Management Studio open Linked Servers and then 'New Linked Server'.
• Inside of appeared wizard – Select the General tab.
• Specify alias name in "Linked server" field.
• Select SQL Native Client as provider.
• Add sql_server in "Product Name" field (that's the magic).
• In "Data Source" – specify name of the host to be used as linked server.
2) Step 2:
• In Security tab – specify proper security options (e.g. security context)
3) Step 3:
• In Server Options tab – put "Data Access", RPC, "Rpc Out" and "Use Remote Collaboration" to be true.
4) Step 4:
• Enjoy.

How to create WCF service proxy without publishing mex endpoint


Some time ago I needed to create WCF service proxy, while I don't wanted to expose and publish MEX endpoint for it (and then generate the proxy from its wsdl). Strangely, but I didn't found any clue on how to do it in the Google depths. Even MSDN articles (1 and 2) devoted to the SvcUtil doesn't mention it in a straightforward way. Here is how to do it:

1) Create WSDL and XSD definitions for your service. Use following command:
svcutil /serviceName:MyService.MyServiceClass MyServiceAssembly.exe /reference:MyServiceContracts.dll
(You'll need to reference additional assemblies related to the service, like I did with MyServiceContracts.dll)

2) Generate proxies and corresponding client WCF configuration in .config file:
svcutil *.wsdl *.xsd /language:C#

Wednesday, August 15, 2007

In order to add an endpoint to the service MyService, a non-empty contract name must be specified.


Are you getting InvalidOperationException while creating ServiceHost for your service and getting message in style of "In order to add an endpoint to the service 'MyService', a non-empty contract name must be specified."? the probable reason is that you've missed contract definition in one of it's endpoints. Go to the endpoints list in your .config file and check that each endpoint has 'contract="MyContracts.IMyInterface"' tag.

DEV012 Building WPF XAML Browser Applications - few patches



Few patches you may need to use for this lab:
  1. You getting "Error 32 SignTool reported an error SignTool Error: Signtool requires CAPICOM version 2.1.0.1 or higher" - solutions is here.

  2. You getting "Request for the permission of type System.Net.WebPermission" - it could be caused by a range of reasons. In my case - I needed to set Execute permissions to "Scripts only" rather than "Scripts and Executables". If it not helps you - here few more receipts:

Thursday, August 09, 2007

Consolas - ClearType font optimized for programming environment

DEV012 Building WPF XAML Browser Applications - few patches

Few patches you may need to use for this lab:

  1. You getting "Error 32 SignTool reported an error SignTool Error: Signtool requires CAPICOM version 2.1.0.1 or higher" - solutions is here.

  2. You getting "Request for the permission of type System.Net.WebPermission" - it could be caused by a range of reasons. In my case - I needed to set Execute permissions to "Scripts only" rather than "Scripts and Executables". If it not helps you - here few more receipts:

Wednesday, August 08, 2007

WCF Performance

JSON Date deserialization fails at client
Some time ago I've developed a Comet infrastructure for the ASP.NET Ajax. As part of its possibilities - it enables to serialize server-side objects and stream them to the handling function at client side. It was working like a breeze, until Ive streamed some object with Date field, say something like that:        
public class TestMessage        
{            
public string _s1 = "s1";            
public int _i1 = 1;            
public DateTime _t1 = DateTime.Now;        
}


Now, an instance of this TestMessage was correctly deserialized into JS object, exclude its DateTime fields, which was appearing in following form:
{...}
_i1: 1
_s1: "s1"
_t1: "/Date(777)/"


If youre affected by similar problem here is the reason:
1) JSON representation for the string was changed from @777@ to \/777\/ in the latest Ajax release (to prevent serialization of strings that looks like date into Date format), where 777 is num of milliseconds since January 1, 1970 UTC.
2) Currently - at the server side DateTime object is serialized as "_t1":"\/Date(777)\/"
3) If you stream it as-is to the client-side JS recognizes single \ as escape character and your date actually became /Date(777)/, which is wrong format for deserialization.

So, if you want to stream your objects correctly you here is small RegEx-based utility Ive did for it:        

private static class ReplaceDateOrchestrationRegularExpression        
{            
private const string _regex =                
"(?\")(?\\\\)(?/Date\\([\\d]+\\))(?\\\\)(?<" + "postfix>/\")";            
private static readonly RegexOptions _options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);            

public static readonly Regex Expression = new Regex(_regex, _options);            
public const string ReplaceOptions =                
@"${prefix}${firstDateSlash}\${body}${secondDateSlash}\${postfix}";        
}        


private static string ConvertToClientSideJson( string jsonedArgument )        
{            

return ReplaceDateOrchestrationRegularExpression.Expression.Replace(
jsonedArgument,
ReplaceDateOrchestrationRegularExpression.ReplaceOptions);        
}

Errors in PageFlowInstanceStore.sql when installing DB for PageFlowQuickstart in WCSF



When trying to install PageFlowQuickstart.sql to create DB for the PageFlowQuickstart of WCSF I've encountered the following errors:



OSQL -S "localhost" -d "PageFlowPersistenceStore" -E -n -i "..\..\Blocks\PageFlow\Scripts\PageFlowInstanceStore.sql"
Msg 137, Level 15, State 2, Server localhost, Procedure pageFlow_DeleteInstance, Line 6
Must declare the scalar variable "@instanceId".
Msg 207, Level 16, State 1, Server localhost, Procedure pageFlow_GetLastRunningInstanceByCorrelationToken, Line 12
Invalid column name 'running'.
Msg 207, Level 16, State 1, Server localhost, Procedure pageFlow_GetInstanceByTypeAndByCorrelationToken, Line 6
Invalid column name 'InstanceId'.
Msg 137, Level 15, State 2, Server localhost, Procedure pageFlow_ChangeInstanceStatus, Line 8
Must declare the scalar variable "@Running".
Msg 137, Level 15, State 2, Server localhost, Procedure pageFlow_SetRunningInstanceForCorrelationToken, Line 24
Must declare the scalar variable "@instanceID".
Msg 207, Level 16, State 1, Server localhost, Procedure pageFlow_GetTypeByInstanceId, Line 9
Invalid column name 'InstanceId'.




If you're getting hit by this problem - here is the reason: whole SQL script is written in assumption that DB collation is case-insensitive.
Just fix the letters case ( @InstanceId instead of @instanceId , etc.) and you have it fixed.

Tuesday, August 07, 2007

How to keep Format Painter active in Office-style applications...


Here is the trick - double click the format painter icon to format multiple elements. Press ESC to end formating.

Monday, July 30, 2007

Free e-book: Rapid C# Windows Development


"Rapid C# for Windows Development" by Joseph Chancellor is available (in .pdf format) for free download from LLBLGen Pro site.

Monday, July 16, 2007

Benchmarking LINQ vs. DAAB vs. ADO.NET



Abstract: This article presents benchmarking results of performance of SP calls using LINQ, Data-access application block and ADO.NET.

Some time ago I was doing LINQ performance benchmarking, looking for an option of replacing our existing data layer with it. One thing that was especially important for me to check - was performance of executing SP's. The reason is that most of our DAL logic resides in SP's at one hand and that performance-critical parts are implemented as SP's as well (for all the good reasons, like possibility to benefit from queries compilation etc).

Below are performance benchmarking results of execution uspGetManagerEmployees SP from AdventureWorks DB. (Basically it does some sort of JOIN to retrieve records of employees data for the specified Manager ID).
I tested three data-access models - raw ADO.NET vs. DAAB (our current DAL workhorse) vs. LINQ (May 2006 preview version).

As a prerequisite for running this test you'll need AdventureWorks DB and installation of LINQ.
Few side-notes:
  • I've left opening of DB connection out of the context of benchmarked section. Only SP execution is measured.

  • I use ExecuteReader rather than ExecuteDataSet, as it is much more lightweight. For LINQ benchmark I using GetEnumerator().

So here goes the test code:

1. Plain ADO.NET:


public static void SqlSPBench()
{
string connectionString =
"Data Source=localhost;Initial Catalog=AdventureWorks;Integrated Security=True";

using( SqlConnection conn = new SqlConnection( connectionString ) )
{
conn.Open();

Stopwatch watch = new Stopwatch();
watch.Start();

int count = 10000;
for( int i = 0; i < count; i++ )
{
using( SqlCommand cmd = new SqlCommand() )
{
cmd.Connection = conn;
cmd.CommandText = "uspGetManagerEmployees";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add( new SqlParameter( "ManagerID", 3 ) );

using( SqlDataReader reader = cmd.ExecuteReader( CommandBehavior.Default ) )
{
//while (reader.Read())
//{
// Console.WriteLine(reader[3]);
//}
}
}
}
watch.Stop();
Console.WriteLine(
"Running " + count +
" SP's using SQL ExecuteReader took " + watch.ElapsedMilliseconds + " ms");
Console.ReadLine();
}
}


2. DAAB (Data Access Application Block):


public static void SqlSpDAAB()
{
Database adventureWorksDataBase = DatabaseFactory.CreateDatabase( "AdventureWorks" );

Stopwatch watch = new Stopwatch();
watch.Start();

int count = 10000;
for( int i =0; i<count; i++ )
{
using( DBCommandWrapper sp_uspGetManagerEmployees =
adventureWorksDataBase.GetStoredProcCommandWrapper(
"uspGetManagerEmployees" ) )
{
sp_uspGetManagerEmployees.AddInParameter( "@ManagerID", DbType.Int32, 3 );
using( IDataReader dataReader =
adventureWorksDataBase.ExecuteReader( sp_uspGetManagerEmployees ) )
{
//DataSet results =
// adventureWorksDataBase.ExecuteDataSet( sp_uspGetManagerEmployees );
}
}
}
watch.Stop();
Console.WriteLine(
"Running " + count + " SP's using DAAB took " +
watch.ElapsedMilliseconds + " ms");
Console.ReadLine();
}


3. LINQ (using ORM layer produced by SQLMetal.exe - "c:\Program Files\LINQ Preview\Bin\SqlMetal.exe" /server:. /database:AdventureWorks /pluralize /sprocs /code:AdventureWorks.cs):



public static void LinqSPBench()
{
string connectionString =
"Data Source=localhost;Initial Catalog=AdventureWorks;Integrated Security=True";
AdventureWorks adventureWorks = new AdventureWorks( connectionString );

Stopwatch watch = new Stopwatch();
watch.Start();

int count = 10000;
for( int i =0; i<count; i++ )
{
StoredProcedureResult<UspGetManagerEmployeesResult> result =
adventureWorks.UspGetManagerEmployees( 3 );
IEnumerator<UspGetManagerEmployeesResult> enumerator = result.GetEnumerator();
//while( enumerator.MoveNext() )
//{
// Console.WriteLine( enumerator.Current.LastName );
//}
}
watch.Stop();
Console.WriteLine(
"Running " + count +
" SP's using LINQ took " + watch.ElapsedMilliseconds + " ms");
Console.ReadLine();
}


Here are timing results of this benchmarking test:
  • Running 10000 SP's using SQL ExecuteReader took 42806 ms

  • Running 10000 SP's using DAAB took 46443 ms

  • Running 10000 SP's using LINQ took 55136 ms




Results
So, comparing to the raw ADO.NET - DAAB is 8% slower and LINQ is 28% slower.
Comparing to DAAB - LINQ is 18% slower.
CPU usage intensity is about 2% average for raw ADO.NET vs. about 8% for DAAB vs. about 20% for LINQ - order of magnitude worse than raw ADO.NET (CPU graphs captured with perfmon below).


Fig. 1 ADO.NET - CPU usage


Fig. 2 DAAB - CPU usage



Fig. 3 LINQ - CPU usage

In overall - this performance overhead is quite disappointing. I still consider to use LINQ, as we have DAL/BLL servers in our architecture, which we may merely upgrade to faster hardware, while isolating thin-client computers from this performance overhead. I think it's a big challenge for the LINQ team to address its performance.



Tuesday, May 22, 2007

Fix DNKA 'invalid request' problem

It seems that every second post in DNKA discussion group shouts something like 'Getting "invalid request" on DNKA page. Not working!"
(If you don't know what DNKA is and how it could be usefull - read this post).
Well, the bad news is that the latest DNKA version (0.49.7) does not works with the newest GDS versions 5.x.x. The good news is that you still may get the last version of GDS that works with DNKA.
Here is how:
  1. Uninstall newer version of GDS if you have it installed.

  2.    
  3. Download GDS v 4.2006.627 from here and install it.

  4.    
  5. Optionally you may change place where your index files would reside - it's specified at HKEY_CURRENT_USER\Software\Google\Google Desktop => data_dir

  6.    
  7. Install DNKA v 0.42 from here. Go to its installation directory and backup the ws2_32.dll file.

  8.    
  9. Install DNKA v 0.49 from here above v 0.42. Replace the ws2_32.dll file with one you've saved aside during previous installation.

  10.    
  11. (All DNKA releases could be found here).

  12.    
  13. Enjoy!


Wednesday, April 11, 2007

Generics collection serializer


Here is small utility class to serialize/deserialize generics collection... My usage of it is passing of multiple parameters to a web service at once.



using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
public class CollectionSerializer<TKey, TValue>
{
public static void Serialize(TextWriter writer, IDictionary<TKey, TValue> dictionary)
{
List<ListEntry<TKey, TValue>> entries = new List<ListEntry<TKey, TValue>>(dictionary.Count);
foreach (TKey key in dictionary.Keys)
{
entries.Add(new ListEntry<TKey, TValue>(key, dictionary[key]));
}

XmlSerializer serializer = new XmlSerializer(typeof(List<ListEntry<TKey, TValue>>));
serializer.Serialize(writer, entries);
}

public static void Deserialize(TextReader reader, IDictionary dictionary)
{
dictionary.Clear();
XmlSerializer serializer = new XmlSerializer(typeof(List<ListEntry<TKey, TValue>>));
List<ListEntry<TKey, TValue>> list = (List<ListEntry<TKey, TValue>>)serializer.Deserialize(reader);

foreach( ListEntry<TKey, TValue> entry in list )
{
dictionary[entry.Key] = entry.Value;
}
}

public class ListEntry<TKeyEntry, TValueEntry>
{
public ListEntry()
{}

public ListEntry(TKeyEntry key, TValueEntry value)
{
Key = key;
Value = value;
}

public TKeyEntry Key;
public TValueEntry Value;
}
}
Please note that standard Tuple type can't be used instead of custom ListEntry as it can't be serialized.

Thursday, March 22, 2007

Export SQL query results with BCP


Following command exports query results with the bcp into the specified text file. It could be used to get, for example, NTEXT fields that are longer than 4000 and cutted out in SQL query analyzer:
>>bcp "select * from MyTable" queryout C:\result.txt -c -S SERVERNAME -U USERNAME -P PASSWORD

Weakest chain amplification principle


What I going to say is actually obvious- but somehow I never thought that the common sense proverb saying "the chain is as weak as its weakest link" is wrong. Really, when you hear it you may visually imagine a chain with a weak link which tears when disruptive force applied to it is much weaker than force needed to disrupt the rest of chain links.
So, what's wrong? The wrong thing is that this proverb usually not being applied to the physical chains. It applies to the chain of circumstances, probabilities or responsibilities.
In fact the chain is much weaker than its weakest link. Really, let's say we are talking about a transportation system in some city. If there is a chance of 50% that your autobus will late and a chance of 50% that your train will late there is a chance of only 25% that you will arrive at time. So, if you're looking at set or related factors where each of them has low failure probability the overall failure probability is much higher. I call it "weakest chain amplification principle".
I think this fact has interesting consequences in a lot of fields. For example in sociology: next time you hear about a 'weak chain' in politic, public sector, police, health system or whatever else you should realize that the overall situation is much worse than this 'weak chain' issue. If some politician is a bit not professional, another one does something a bit not completely legal and another one is a bit dumb all together they form a government that is not a bit weak, but really weak.
Of course - all above applies only when elements or factors are strongly related, i.e. when they are actually bound into 'chain'. And this, in turn, has some interesting implication in creation of complex systems, e.g. in software development. The thing is that, taking a SW development as an example - we may note that any big software complex has its own weak chain (bugs, design mis-considerations, etc), even in its final stage. Then - why at all those big programs are able to work? Considering all said above - it should be impossible to create a stable SW product in principle. How they work then? Well, they work since usually, after some polishing - bugs became kind of sparsely spread around and not related to each other. Theyhappen in certain conditions and with relatively low probability. And then the weakest chain amplification principle doesn't apply to them.

p.s.

Small note there is an obvious connection between above considerations and 'explicit boundaries' and 'autonomous evolution' principles in SOA.

Sunday, March 11, 2007

Is saying that C# is 'better' than VB.NET is a mauvais ton?




One of my favourite childhood books was book of a semi-forgotten today Russian author - L. Kassil. Misfortunately he didn't stand in competition with McDonald's of today literature world a'la Harry Potter.

Now, you would ask - how it relates to the C#? - Here is the story: heroes of the book were arguing who's stronger - marine or soldier? Whale or an elephant? … - well, you got an idea.

Now an interesting article in SDK Dev' Team blog paradoxically resembled me all of it - marine, soldier and whale :)

In this article SDK developers present a coverage of various themes done for C# and VB.NET in Vista SDK samples:

.NET 3.0 Samples # of Unique C# Coverage VB Coverage
WCF 146 100% 72%
WF 60 100% 95%
WPF 434 98% 58%
Cross Technology 23 96% 9%
.NET Framework 2.0 138 95% 80%
Totals 801 98% 66%

Do you notice that C# coverage is a bit better?

That's why I going to stand on the mauvais ton side and say that C# is better than VB.NET.
Yes, yes, everything could be implemented in language constructions of both languages. But:
1) There is more important development in C# than in VB.NET (e.g. Enterprise Libraries).
2) I think that for historical reasons - most of the people writing in VB.NET are peoples who did a transaction from some sort of visual basic development. And VB projects in the pre .net era were kind of less 'hardcore' than, say, C++ projects, whose developers probably evolved into the C# rather than into the VB.NET.
Except, how else you may explain that market offers higher wages for C# pplz (than to VB.NET)?

Wednesday, March 07, 2007

How to use w.bloggar after switching to Google Account on blogspot.com


Here is a detailed explanation on how to use w.bloggar for posting to blogspot after switching to Google Account.
Just to add that host to be referenced is still beta.blogspot.com

I'm back


1. I'm back after really, really long blackout.
2. A lot to tell - it's even difficult to chose what to start with.