funcakes’s posterous

funcakes’s posterous

Leon Jollans  //  Music, computers, freelance systems analysis and programming, Cardiff, whatever. This is me. Never bothered to keep a blog for long before, but this rocks my world.

Oct 19 / 12:41am

Adding elements to Lists in the XmlSerializer

I've been here a couple of times before. You have some list of data in xml you want to load into a list. for example

<?
xml version="1.0" encoding="utf-8" ?>
<
items>
    <item id="1" text="some text" />
    <
item id="2" text="some more text"/>
</
tasks>

Now I've blogged a few times about the XmlSerializer, so you may know I like it, and that I've torn it to pieces in the past. So anyway, my immediate reaction to needing to load xml data like this is to write code such as the following

[Serializable, XmlRoot("item"), XmlType("item")]
public class
Item
{
   [XmlAttribute("text")]
    public string Text { get; set; }

    [XmlAttribute("id")]
    public int Id { get; set; }
}

XmlSerializer itemsSerializer = new XmlSerializer(typeof(Item[]));
Item[] arrItems = (Item[]) itemSerializer.Deserialize(filestream);

 

and lo and behold, it works perfectly. Well, I wanted to add a property to the file like <items prop="value"> Obviously neither an Item[] nor a List<Item> offers any properties I can use, but this should be easy, right. simply subclass List<T> and add my property, tagging it up for XML, and then swap the XmlSerializer constructor to take my new type.

 

[Serializable]
[XmlRoot("items"), XmlType("items"
)]
public class ItemList : List<Item
>
{
   private string prop = null
;

    [XmlAttribute("prop")]
    public string
 Prop
    {
        get { return
prop; }
        set { prop = value
; }
    }
}

Wrong! My new data in the xml file is never loaded. So a little later in snippet compiler, I find out it's not written either. What's going on?

Well after trying various things out, it looks like anything inheriting from IEnumerable<T> gets intercepted by the XmlSerializer, and uses a built in serializer instead. This means it never honours your extra properties, either for writing or reading, since it doesn't ever generate the code to look for them. Frustrating eh.

Well, imagine my surprise to find out for the first time after 8 years of .NET development that you don't need to implement IEnumerable explicitly to get foreach! Well, since I'm only loading the data and looping over it, this is perfect. We have to be a little clever with the attributes to get the xml to work the same as a straight IEnumerable serializer job, but that's easy enough (XmlElementAttribute against the nested List will do it) and Bingo. The following class

[Serializable]
[XmlRoot("items"), XmlType("items"
)]
public class
ItemList
{
    private string prop = null
;
    private List<Item> items = new List<Item
>();

    [XmlAttribute("prop")]
    public string 
Prop
    {
        get { return
prop; }
        set { prop = value
; }
    }

    [XmlElement("item")]
    public List<Item
> Items
    {
        get { return
items; }
        set { items = value
; }
    }

    public IEnumerator<Item> GetEnumerator()
    {
        return
items.GetEnumerator();
    }
}

will successfully load and save effectively the same XML as if you were working directly off a List or Array, but wanted to add a property.

Now, all we have to work out is how to do this and get an immediate IList implementation on the class as well!
Loading mentions Retweet

Comments (0)

Oct 8 / 2:27pm

Why I hate marketing people

This is just horrible. This is the marketing of which Bill Hicks railed against, and which people in that industry totally failed to understand. It's pure evil. Ugly, snide, evil. So desperately trying to be cool, and so desperately failing. This from a company that gives you free salt and vinegar but *charges* for a squirt of ketchup. ugh.

Loading mentions Retweet

Comments (0)

Sep 30 / 7:53pm

Loading resources in asp.net

Just had a gotcha with loading resources. We're currently working on a large tiered solution where the web tier is supported by multiple customer-specific solutions, each of which comprises (among other things) the core web dll, and a customer specific web project which runs an xcopy on postbuild copying web files (aspx, ascx etc) to the main web root directory.

I just wrote some code in a customer specific project to load an embedded resource, using

GetType().Assembly.GetManifestResourceStream( ... )

Which should be fine, right? Done it enough times... But it wasn't working. I stuck the debugger on, and ran GetManifestResourceNames in the Immediate window... And it wasn't there! Weird. So, I fired up reflector on the customer dll, and sure enough, there was the resource. So what was going wrong?

Well, it turns out that because we're not writing these pages and controls in the web root project itself but rather copying the markup files over to the web root they get recompiled by asp.net runtime into the ASP namespace, even though they're inheriting from the classes in the customer project, and yet, GetType() in the codebehind returns the dynamically compiled aspx type, not the codebehind class.

So, easy solution, we don't use GetType() to target the Assembly for loading resources, we have to be explicit and use typeof([PageClassName]) to target the supporting dll.

I thought I'd share this as it caught me by surprise, and I know that the postbuild xcopy trick is common in umbraco based projects, and I have a few twitter followers and readers who use umbraco.

So if you're ever using multiple projects to target a single web root, using postbuild scripts or similar to push those files across, remember you can't quite use GetType() like you'd expect, or at least you might be surprised by the results.

Hope that helps somebody

Loading mentions Retweet

Comments (0)

Sep 29 / 2:57am

Bye bye 79 Glenroy St. End of an era.

I can still hear the jungle techno, gay house, buckets, animal impressions, shits and giggles, tears and laughter. Let all good etc. Here's to the future, and mum's lovely new house - I hope it's the turning point it deserves to be.

Loading mentions Retweet

Comments (0)

Sep 27 / 12:22pm

AutoEventWireup is evil

I just had a tweet from ASP.NET MVP and all-round guru @Plip, who'd been caught out by a misspelling in a method name. It happens to the best of us. But something struck me. The method in question: Page_PreRen[d]er.

And this is why AutoEventWireup is evil. Along with any convention based software. This is what OO was *designed* to overcome. The aspx webforms model offers protected virtual On[event] methods for (probably) all the events its objects fire, and you can't cock up overriding these - the compiler *won't let you*. Hell, VS even autocompletes half the job for you.

So why does the default template for a new webform *still* have AutoEventWireup set and a skeleton Page_Load method? This is a VB convention from 10 years ago. Haven't we all moved on?

For those reading who aren't scholars of object oriented programming, let me clarify. There are three tenets of OO. Encapsulation, Inheritance and Polymorphism.

Encapsulation means that you write pieces of code in a self contained unit. The internal implementation details should not be relevant, and hence not visible. This means nobody can break your encapsulated code by changing its internal state - or at least not without jumping through enough hoops to question the validity of the approach. Take the Page class in asp.net, this does a bunch of things that you don't have to care about, and frankly you can't easily change, it just works the way it does. If you want to change the behaviour of an aspx Page, which by default is quite boring to look at, you have to derive from it and add your own logic. The mechanism for this is...

Inheritance, which is the ability to derive more specific code from code that exists already. By inheriting, or if you prefer, deriving from it, you gain that functionality in your own code, and can specialise and enhance that behaviour for a more specific purpose. For example, by deriving from Page and overriding Render, you get to change what the html output of that Page looks like.

Polymorphism is the ability for other code to treat both the more general code, and the derived code equally, and swap out one piece of code from another. In the Page example above, it is polymorphism that allows the rest of ASP.NET to use your derived Page as if it was any other Page without needing any other changes, except at the encapsulated site (i.e. Your custom aspx page)

.NET also supports events as a first class construct. This is close enough to the GoF Observer pattern as to not really matter. It's effectively a means of transferring control from one piece of code to another interested party in response to some "event" such as "I am about to render html". Subscribing to events allows code in another place to act in response, perhaps to switch the target browser to mobile, or to drop a timestamp literal into the page, who knows. But this is what they're for, external objects are notified when things are about to happen or have happened, and they can then act accordingly.

But AutoEventWireup changes all of that. The first mistake is subscribing to your own events. Firstly, there is an overhead in doing this. Not a huge one, but enough to matter on a heavily visited site. Secondly, it's detached from the source of the event - your event handler isn't guaranteed to be called, a base class in your inheritance chain is quite within its rights to *not fire* the event at all.

The second mistake is in requiring the handler method's name to match a naming convention as it's vulnerable to typos

Thirdly, you can switch it off without requiring recompilation, either in the aspx markup or in web.config. This will break your site like crazy if you take advantage of autoeventwireup (or the default new webform template), and you're going to struggle to work out why. Worse, it's *on* by default. You could find yourself with a new web.config file in deployment that doesn't switch it off, and some old random code could get called on *some* of your pages (probably the ones you outsourced to the lowest bidder) and you'll never work out why.

So please please MS, and MS devs, always override the OnEvent methods instead, it can't be broken by client code like events can, it's more OO (encapsulated, and polymorphic) and your code will be cleaner and more robust for it.

That's all.

Loading mentions Retweet

Comments (0)

Sep 9 / 1:14am

Marc Bolan Corner

Amen.

Loading mentions Retweet

Comments (0)

Sep 8 / 2:00pm

Terror Banker?

Come on, you're having a laugh. Terror Banker? Stick to Diana - you were better at that.

Loading mentions Retweet

Comments (0)

Sep 5 / 9:10am

Diversity in Cardiff

They'll let anyone in here these days

Loading mentions Retweet

Comments (0)

Sep 1 / 2:00pm

Good old Blue, he took the Milky Way

It's funny the things you remember. One of those things is the old Milky Way advert they've just started showing again, what, 15 years later? The red car and the blue car had a race
All red wants to do is stuff his face.

 And so on. Strangely though they've changed the chorus. It used to go

 He's looking for a chocolate treat,
That's fluffy and light
'Cause he knows it won't spoil
his appetite.

 But now it ends:
'Cause he knows it's something
That tastes just right.

 Have the ASA been all over this I wonder? Did one parent complain, taking it off the air for 15 years? Has it been proven that milky ways can indeed spoil your appetite?

 Or more likely is it yet another reminder that you shouldn't believe everything you hear?

 Whichever it is, I think it's probably more worrying that I noticed at all. I think I may need a girlfriend.

Loading mentions Retweet

Comments (0)

Aug 13 / 12:19pm

Flars

Loading mentions Retweet

Comments (0)