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;
}
}