I read somewhere recently that C# 4.0 will also have optional parameters, like VB6 and VB.Net had all along.
When moving to .Net I decided not to use optional parameters in VB.net since they were kind of looked at as a remnant of VB6, not CLR compliant, not available in C# etc.
And the "preferred way" was to use overloads instead of Optional Parameters.
So now after I read that C# 4.0 will have optional parameters (and the fact that I am kind of "over" the many overloads that are sometimes necessary, especially if you have logging methods etc.) I was thinking of going back to using Optional Parameters.
I always assumed that the compiler for VB.Net would just created the overloads in the background, substituting it with the default values given to the Optional Parameters.
But that is not the case. The compile hard-compiles the default values into the CALLING method/object and not as an overload into the called method.
Joel On Software
VB.NET Optional parameters
Optional Parameters (VB.NET)
Now this was a big red flag for me, because that means each time you change the value of one of the default parameters, you would need to recompile ALL the CALLING classes as well (if they call with some of the optional parameters omitted).
So if you have a live enterprise system with multiple DLLs and you need to deploy hotfixes as individual DLLs then you'd have to deploy the changed DLL and all the DLLs that call it. Otherwise the "old" DLLs will still call your method with the "old" default value and this could introduce some hard-to-find side effects.
One might argue how often do you really need to change the default value of an Optional Parameter and that that indicates a deeper design issue.
But still, for complex system or legacy code that you are refactoring this might be a real possibility.
Furthermore in VB.Net 3.5 you cannot use Nullable types as optional parameters, i.e. you cannot do this:
Public Sub DoStuff(Optional ByVal intEntityID As Nullable(Of Integer) = Nothing)
End Sub
So my conclusion at this point is to stick with overloads instead of Optional Parameters. More predictable and less things to remember as possible pitfalls. :)
I got enough other stuff to cram into my head ...
Tuesday, December 16, 2008
Thursday, November 13, 2008
HTTP concurrent connections from IE - AJAX
I have been stumbling across articles about the two-concurrent-connection limit of IE7 recently.
Tools like the Visual Round Trip Analyzer from Microsoft also mention this in the set of criteria they evaluate against.
It seems that in IE8 the limit of 2 connections is increased to 6 as per here:
AJAX - Connectivity Enhancements in Internet Explorer 8
But it can also be tweaked in IE7 and below as decsribed in the KB article:
http://support.microsoft.com/kb/183110
Other links:
12 Steps To Faster Web Pages With Visual Round Trip Analyzer
Case Study: Much ado about Browser's HTTP connection
Tools like the Visual Round Trip Analyzer from Microsoft also mention this in the set of criteria they evaluate against.
It seems that in IE8 the limit of 2 connections is increased to 6 as per here:
AJAX - Connectivity Enhancements in Internet Explorer 8
But it can also be tweaked in IE7 and below as decsribed in the KB article:
http://support.microsoft.com/kb/183110
Other links:
12 Steps To Faster Web Pages With Visual Round Trip Analyzer
Case Study: Much ado about Browser's HTTP connection
Friday, November 7, 2008
Nested JOINS (mix of inner and outer joins in SQL)
I just ran into this today:
Be Careful When Mixing INNER and OUTER Joins
It's not rocket science, but it can be somewhat counter-intuitive. How to tell the SQL server query engine what you want as an inner join vs an outer join.
I ended up using the nested join syntax by the way, seems cleanest to me and is not relying on the position of the JOIN line in the query.
Basically:
Be Careful When Mixing INNER and OUTER Joins
It's not rocket science, but it can be somewhat counter-intuitive. How to tell the SQL server query engine what you want as an inner join vs an outer join.
I ended up using the nested join syntax by the way, seems cleanest to me and is not relying on the position of the JOIN line in the query.
Basically:
select People.PersonName, Pets.PetName, PetTypes.PetType
from People
left outer join
(Pets inner join PetTypes on Pets.PetTypeID = PetTypes.PetTypeID)
on Pets.OwnerID = People.PersonID
Monday, November 3, 2008
Stored Procedures - Best Practices
Excellent post where Aaron Bertrand shares his best practices for developing stored procedures covering both coding style as well as some coding best practices (good use of NOCOUNT etc).
http://sqlblog.com/blogs/aaron_bertrand/archive/2008/10/30/my-stored-procedure-best-practices-checklist.aspx
http://sqlblog.com/blogs/aaron_bertrand/archive/2008/10/30/my-stored-procedure-best-practices-checklist.aspx
Windows Azure - behold the cloud
A lot of buzz is being generated at the moment about the Microsoft Azure Services platform. Here is a brief collection of links to get started on it.
Microsoft’s official Azure site, containing links to the key parts of the platform and documentation:
http://www.microsoft.com/azure/default.mspx
Microsoft's official press release:
http://www.microsoft.com/presspass/press/2008/oct08/10-27PDCDay1PR.mspx
Overview blog post by Paul Gielens:
http://weblogs.asp.net/pgielens/archive/2008/10/27/a-lap-around-windows-azure.aspx
Some details on how the Windows Azure back end infrastructure is laid out:
http://blogs.msdn.com/domgreen/archive/2008/10/30/windows-azure-back-end.aspx
Getting Started with Windows Azure - The Cloud Computing Tools Team has a nice post gathering together the downloads, tools and some information about the tools and SDK:
http://blogs.msdn.com/cloud/archive/2008/10/27/getting-started-windows-azure-tools-for-microsoft-visual-studio.aspx
Here's a tutorial on the process of storing information in Azure with plenty of screenshots and code samples included in the post:
http://blogs.msdn.com/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
A tutorial on the process of getting up and running with Azure, from setting up the development environment to publishing your first application:
http://blogs.msdn.com/olavt/archive/2008/10/30/how-to-create-and-publish-your-first-windows-azure-application.aspx
Clemens Vasters blogs about the Microsoft .Net ServiceBus that is part of the Azure platform:
http://vasters.com/clemensv/PermaLink,guid,92d78bee-2cfd-4a29-95ab-c5abb9b905e7.aspx
Microsoft’s official Azure site, containing links to the key parts of the platform and documentation:
http://www.microsoft.com/azure/default.mspx
Microsoft's official press release:
http://www.microsoft.com/presspass/press/2008/oct08/10-27PDCDay1PR.mspx
Overview blog post by Paul Gielens:
http://weblogs.asp.net/pgielens/archive/2008/10/27/a-lap-around-windows-azure.aspx
Some details on how the Windows Azure back end infrastructure is laid out:
http://blogs.msdn.com/domgreen/archive/2008/10/30/windows-azure-back-end.aspx
Getting Started with Windows Azure - The Cloud Computing Tools Team has a nice post gathering together the downloads, tools and some information about the tools and SDK:
http://blogs.msdn.com/cloud/archive/2008/10/27/getting-started-windows-azure-tools-for-microsoft-visual-studio.aspx
Here's a tutorial on the process of storing information in Azure with plenty of screenshots and code samples included in the post:
http://blogs.msdn.com/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
A tutorial on the process of getting up and running with Azure, from setting up the development environment to publishing your first application:
http://blogs.msdn.com/olavt/archive/2008/10/30/how-to-create-and-publish-your-first-windows-azure-application.aspx
Clemens Vasters blogs about the Microsoft .Net ServiceBus that is part of the Azure platform:
http://vasters.com/clemensv/PermaLink,guid,92d78bee-2cfd-4a29-95ab-c5abb9b905e7.aspx
Tuesday, August 5, 2008
Copy data between 2 SQL servers - Take 2
Alright, so one of the issues my previous post did not address was the treatment of Identity columns when using BCP and BULK import.
By default, identity column data is not part of a BCP export, so when doing a BULK IMPORT SQL server will assign new values to the identity Column .
Fortunately, that is relatively easy to address, as decribed here:
http://msdn.microsoft.com/en-us/library/ms186335.aspx
Basically when doing a BCP export, add the "-E" parameter.
Example:
bcp Northwind.dbo.Authors out C:\Temp\DataExport.dat -n -E -T -S MPDESKTOP\SQL2005
And when importing, use the KEEPIDENTITY parameter in the BULK INSERT like this:
USE Northwind
GO
BULK INSERT Authors
FROM 'G:\Transfer\Tempfiles\DataExport.dat'
WITH (KEEPIDENTITY, DATAFILETYPE='native');
GO
This will preserve the values of identity columns when copying data between 2 servers/databases. Keep in mind that there still might be issue with referential integrity constraints etc. that you need to address when moving data between databases.
By default, identity column data is not part of a BCP export, so when doing a BULK IMPORT SQL server will assign new values to the identity Column .
Fortunately, that is relatively easy to address, as decribed here:
http://msdn.microsoft.com/en-us/library/ms186335.aspx
Basically when doing a BCP export, add the "-E" parameter.
Example:
bcp Northwind.dbo.Authors out C:\Temp\DataExport.dat -n -E -T -S MPDESKTOP\SQL2005
And when importing, use the KEEPIDENTITY parameter in the BULK INSERT like this:
USE Northwind
GO
BULK INSERT Authors
FROM 'G:\Transfer\Tempfiles\DataExport.dat'
WITH (KEEPIDENTITY, DATAFILETYPE='native');
GO
This will preserve the values of identity columns when copying data between 2 servers/databases. Keep in mind that there still might be issue with referential integrity constraints etc. that you need to address when moving data between databases.
Tuesday, June 10, 2008
Updating the Main UI from a different thread
As you probably know, the availability of threading in .Net can lead to all kinds of little surprises, together of course with the power to write much more responsive applications.
For instance if you have a WinForms app that spawns a worker thread, and then that worker thread needs to update any UI elements on the main form, it will not work, since you can only update UI elements from the same thread they are created on.
I specifically ran into this when using a custom NUnit TestRunner (see previous post). It turns out, the TestRunner runs the test fixtures on a different thread, so you can't just do a frmMain.txtMessage.Text = "New Text from Test Fixture". Would have been too easy.
In addition, VB.Net also has the concept of default form instances, so when you do the above "frmMain.txtMessage" from a different thread than the main UI thread, VB.Net actually instantiates a new form, and then discards it when you are done. Thus there will be no exception raised for the above code, and putting in a brekpoint in the work thread shows the text properly updated. But in the UI the textbox will be empty.
It is much better explained in this post.
But the gist of it is this:
1. You have to use My.Application.OpenForms to get the correct UI thread instance of your form that you want to update
2. you have to use Invoke/BeginInvoke together with delegates to properly update the controls on the Main UI thread from a different thread.
3. The Control base class has a neat little method called InvokeRequired that will return True if the method is called from a different thread. This way you can write a generic function that works both on the UI thread and from other threads. Something like this:
Public Class frmMain
'some magic voodo that needs to be done here to allow updating of the text box from a different thread
Private Delegate Sub PostMessageDelegate(ByVal strNewMessage As String)
'this is part 2 of the magic voodo: this is a public method that will be called on this form from the
'outside, from different threads, so the text box can be updated
Public Sub PostMessage(ByVal strMessage As String)
If txtMessages.InvokeRequired Then
'this method is called form a different thread, so we need to use BeginInvoke to update the UI
txtMessages.BeginInvoke(New PostMessageDelegate(AddressOf PostMessage), New Object() {strMessage})
Else
txtMessages.Text &= Environment.NewLine & strMessage
End If
End Sub
...
End Class
For instance if you have a WinForms app that spawns a worker thread, and then that worker thread needs to update any UI elements on the main form, it will not work, since you can only update UI elements from the same thread they are created on.
I specifically ran into this when using a custom NUnit TestRunner (see previous post). It turns out, the TestRunner runs the test fixtures on a different thread, so you can't just do a frmMain.txtMessage.Text = "New Text from Test Fixture". Would have been too easy.
In addition, VB.Net also has the concept of default form instances, so when you do the above "frmMain.txtMessage" from a different thread than the main UI thread, VB.Net actually instantiates a new form, and then discards it when you are done. Thus there will be no exception raised for the above code, and putting in a brekpoint in the work thread shows the text properly updated. But in the UI the textbox will be empty.
It is much better explained in this post.
But the gist of it is this:
1. You have to use My.Application.OpenForms to get the correct UI thread instance of your form that you want to update
2. you have to use Invoke/BeginInvoke together with delegates to properly update the controls on the Main UI thread from a different thread.
3. The Control base class has a neat little method called InvokeRequired that will return True if the method is called from a different thread. This way you can write a generic function that works both on the UI thread and from other threads. Something like this:
Public Class frmMain
'some magic voodo that needs to be done here to allow updating of the text box from a different thread
Private Delegate Sub PostMessageDelegate(ByVal strNewMessage As String)
'this is part 2 of the magic voodo: this is a public method that will be called on this form from the
'outside, from different threads, so the text box can be updated
Public Sub PostMessage(ByVal strMessage As String)
If txtMessages.InvokeRequired Then
'this method is called form a different thread, so we need to use BeginInvoke to update the UI
txtMessages.BeginInvoke(New PostMessageDelegate(AddressOf PostMessage), New Object() {strMessage})
Else
txtMessages.Text &= Environment.NewLine & strMessage
End If
End Sub
...
End Class
Implement your own NUnit TestRunner - Part 2
After I blogged about creating a basic NUnit TestRunner in Part 1 of this series, this is the follow-up that shows how to extract and display the test results in a simple fashion.
Basically the TestResult object that is being returned from the Run method of the TestRunner contains probably most of the information you need.
Here is the Code:
Imports System.Text
Imports System.Xml
Imports System.IO
Imports System.Reflection
Imports System.Resources
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
'run the test and create the result
Dim objTestResult As TestResult = objTestRunner.Run(New NullListener)
'get the result summary in XML format
Dim strResultSummary As String = CreateXmlOutput(objTestResult)
'now transform the XML into more display-friendly code using the default style sheet
Dim sbResultSummary As New StringBuilder
Dim objXFormReader As XmlTextReader = GetTransformReader(Nothing)
Dim objXMLXform As XmlResultTransform = New XmlResultTransform(objXFormReader)
objXMLXform.Transform(New StringReader(strResultSummary), New StringWriter(sbResultSummary))
txtResults.Text = sbResultSummary.ToString()
End Sub
Private Shared Function CreateXmlOutput(ByVal objResult As TestResult) As String
Dim sbXML As New StringBuilder()
Dim objResultVisitor As New XmlResultVisitor(New StringWriter(sbXML), objResult)
objResult.Accept(objResultVisitor)
objResultVisitor.Write()
Return sbXML.ToString()
End Function 'CreateXmlOutput
Private Shared Function GetTransformReader(ByVal strXSLFileName As String) As XmlTextReader
Dim objXMLReader As XmlTextReader = Nothing
If String.IsNullOrEmpty(strXSLFileName) Then
Dim objNUnitAssembly As Assembly = Assembly.GetAssembly(GetType(XmlResultVisitor))
Dim objResourceMgr As New ResourceManager("NUnit.Util.Transform", objNUnitAssembly)
Dim strXmlData As String = CStr(objResourceMgr.GetObject("Summary.xslt"))
objXMLReader = New XmlTextReader(New StringReader(strXmlData))
Else
Dim objXsltInfo As New FileInfo(strXSLFileName)
If Not objXsltInfo.Exists Then
Throw New FileNotFoundException("Transform file: {0} does not exist", objXsltInfo.FullName)
objXMLReader = Nothing
Else
objXMLReader = New XmlTextReader(objXsltInfo.FullName)
End If
End If
Return objXMLReader
End Function 'GetTransformReader
End Class
this will then show the results in a user-friendly form in the text box txtResults.
Where this comes in handy is if you have a WinForms App and you want to run your Unit tests as part of the WinForms app without having to launch the NUnit GUI (or Console).
This is admittedly a very simple implementation, does not have a lot of the bells and whistles of a more graphical UI, but it tells you which tests failed and how long they took and where they failed.
Basically the TestResult object that is being returned from the Run method of the TestRunner contains probably most of the information you need.
Here is the Code:
Imports System.Text
Imports System.Xml
Imports System.IO
Imports System.Reflection
Imports System.Resources
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
'run the test and create the result
Dim objTestResult As TestResult = objTestRunner.Run(New NullListener)
'get the result summary in XML format
Dim strResultSummary As String = CreateXmlOutput(objTestResult)
'now transform the XML into more display-friendly code using the default style sheet
Dim sbResultSummary As New StringBuilder
Dim objXFormReader As XmlTextReader = GetTransformReader(Nothing)
Dim objXMLXform As XmlResultTransform = New XmlResultTransform(objXFormReader)
objXMLXform.Transform(New StringReader(strResultSummary), New StringWriter(sbResultSummary))
txtResults.Text = sbResultSummary.ToString()
End Sub
Private Shared Function CreateXmlOutput(ByVal objResult As TestResult) As String
Dim sbXML As New StringBuilder()
Dim objResultVisitor As New XmlResultVisitor(New StringWriter(sbXML), objResult)
objResult.Accept(objResultVisitor)
objResultVisitor.Write()
Return sbXML.ToString()
End Function 'CreateXmlOutput
Private Shared Function GetTransformReader(ByVal strXSLFileName As String) As XmlTextReader
Dim objXMLReader As XmlTextReader = Nothing
If String.IsNullOrEmpty(strXSLFileName) Then
Dim objNUnitAssembly As Assembly = Assembly.GetAssembly(GetType(XmlResultVisitor))
Dim objResourceMgr As New ResourceManager("NUnit.Util.Transform", objNUnitAssembly)
Dim strXmlData As String = CStr(objResourceMgr.GetObject("Summary.xslt"))
objXMLReader = New XmlTextReader(New StringReader(strXmlData))
Else
Dim objXsltInfo As New FileInfo(strXSLFileName)
If Not objXsltInfo.Exists Then
Throw New FileNotFoundException("Transform file: {0} does not exist", objXsltInfo.FullName)
objXMLReader = Nothing
Else
objXMLReader = New XmlTextReader(objXsltInfo.FullName)
End If
End If
Return objXMLReader
End Function 'GetTransformReader
End Class
this will then show the results in a user-friendly form in the text box txtResults.
Where this comes in handy is if you have a WinForms App and you want to run your Unit tests as part of the WinForms app without having to launch the NUnit GUI (or Console).
This is admittedly a very simple implementation, does not have a lot of the bells and whistles of a more graphical UI, but it tells you which tests failed and how long they took and where they failed.
Implement your own NUnit TestRunner - Part 1
I wanted to be able to run NUnit unit tests from my own test runner within a WinForms App. Easier said than done, not a lot of examples out there. I looked through the NUnit-Console code and the NUnit-Gui code and pieced together bits and pieces. Then I also stumbled across this blog post from a fellow german which helped with the last stumbling block:
http://achblah.blogspot.com/2007/04/monocov-and-my-contribution-to-it.html
The end result is this piece of VB.net code that will run any tests within your current EXE:
Imports System.Reflection
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
objTestRunner.Run(New NullListener)
End Sub
End Class
Of course this does not show any test results or exceptions because of using the "NullListener". In Part 2 I will fix that.
http://achblah.blogspot.com/2007/04/monocov-and-my-contribution-to-it.html
The end result is this piece of VB.net code that will run any tests within your current EXE:
Imports System.Reflection
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
objTestRunner.Run(New NullListener)
End Sub
End Class
Of course this does not show any test results or exceptions because of using the "NullListener". In Part 2 I will fix that.
Friday, April 18, 2008
Life Cycle of static variables in ASP.Net
Have you ever wondered about the scope and life time of static (Shared in VB.Net) variables in ASP.Net?
- Do they get destroyed after each requests?
- Do they get destroyed after the IIS services is restarted?
- multiple apps run in the same Application Pool, do they all get the same copy (and value) of static variables?
- Does a Singleton make sense in ASP.Net
Here is what I could gather from doing some research on the web:
- static variables work in ASP.Net the same way they work in a Windows app: they are global across the whole .Net AppDomain
- each ASP.Net application gets their own AppDomain, even if they are hosted in the same application pool (same w3wp.exe or aspnet_wp.exe)
- so even if you have multiple ASP.Net applications per Application Pool, they would still get their own AppDomains, and thus the singletons/shared variables would be isolated from each other
Some people encourage initializing the singletons/static variables in the Application_Startup event, just to make sure that all the ASP.Net infrastructure.
Here are some supporting links:
http://weblogs.asp.net/jeff/archive/2007/09/21/how-do-you-get-a-true-singleton-in-an-asp-net-app.aspx
http://www.odetocode.com/Articles/305.aspx
http://blogs.msdn.com/david.wang/archive/2005/09/01/HOWTO-Provision-ASP-dotNet-AppDomains-and-IIS6-Application-Pools.aspx
http://www.vzyl.co.za/post/2008/04/Singleton-Design-Pattern-amp3b-Lifetime-of-a-static-variable-in-ASPNET-20.aspx
http://www.yoda.arachsys.com/csharp/singleton.html
- Do they get destroyed after each requests?
- Do they get destroyed after the IIS services is restarted?
- multiple apps run in the same Application Pool, do they all get the same copy (and value) of static variables?
- Does a Singleton make sense in ASP.Net
Here is what I could gather from doing some research on the web:
- static variables work in ASP.Net the same way they work in a Windows app: they are global across the whole .Net AppDomain
- each ASP.Net application gets their own AppDomain, even if they are hosted in the same application pool (same w3wp.exe or aspnet_wp.exe)
- so even if you have multiple ASP.Net applications per Application Pool, they would still get their own AppDomains, and thus the singletons/shared variables would be isolated from each other
Some people encourage initializing the singletons/static variables in the Application_Startup event, just to make sure that all the ASP.Net infrastructure.
Here are some supporting links:
http://weblogs.asp.net/jeff/archive/2007/09/21/how-do-you-get-a-true-singleton-in-an-asp-net-app.aspx
http://www.odetocode.com/Articles/305.aspx
http://blogs.msdn.com/david.wang/archive/2005/09/01/HOWTO-Provision-ASP-dotNet-AppDomains-and-IIS6-Application-Pools.aspx
http://www.vzyl.co.za/post/2008/04/Singleton-Design-Pattern-amp3b-Lifetime-of-a-static-variable-in-ASPNET-20.aspx
http://www.yoda.arachsys.com/csharp/singleton.html
Subscribe to:
Posts (Atom)