Thursday, September 13, 2007

Usually I post solutions I've discovered or created to problems I've encountered.  Now, I've run into a problem with the XmlSerializer and I need your help solving it.  Scroll to the bottom for an update.

The Problem

I have a class called Foobar.  Foobar inherits from List<string>, and contains one member Title.  When I use the XmlSerializer to serialize and deserialize Foobar, all the items in the List are make it through safely, but the member Title does not.

The Code

using System; using System.Collections.Generic; using System.IO; using System.Xml.Serialization; internal class Program { private static void Main() { Foobar f = new Foobar(); f.Add("1"); f.Add("2"); f.Title = "Title"; MemoryStream mem = new MemoryStream(); XmlSerializer xs = new XmlSerializer(typeof(Foobar)); xs.Serialize(mem, f); mem.Seek(0, 0); mem.Seek(0, 0); Foobar deser = (Foobar)xs.Deserialize(mem); Console.WriteLine(deser); } } [Serializable] public class Foobar : List<string> { public string Title; }

The Solution

One way I came up with to solve this problem is make Foobar not inherit from List<string>, and make a member called Items that is a List<string>, but that's kind of hokey.  I've searched Google and can't find a solution.  So I'm appealing to my dear readers for a better solution.

Update

Looks like I was being way to specific in my Google search, searching on "XmlSerializer List" gives us this http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=566175&SiteID=1 as the first item.  In the post,

Elena Kharitidi says "XmlSerializer does not serialize any members if a collection. Only collection items get serialized. This is by design, basically a decision was made to handle collections as arrays not as classes with multiple properties, so collections should look like arrays on the wire, therefore they do not have any members other then collection items, and can be “flattened” by adding the [XmlElement] to the member of the ICollection type."

Long and short, I need to use the hokey solution I came up with (or something like it), or write my own serializer.

posted on Thursday, September 13, 2007 6:22:29 AM (Alaskan Standard Time, UTC-09:00)  #    Comments [0]
 Sunday, August 26, 2007

I downloaded the very excellent Resource Refactoring Tool (http://www.codeplex.com/ResourceRefactoring) the other day.  It works great in code files, but I found that it didn't work at all for ASPX/HTML pages.  Seeing this as a challenge, I decided to hack something up in VBA to automatically extract the selected text, create a resx name for the text, add it to the resource file, and insert the ASP.NET literal control.

How to use it

This is split up into two different macro modules, one named Utilities, and the other named what ever you want.  Then add them to your Visual Studio tool bar so you have something convenient you can click on (Right click the tool bar, click Customize, click Commands, then Macros under categories, find what you named the macro and then drag it up to your tool bar.  You can either drag it to an existing tool strip, or create your own.  Finally right click on the item while still in customize mode and add an image).

 

Caller:

Imports System Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics Public Module MoreMacros Public Sub AspTextLiteral() Dim resx as ProjectItem = DTE.ActiveWindow.Object.GetItem("solution\project\folder\ResourceFile.resx") Utilities.AspTextLiteral(resx) End Sub Public Sub InQuoteLiteral() DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate() Dim resx as ProjectItem = DTE.ActiveWindow.Object.GetItem("solution\project\folder\ResourceFile.resx") Utilities.InQuoteLiteral(resx) End Sub End Module

Utilities:

Imports System Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics Imports System.Xml Public Module Utilities Public Sub AspTextLiteral(ByRef resourceFile As ProjectItem) Const literalFormat = "<asp:Literal runat=""server"" Text=""<%$ Resources:{0},{1}%>"" />" Const inQuotesFormat = "<%$ Resources:{0},{1}%>" LiteralReplacer(resourceFile, literalFormat, 4) End Sub Public Sub InQuoteLiteral(ByRef resourceFile As ProjectItem) Const inQuotesFormat = "<%$ Resources:{0},{1}%>" LiteralReplacer(resourceFile, inQuotesFormat, 3) End Sub Private Sub LiteralReplacer(ByRef resourceFile As ProjectItem, ByVal template As String, ByVal delete As Int16) Dim ts As TextSelection = DTE.ActiveDocument.Selection Dim name As String = StripNonAllowedChars(ts.Text).Trim.ToLower Dim value As String = ts.Text Dim path As String = resourceFile.Properties.Item("LocalPath").Value Dim resName As String = System.IO.Path.GetFileNameWithoutExtension(resourceFile.Name) name = AddResourceEntry(path, name, value) ts.Text = String.Format(template, resName, name) DTE.ActiveDocument.Selection.Delete(delete) End Sub 'Returns the value of the name used Public Function AddResourceEntry(ByRef resourceFilePath As String, ByVal name As String, ByVal value As String) As String Dim doc As XmlDocument = New XmlDocument doc.Load(resourceFilePath) 'See if it exists first Dim root As XmlElement = doc.DocumentElement Dim e As XmlElement = root.SelectSingleNode(String.Format("data[@name=""{0}""]", name)) If e Is Nothing Then name = CreateUniqueName(root, name) Dim elem As XmlElement = CreateResourceFileElement(doc, name, value) root.AppendChild(elem) Else If e.SelectSingleNode("value").InnerText.ToLower = value.ToLower Then Return name Else name = CreateUniqueName(root, name) Dim elem As XmlElement = CreateResourceFileElement(doc, name, value) root.AppendChild(elem) End If End If doc.Save(resourceFilePath) Return name End Function Private Function CreateUniqueName(ByRef root As XmlElement, ByVal name As String) As String If IsNumeric(name.Substring(0, 1)) Then name = "n" & name End If 'Name doesn't exist, use it If Not CheckNameExists(root, name) Then Return name End If Dim result As String 'Build a unique name For I As Int16 = 1 To 100 result = name & I If Not CheckNameExists(root, result) Then Return result End If Next Return name & Guid.NewGuid.ToString End Function Private Function CheckNameExists(ByRef root As XmlElement, ByVal name As String) As Boolean Dim e As XmlElement = root.SelectSingleNode(String.Format("data[@name=""{0}""]", name)) Return Not (e Is Nothing) End Function Private Function CreateResourceFileElement(ByRef doc As XmlDocument, ByVal name As String, ByVal value As String) As XmlElement Dim result As XmlElement = doc.CreateElement("data") SetAttribute(result, "name", name) SetAttribute(result, "xml:space", "preserve") Dim valueElem As XmlElement = doc.CreateElement("value") valueElem.InnerText = value result.AppendChild(valueElem) Return result End Function Private Function SetAttribute(ByRef element As XmlElement, ByVal attr As String, ByVal value As String) As XmlElement If element.Attributes.GetNamedItem(attr) Is Nothing Then Dim attrib As XmlAttribute = element.OwnerDocument.CreateAttribute(attr) attrib.Value = value element.Attributes.Append(attrib) Else element.Attributes.Item(attr).Value = value End If Return element End Function Private Function StripNonAllowedChars(ByVal text As String) As String Const non_allowed = """';:,<.>/?\|`~!@#$%^&*()-=+[{]} " For I As Integer = 0 To non_allowed.Length - 1 text = text.Replace(non_allowed(I).ToString, "") Next Return text End Function End Module

 

del.icio.us Tags: , , ,
posted on Sunday, August 26, 2007 7:56:04 PM (Alaskan Standard Time, UTC-09:00)  #    Comments [0]
 Thursday, July 26, 2007

When I started this blog about 8 months ago, I decided I would write the kind of blog I like to read.  No non-sense, not filled with drivel about my life, and most importantly (to me any ways) technology related.

This post kind of blurs the lines a little bit, but I think in a good way.  My wife and I found out the end of March we are going to have a baby (Yay!).  I've known for a long time that when we did finally get pregnant, we wanted to be able to hear the heart beat any time we wanted.

To that end, I did a whole lot of research on fetal heart monitors.  Turns out, a lot of the consumer fetal heart monitors (especially the ones under $50) are glorified stethoscopes.  What self respecting geek would use something that cheesy?  Not I!

Once you move above the $100 mark, you start to get into Doppler.  These are the kind your ob/gyn and midwife have.  I knew this was what we wanted.  After more research, I settled on the Hi-Bebe-200 by Bistos.

What I really liked about the Hi-Bebe-200 I bought, was everything was included in the box.  Batteries, gel, the unit, instructions and carrying case.  When the device arrived, we immediately tried it out, and within about 5 minutes we had found the heart beat.  It was a very awesome experience!  Our second time using the device I found the heart beat in about 2 minutes.

One thing I wish they included was a 6 foot 1/8th inch audio patch cord so you can record it on your computer right away.  But a quick trip to Radio Shack and I have everything I need to be able to record the heart beat.

The eBay seller, Uncle Bobs Store was awesome.  Item shipped right away, shipping was only $6; and the item got here right away!

Enough non-geek talk.  Oh yeah, go listen to heart beat :)

posted on Thursday, July 26, 2007 2:00:15 PM (Alaskan Standard Time, UTC-09:00)  #    Comments [0]