Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple Blog using a Quick and Easy Saveable Object Class, JSON, and LINQ

0.00/5 (No votes)
9 Dec 2007 1  
Learn how to create classes that automatically save and retrieve their data (), and how to quickly query that data with LINQ. The sample implementation of my class Saveable shows just how easy it is to create a blog.
Screenshot of Blog implementation

Introduction

Ever created a stellar class and then had to write subroutines to save and retrieve it? Ugh. I got tired of this, so I created the Saveable class. You can extend this class through any class you've written using inheritance.

It uses JSON (JavaScript Object Notation) serialization (now built-into the .NET Framework 3.5 and Visual Studio 2008) to iterate through the members of a class, retrieve the data and save it to a file.

Wait!? You're using JSON for a database?! Yeah, that's right. JSON serialization is faster and creates smaller files than XML serialization while still maintaining human-readability. I know this was not the original purpose of JSON, but it works, and it works very well.

The example implementation I've included is a blog engine. WARNING: It's ultra-simple just to show off the features of Saveable(Of T). It would need a lot of work before putting it out in the real world. But it does include code for managing posts and comments. It also has code for performing ranked searches on the posts using RegularExpression and LINQ.

Using the Code

The core of my Saveable class is the two methods: ToJSON, and FromJSON:

Shared Serializer As New Runtime.Serialization.Json.DataContractJsonSerializer(GetType(T))
    Public Shared Function ToJSON(ByVal Obj As Object) As String
        Dim tt As New IO.MemoryStream
        Serializer.WriteObject(tt, Obj)
        tt.Close()
        Return System.Text.Encoding.ASCII.GetString(tt.ToArray)
    End Function

    Public Shared Function FromJSON(ByVal Data As String, ByVal Type As Type) As Object
        If String.IsNullOrEmpty(Data) Then Return Nothing
        Dim tt As New IO.MemoryStream(System.Text.Encoding.ASCII.GetBytes(Data))
        Return Serializer.ReadObject(tt)
    End Function

These methods convert your object to and from text.

To get started using the class, create your own class that inherits from Saveable(Of T), where T is the type of your class. Then import System.Runtime.Serialization and add a DataContract attribute.

Imports System.Runtime.Serialization

 Public Class BlogMessage : Inherits Saveable(Of BlogMessage)

End Class

Next, add whatever properties your class needs. The Saveable(Of T) class already contains properties for ID as GUID, DateCreated as Date, and DateModified as Date.

Imports System.Runtime.Serialization

<DataContract()> Public Class BlogMessage : Inherits Saveable(Of BlogMessage)
    Dim _Title As String
    <DataMember()> Public Property Title() As String
        Get
            Return _Title
        End Get
        Set(ByVal value As String)
            _Title = value
        End Set
    End Property

    Dim _message As String
    <DataMember()> Public Property Message() As String
        Get
            Return _message
        End Get
        Set(ByVal value As String)
            _message = value
        End Set
    End Property
End Class

Now, you can do the cool stuff:

'Create a New One



Dim b as New BlogMessage With { .Title = "My New Post!", _
        .Message = "This is the content for the post." }
b.Save()

The Save() method creates a new ID if necessary, sets the DateCreated if blank, updates the DateUpdated, serializes the object into text, and saves it to a *.js file--named after the ID, under a folder named after the object (BlogMessage in this case) under the App_Data folder (i.e. ~/App_Data/BlogMessage/42dc0fb5-c516-4536-b273-6bbff8ed33ae.js).

Loading the object back into memory is just as easy:

'Load an Old One



Dim b as BlogMessage = BlogMessage.Load("42dc0fb5-c516-4536-b273-6bbff8ed33ae")
'Now do something with it



Response.Write(b.Message)

And now, take your class into high gear. I added another class BlogComment, which also inherits from Saveable(Of T). Then I added some LINQ (which is just AWESOME, by the way):

Imports System.Runtime.Serialization
Imports System.Linq

<DataContract()> Public Class BlogMessage : Inherits Saveable(Of BlogMessage)
    <DataMember(Name:="Comments")> Dim _comments As Generic.Dictionary_
            (Of Guid, BlogComment)
    Public ReadOnly Property Comments() As Generic.Dictionary(Of Guid, BlogComment)
        Get
            If _comments Is Nothing Then _comments = _
                    New Generic.Dictionary(Of Guid, BlogComment)
            Return _comments
        End Get
    End Property

    Dim _Title As String
    <DataMember()> Public Property Title() As String
        Get
            Return _Title
        End Get
        Set(ByVal value As String)
            _Title = value
        End Set
    End Property

    Dim _message As String
    <DataMember()> Public Property Message() As String
        Get
            Return _message
        End Get
        Set(ByVal value As String)
            _message = value
        End Set
    End Property

    Public Shared Function GetPostByTitle(ByVal Title As String) As BlogMessage
        Dim o As Generic.IEnumerable(Of BlogMessage) = From b As BlogMessage In _
            BlogMessage.GetAll Where b.Title.Equals_
            (Title, StringComparison.OrdinalIgnoreCase) Take 1
        If o.Count = 0 Then Return Nothing
        Return o.First
    End Function

    Public Shared Function Search(ByVal Terms As String) As BlogMessage()
        Dim r As New Regex("(" & Terms.Trim.Replace(" ", ")|(") & ")", _
            RegexOptions.Singleline Or RegexOptions.IgnoreCase Or _
            RegexOptions.Compiled)
        Return (From b As BlogMessage In BlogMessage.GetAll Select b, k = _
            b.Rank(r) Where k >= 0 Order By k Descending Select b).ToArray
    End Function

    Private Function Rank(ByVal r As Regex) As Double
        Dim c As String = Title & vbNewLine & Message
        Dim m As MatchCollection = r.Matches(c)
        If m.Count = 0 Then Return -1
        Return Aggregate dm As Match In m Into Sum(dm.Index / c.Length)
    End Function
End Class

Points of Interest

JSON and LINQ are cool!
To Do: Learn more LINQ! It's awesome and incredibly powerful. Check out the examples here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here