Kirk Marple

Musings of a Yukon and Whidbey pioneer... and feeling the arrows in my back...

<August 2008>
SuMoTuWeThFrSa
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456


Navigation

Subscriptions

Post Categories



Whidbey, .NET 2.0 (RSS)

Whidbey, .NET 2.0
Problem after Indigo CTP install with devenv and SOAP...

i tried to open up my Whidbey solution after installing the Indigo and Avalon CTPs, and my SourceGear Vault client started giving me “Object reference not found“ errors when trying to login to my Vault server.

i uninstalled and reinstalled Vault, but it didn't help.

i then played around with the settings of Vault, and attempted to download the current repository list.  at that point, i got a .NET exception popup referencing something about Microsoft.Tools.Indigo.SoapImporter, and devenv.exe.config.

so i found that .config file, and commented out this chunk of XML below:

  <system.web>
    <webServices>
      <soapExtensionImporterTypes>
        <add type="Microsoft.Tools.Indigo.SoapImporter.IndigoSoapImporter,TemplateInstaller, Version=5.0.0.0, Culture=neutral, PublicKeyToken=8a6b4c2a8d4d0b53" />
      </soapExtensionImporterTypes>
    </webServices>
  </system.web>

problem solved!

i guess it was having some problem loading that SOAP extension when it was accessing my Vault server.

posted Wednesday, March 16, 2005 5:45 PM by kmarple with 4 Comments

Replacement for VS.NET "create command file"
During my Yukon/Whidbey testing, one the the bugs i filed was that "Create Command File" was missing from the VS.NET IDE.

I'd found this to be a useful helper, where it would create a command file (.cmd) from the SQL scripts in my database project.

In the November CTP, there's no support for database projects, but they've also said that "Create Command File" has been removed.

This was somewhat of a pain, since there's really no good way to execute directories of scripts easily.

So, today i decided to finally whip together a little .cmd file of my own that would recurse thru a directory path, and run 'osql' on the scripts in there.

Whew! What a relief... finally an easy way to zip thru all my scripts and update all the stored procedures at once.

@echo off
REM: Usage: RunScripts [Path] [Server] [Database]

if '%1' == '' goto usage
if '%2' == '' goto usage
if '%3' == '' goto usage

if '%1' == '/?' goto usage
if '%1' == '-?' goto usage
if '%1' == '?' goto usage
if '%1' == '/help' goto usage

ECHO Path: %1
ECHO Server: %2
ECHO Database: %3

for /r %1 %%f in (*.sql) DO osql -S "%2" -d "%3" -E -b -i "%%f"

goto finish

REM: How to use screen
:usage
echo.
echo Usage: RunScripts Server Database
echo Server: the name of the target SQL Server
echo Database: the name of the target database
echo.
echo Example: RunScripts Path MainServer MainDatabase
echo.
echo.
goto done

REM: finished execution
:finish
echo.
echo Script execution is complete!
:done
pause
@echo on

posted Thursday, February 24, 2005 11:59 AM by kmarple with 2 Comments

Lovin' the MSDN feedback center...
Now, that's cool.

I posted earlier today about the need to serialize URIs in my .NET web service application.

I wrote a wrapper class, SerializableUri, which fit the bill for my needs, but I'd obviously prefer a more seamless solution with the .NET fx.

So, i posted to the MSDN Product Feedback Center with a suggestion to make System.Uri serializable to XML. At first, it was resolved by design, but after some discussion about the usefulness of System.Uri being directly serializable, they've reopened the bug and are considering it for a later release.

>> 	
Hi Kirk,

I discussed this feature with the owner of the XML seriailization engine, and it is now being 
considered for the current release. We will update you on the progress of this feature request 
once more information is available.

Thanks for you feedback!

(name removed)
System.Net
<<

Now that's great service! I'm lovin' the new "transparent" MSFT today... :)

posted Wednesday, February 23, 2005 4:46 PM by kmarple with 3 Comments

Making System.Uri XML serializable...

One of the issues with developing message-based web services has been passing around URIs within the SOAP messages.

Out of the box, in .NET 2.0, System.Uri only supports ISerializable, not IXmlSerializable.  So when serializing a URI to XML, it will fail with “no default public constructor“.

So, instead of storing URIs just as strings, or mirroring the URI property with a string property for persistence, I've come up with this SerializableUri class that can be used instead of System.Uri.

I'd never had to use the C# implicit conversion operators for anything, so it was an interesting example to use for learning about them.   So, now this class will implicitly convert to/from System.Uri.

Also, the trick to serialize the proper element name is to put [XmlElement(“<element-name>“)] on the Serializable field/property in the class you are serializing.   Otherwise it will just serialize as <SerializableUri>http://server/default.htm</SerializableUri>.

	public sealed class SerializableUri : IXmlSerializable	
	{
		private Uri _uri = null;
		public Uri Uri
		{
			get
			{
				return _uri;
			}
			set
			{
				_uri = value;
			}
		}

		public SerializableUri()
		{
		}

		public SerializableUri(Uri uri)
		{
			if (uri == null)
				throw new ArgumentNullException("uri", "Invalid Uri parameter.");

			_uri = uri;
		}

		public SerializableUri(string uri)
		{
			if (String.IsNullOrEmpty(uri))
				throw new ArgumentNullException("uri", "Invalid Uri parameter.");

			_uri = new Uri(uri);
		}

		public static implicit operator Uri(SerializableUri uri)
		{
			return uri.Uri;
		}

		public static implicit operator SerializableUri(Uri uri)
		{
			return new SerializableUri(uri);
		}

		#region IXmlSerializable Members

		System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
		{
			return null;
		}

		void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
		{
			try
			{
				_uri = new Uri(reader.ReadString());
			}
			catch (Exception e)
			{
				_uri = null;
			}
		}

		void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
		{
			writer.WriteString((_uri != null) ? _uri.AbsoluteUri : "");
		}

		#endregion

		public override string ToString()
		{
			return (_uri != null) ? _uri.AbsoluteUri : null;
		}
	}
 

posted Wednesday, February 23, 2005 8:07 AM by kmarple with 3 Comments

Namespaces... useful tools for logical design...
Jeff Atwood posted an entry on his blog about .NET namespaces, and how he felt they were less than functional.

Almost every time I see namespaces used, they're not functional. They don't solve any collision or duplication problems for me. They're little more than vanity license plates for the author's code.

I disagree pretty heavily with this. For my company, I've used a set of namespaces that look like this:

AgnosticMedia.Common.*
AgnosticMedia.Frameworks.*
AgnosticMedia.[application-name].*

For classes that are common for all applications and all libraries, I put them in AgnosticMedia.Common. Some things are custom helper classes, and some wrap similarly namespaced .NET fx classes.

Examples are:

AgnosticMedia.Common.Logging
AgnosticMedia.Common.Data -> System.Data
AgnosticMedia.Common.Web.Services -> Microsoft.Web.Services2

Each logical library of classes gets put under AgnosticMedia.Frameworks.*, and each vertical application built on our Frameworks gets a unique namespace (i.e. AgnosticMedia.MyApplication.*). It's a logical way of managing the many classes we've created, and provides a benefit of localizing classes within their specific area.

Using namespaces as building blocks for managing code gives a way for new developers to come up to speed on our architecture. They can quickly distinguish between reusable code and app-specific code.

Also, the postfix of a namespace can be very useful as a naming convention:

AgnosticMedia.Common.Handlers
AgnosticMedia.Frameworks.*.Handlers

In AgnosticMedia.Common.Handlers, I'll put the base classes (i.e. HandlerBase) which get reused in every "framework". So, in AgnosticMedia.Frameworks.Foo.Handlers, there are classes that derive from HandlerBase.

posted Wednesday, January 19, 2005 5:01 PM by kmarple with 2 Comments

New C# 2.0 fact of the day...
I started using Nullable<T> types today for the first time. I found a great use for them - a better default state for API properties. For example, instead of using -1 for the default value for integers, i now use Nullable<int> and set the default to null. Makes it easier to differentiate between null as "initialized" and null as what the caller actually set.

Another key point - i found the Nullable class, and there are some very useful helper methods in there. I needed to use Nullable.Unwrap(o) to grab the inner value from the nullable object. I had a case where i was using reflection to lookup property values, and they were nullable types. So, i had to use the Nullable.Unwrap method to pull out the actual value before using it. If the value was null, then i would skip it.

Cool, eh?

posted Tuesday, January 18, 2005 7:44 PM by kmarple with 4 Comments

Interesting XmlSerializer issue with "circular reference"
I've been banging my head against this issue for the last day, and I finally narrowed it down to a simple test case.

(BTW, I'm using the Nov CTP of Whidbey and .NET 2.0 for this code.)

While sending SOAP messages between my Web services, I'd been using XML serialization to pass CLR objects (DTOs). When trying to send a specific type of object, the serialization barfed with this exception:

System.InvalidOperationException: There was an error generating the XML document
. ---> System.InvalidOperationException: A circular reference was detected while serializing an object of type TestXmlSerializer.MyObject.

I could verify that there definitely wasn't a simple circular reference of object A referencing object B, and vice versa. However, it did have something to do with object A owning a collection to (or keeping a reference to) object B. Object B didn't reference object A, though.

I first thought it was an issue with object A and B having common base classes, but that wasn't it.

Finally, i narrowed it down to an issue with the base class supporting an object ID of type System.Guid. I'd overridden Equals(object o) to state that objects were equal when their object IDs were equal.

Unfortunately, but understandably, it looks like the XML serializer uses Object.Equals to find circular references in any object graph. So, if there were initialized objects that had the empty GUID as the object ID, it would consider them the same object and throw this exception.

I still have to review my code to see the effect of removing the overridden Equals operator. I'm keeping all object instances in generic List<T> collections. I probably just need to implement a different method to test object equivalence, if i need it in my methods.

See the code sample below... the first object instance 'dd' throws the exception, but if i assign a valid GUID to each object, the second instance of the object 'dd' serializes properly.


Code Sample

#region Using directives

using System;
using System.IO;
using System.Collections.Generic;

using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Globalization;

#endregion

namespace TestXmlSerializer
{
	public abstract class Base
	{
		private Guid _objectId = Guid.Empty;
		public Guid ObjectId
		{
			get

			{
				return _objectId;
			}

			set
			{
				_objectId = value;
			}
		}

		public Base()
		{
		}

		public override bool Equals(object obj)
		{
			Base ro = obj as Base;

			if (ro != null)
				return (ro.ObjectId == _objectId);
			else

				return false;
		}

		public override int GetHashCode()
		{
			return _objectId.GetHashCode();
		}
	}

	public class MyObject : Base
	{
		private string _name = null;
		public string Name
		{
			get

			{
				return _name;
			}

			set
			{
				_name = value;
			}
		}

		public MyObject()
		{
		}
	}

	public class D : Base
	{
		public List<Base> Objects = new List<Base>();

		private string _name = null;
		public string Name
		{
			get

			{
				return _name;
			}
			set
			{
				_name = value;
			}
		}

		public D()
		{
		}
	}
	
	class Program
	{
		public static string ToXmlString(object o, Type[] extraTypes)
		{
			if (o == null)
				return null;

			StringBuilder sb = new StringBuilder();

			try

			{
				XmlSerializer x = null;
				StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);

				XmlWriterSettings xmlSettings = new XmlWriterSettings();
				xmlSettings.OmitXmlDeclaration = true;
				xmlSettings.ConformanceLevel = ConformanceLevel.Document;
				xmlSettings.Indent = true;

				XmlWriter xmlWriter = XmlTextWriter.Create(sw, xmlSettings);

				if (extraTypes != null)
					x = new XmlSerializer(o.GetType(), extraTypes);
				else

					x = new XmlSerializer(o.GetType());

				x.Serialize(xmlWriter, o);

				xmlWriter.Flush();
				xmlWriter.Close();

				sw.Flush();
				sw.Close();
			}
			catch (Exception e)
			{
				Console.WriteLine("Failed serializing to XML.");
				Console.WriteLine(e.ToString());
			}

			return sb.ToString();
		}

		static void Main(string[] args)
		{
			D dd = new D();
			dd.Name = "foo";

			MyObject myo = new MyObject();
			myo.Name = "baz";

			dd.Objects.Add(myo);

			Console.WriteLine("Serializing D....");
			Console.WriteLine(ToXmlString(dd, new Type[] { typeof(MyObject), typeof(Base) }));
			Console.WriteLine("... done.");
			Console.WriteLine();

			dd = new D();
			dd.Name = "foo";
			dd.ObjectId = Guid.NewGuid();

			myo = new MyObject();
			myo.Name = "baz";
			myo.ObjectId = Guid.NewGuid();

			dd.Objects.Add(myo);

			Console.WriteLine("Serializing D (unique)....");
			Console.WriteLine(ToXmlString(dd, new Type[] { typeof(MyObject), typeof(Base) }));
			Console.WriteLine("... done.");
			Console.WriteLine();

			Console.WriteLine("Press <enter> to continue.");
			Console.ReadLine();
		}
	}
}

posted Tuesday, January 11, 2005 1:24 PM by kmarple with 4 Comments

DbParameter.CopyTo now obsolete... Reflector to the rescue
I'd been using DbParameter.CopyTo method for cloning DbParameters, but then found with the Nov CTP that it's going away (marked obsolete).

Unfortunately, MSFT failed to provide any documentation as to what to use instead. I've posted newsgroup msgs and filed a Product Feedback Center question about it, but got no response.

Since i was getting back to my .NET 2.0 project today, i pulled out Lutz Roeder's .NET Reflector to try and solve this. Man, this is the *best* free tool out there. It's just indispensible for figuring out the intricacies of the Frameworks, especially where there's no documentation available.

It's interesting because it basically converts the Frameworks into an "exposed source" library, like MFC used to be.

Here's what CopyTo looks like:

[Obsolete("Do not use, will be removed post pd9.")]
public override void CopyTo(DbParameter destination)
{      

ADP.CheckArgumentNull(destination, "destination");      
this.CloneHelper((SqlParameter) destination);
}

But if it's going away, I needed a replacement. So, I noticed that CopyTo was calling CloneHelper, and also saw that .ctor(SqlParameter) called CloneHelper. But it also called ICloneable.Clone. It hit me that using ICloneable.Clone is probably the "preferred" approach (since CloneHelper is private). I tried replacing CopyTo with that, and it looks like it's working so far.

posted Friday, January 07, 2005 11:02 AM by kmarple with 4 Comments




Powered by Dot Net Junkies, by Telligent Systems