JSON and XML View Engines in ASP.NET MVC

by Jon Davis 28. March 2008 18:28

I posted earlier that we're working on a client-side MVC framwork that compliments the ASP.NET MVC framework. It's actually not formally MVC on the client, but it comes close. The view side is entirely controller-driven, even the event model. The "model" side of it is the ASP.NET server itself. So the server spits out both templated markup for the client-side controls, as well as the AJAX'd data models. These data models are models to the client but they are views to the server, or at least that's the way we're designing it.

So my co-worker posted his solution to XML and JSON callbacks, since ASMX is not MVC-friendly. It's a JSON view engine for MVC.

"I recently saw Scott Guthrie at a local .NET User Group event, and he mentioned that the ASP.NET MVC Framework was completely "pluggable", and you could easily replace the built-in View Engine.  So, I immediately searched for examples, found one ... tossed it out and whipped together a really quick and simple 'JsonViewEngine' class. Here's the code ..."

http://www.fragmentedcode.com/2008/03/27/jsonviewengine-for-aspnet-mvc-framework/

kick it on DotNetKicks.com

Currently rated 1.5 by 21 people

  • Currently 1.47619/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

Software Development | Web Development

XML Encoding Text Really, Really Easily

by Jon Davis 18. January 2008 00:31

Frequently I need to pass some text along in an XML document that may have special characters like less-than (<), greater-than (>), or the really annoying nuisance, ampersand (&). Most people fix this lazily by using CDATA nodes. But I hate CDATA nodes with a passion!! I've been using a trick I've used for years and I dunno why I never blogged it. You don't need to use CDATA, nor do you need to manually perform a scan and replace for these special characters. Microsoft already did the dirty work for you in XmlDocument by setting a node's InnerText value and getting the InnerXml value back.

So when I'm generating an XML file, such as with using a StringBuilder or using repeaters on an .aspx template, this is what I sneak into the code-behind:


    private static System.Xml.XmlDocument _staticDoc = null;
    public static string XmlEncode(string str)
    {
        if (str == null) return "";
        if (_staticDoc == null)
        {
            _staticDoc = new System.Xml.XmlDocument();
            _staticDoc.LoadXml("<text></text>");
        }
        lock (_staticDoc)
        {
            _staticDoc.LastChild.InnerText = str;
            return _staticDoc.LastChild.InnerXml;
        }
    }

Then I can just use: 

<%# XmlEncode("Ed & Bob")%>

.. where "Ed & Bob" actually comes from a data object. :) This in turn outputs "Ed &amp; Bob".

There's also XmlTextWriter, which I haven't tried yet.

UPDATE: Alright, now I've tried XmlTextWriter. I had a need for ASCII enforcement of XML encoding so that weird Unicode characters are converted to their "&#??;" entity replacements. The method isn't so simple anymore but first tests seem to pass. I'll update this again if I find it to be flawed. Note that I'm putting this among other things into a shared XmlUtil class full of handy static methods. But this update in particular is important because XmlDocument.Load() was failing to load because of some Unicode characters that could be best described in XML entities.

namespace XmlUtil {

private static XmlDocument _staticDoc = null;
private static StringWriter _staticStringWriter = null;
private static XmlWriter _staticXmlWriter = null;
 
/// <summary>Converts Unicode text into ASCII-compliant XML encoded text</summary>
public static string EncodeText(string str)
{
    if (str == null) return "";
    if (_staticDoc == null)
    {
        _staticDoc = new System.Xml.XmlDocument();
        _staticDoc.LoadXml("<text></text>");
        _staticStringWriter = new StringWriter();
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.ConformanceLevel = ConformanceLevel.Fragment;
        _staticXmlWriter = XmlTextWriter.Create(_staticStringWriter, settings);
    }
    lock (_staticDoc)
    {
        _staticDoc.LastChild.InnerText = str;
        str = _staticDoc.LastChild.InnerXml;
    }
 
    // ASCII enforcement
    StringBuilder sb = new StringBuilder();
    char[] chars = str.ToCharArray();
    for (int i = 0; i < chars.Length; i++)
    {
        char c = chars[i];
        if ((int)c > 127) // goes beyond ASCII charset
        {
            lock (_staticStringWriter)
            {
                lock (_staticXmlWriter)
                {
                    _staticXmlWriter.WriteCharEntity(c);
                    _staticXmlWriter.Flush();
                    StringBuilder _sb = _staticStringWriter.GetStringBuilder();
                    sb.Append(_sb.ToString());
                    _sb.Length = 0;
                }
            }

        }
        else sb.Append(c);
    }
    return sb.ToString();
}

}

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

Software Development | Web Development

XML-to-C# Code Generation

by Jon Davis 1. May 2007 23:16

Altova probably hates me. Not their products, but the company. I've frequently wanted to give their product line a noble shot for utilization, but I never have time to give it a fair shot, so I am never able to afford to purchase it or give it a full recommendation to my employer. My old user ID shows up in their tutorial videos alongside generic examples of hackers and spammers. For years, I'd try reinstalling the product to get past the 30-day trial in hopes that I'd have time to really check their cool tools out. When they killed that ability, I tried doing it within a virtual machine. Now in VMs I cannot get a trial key anymore; perhaps my e-mail domain name is blocked.

But I often forget that there is no real need for an investment in some third party XML code generation tool like Altova's XMLSpy or MapForce if you need a complete object model written in C# to introspect a deserialized XML file. After spending hours Googling for C# code generators from XML, I realized that the solution is right under my nose. And I don't have to spend a dime for it.

Why Generate?

You might be asking, why are you trying to generate C# code? Doesn't System.Xml.XmlDocument and its XPath support work well enough to do what you need to do with an XML document? The answer is, yes, sometimes. Sometimes Notepad.exe is sufficient to edit an .aspx file, too, but that doesn't mean that having a good ASP.NET IDE w/ code generation, like Visual Studio, should be ignored for Notepad.

In fact, I was happy with using XmlDocument until I realized that some of the code I was tasked to maintain consisted of hundreds of lines of code that would read CDATA values into a business object's own properties, like this:

XmlNode node = storyNode.SelectSingleNode("./title");
if (node != null && node.ChildNodes.Count > 0 && node.ChildNodes[0].value != null)
{
	this._title = node.ChildNodes[0].Value
}

node = storyNode.SelectSingleNode("./category");
if (node != null && node.ChildNodes.Count > 0 && node.ChildNodes[0].value != null)
{
	this._category = node.ChildNodes[0].Value
}

...

This just seemed silly to me. When I started working with a whole new XML schema that was even more complex, I decided that manually writing all that code is just ludicrous.

XML -> XSD

Visual Studio 2005 (of which there are freely downloadable Express versions, of course) has the ability to introspect an XML document to generate an XML Schema (.xsd). It's really very simple: load the XML file into the IDE, then select "Create Schema" from the "XML" menu. Overwhelmed by the complexity of it all yet?

Bear in mind that the resulting Schema is not perfect. It must be validated--by you. If at first glance the schema looks fine, there's a simple test to validate it: simply programmatically load your XML document while enforcing the schema. For my purposes, I found that most of the adjustments I needed to make were just to make "required" elements "optional", unless of course they were indeed required.

XSD -> C# Code

If the schema's clean, all you need is the .NET Framwork SDK, which comes bundled with Visual Studio 2005. Tucked away therein is XSD.exe, which does the magic for you. All you have to do is pass it "/c" along with the name of the .xsd file and the new name of the .cs file you want it to auto-generate.

The generated C# code isn't always perfect, either. To say nothing of the rough comment stubs, one or two textual content elements were completely ignored in my case--the attributes were exposed as C# properties but the content, which was CDATA, was not. Easy enough to fix. This was likely due to an imperfect XSD file, but since this was really a run-once-and-forget-about-it effort, I was not afraid of diving into the C# to add the missing properties.

        private string _value;
        [System.Xml.Serialization.XmlText()]
        public string value
        {
            get { return _value; }
            set { _value = value; }
        }

System.Xml.Serialization.XmlSerializer works flawlessly with the generated C# code. I created the following generic class for the generated classes to inherit, so that they automatically offer a Deserialize() method:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace MyProject.XmlGen
{
    public class XmlDeserializer<T>
    {
        public static T Deserialize(string xmlFilePath)
        {
            using (FileStream stream = new FileStream(xmlFilePath, FileMode.Open))
            {
                return Deserialize(stream);
            }
        }
        public static T Deserialize(Stream xmlFileStream)
        {
            return (T)Serializer(typeof(T)).Deserialize(xmlFileStream);
        }

        public static T Deserialize(TextReader textReader)
        {
            return (T)Serializer(typeof(T)).Deserialize(textReader);
        }

        public static T Deserialize(XmlReader xmlReader)
        {
            return (T)Serializer(typeof(T)).Deserialize(xmlReader);
        }

        public static T Deserialize(XmlReader xmlReader, string encodingStyle)
        {
            return (T)Serializer(typeof(T)).Deserialize(xmlReader, encodingStyle);
        }

        public static T Deserialize(XmlReader xmlReader, XmlDeserializationEvents events)
        {
            return (T)Serializer(typeof(T)).Deserialize(xmlReader, events);
        }

        public static T Deserialize(XmlReader xmlReader, string encodingStyle, XmlDeserializationEvents events)
        {
            return (T)Serializer(typeof(T)).Deserialize(xmlReader, encodingStyle, events);
        }

        private static XmlSerializer _Serializer = null;
        private static XmlSerializer Serializer(Type t)
        {
            if (_Serializer == null) _Serializer = new XmlSerializer(t);
            return _Serializer;
        }

    }
}

So with this I just declare my generated C# as such:

public class MyGeneratedClass : XmlDeserializer<MyGeneratedClass>
{
 ...
}

Literally, now it takes a whopping ONE line of code to deserialize an XML file and access it as a complex object model.

MyGeneratedClass myObject = MyGeneratedClass.Deserialize(xmlFilePath);

Cheers.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , ,

Software Development


 

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

Jon Davis (aka "stimpy77") has been a programmer, developer, and consultant for web and Windows software solutions professionally since 1997, with experience ranging from OS and hardware support to DHTML programming to IIS/ASP web apps to Java network programming to Visual Basic applications to C# desktop apps.
 
Software in all forms is also his sole hobby, whether playing PC games or tinkering with programming them. "I was playing Defender on the Commodore 64," he reminisces, "when I decided at the age of 12 or so that I want to be a computer programmer when I grow up."

Jon was previously employed as a senior .NET developer at a very well-known Internet services company whom you're more likely than not to have directly done business with. However, this blog and all of jondavis.net have no affiliation with, and are not representative of, his former employer in any way.

Contact Me 


Tag cloud

Calendar

<<  May 2018  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar