Posts for the tag: MVC

Jun
4
2012

Building a Blog Redux - Mapping View Models to Entities Using AutoMapper (Part 6)

This is the sixth post in a series of posts about how I went about building my blogging application.

  1. Building a Blog Redux - Why Torture Myself (Part 1)
  2. Building a Blog Redux - The tools for the trade (Part 2)
  3. Building a Blog Redux - Entity Framework Code First (Part 3)
  4. Building a Blog Redux - Web fonts with @font-face and CSS3 (Part 4)
  5. Building a Blog Redux - Goodreads feed using Backbone.js (Part 5)

In the basic building parts of a MVC web application there are the models, the views, and the controller. The models represent the data that will be placed in the view. The controller is the guy that goes and gets the data (the model) and puts it in the view. Then finally, view is responsible for presenting the data to the user. If the data schema is simple, you could use an ORM like Entity Framework, nHibernate, LINQ, or go old school data-access-layer and pass the entity that represents a SQL table directly to the view and display it on the page.

However, as views get more complicated, the data in the entities needs to be manipulated and changed before you can display it in a view. Often times, the views have fields that are not needed in an entity or vice-versa. You could end up with bloated entities that have a lot of properties that are not mapped to any field in a database. Back in the days of yore, we might resorted to creating stored procedures to manipulate the data to return properties we needed, but then the next guy to come along and work who wanted to make changes to that application learned quickly that this was a very bad idea.

My Approach

My MVC applications are really MVCS applications. That is, I typically add a service layer to my applications between the controller and the models, where I try and keep the lion share of my business (domain) logic. Also, instead of having entities display on the page, I create classes that represent a view models and then I map the entities to the view model which then get sent to the views. This mapping takes place in my new service layer that I just created.

Doing this gives keeps my entities clean and provides for a better separation of concerns between my database and my front end views. However, mapping entities to views and vice-versa can be a challenge especially as your application grows in both size and complexity. It can also be quite tedious, and makes for a laborious day of coding.

Enter AutoMapper

So to handle all my mappings, I use AutoMapper. Here is what AutoMapper is in their own words.

"AutoMapper is an object-object mapper. Object-object mapping works by transforming an input object of one type into an output object of a different type. What makes AutoMapper interesting is that it provides some interesting conventions to take the dirty work out of figuring out how to map type A to type B. As long as type B follows AutoMapper's established convention, almost zero configuration is needed to map two types."

Configuring AutoMapper.

Before mapping an entity object to a view model object, I need to tell AutoMapper the details about these mappings. Most times, the defaults were used, which by convention, is if object A has property with the same name as object B then those to fields will be automatically mapped. If object A has a property that object B doesn't have, then I can ignore it, or do something custom to account for that field. In an MVC web application, these configuration steps are done when the application starts.

In my Application_Start event in the global.asax.cs file, I have the following code.

Bootstrapper.RegisterMappings();

Inside this function, I register a profile for each of my mappings. These profile class is what tells AutoMapper the details of each of the mappings.

 public static void RegisterMappings()
        {
            Mapper.Initialize(x =>
                                  {
                                      x.AddProfile(new UserMapperProfile());
                                      x.AddProfile(new UserRoleMapperProfile());
                                      x.AddProfile(new BlogSiteMapperProfile());
                                      x.AddProfile(new PostMapperProfile());
                                      x.AddProfile(new SettingMappingProfile());
                                      x.AddProfile(new PingServiceMappingProfile());
                                  });;
        }

Here is an example of a simple configuration.

public class SettingMappingProfile : Profile
    {
         public const string ViewModel = "SettingProfile";
 
        public override string ProfileName
        {
            get { return ViewModel; }
        }
 
        protected override void Configure()
        {
            CreateMap<SettingSettingViewModel>();
            CreateMap<SettingViewModelSetting>();
        }
    }

In this case, I have a maping from the entity to the view and also from the view to the entity. Also, notice that my mapping class is inheriting from the Profile base class which is doing all of the magic and taking care of all of my mappings.

Where I have mappings that I need to ignore a field, I can use the Ignore option.

CreateMap<BlogSiteViewModelBlog>()
                .ForMember(dest => dest.Id, opt => opt.MapFrom(x => x.BlogId))
                ;

If I have a property that is itself an object and I want to map the Id property to its Is property and then instantiate the object, I could do the following.

CreateMap<HtmlFragmentViewModelHtmlFragment>()
                .ForMember(dest => dest.Blogs, opt => opt.Ignore())
                .ForMember(dest => dest.Location,
                           opt => opt.MapFrom(x => new HtmlFragmentLocation {Id = Convert.ToInt32( x.SelectedLocationId)}));
                ;

In some cases, I have property that I want to do special things with. In those cases, I can use what's called a value resolver. For example for my tags, I want to store them in the database as a collection; however, I want to display them on the page as comma delimited property. Here's how I can do this using AutoMapper.

First specify in the configuration to use a custom ValueResolver.

.ForMember(dest => dest.TagListCommaDelimited, opt => opt.ResolveUsing<TagListToDelimiterResolver>())

Then in the derived value resolver class, add the code to handle the list to delimiter functionality.

    public class TagListToDelimiterResolver : ValueResolver<Poststring>
    {
        protected override string ResolveCore(Post source)
        {
            if (source == nullreturn string.Empty;
            if (source.Tags == nullreturn string.Empty;
            string tagDelimited = source.Tags.Aggregate(string.Empty,
                                                        (current, tag) => current + string.Format("{0},", tag.TagName));
 
            return !string.IsNullOrEmpty(tagDelimited)
                       ? tagDelimited.Substring(0, tagDelimited.Length - 1)
                       : tagDelimited;
        }
    }

Testing

One of the things I like about AutoMapper is that it has an assert routine you can use to set up tests to test that your configuration works. When a test fails, the assert function does a good job of letting you know where the problem lies and which property is have an issue. Leaning on these mapping unit tests save me lots of time configuring my mappings, and I pretty much knew that if my tests were passing, then my web application would handle the mappings without any issues.

        [TestMethod]
        public void Should_be_able_to_configure_user_profile_to_view()
        {
            Bootstrapper.RegisterMappings();
            Mapper.AssertConfigurationIsValid();
        }

Mapping

Once the configurations are in place, the Mapper.Map function can be called and the views will be mapped to entities and entities map to views. Typically, I like to add some further abstraction and place these tasks in there own classes. This way, I can mock the results in a tests and add some additional customization if needed.  It also makes the mappings a little more maintainable.

public class PostMappingService : IPostMappingService
    {
        public Post MapToEntity(PostViewModel viewModel)
        {
            return Mapper.Map<PostViewModelPost>(viewModel);
        }
 
        public PostViewModel MapToView(Post entity)
        {
            return Mapper.Map<PostPostViewModel>(entity);
        }
    }

Conclusion

Hope this helps. As usual, you can see all of the code at GitHub.

 

 

 

May
8
2012

Building a Blog Redux - Goodreads feed using Backbone.js (Part 5)

This is the fifth post in a series of posts about how I went about building my blogging application.

  1. Building a Blog Redux - Why Torture Myself (Part 1)
  2. Building a Blog Redux - The tools for the trade (Part 2)
  3. Building a Blog Redux - Entity Framework Code First (Part 3)
  4. Building a Blog Redux - Web fonts with @font-face and CSS3 (Part 4)

So I put a right rail column on my blog site thinking I probably would put some content over there to engage you users. I had my tag cloud, and eventually I am going to put a search box there as a future feature, but I wasn't really excited about what else to put there. I thought about a dated archive list but I have a dedicated page for that and besides, who really ever clicks on those links.

I could put some ads, but admittedly, I don't have enough traffic to consider that, and even if I did, I still probably would not do that right away. Although, I did put placeholder on the right side in case I changed my mind.

I could put my twitter feed, but I don't know; I don't think that is very interesting to user reading my blog, plus it's sort of been done by everybody already.

Goodreads

Enter Goodreads. If you read books and are social, Goodreads is the perfect site for you. You can keep track of all the books you read, categorizing them by  "Currently Reading", "Read", and "To Read". You can also categorize books by genres or whatever classification you want. The great thing about categorizing the books is Goodreads will give you recommendations based on how you have your books categorized.

Goodreads is social site, so just like Twitter, Facebook, etc. You make friends and then you can see what books they are reading and they have rated and reviewed.

And just like most other social sites, Goodreads has a developer section with an API and other tools for you to use. You just go to their website, request an application key, agree to their terms of use and then you are pretty much good to go.

The API

The API call I am using is the one called "user.show". It pretty much contains the basic information about, me, the user, such as what my bookshelves are, and (what I am most interested in) my book status updates.

The particular node I want is the action_text. Every time I update my status with a book I read or started reading, I get a new one of these nodes. The node value is HTML encoded so that task is already done by Goodreads.

<action_text>
  <![CDATA[
  gave 4 stars to: <a href="http://www.goodreads.com/book/show/12371896-the-node-beginner-book">
  The Node Beginner Book (ebook)</a> by <a href="http://www.goodreads.com/author/show/5132009.Manuel_Kiessling">
  Manuel Kiessling
  </a>
]]>
</action_text>

To get the XML for this particular message, I just need to make a GET reques to their server. Unlike Twitter, I didn't have to add a whole bunch of entries in the request header (I am going to write a post about how to do that later), I only needed the Goodreads API URL which looks like this.

http://www.goodreads.com/user/show/{user_id_number}.xml?key={your_key}

The call is a basic HttpWebRequest and HttpWebResponse.

public class HttpRequestHelper : IHttpRequestHelper
    {
        public string GetResponse(HttpWebRequest request)
        {
            ServicePointManager.Expect100Continue = false;
 
            if (request != null)
                using (var response = request.GetResponse() as HttpWebResponse)
                {
 
                    try
                    {
                        if (response != null && response.StatusCode != HttpStatusCode.OK)
                        {
                            throw new ApplicationException(
                                string.Format("The request did not compplete successfully and returned status code:{0}",
                                              response.StatusCode));
                        }
                        if (response != null)
                            using (var reader = new StreamReader(response.GetResponseStream()))
                            {
                                return reader.ReadToEnd();
                            }
                    }
                    catch (WebException exception)
                    {
                        return exception.Message;
                    }
                }
            return "The request is null";
        }
 
 
        public HttpWebRequest GetRequest(string fullUrl, string authorizationHeaderParams, string method)
        {
            var hwr = (HttpWebRequest)WebRequest.Create(fullUrl);
            if (! string.IsNullOrEmpty(authorizationHeaderParams)) hwr.Headers.Add("Authorization", authorizationHeaderParams);
            hwr.Method = method;
            hwr.Timeout = 3 * 60 * 1000;
            return hwr;
        }
    }

I have a function to build the HttpWebRequest and then I pass that request to function which makes the request and gets the HttpWebResponse.

Mapping the XML Response

I could have serialized the XML to an object using the XmlSerializer, but since I was only needing a few of the fields from a rather large XML response, I decided to just map the XML to a CLR object manually using LINQ to XML.

var view = new GoodReadsUserShowViewModel {Updates = new List<GoodReadsUpdateViewModel>()};
XDocument doc = XDocument.Parse(xml);

 

Creating the MVC Partial View

Once I have my object built, I then pass it back to the MVC controller which will then intern pass it back to a partial view.

        [OutputCache(Duration = 60000, VaryByParam = "*")]
        public ActionResult Index(string id)
        {
            try
            {
                GoodReadsUserShowViewModel result = GetGoodReadsUserShowViewModel(id);
                return PartialView("_Goodreads", result);
            }
            catch(Exception ex)
            {
                ErrorSignal.FromCurrentContext().Raise(ex);
                return PartialView("_Goodreads"new GoodReadsUserShowViewModel {ErrorMessage = ex.Message});
            }
        }

Things to note up until this point. Since I know that this feed is not going to change much (I mean I can only read books so fast), I am caching the response for a fairly long time. In this case, performance is more important than timeliness because I don't care that you see the latest status the second after I update it.

Also, I could have passed back a JsonResult, but in this case, Backbone.js actually recommends that you have your data already bootstrapped into the request. Therefore, on my Goodreads partial view, I am taking the view model and passing it to a helper class that will serialize my model JSON and put it in a JavaScript variable.

<script src="@Url.Content("~/js/goodreads.js")" type="text/javascript"> </script>
<script type="text/javascript">
    var grApp = new GoodreadsApp(@Model.ToJson());
    grApp.start();
</script>

 

The helper class ToJson looks like this.

using System.Web.Mvc;
using Newtonsoft.Json;
 
namespace AviBlog.Core.Helpers
{
    public static class JavaScriptSerializerHelper
    {
 
        public static MvcHtmlString ToJson(this object model)
        {
            string json = JsonConvert.SerializeObject(model);
            return new MvcHtmlString(json);
        }
         
    }
}

So when the page is actually rendered the JavaScript model that is rendered will look something like this.

<script type="text/javascript">

    var grApp = new GoodreadsApp({
        "UserId":"3425042",
        "UserName":"avington",
        "Name":"Steve Moseley",
        . . . });

    grApp.start();

</script>

 

Backbone.js Implimentation

Here is what the Backbone.js website has to say about what backbone.js is.

"Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface."

It essentially provides a clean way to bind your front-end code to different events to provide a rich user interaction. In this case, I am using it in a very simple fashion and just binding the initial response of the Goodreads data to template and binding it using jQuery Templates. Later on I am probably going to switch out jQuery Templates for jsRender, but for now jQuery Templates it is.

Derick Baily who probably has the best blog articles on Backbone, put a response in StackOverflow as what the best way to render data on a page on the initial load and as you can see from his response and my code, I pretty much did the same thing. Here is my backjone.js code.

GoodreadsApp = (function (Backbone, _, $) {
    var GoodreadsModel = Backbone.Model.extend({});
 
    var GoodreadsCollection = Backbone.Collection.extend({
        model: GoodreadsModel
    });
 
    var GoodreadsView = Backbone.View.extend({
        el: $('.goodreads-widget'),
 
        initialize: function () {
            this.collection.bind("reset"this.render, this);
        },
 
        render: function () {
            var data = this.collection.models[0].attributes;
            if (data) {
                var $template = $('#goodreads-template');
                var goodreadsHtml = $template.tmpl(data);
                $(this.el).html(goodreadsHtml);
            }
        }
    });
 
    var goodreadsApp = function (initialModels) {
        this.start = function () {
            this.models = new GoodreadsCollection();
            this.myView = new GoodreadsView({ collection: this.models });
            this.models.reset(initialModels);
        };
    };
 
    return goodreadsApp;
})(Backbone, _, jQuery);

In this example taken from StackOverflow, when the start function is called, an empty model is initialized. The reset backbone even is called which clear out the collection of models and fills the collection with a new set (in this case taken from the serialized JSON data). The render event is hooked up to the reset function so that when it is called the template is rendered.

The jQuery template looks like this.

<script id="goodreads-template" type="text/x-jquery-tmpl">
    <h4>Goodreads Status</h4>
    <ul>
        {{each Updates}}
        <li class="clear">
            <img class="goodreads-book-img" src="${BookImageUrl}"/>
            <div><a href="${UserLink}">${Name}</a> {{html ActionText}}</div>
        </li>
        {{/each}}
        <li class="last-goodreads-item">Follow me on <a href="${UserLink}">Goodreads</a></li>
    </ul>
    
 
</script>

Conclusion

I would have put a picture of the result here, but if you take a look over here on the right. Yeah the right hand panel you can see it there for yourself. I think its a pretty cool section for only a couple hours of work. As always, you can see all the code for the application at Github.

Resources

 

Apr
10
2012

Building a Blog Redux - Entity Framework Code First (Part 3)

This is the third post in a series of posts about how I went about building my blogging application.

  1. Building a Blog Redux - Why Torture Myself (Part 1)
  2. Building a Blog Redux - The tools for the trade (Part 2)

As I stated in my last post in the series, I really like what the ADO.Net team has done with the Entity Framework tool. I'm sure there are better ORM tools out there but this works well for what I need and want when CRUD operations.

Installing

With the inception of Nuget, getting Entity Framework installed is almost an after thought. I think it might actually be installed in an MVC 3 internet application by default, but you will still need to go into NuGet and upgrade the assemblies to get the latest version. As I write this post they are up to version 4.3.1. The latest release has the Code First Migration feature which allows you to update an already existing database without dropping it and then recreating it, but as of yet I have not have had a reason to use that feature.

To get to the NuGet package I right clicked on the web project and then selected the "Manage NuGet Packages" option.

Mange NuGet Packages

After that I updated the NuGet Entity Framework package.

Entity Framework 431

Entities and Context

Once the framework was installed, I could then start building entities. Now, I should say that I prefer my entities to be plain ole CLR objects (POCO). That is, I don't want my objects to have any type of decorations on them that would cause them to be dependent on external frameworks or other code in general. The reason being, is that should I ever want to switch to another Framework or re-architect the application somehow, I don't want to have to go in modify these classes removing the dependencies.

The latest versions of Entity Framework allows you to accomplish this with Entity Type Configurations. I will show you that in a but let's look at the Post entity.


using System;
using System.Collections.Generic;
 
namespace AviBlog.Core.Entities
{
    public class Post
    {
        public int Id { getset; }
        public virtual Blog Blog { getset; }
        public virtual UserProfile User { getset; }
        public string Title { getset; }
        public string Description { getset; }
        public string PostContent { getset; }
        public DateTime DateCreated { getset; }
        public DateTime? DateModified { getset; }
        public DateTime? DatePublished { getset; }
        public bool IsPublished { getset; }
        public string Slug { getset; }
        public bool IsDeleted { getset; }
        public virtual ICollection<Category> Categories { getset; }
        public virtual ICollection<Tag> Tags { getset; }
        public virtual ICollection<Trackback> Trackbacks { getset; }
        public Guid UniqueId { getset; }
    }
}

Nothing crazy here. Just a POCO class with no dependencies on anything. If I wanted to I could switch out Entity Framework and I would not have any issues with this class. That's good. That's what I want.

Another thing to notice here is that Entity Framework has a convention that says, if you name a property "Id" it will automatically assume that this is the primary key for the table and will make it so in the corresponding table.

To reference other tables like Blog and the collection of Categories, I had to set those property as virtual so Entity Framework can go in and overide those property with corresponding data from the SQL tables. When, in this case, my Post class has a collection of Categories and my Category class has a collection Posts, Entity Framework will create a joining SQL table to allow a many-to-many relationship.

Aviblog SQL Table sample

To customize these properties so that the SQL table fields have specific information, I created a context class as well as for each table I created a configuration class to address the specifics so let's look at those.


using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using AviBlog.Core.Context.Configurations;
using AviBlog.Core.Entities;
 
namespace AviBlog.Core.Context
{
    public class BlogContext : DbContextIDbConnectionFactory
    {
        protected BlogContext()
        {
        }
 
        public BlogContext(string nameOrConnectionString) : base(nameOrConnectionString)
        {
        }
 
        public DbSet<Blog> Blogs { getset; }
        public DbSet<Post> Posts { getset; }
        public DbSet<Category> Categories { getset; }
        public DbSet<HtmlFragment> HtmlFragments { getset; }
        public DbSet<Tag> Tags { getset; }
        public DbSet<UserProfile> UserProfiles { getset; }
        public DbSet<UserRole> UserRoles { getset; }
        public DbSet<Trackback> Trackbacks { getset; }
        public DbSet<HtmlFragmentLocation> HtmlFragmentLocations { getset; }
        public DbSet<Setting> Settings { getset; }
        public DbSet<PingService> PingServices { getset; }
        public DbSet<StopWord> StopWords { getset; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new PostConfiguration());
            modelBuilder.Configurations.Add(new BlogConfiguration());
            modelBuilder.Configurations.Add(new CategoryConfiguration());
            modelBuilder.Configurations.Add(new HtmlFragementConfiguration());
            modelBuilder.Configurations.Add(new TagConfiguration());
            modelBuilder.Configurations.Add(new UserProfileConfiguration());
            modelBuilder.Configurations.Add(new UserRoleConfiguration());
            modelBuilder.Configurations.Add(new TrackbackConfiguration());
            modelBuilder.Configurations.Add(new HtmlFragmentLocationConfiguration());
            modelBuilder.Configurations.Add(new SettingsConfiguration());
            modelBuilder.Configurations.Add(new PingServiceConfiguration());
            modelBuilder.Configurations.Add(new StopWordConfiguration());
            base.OnModelCreating(modelBuilder);
        }
 
        public DbConnection CreateConnection(string nameOrConnectionString)
        {
            return new SqlConnection(nameOrConnectionString);
        }
    }
}

The context class is derived from the DBContext base class which has all the magic to wire my SQL tables up. To specify field lengths and other fields attributes each entity has a configuration class which is wired up on the OnModelCreating function which is overridden from the base class. The DBSet<> properties is what maps the specified entity to the SQL table.

Let's look at one of the configuration classes.


using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration;
using AviBlog.Core.Entities;
 
namespace AviBlog.Core.Context.Configurations
{
    public class PostConfiguration : EntityTypeConfiguration<Post>
    {
        public PostConfiguration()
        {
            Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(x => x.PostContent).IsRequired();
            Property(x => x.Title).IsRequired();
            Property(x => x.Title).HasMaxLength(200);
            Property(x => x.Slug).HasMaxLength(500);
        }
    }
}

When Entity Framework builds your tables, it will look at this configuration code and will build out the SQL tables accordingly. You cal also do other things like map your entity to an existing table or if you happen to have properties in your entity that you don't want to map to a table you could tell the framework to ignore that property.

Once the tables are set up I could then run code to create the database. I did this with an initializer class that I could call both from the application startup event or a test class. I have both, but pointing to different databases. The initializer code will create the database and then seed the tables with any initial data you would like the database to have.


using
 System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using AviBlog.Core.Context;
using AviBlog.Core.Encryption;
using AviBlog.Core.Entities;
 
namespace AviBlog.Web.Tests.Initializers
{
    public class BlogDbInitializer : DropCreateDatabaseAlways<BlogContext>
    {
        protected override void Seed(BlogContext context)
        {
            var enc = new EncryptionHelper();
            var blog = new Blog
                           {
                               BlogName = "Steven Moseley's Ruminations",
                               IsActive = true,
                               IsPrimary = true,
                               SubHead = "About that art of writing code, plus other minutiae"
                           };
            var user = new UserProfile
                           {
                               FirstName = "Steven",
                               LastName = "Moseley",
                               UserName = "admin",
                               Blog = blog,
                               IsActive = true
                           };
 
            var users = new List<UserProfile> {user};
            var roleAdmin = new UserRole
                                {
                                    RoleName = "Admin",
                                    UserProfiles = users
                                };
            var roleUser = new UserRole
                               {
                                   RoleName = "Aviblog User"
                               };
            var tags = new List<Tag> { new Tag{ TagName = "tag" }};
            var post = new Post
                           {
                               Blog = blog,
                               DateCreated = DateTime.Now,
                               DateModified = DateTime.Now,
                               Description = "description",
                               IsDeleted = false,
                               IsPublished = true,
                               PostContent = "post content",
                               Title = "title",
                               User = user,
                               Slug = "slug",
                               Tags = tags,
                               UniqueId = Guid.NewGuid()
                           };
            
            var posts = new List<Post> {post};
            var category = new Category
                               {
                                   CategoryName = "Test",
                                   Posts = posts
                               };

            context.Blogs.Add(blog);
            context.Posts.Add(post);
            context.UserProfiles.Add(user);           
            context.Categories.Add(category);
            context.UserRoles.Add(roleAdmin);
            context.UserRoles.Add(roleUser);
            
            base.Seed(context);
        }
    }
}

Inheriting from the DropCreateDatabaseAlways class, will tell Entity Framework to drop your database and recreated it if there is a change in any of the entities, so its good to backup or have a copy of your development database when you run this code. There are other options and you can also pass in null to this routine and Entity Framework will skip this step.

Finally, lets look at one of the repository classes I created.


using System.Configuration;
using System.Linq;
using AviBlog.Core.Context;
using AviBlog.Core.Entities;
 
namespace AviBlog.Core.Repositories
{
    public class BlogSiteRepository : IBlogSiteRepository
    {
        private readonly BlogContext _context;
 
        public BlogSiteRepository()
        {
            string connection = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
            _context = new BlogContext(connection);
        }
 
        public IQueryable<Blog> GetAllBlogs()
        {
            return _context.Blogs.AsQueryable();
        }
 
        public string Add(Blog blog)
        {
            _context.Blogs.Add(blog);
            _context.SaveChanges();
            _context.Dispose();
            return string.Empty;
        }
 
        public string DeleteBlog(int id)
        {
            var blog = _context.Blogs.FirstOrDefault(x => x.Id == id);
            if (blog == nullreturn "The specified blog could not be found.";
            _context.Blogs.Remove(blog);
            _context.SaveChanges();
            _context.Dispose();
            return string.Empty;
        }
 
        public string Save(Blog blog)
        {
            var temp = _context.Blogs.FirstOrDefault(x => x.Id == blog.Id);
            if (temp == nullreturn "The specified blog could not be found.";
            temp.BlogName = blog.BlogName;
            temp.HostName = blog.HostName;
            temp.IsActive = blog.IsActive;
            temp.IsPrimary = blog.IsPrimary;
            temp.SubHead = blog.SubHead;
            _context.SaveChanges();
            _context.Dispose();
            return string.Empty;
        }
 
        public Blog GetBlogId(int selectedBlogId)
        {
            return _context.Blogs.Find(selectedBlogId);
        }
    }
}

This code has all the basic functions for all the CRUD operations.  I'm thinking i'll refactor this code and use the Unit of Work pattern later on. Haven't dont it yet, but I'll write about that in an upcoming post.

As always you can see all of the code up on Github so checkit out, fork it make changes and let me know how I can improve it.

 

Apr
4
2012

Building a Blog Redux -ASP.NET MVC, Razor, & Other Tools (Part 2)

This is the second post in a series of posts about how I went about building my blogging application.

  1. Building a Blog Redux - Why Torture Myself (Part 1)

In this post, I want to briefly discuss some of the tools, frameworks, best practices I used to build this blog site. I'll go into more details in future posts but for now I am just going to discuss the project setup.

ASP.Net MVC

The website itself is an ASP.Net MVC 3 project using the Razor View Engine. I also have a core project and a unit test project within the solution.

I am using the Razor View Engine, and although I still think that the Spark View Engine did some things better like adding repeaters right with the markup, I think Razor is a pretty good and with the backing of Microsoft as well as a large development community behind it, it should continue to keep getting better.

So with that said let;s take a quick look. Below is the partial view for posts.

@model AviBlog.Core.ViewModel.PostViewModel
 
<article>
    <div  class="post-heading">
        @Html.Partial("_PublishDate", Model.DatePublished)
        <h2>@Html.ActionLink(Model.Title, "Post""Posts", 
            new {id = Model.Slug}, new {@class = "post-title-link"})</h2>
    </div>
    <div>@Html.Raw(Model.PostContent) </div>
    <div class="post-meta-info">
        <ul>        
            @if (Model.DatePublished.HasValue)
            {
                <li class="align-left">Published on: @Model.DatePublished.Value.ToLongDateString()</li>
            }
        </ul>
    </div>
</article>

One of the nice things about Razor markup is that it does a good job of understanding where the server-side code ends and the HTML resumes. Even when you server code wraps on to another line, like it does above, it still transitions back to the HTML smoothly. This make the markup pretty clean and readable.

Another thing to notice is that Razor has the HTML encoding logic is reveresed from the Web Forms approach. In order to render HTML markup, I needed to use the HTML helper function "Raw", otherwise my content would be rendered as text.

Dependency Injection and Inversion of Control Using StructureMap

As with all MVC sites that I build, I always incorporate a strategy of Inversion Control. For more than a couple of years now, I have been exclusively using StructureMap as the framework of choice.

Dependency Injection simply means that all objects that your specified object is dependent on is injected into itself via the constructor or a getter. The most common approach seems to be through the constructor, and that is the approach that I am using as well.  Another thing to note here is that a dependent object is always specified as an interface. So when building your class your constructor would like as follows:

        private readonly IBlogSiteRepository _blogSiteRepository;
        private readonly IBlogsSiteMappingService _mappingService;
 
        public BlogSiteService(IBlogSiteRepository blogSiteRepository, IBlogsSiteMappingService mappingService)
        {
            _blogSiteRepository = blogSiteRepository;
            _mappingService = mappingService;
        }

Using this pattern in a MVC application really makes it more maintainable and easier to write unit tests for. The application is far less coupled, which is always a good thing in world of object oriented programming.

Inversion of Control states that an object should not be responsible to instantiate another object it is dependent on, but rather it should depend on a common "assembler" object that does the instantiating task for it. The specified object should not know anything "concrete" about the dependent object except for its specified interface. So essentially what happens at runtime is when an object is entered into by the program flow, it has already been handed all the dependent object it needs to complete its task.

I am using the MVC 2 setup of the StructureMap approach and not the new DependencyResolver that was shipped with MVC 3 only because, the older approach works pretty well. Its limitation is that it is only able to inject objects into MVC controller and not ActionFilters, ModelBinders, etc.; however, up until now, I have only needed it in two places outside of controllers and so that is not enough for me to change. I see there is a Nuget package for installing StructureMap as a DependencyResolver, so perhaps in the future I will switch to that approach instead.

But for now you can see a really good post of how I am implementing Structure map by Elijah Mannor.

There are several different IofC containers such as NInject, Castle Windsor, Unity, Autofac etc, but I use StructureMap mainly for one feature and that is scanning. The ability to scan all you assemblies and then map the interfaces to the concrete classes based on a "convention" is such a time saver. For example; a StructureMap scan will automatically map the interface IFoo to the concrete class Foo because the like name Foo. StructureMap assumes that IFoo and Foo belong together and thus maps them to each other. I used to use Unity, but would end up with configuration files that were several pages long and a pain to maintain. Now with StructureMap, I only have to explicitly map the exceptions (such as a class that has a different name than the interface) which in this Aviblog solution there are none. I think now at the time of the writing this post, all of the previously mention IofC containers have this feature with the exception of Unity.

Entity Framework 4.3

Entity Framework has come such a long way from its early days. I was really disappointed with its earlier releases and said so. But hats off to the Entity Framework team for listening to the community of developers and making an OR Mapper that is quite good. I built this blog application using the "Code First" approach and it worked out quite well.

In my next post in this series, I will go into further detail about how I set up Entity Framework and include some code samples.

​HTML5 and CSS3

I am using the HTML5 semantics in tags such as "header", "footer", "article" and "aside" for the first time. I am also using new CSS3 features such as rounded corners, shadows, and media queries to detect the size of the browser window.

Those of you viewing this post from an older browser will see that I haven't quite got all the symantics working, but I'll fix those issues and write a post about the experience as well.

Fonts

Who knew there were other fonts besides Verdana or Tahoma? Another big learning experience for me, so I'll write more about this in a future post.

I'll state here that I am using one of the Google Open Source Web Fonts, mainly because it was pretty simple to set up and I liked couple fonts that were on that site.

AutoMapper

When building an MVC application, its good to have a model that is specific for that view and same model being used by your database. For example, a user registration view could have a password and a re-enter password field, but you would only have a password field in the database table.

AutoMapper is a good way to separate the two models and then provide a process to map those data from your entity to your view model and vice-versa without having to write a lot of tedious code.

So with that said I am using AutoMapper to map my views to my entities, and and my entities to my views. I setup the mapping configurations on the application startup using configuration classes so I don't need to write any mapping code every time I want to map something. I'll talk more about this in a future post.

​What Else?

These are some of the big potatoes in the field, but I will also about other things like topics such as performance improvements, refactoring opportunities, SEO implementations and much more so stay tuned. I also promise to include some samples and links to good resources that I found useful and hopefully you might useful as well.

You can also checkout the code base at GitHub.

 

Nov
4
2011

Changing Your Website Theme based on the Users Language or Culture

Currently I am working on pretty interesting project where if the user is not from the United States but speaks English, I need to present to them an entirely different themed experienced while still  providing the same website functionality.

ASP.Net MVC does a very nice thing by encapsulating the view engine code so that is pluggable. As a matter of fact, you can actually use more than one view engine for your website if you wanted, as seen in Scott Hanselman’s post.

In my case, I still want to use the Razor View Engine but I just want to add functionality to dynamically change the paths to the views so that when user hits the web site and their current thread’s UI Culture is say United Kingdom English, I want to point them to an entirely different view engine location where the markup is very different but uses the same model.

Overriding the Razor View Engine

The way to do this is to override the RazorViewEngine class modifying its functions to dynamically change the path based on the current culture.

 

 1: using System.Web.Mvc;
 2: using Infrastructure.Http;
 3: using Infrastructure.Theming.Context;
 4: using StructureMap;
 5:  
 6: namespace Infrastructure.Theming.ViewEngines
 7: {
 8:     public class ThemingRazorViewEngine : RazorViewEngine
 9:     {
 10:         private readonly IThemingContext _themingContext;
 11:         public ThemingRazorViewEngine()
 12:         {
 13:             _themingContext = ObjectFactory.GetInstance<IThemingContext>();
 14:             LoadFormats();
 15:         }
 16:  
 17:         public ThemingRazorViewEngine(IThemingContext themingContext)
 18:         {
 19:             _themingContext = themingContext;
 20:             LoadFormats();
 21:         }
 22:  
 23:         private void LoadFormats()
 24:         {
 25:             AreaViewLocationFormats =
 26:                 new[]
 27:                     {
 28:                         "~/Areas/{2}/Views/%G/{1}/{0}.cshtml",
 29:                         "~/Areas/{2}/Views/%G/{1}/{0}.vbhtml",
 30:                         "~/Areas/{2}/Views/%G/Shared/{0}.cshtml",
 31:                         "~/Areas/{2}/Views/%G/Shared/{0}.vbhtml"
 32:                     };
 33:             AreaMasterLocationFormats =
 34:                 new[]
 35:                     {
 36:                         "~/Views/%G/{1}/{0}.cshtml",
 37:                         "~/Views/%G/Shared/{0}.cshtml",
 38:                         "~/Areas/{2}/Views/%G/{1}/{0}.cshtml",
 39:                         "~/Areas/{2}/Views/%G/Shared/{0}.cshtml"
 40:                     };
 41:  
 42:             AreaPartialViewLocationFormats =
 43:                 new[]
 44:                     {
 45:                         "~/Areas/{2}/Views/%G/{1}/{0}.cshtml",
 46:                         "~/Areas/{2}/Views/%G/Shared/{0}.cshtml"
 47:                     };
 48:  
 49:             ViewLocationFormats =
 50:                 new[]
 51:                     {
 52:                         "~/Views/%G/{1}/{0}.cshtml",
 53:                         "~/Views/%G/Shared/{0}.cshtml"
 54:                     };
 55:  
 56:             MasterLocationFormats =
 57:                 new[]
 58:                     {
 59:                         "~/Views/%G/{1}/{0}.cshtml",
 60:                         "~/Views/%G/Shared/{0}.cshtml"
 61:                     };
 62:  
 63:             PartialViewLocationFormats =
 64:                 new[]
 65:                     {
 66:                         "~/Views/%G/{1}/{0}.cshtml",
 67:                         "~/Views/%G/Shared/{0}.cshtml"
 68:                     };
 69:         }
 70:  
 71:         
 72:  
 73:         protected override IView CreatePartialView
 74: (ControllerContext controllerContext, string partialPath)
 75:         {
 76:             var compCulture = GetCompCulture();
 77:             string replacedPath = partialPath.Replace("%G", compCulture);
 78:             return base.CreatePartialView(controllerContext, replacedPath);
 79:         }
 80:  
 81:         protected override IView CreateView
 82: (ControllerContext controllerContext, string viewPath, string masterPath)
 83:         {
 84:             var compCulture = GetCompCulture();
 85:             string replacedMasterPath = masterPath.Replace("%G", compCulture);
 86:             string replaceViewPath = viewPath.Replace("%G", compCulture);
 87:             return base.CreateView(controllerContext, replaceViewPath, replacedMasterPath);
 88:         }
 89:  
 90:         protected override bool FileExists
 91: (ControllerContext controllerContext, string virtualPath)
 92:         {
 93:             var compCulture = GetCompCulture();
 94:             string replaceVirtualPath = virtualPath.Replace("%G", compCulture);
 95:             return base.FileExists(controllerContext, replaceVirtualPath);
 96:         }       
 97:  
 98:         private string GetCompCulture()
 99:         {
 100:             string folder = _themingContext.GetFolderName();
 101:             if (string.IsNullOrEmpty(folder))
 102:             {
 103:                 folder ="enUS";
 104:             }
 105:  
 106:             return folder;
 107:         }
 108:  
 109:  
 110:     }
 111: }

On every request this request for the view path will first to check to see if the file exists using the FileExists functionion and then if does Exists depending on what type of view request it is, the CreateView, or CreatePartialView will be called. As you can see, I have added functionality to replace the “%G” in the path with what ever the culture is returned from the GetCompCulture function.

All my GetCompCulture function is doing is injection a business object that is getting the users current culture from current thread and then stripping out the “-“ so that “en-US” is “enUS”. It is also defaulting any language culture that we have not set up to also be “enUS”.

Once I have a custom view engine, I just need to tell the MVC framework to only use it instead of the default Razor view engine. I can do that in the application startup event in the Global.cs file.

 1: ViewEngines.Engines.Clear();
 2: ViewEngines.Engines.Add(new ThemingRazorViewEngine());

The Folder Structure

Once my view engine is setup, I then need to setup my folder structure to match. Note, that if you are using a _viewStart.cshtml file, you will need to change the path of the _Layout file in that file.

 1: @{
 2:     Layout = "~/Views/enUS/Shared/_Layout.cshtml";
 3: }

The folder structure looks something like this.

internationaltheming

And that’s it. Your views can now be totally separate and totally different markup based on your language criteria, or any criteria you want to provide for that matter.

Hope that helps.

Oct
23
2010

Using the ASP.Net MVC & Jquery Template to repeat a HTML Fragment

I have been playing around with the new jQuery Template plugin and I’ve got to say that I am pretty impressed. I haven’t seen too many code samples so I thought I would share my approach as I had some somewhat sophisticated requirements that I haven’t really seen covered anywhere.

Approach

The repeating HTML is pretty busy so I wanted to isolate it because if it ever changes I could just publish an HTML file instead of doing a build or even republishing the view. (We use a CMS system that makes publishing content pretty easy to do.) I also wanted to reuse the fragment in different views while keeping things DRY (Don’t Repeat Yourself) at the same time. 

To do this, I created an HTML Helper that reads the HTML fragment caches it and renders inside the JavaScript tag. So this is my HTML tag:

   1: <li>
   2:     <div style='float: left;'>
   3:         <img style='border: 0px none; width: 200px;' alt='${Name}' src='${TopImagePath}'>
   4:     </div>
   5:     <div style='margin-left: 210px;'>
   6:         <div style='padding: 5px;'>
   7:             <b>
   8:                 <a href='/Activities/Activity/Detail/${Code}/'>${Activities}</a>
   9:             </b>
  10:         </div>
  11:         {{html ShortDescription}}<br>
  12:         <b>Duration:</b> ${Duration}<br>
  13:         <b>Code:</b> ${Code}<br>
  14:         <b>Level:</b> ${Level} <br>
  15:         <b>Activity Types:</b> ${Types}<br>
  16:         <b>Activity Level:</b> ${Level}<br><b>Price:</b> $<br>
  17:     </div>
  18: </li>
 

I’m going to move the styles to a CSS file, but you get the idea. This HTML is sitting in a content folder off the root of the website, and the name of the file is ActivityItem.htm.

Notice that the placeholders are designated as ${fieldName}, and if I want to encode the HTML, I could use the placeholder {{html fieldName}}.

I then render the HTML in the JavaScript tag. The JavaScript tag has an id that will referred to by jQuery Template plugin and also uses the specific type “html/text” so it does not force a syntax check from the JavaScript engine or display it prematurely in the browser.

   1: <script id="activityItemsTemplate" type="text/html">
   2:     <%= Html.RenderPath("Controls/activityItem.html") %>
   3: </script>

 

The only thing the RenderPath HTMLhelper does is get the HTML content from cache, and if it is not there; it reads the content from the HTML file, and adds back to cache, and renders it. The caching is nothing fancy. Its just the common caching technique used forever it seems like.

When the HTML Helper renders the content from cache the the JavaScript tag looks like this.

   1: <script id="activityItemsTemplate" type="text/html">
   1:  
   2:     <li>
   3:     <div style='float: left;'>
   4:         <img style='border: 0px none; width: 200px;' alt='${Name}' src='${TopImagePath}'>
   5:     </div>
   6:     <div style='margin-left: 210px;'>
   7:         <div style='padding: 5px;'>
   8:             <b>
   9:                 <a href='/Activities/Activity/Detail/${Code}/'>${Activities}</a>
  10:             </b>
  11:         </div>
  12:         {{html ShortDescription}}<br>
  13:         <b>Duration:</b> ${Duration}<br>
  14:         <b>Code:</b> ${Code}<br>
  15:         <b>Level:</b> ${Level} <br>
  16:         <b>Activity Types:</b> ${Types}<br>
  17:         <b>Activity Level:</b> ${Level}<br><b>Price:</b> $<br>
  18:     </div>
  19: </li>
</script>

 

Now all I have to do is make an AJAX call to get the JSON collection object and map it to the template.

   1: $.getJSON(url, { Prices: prices, Levels: levels, Experiences: experiences, currentPage: currentPage, pageSize: pageSize }, function (data) {
   2:  
   3:     var list = data.ActivityList;
   4:     
   5:     var markup = $("#activityItemsTemplate").html();
   6:  
   7:     $.template("activityItemsTemplate", markup);
   8:     $.tmpl("activityItemsTemplate", list).appendTo("#activityItemsContainer");
   9:     }
  10: });

 

The Container is just the ID of the UL tag.

   1: <ul id="activityItemsContainer">       
   2: </ul>
Hope that helps
Apr
3
2010

JQuery, Asp.Net MVC 2 Multi Project Areas and Other News Minutia

jQuery News

I know this nugget is a couple of weeks old now, but did anyone catch the news that Microsoft is throwing its support behind jQuery?

So it seems that if you have been using the Microsoft AJAX tools you are probably not going to be seeing much of an effort to improve those tools in the future. Not that it really matters, since it seems that most developers have abandon that toolset about a year ago, and with the emergance of MVC, they were becoming irrelevant anyway. Also, the earlier versions of the Microsoft AJax framework had performance problems under heavy load and although they have done a lot of work to make improvements, jQuery is still far and away much faster. Plus, when working with designers who are not Microsoft centric, jQuery built a bridge for the developer and designer to work together.

I have several examples on jQuery Ajax calls in case you are interested.

My first official large site using ASP.Net MVC 2

So this past month I started working on my first large MVC web application using MVC 2, and although I have been playing around with for more than a year now, I have learned a lot in the few months. The book that was really helpful was “Pro ASP.Net MVC” Framework by Steven Sanderson. I highly recommend it if you are getting started, but you might want to wait until the MVC 2 revision comes out. If you can't wait for the revision there is the eBook "Asp.Net MVC 2 In Action." This book is good in that it covers some more advanced topics like how to keep you controllers light. I think the two books together will get you well on the way to developing in ASP.Net MVC.

So far the only hang up I had was that I had set up my solution to incorporate multi project areas which was supported in the MVC 2 preview releases of Areas. However, when the RTM came out it was no longer supported. I searched and searched for solutions to my dilemma, but the only thing I could find was post by Jonathon who basically had the same experience I had, and a reference to an obscure message on a message board saying (by what appeared to be some one from the ASP Team) that it was not supported. To date, I haven't found any more formal post or article saying that was not the case.

I looked at trying the MvcContrib’s portable area alternative, and it’s a pretty nice approach, but I would like my views deployed to production as separate files and not as a resource file in a assembly, so I decided not go that route. I think for now, I am just going to include the areas in a single project and when the next version of MVC comes out—pull the different areas out into different projects then—if that is, they will have that feature in future releases.

TFS license for VS 2008

I heard this week, not from someone official, that once Visual Studio 2010 is released, they will also include Team Foundation Server for Visual Studio 2008 as a part of the MSDN license. That good news for me as I have been using the trial version for the past few weeks. I suppose the cool tool now is GIT so maybe I should take a look at that as well. At least for my VS 2010 stuff. My only thing is I am getting kind of tired of having to learn a new source control repository every year, there are other cooler things I could be learning, but I guess that is part of the job.

Mar
14
2010

MVC 2 Strongly Typed HTML Helper and Enhanced Validation Sample

In lue of the off the official release of ASP.NET MVC 2 RTM, I decided I would put together a quick sample of the enhanced HTML.Helpers and validation controls.

I am going to use my sample event site where I will have a form so a user can search for information about a certain events. So when the Search page loads the Search action is fired return my strongly typed model. to the view.

   1: [HttpGet]
   2: public ViewResult Search(): public ViewResult Search()
   3: {
   4:     IList<EventsModel> result = _eventsService.GetEventList();
   5:     var viewModel = new EventSearchModel
   6:                         {
   7:                             EventList = new SelectList(result, "EventCode","EventName","Select Event")
   8:                         };
   9:     return View(viewModel);
  10: }

Nothing special here, although I did want to show how to load up a strongly typed drop down list because that hung me up for a little bit. So to that, I am going to pass back a SelectList to the view and my HTML helper should no how to load this.

So lets take a look at the mark up for the view.

   1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
   2: Inherits="System.Web.Mvc.ViewPage<EventsSample.Models.EventSearchModel>" %>
   3:  
   4: <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
   5:     Search
   6: </asp:Content>
   7:  
   8: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
   9:  
  10:     <h2>Search for Events</h2>
  11:  
  12:     <% using (Html.BeginForm("Search","Events")) {%>
  13:         <%= Html.ValidationSummary(true) %>
  14:         
  15:         <fieldset>
  16:             <legend>Fields</legend>
  17:             
  18:             <div class="editor-label">
  19:                 <%= Html.LabelFor(model => model.EventNumber) %>
  20:             </div>
  21:             <div class="editor-field">
  22:                 <%= Html.TextBoxFor(model => model.EventNumber) %>
  23:                 <%= Html.ValidationMessageFor(model => model.EventNumber) %>
  24:             </div>
  25:             
  26:             <div class="editor-label">
  27:                 <%= Html.LabelFor(model => model.GuestLastName) %>
  28:             </div>
  29:             <div class="editor-field">
  30:                 <%= Html.TextBoxFor(model => model.GuestLastName) %>
  31:                 <%= Html.ValidationMessageFor(model => model.GuestLastName) %>
  32:             </div>
  33:             
  34:             <div class="editor-label">
  35:                 <%= Html.LabelFor(model => model.EventName) %>
  36:             </div>
  37:             <div class="editor-field">
  38:                 <%= Html.DropDownListFor(model => model.EventName, Model.EventList,"Select Event") %>
  39:                 <%= Html.ValidationMessageFor(model => model.EventName) %>
  40:             </div>
  41:             
  42:             <p>
  43:                 <input type="submit" value="Save" />
  44:             </p>
  45:         </fieldset>
  46:  
  47:     <% } %>
  48:  
  49:     <div>
  50:         <%= Html.ActionLink("Back to List", "Index") %>
  51:     </div>
  52:  
  53: </asp:Content>

 

A nice feature is the scaffolding that MVC has to generate code. I simply right clicked inside my Search() action, inside the EventsController and selected “Add View” and then I selected my strongly typed object that I wanted to pass to the view and also selected that I wanted the content type be “Edit”. With that the aspx page was completely generated, although I did have to go back in and change the textbox for the Event Names to a drop down list of the names to select from.

The new feature with MVC 2 are the strongly typed HTML helpers. So now, my textboxes, drop down list, and validation helpers are all strongly typed to my model.  This features gives you the benefits of intellisense and also makes it easier to debug. “The Gu” has a great post about the feature in case you want more details. The DropDownListFor function to generate the drop down list was a little tricky for me. You first need to use a Lanbda expression to pass in the property you want the selected value assigned to in your model, and then you need to pass in the list directly from the model.

Validations

To validate the form, you can use the strongly type validation HTML helpers which will inspect your model and return errors if the validation fails. The definitions of these rules are set directly on the Model itself so lets take a look.

   1: using System.ComponentModel.DataAnnotations;
   2: using System.Web.Mvc;
   3:  
   4: namespace EventsSample.Models
   5: {
   6:     public class EventSearchModel
   7:     {
   8:         [Required(ErrorMessage = "Please enter the event number.")]
   9:         [RegularExpression(@"\w{6}", 
  10:             ErrorMessage = "The Event Number must be 6 letters and/or numbers.")]
  11:         public string EventNumber { get; set; }
  12:  
  13:         [Required(ErrorMessage = "Please enter the guest's last name.")]
  14:         [RegularExpression(@"^[A-Za-zÀ-ÖØ-öø-ÿ1-9 '\-\.]{1,22}$", 
  15:             ErrorMessage = "The gueest's last name must 1 to 20 characters.")]
  16:         public string GuestLastName { get; set; }
  17:  
  18:         public string EventName { get; set; }
  19:         public SelectList EventList { get; set; }
  20:     }
  21: }

Pretty cool!

Okay, the only thing left to do is perform the validation in the POST action.

   1: [HttpPost]
   2: public ViewResult Search(EventSearchModel eventSearchModel)
   3: {
   4:     if (ModelState.IsValid) return View("SearchResults");
   5:     else
   6:     {
   7:          IList<EventsModel> result = _eventsService.GetEventList();
   8:         eventSearchModel.EventList = new SelectList(result, "EVentCode","EventName");
   9:  
  10:         return View(eventSearchModel);
  11:     }
  12: }
  13:     }

 

If the form entries are valid, here I am simply displaying the SearchResult, but in a real world sample I would also go out get the results first. You get the idea though. In my case, when the form is not valid, I also had to reload my SelectList with the event names before I loaded the page again. Remember this is MVC, no _VieState here :)

So that’s it. Now my form is validating the data and when it fails it looks like this.

response

Mar
11
2010

Filtering Dropdowns in a ASP.Net MVC App using jQuery and jSon.

I have often come across the need to load a dropdown list based on the selection of another drop down list on a form.  In web forms it is really easy, especially if you were just doing a regular page post back.  You simply set the dropdown’s AutoPostBack property to true and then on the change event load the second dropdown based on the value of the first event.

Then along came the Ajax Toolkit that had Ajax server controls that would basically do that for you pretty simply without a full page postback.  You could see a demo of that functionality here.

How to do this with MVC

Now in MVC all the cool server controls are gone but with just a little extra work we can get the same functionality pretty easily.  Moreover, using the Json protocol makes the population of the second drop down much lighter accross the wire.

In my example, I have a pretend scenario where the user selects an event from the first drop down and based on the value of the first selection, the options of the second is dropdown is populated.

Here is the view code I am using for this example. (Note: I am using the Sparks View Engine for the View Framework instead of the Microsoft MVC View Framework because it makes the mark up much cleaner.

   1: <viewdata EventList="SelectList" />
   2:  
   3:  
   4: <content name="head">
   5:     <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min-vsdoc.js" type="text/javascript"></script>
   6:     <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>
   7: </content>
   8:  
   9:  
  10:  
  11:  
  12: #using (Html.BeginForm())
  13: #        {
  14:           
  15:  <div>
  16:             <fieldset>
  17:                 <legend>Event Information</legend>
  18:                 <p>
  19:                     <label for="eventname">Event name:</label>
  20:                     ${Html.DropDownList("eventname", EventList)}
  21:                 </p>
  22:                 <p>
  23:                     <label for="eventdate">Event Date:</label>
  24:                     <select id="eventdate">
  25:                         <option value="">Select Date:</option>
  26:                     </select>
  27:                 </p>
  28:                 <p>
  29:                     <input type="submit" value="See Event Info" />
  30:                 </p>
  31:             </fieldset>
  32:         </div>         
  33:           
  34:           
  35: #}

 

If you are wondering why my second selection list is not generated by the HtmlHelper class it is only because I was not able to append to it using jQuery.  Since it really wasn’t needed anyway I just decided not to bother.

The name of my view is called Events and it resides in my Home controller and the code for populates that view looks like this.

   1: public ActionResult Events()
   2:         {
   3:             IList<EventDto> events = new List<EventDto>();
   4:             const int upper = 5;
   5:             for (int i = 0; i < upper; i++)
   6:             {
   7:                 var eventItem = new EventDto() {EventCode = i.ToString(), Eventname = string.Format("Name {0}", i)};
   8:                 events.Add(eventItem);
   9:             }
  10:  
  11:             var eventList = new SelectList(events, "EventCode", "EventName");
  12:             ViewData["EventList"] = eventList;
  13:             return View();
  14:         }

 

Nothing special here.  I am just creating a list of events and then passing it to a SelectList so it can be populated in the view.

So when the page loads the HTML looks like this:

   1:  
   2:                 <legend>Event Information</legend>
   3:                 <p>
   4:                     <label for="eventname">Event name:</label>
   5:                     <select id="eventname" name="eventname"><option value="0">Name 0</option>
   6: <option value="1">Name 1</option>
   7: <option value="2">Name 2</option>
   8: <option value="3">Name 3</option>
   9: <option value="4">Name 4</option>
  10: </select>
  11:                 </p>
  12:                 <p>
  13:                     <label for="eventdate">Event Date:</label>
  14:                     <select id="eventdate">
  15:                         <option>Select Date:</option>
  16:                     </select>
  17:                 </p>
  18:                 <p>
  19:                     <input value="See Event Info" type="submit">
  20:                 </p>
  21:             

And the page looks like this:

page1

The JsonResult Function

ASP.Net MVC comes with different controller actions, one of them being the JsonResult action.  Like the ActionResult, the JsonResult sends data back to the view but in this case, the response is converted into JSON.

   1: [AcceptVerbs(HttpVerbs.Get)]
   2:         public JsonResult EventDates(string eventCode)
   3:         {
   4:             IList<EventDateDto> eventDates = BuildEventDates(eventCode);
   5:             return Json(eventDates);
   6:         }

In writing the function, first I have to tell it action to respond do.  In this case I want it to respond to “GET” requests, so I need to add the AcceptVerbs attribute to the function with the “GET” verb stated.  The function needs to have the parameter for the event code that the user selected in the dropdown, and then based on the parameter the application gets a list of dates.  These collection dates (are formatted as strings in this case) are then passed back by calling the Json() function.

 

The jQuery function:

So in order to get the data for the second dropdown we need to make an AJAX call to the server and pass it the value of the first dropdown when its “change” event is fired.

When the event is fired, we can then use the jQuery $.AJAX call to make a “GET” request to the URL as such:  …/Home/EventDates?eventCode=3.  When you look at the header of the request you also notice that “Accept” attribute is set to “application/json, text/javascript, */*”.

   1: <script type="text/javascript" charset="utf-8">
   2:         $(function(){
   3:           $("select#eventname").change(function(){
   4:                 var data = $(this).val();
   5:                 var json = {eventCode: data};
   6:                 
   7:                 
   8:                 $.ajax({
   9:                   type: "GET",
  10:                   url: "/Home/EventDates",
  11:                   data: json,
  12:                   dataType: "json",
  13:                   error: function(xhr, status, error) {
  14:                     alert("error routine");
  15:                   },
  16:                   success: function(res){
  17:                     var $dropdown = $("select#eventdate");
  18:                     $dropdown.find('option').remove().end();
  19:                     $dropdown.append('<option value="">Select Date</option>');
  20:                     for (var i = 0; i < res.length; i++) {
  21:                         $("select#eventdate").append('<option value="' + res[i].EventDateName + '">' + res[i].EventDateName + '</option>');
  22:                       }
  23:                       
  24:                   }
  25:                 });
  26:           });
  27:         })
  28:         </script>

Notice that the data we are passing must in the request must be in a jSon format.  So in the case the data we are passing is {eventCode:3}.  The response we get back is:

[{"EventDateCode":"10/27/2009","EventDateName":"10/27/2009"},{"EventDateCode":"10/30/2009","EventDateName":"10/30/2009"},
{"EventDateCode":"11/2/2009","EventDateName":"11/2/2009"},{"EventDateCode":"11/5/2009","EventDateName":"11/5/2009"},
{"EventDateCode":"11/8/2009","EventDateName":"11/8/2009"},{"EventDateCode":"11/11/2009","EventDateName":"11/11/2009"},
{"EventDateCode":"11/14/2009","EventDateName":"11/14/2009"},{"EventDateCode":"11/17/2009","EventDateName":"11/17/2009"},
{"EventDateCode":"11/20/2009","EventDateName":"11/20/2009"}]

 

If the response is successful, the callback function takes the collection that is returned and build a string of <option> tags and append it to the select object.

page1after

Update:

In the MVC 2 version the JsonResult response will by default throw an exception. This is because of a subtle vulnerability in which someone could gain access to sensitive information. You can get the details from Phil Haack's post. So the moral of the story is if you passing sensitive imformation in the response, it is probably better for you to make a POST rather than doing GET like I did in this example. If you are not passing sensitive information and you still would to use a GET request then you will need to change the JSon method from:

return JSon(eventDates);

to

return JSon(eventDates, JSonRequestBehavior.AllowGet);

Feb
13
2010

Spark View Engine – Render Partial While Passing the Model

Just a quick follow up on my previous post specifically about rendering partial views using the Spark View Engine.  If you want to use a partial view and you also want to pass it a model, you just create parameter and pass the model in that parameter.

 

As I stated, the convention for the shared content is to create a file in the “Shared” view directory and prefix the file with the “_”.

 

For example:

I have created a post list partial file and I am going to call it from my “Index” view in the “Home” folder.

renderpartialsamp1

 

In the HomeController class, the Index action is just returning 10 items in a IList collection.

 

   1: public ActionResult Index()
   2: {
   3:     IList<PostDto> items = _postService.GetMostRecentPosts();
   4:  
   5:     ViewData["BasicPosts"] = items;
   6:     return View();
   7: }

Next, my Index view passes the collection of posts to the partial control.  The Index.spark file has the following code.

   1: <viewdata BasicPosts="IList<PostDto>">
   2:  
   3:  
   4: <postList posts="BasicPosts" />

 

 

Now the model is in the partial file and I can do with it what ever I want. In this example, the _postList.spark file has the following code that loops through the collection of posts and displays the “Title”.

   1: <ul>
   2: <for each="var post in posts">
   3:     <li>${post.Title}</li>
   4: </for>
   5: </ul>

 

 

The above sample produces this partial view.

partialResult

Dec
27
2009

Building an List of Links Asynchronously Using jQuery, AJAX, PURE, and Spark View Engine for MVC

Yes, I know the title is a mouthful, but its all the cool stuff I used to make this trick work.  I have mentioned before that I have been using the Spark View Engine with ASP.Net MVC just because I think it is much cleaner markup when it comes to intermingling HTML with C#.  I also mentioned that I have been working on my blog app and like my own home blog page, I want to have a blog roll.  So what I did was create a table with two records containing information about my two favorite blogs.

blog_table

Now what I want to do is on the Master Page that I am using is have to these two links display on the page asynchronously after the base HTML loads.

The Spark Master Page and Partial Rendering

There is pretty good documentation for Spark for getting started, so I won’t go into detail about it here; but there are a few things I wanted to mention.  The default way to use a Master Page in the Spark View Engine is to create a folder named “Layouts” inside the “View” folder and then to add a file named “Application.spark” in that folder.  This is the convention that will allow all other views to access that Master Page unless otherwise specified.

   1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   2: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   3:   <head>
   4:     <title>${H(Title)}</title>
   5:     <link rel="stylesheet" href="~/Content/Site.css" type="text/css" />
   6:     <use content="head"/>
   7:      <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min-vsdoc.js" type="text/javascript"></script>
   8:     <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>
   9:     <script src="/Scripts/pure.js" type="text/javascript"></script>
  10:   </head>
  11:   <body>
  12:     <div id="wrapper">
  13:         <div id="header">
  14:             <div id="logo">
  15:                 <h1>Website Logo Goes Here</h1>
  16:             </div>
  17:             <div id="search">
  18:                 Search goes here
  19:             </div>
  20:         </div>
  21:         <div id="header_menu">
  22:             <ul id="menu">
  23:                 <li>
  24:                     <a title="" accesskey="1" href="#">Home</a>
  25:                 </li>
  26:                 <li>
  27:                     <span>|</span>
  28:                 </li>
  29:                 <li>
  30:                     <a title="" accesskey="2" href="#">Blog</a>
  31:                 </li>
  32:                 <li>
  33:                     <span>|</span>
  34:                 </li>
  35:                 <li>
  36:                     <a title="" accesskey="3" href="#">About Me</a>
  37:                 </li>
  38:                 <li>
  39:                     <span>|</span>
  40:                 </li>
  41:                 <li>
  42:                     <a title="" accesskey="4" href="#">Contact</a>
  43:                 </li>
  44:             </ul>
  45:             <div id="menu_spacer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  46:             </div>
  47:         </div>
  48:         <div id="content">
  49:             <div id="colOne">
  50:                 <div class="box">
  51:                      
  52:                     <myLinks />
  53:                 </div>
  54:             </div>
  55:             <div id="colTwo">
  56:                 <use content="view"/>
  57:             </div>
  58:         </div>
  59:         
  60:     
  61:   </body>
  62: </html>

Some things to notice on the master page here, is that I am accessing jQuery, and PURE.  Of course, jQuery is the JavaScript framework that makes almost everything JavaScript related really easy.  The other script tag for PURE is also a JavaScript framework but it is mainly to make the mapping of markup to your JSON response much easier.  We use it a lot where I work, so I have become a big fan of it.  I will demonstrate that later.

Also another thing to notice in this code is the tag <myLinks />.  This is how Spark does partial HTML rendering.  The convention for partial rendering in Spark is to create a file in the “Views/Shared” folder that is prefixed with “_” and has the extension “spark” like all the other views.  So for my example above, I have a file located at “<project_location>/View/Shared/_myLinks.spark”.

 

 

 

 

 

 

 

 

 

The Controller Class

Nothing special here. I have a controller class that returns a JSON response.  The only thing I should mention though is in order for PURE to work with a list of records you will need to rap your List object in another object.  Also, as mentioned in a previous post, I need to return a JsonResult to get the properly formatted response.  Since these links won’t change much (I am not that fickle) I am caching this action using the OutputCache attribute.

   1: using System.Collections.Generic;
   2: using System.Web.Mvc;
   3: using Aviblog.Core.Dto;
   4: using Aviblog.Core.Services;
   5:  
   6: namespace Aviblog.Web.Controllers
   7: {
   8:     public class LinksController : Controller
   9:     {
  10:         private readonly ILinksService _linksService;
  11:  
  12:         public LinksController(ILinksService linksService)
  13:         {
  14:             _linksService = linksService;
  15:         }
  16:  
  17:         [AcceptVerbs(HttpVerbs.Get)]
  18:         [OutputCache(Duration = 60, VaryByParam = "None")]
  19:         public JsonResult All()
  20:         {
  21:             Links links;
  22:             IList<LinkDto> result = _linksService.GetActiveLinks();
  23:             links = result != null ? new Links() {LinkList = result} : null;
  24:             return Json(links);
  25:         }
  26:     }
  27: }

My Links class looks like this:

   1: using System.Collections.Generic;
   2:  
   3: namespace Aviblog.Core.Dto
   4: {
   5:     public class Links
   6:     {
   7:         public IList<LinkDto> LinkList { get; set; }
   8:     }
   9: }

This will generate a JSON response as follows:

{"LinkList":
[{"LinkId":1,"Title":"Scott Gunthie","Description":"Scott Gunthrie\u0027s Blog","BlogUri":http://weblogs.asp.net/scuttgu/,
"FeedUri":null,"IsActive":true},{"LinkId":2,"Title":"Scott Hanselman",
"Description":"Scott Hanselman\u0027s Blog","BlogUri":"http://www.hansleman.com/","FeedUri":null,"IsActive":true}]}

Notice, that I now have my wrapper class called LinkList that I can use to tell PURE that this is my collection.

 

The Partial HTML that Loads the Links

So in my _myLinks.spark file I have the JavaScript that is going to make an AJAX call to get the links, and the PURE code that will map the response back to the unordered list.

   1: <script type="text/javascript">
   1:  
   2:     $(document).ready(function() {
   3:         $.ajax({
   4:             type: "GET",
   5:             url: "/Links/All",
   6:             dataType: "json",
   7:             success: function(res) {
   8:                 var $blogRollList = $("ul#blogRollList");
   9:                 
  10:                 var directive = {
  11:                     'li':{
  12:                         'link<-LinkList':{
  13:                             'a':'link.Title',
  14:                             'a@href':'link.BlogUri'
  15:                         }
  16:                     }
  17:                 };
  18:                 
  19:                  $blogRollList.render(res, directive);
  20:  
  21:             }
  22:         });
  23:     });
</script>
   2:  
   3:         
   4: <h3>Bloggroll</h3>
   5: <div id="blogRoll">
   6:     <ul id="blogRollList">
   7:         <li><a></a></li>
   8:     </ul>
   9: </div>

I am using the $.Ajax function to make a call out to my controller class “LinksController” and the action “All”.  If the code returns a successful response, the PURE code maps the response to the list.

The $blogRollList variable is the ul tag that I want my response to be loaded into.

The directive variable is how I tell PURE to map my response.  It is saying for each item in the response, create a list tag.  The “link<-LinkList” is saying for the collection LinkList there will be items named “link”.  Inside that declaration I am then using each “link” item that was defined and them mapping it to an anchor tag.

 

 

 

The Result

So now when the page loads I get the result:

blogroll

Dec
15
2009

Syndicating RSS in an ASP.Net MVC app using WCF

About a month back Rob Conery mentioned that he was going to create a blogging application using MVC, which caused me to think to myself: “SELF! why don’t you try something like that and see what you can come up with?”  So in my spare time when I am not doing real work or at home shuttling kids around, I’ve been playing around with this idea.  I am really happy with my BlogEngine.Net set up and probably will continue to use it even if I were to finish this app but I figure this would be an opportunity to just do something different than I have been doing lately and learn some new things that I have not had a chance to work with as of yet.

So with that in mind, one of the first things I decided to tackle was going about syndicating an RSS feed and as it turns out it is not too terribly difficult to do; although, there are some things I did struggle with—uhhh---but I am getting ahead of myself.

 

Build you own ActionResult

I mention in my previous post that ASP.Net come with several different controller actions, and the one that I used in the that example was the JsonResult.  Well JsonResult really is just a class that is derived from the abstract class ActionResult.  I can write my own class that derives from ActionResult to return back to the view an RSS feed which is what I am going to do in this example.

 

   1: using System.ServiceModel.Syndication;
   2: using System.Web.Mvc;
   3: using System.Xml;
   4:  
   5: namespace Aviblog.Core.ActionResults
   6: {
   7:     public class RssResult : ActionResult
   8:     {
   9:         private readonly SyndicationFeed _feed;
  10:  
  11:         public RssResult(SyndicationFeed feed)
  12:         {
  13:             _feed = feed;
  14:         }
  15:  
  16:         public override void ExecuteResult(ControllerContext context)
  17:         {
  18:             context.HttpContext.Response.ContentType = "application/rss+xml";
  19:             var formatter = new Rss20FeedFormatter(_feed);
  20:  
  21:             using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
  22:                 if (writer != null) formatter.WriteTo(writer);
  23:         }
  24:     }
  25: }

So in my custom RssResult that inherits from ActionResult, I need to then override the ExecuteResult method.  Inside that method I then need to set the response type to “application/rss+xml” so it can be rendered as RSS.  The next thing to notice is that in my constructor I am passing in an object of type SyndicationFeed which is a part of WCF.  It is in the System.ServiceModel.Syndication namespace.  You can find it by referencing the System.ServiceModel.Web assembly.  I can then use the Rss20FeedFormatter to generate XML which is RSS compliant.

Building the SyndicationFeed

Building the SyndicationFeed object is where I had the most trouble. If you just want a simple compliant RSS feed, this guy works great; however, as you can see just from looking at my own RSS feed there many other elements you can extend to an RSS feed and adding those to the SyndicationFeed element is a bit tricky.

   1: public SyndicationFeed Buildfeed()
   2:         {
   3:             var settingQry = _settingsRepository.GetSettings();
   4:             const string nameKey = "name";
   5:             const string nameDescription = "description";
   6:             const string link = "link";
   7:             string blogTitle = _settingsService.GetValue(settingQry, nameKey);
   8:             string blogDescription = _settingsService.GetValue(settingQry, nameDescription);
   9:             Uri blogUrl = _settingsService.GetUri(settingQry, link);
  10:  
  11:             var feed = new SyndicationFeed(blogTitle, blogDescription, blogUrl);
  12:  
  13:             foreach (var element in _feedRepository.GetFeedElements())
  14:                 feed.ElementExtensions.Add(BuildXmlElement(element));
  15:  
  16:             feed.Items = LoadPosts(_postService.GetMostRecentPosts());
  17:             return feed;
  18:         }
  19:  
  20:         private static XmlElement BuildXmlElement(FeedElementDto element)
  21:         {
  22:             var doc = new XmlDocument();
  23:             XmlElement feedElement = doc.CreateElement(element.Prefix, element.Element, element.Namespace);
  24:             feedElement.InnerText = element.InnerText;
  25:             return feedElement;
  26:         }

 

From the code you can see that when I am instantiating the SyndicationFeed object I am passing in the title of the blog, the blog description, and the URL.  Where it got a bit hairy, was adding other elements that prefixed a common namespace.  I could add the namespace for each element (as seen in the code) but there does not seem to be a way to put the common namespaces in say the channel element and then just use the prefix to those namespaces later. I ended up having to repeat the same namespaces over again.  But that being said, it is still pretty easy to build the feed.

Once the feed object is ready I then could add each of the posts by mapping them to a SyndicationItem object and then add those collection of objects to the items collection in the feed.

   1: private static IEnumerable<SyndicationItem> LoadPosts(IEnumerable<PostDto> posts)
   2:         {
   3:             IList<SyndicationItem> items = new List<SyndicationItem>();
   4:             foreach (var post in posts)
   5:             {
   6:                 var item = new SyndicationItem();
   7:                 item.Title = new TextSyndicationContent(post.Title);
   8:                 item.Authors.Add(new SyndicationPerson(post.Author));
   9:                 item.Content = SyndicationContent.CreateHtmlContent(post.PostContent);
  10:                 items.Add(item);
  11:             }
  12:             return items;
  13:         }

 

 

 

The Controller Class

Now that I have my RssResult and my functionality to build the SyndicationFeed object, I can then create an action inside my controller class that puts the two together.

   1: public class SyndicationController : Controller
   2:     {
   3:         private readonly IRss20SyndicationService _rss20SyndicationService;
   4:  
   5:         public SyndicationController(IRss20SyndicationService rss20SyndicationService)
   6:         {
   7:             _rss20SyndicationService = rss20SyndicationService;
   8:         }
   9:  
  10:         public RssResult Rss()
  11:         {
  12:  
  13:             return new RssResult(_rss20SyndicationService.Buildfeed());
  14:         }
  15:     }

 

 

The Result

So when I browse to domain/controller/action in this case http://localhost:64533/Syndication/Rss I get the following RSS sample:

 

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
   3:   <channel>
   4:     <title>Steve Moseley</title>
   5:     <link>http://www.test.com/</link>
   6:     <description>Trying my best to apprehend all these dev changes.</description>
   7:     <blogChannel:blogRoll xmlns:blogChannel="http://backend.userland.com/blogChannelModule">http://www.avingtonsolutions.com/blog/opml.axd</blogChannel:blogRoll>
   8:     <blogChannel:blink xmlns:blogChannel="http://backend.userland.com/blogChannelModule">http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
   9:     <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Steve Moseley</dc:creator>
  10:     <dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Steve Moseley</dc:title>
  11:     <geo:lat xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">0.000000</geo:lat>
  12:     <geo:long xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">0.000000</geo:long>
  13:     <item>
  14:       <author>Steve</author>
  15:       <title />
  16:       <description>
  17:        blah, blah, blah
  18:       </description>
  19:     </item>
  20:   </channel>
  21: </rss>

 

Looks pretty good, although, if you look at my actual RSS feed and this one, you will notice that the name spaces are repeated verses being listed at the top as they probably should be.  I need to play around with it some more but this gets the job done and I did not have to write all that much code, which is nice.