Running applications on different versions of the .Net framework
Peter Laudati posted about migrating applications from .Net 1.1 to .Net 2.0. In doing so, he listed the different behaviours of .Net applications when running on computers with different versions of the .Net Framework installed:
| Application type | Computer with 1.1 | Computer with 2.0 | Computer with 1.1 and 2.0 |
|---|---|---|---|
| 1.1 stand-alone application (Web or Microsoft Windows client) | Loads with 1.1 | Loads with 2.0 | Loads with 1.1 |
| 2.0 stand-alone application (Web or Microsoft Windows client) | Fails | Loads with 2.0 | Loads with 2.0 |
| 1.1 add-in to a native application (such as Office or Internet Explorer) | Loads with 1.1 | Loads with 2.0 | Loads with 2.0 unless the process is configured to run against 1.1 |
| 2.0 add-in to a native application (such as Office or Internet Explorer) | Fails | Loads with 2.0 | Loads with 2.0 |
Managed stack explorer
A neat little project on CodePlex called Managed Stack Explorer enables you to monitor running .Net applications.
Using this tool, you can view all currently running managed applications, monitor all of their threads, and even collect stack traces at regular intervals. Very useful for getting information about applications whilst running outside of a debugger.
Suppressing FxCop message
Using the latest version (1.35) of FxCop, it is possible to exclude generated warning messages in the source code instead of having to exclude them in the FxCop project file. This is accomplished using the System.Diagnostics.CodeAnalysis.SuppressMessageAttribute class.
To exclude a message, simply mark up the method with the SuppressMessage attribute, declaring both the rule category and the specific rule to exclude:
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public string ConvertToString(object obj)
{
return obj.ToString();
}The above example will exclude the “Validate Arguments Of Public Methods” rule from the Design category for the ConvertToString method (although in this contrived example it is probably a bad idea to do so as passing in a null will clearly cause problems).
One extra “tweak” that can be utilised in this scenario is the Justification property. Altering the above code to:
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods", Justification="I do have a valid reason")]
public string ConvertToString(object obj)
{
return obj.ToString();
}will allow the person excluding a message to provide a reason for doing so in the code, alongside the exclusion. FxCop (v1.35) currently doesn’t display this in its output, but will do in the next release (source). It does however output the justification to a generated report if the options are set to output exclusions to the report.
Excluding FxCop messages in the source code has advantages over excluding them in the FxCop project as it demonstrates that the message has been specifically excluded for that particular case, but also will withstand class and namespace changes. It also makes switching from the standalone FxCop to Visual Studio’s code analysis an easier process.
In order to allow the SuppressMessage attribute to work, a CODE_ANALYSIS conditional compilation symbol must be defined for the project. Without this, FxCop will ignore the suppressed attribute and will still generate a warning.
More details can be found on the FxCop blog.
SerializationException and System.Data.SqlClient.SqlError
When remoting, it’s possible to get a strange exception if a SQLException occurs on the server.
The stack trace of the error is:
Exception: System.Runtime.Serialization.SerializationException Message: Member name ‘System.Data.SqlClient.SqlError server’ not found. Stack trace: at System.Runtime.Serialization.Formatters.Binary.ReadObjectInfo.GetMemberTypes (String[] inMemberNames) at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable) at System.Runtime.Serialization.Formatters.Binary.ObjectMap.Create(String name, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable) at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record) at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum) at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage) at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryResponseMessage(Stream inputStream, IMethodCallMessage reqMsg, Boolean bStrictBinding) at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)
What is actually happenning here is that the System.Data.dll on the client is a slightly different version to that on the server. When the SQLException is deserialised at the client end, there is a missing property on the client that cannot be deserialised.
This error usually occurs when remoting to a Windows 2003 Server box from a non-Windows 2003 client box. The client has a System.Data.dll of version 1.1.4322.2032. The server has a System.Data.dll of version 1.1.4322.2300. The difference is that the server property of the SqlError class is never set in v1.1.4322.2032, causing the serialisation error. More detailed info can be found on the DevNewsGroups site.
Microsoft has two knowledge base articles, KB884871 and KB887549, that pertain to this issue. The suggested solution is a .NET Framework 1.1 post-SP1 hotfix, but this is only available by contacting Microsoft directly.
The hotfix solves the problem, but then stops old SqlError types from being deserialised, resulting in the exception:
Exception: System.Runtime.Serialization.SerializationException Message: Wrong number of Members. Object System.Data.SqlClient.SqlError has 8 members, number of members deserialized is 7. Stack trace: at System.Runtime.Serialization.Formatters.Soap.ReadObjectInfo.PopulateObjectMembers() at System.Runtime.Serialization.Formatters.Soap.ObjectReader.ParseObjectEnd(ParseRecord pr) at System.Runtime.Serialization.Formatters.Soap.ObjectReader.Parse(ParseRecord pr) at System.Runtime.Serialization.Formatters.Soap.SoapHandler.EndElement(String prefix, String name, String urn) at System.Runtime.Serialization.Formatters.Soap.SoapParser.ParseXml() at System.Runtime.Serialization.Formatters.Soap.SoapParser.Run() at System.Runtime.Serialization.Formatters.Soap.ObjectReader.Deserialize(HeaderHandler handler, ISerParser serParser) at System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize(Stream serializationStream, HeaderHandler handler) at System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize(Stream serializationStream)
This means that the hotfix is not backwards-compatible. The only way to get everything happy is to upgrade all Windows 2003 boxes to SP1 and all clients (Windows 2000 and Windows XP) to .Net 1.1 SP1 plus the hotfix.
Guidance explorer
Microsoft recently released Guidance Explorer, a tool that contains a browsable collection of best-practice patterns for developing .Net and ASP.Net applications.
Both the tool and its guidance library have regular updates, containing best-practices for performance and security related issues.
The tool also has the ability to add custom sets of guidance to allow corporate/team standards to be included.
