Making web service calls with JQuery

Posted by Jack Altiere on April 5th, 2010

JQuery is an amazing Javascript library.   If you haven’t used it yet, you are REALLY missing out.  This article is going to talk about how you can use JQuery to make an AJAX call from an MVC application, and how you can receive JSON rather than XML from the web service.

First we’ll deal with the why.  Why would we want to receive JSON rather than XML to our web service?  To me, the answer to that starts with the fact that if we’re making an AJAX call, we’re going to do something with the results in client code.  It makes sense to use a format that is inherently understood by Javascript, which is what the client code is going to be written in most of the time.  The fact that we can send JSON data to our .NET web service allows us to pass objects back and forth from .NET and Javascript easily.

Our use case is going to be relatively simple, I want to be able to add a user to our database from an HTML form, and update the user interface when the task is done asynchronously.  I have a sample database with a very simple user table set up for this example.  I created a .dbml file with LINQ to SQL for my data layer:

data 

I created an index view for my form, the code looks like this:

<fieldset>
    <legend>Enter User Information</legend>

    <p>
    <label for="FirstName">First Name</label>
    <input type="text" id="FirstName" />
    </p>

    <p>
    <label for="LastName">Last Name</label>
    <input type="text" id="LastName" />
    </p>

    <p>
    <label for="Email">Email</label>
    <input type="text" id="Email" />
    </p>

    <p>
    <label for="Phone">Phone</label>
    <input type="text" id="Phone" />
    </p>

</fieldset>

<br />

<div class="buttons">
    <button type="submit" class="positive" name="save" id="btnSave">
        <img src='<%= Url.Content("~/Content/Images/apply.png") %>' alt=""/>
        Save
    </button>
</div> 

<br /><br />
<div id="result"></div>

The div at the bottom is where I plan to show if my service call was successful or not.  One thing I did here was use a tip I picked up by Dave Ward at Encosia.com and make the ID’s of my inputs match the property names on my user object.  This makes life easier on us later.  Then, to fix up the look and feel of the site a little, I just add a little CSS:

fieldset {
    border: 1px solid #226078;
    background: #62B1D0;
    width: 320px;
    padding: 2px;
}
fieldset legend {
    border: 1px solid #226078;
    font-family: Tahoma;
    font-size: 9pt;
    font-weight: bold;
    background: #0776A0;
    color: #FF8500;
    padding: 6px;
}

label {
    display: block;
    float: left;
    font-family: Tahoma;
    font-size: 8pt;
    font-weight: bold;
    color: #024C68;
    width: 150px;
}

label:after { content: ": " }


This makes my end UI look (slightly) more presentable.  I know, you envy my crazy user interface skills.

interface

The next thing to do is set up the JQuery code so that our button click even sends an asynchronous request to the web service.

<script language="javascript" type="text/javascript">
    $(document).ready(function() {
        $("#btnSave").click(function(event) {
            var user = {};

            // Use JQuery to iterate over the text fields and build the object.
            $(':text').each(function() {
                user[this.id] = this.value;
            });

            // Create a data transfer object (DTO) with the proper structure.
            var DTO = { 'user': user };

            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "DataService.asmx/AddUser",
                data: JSON.stringify(DTO),
                dataType: "json",
                success: function(result) {
                    if (result.d)
                        $("#result").html("<span style='color:#529214'>User added successfully.</span>");
                    else {
                        $("#result").html("<span style='color:#d12f19'>Operation failed.</span>");
                    }
                }
            });
        });
    });
</script>


In the above code, you will see why we named the textboxes the same as the user object properties.  I used the JQuery each construct to loop through all the text boxes and populate the user object.  This is a much cleaner way to populate the object than manually setting every property.  The ajax call is pretty straight forward, I’m using the stringify method in the json2js library to turn my string into valid JSON, and lastly I’m wrapping my user object in a data transfer object to make the client code a little cleaner.  (another tip from Dave Ward)  On success of the asynchronous call, I’m parsing the result to determine whether the user was added successfully or not. 

Since I used LINQ to SQL to generate my objects, I decided to make it easy on myself by adding the “add user” logic in a partial user class.

public partial class User
{
    public void Add()
    {
        var db = new BlogSamplesDataContext();
        db.Users.InsertOnSubmit(this);
        db.SubmitChanges();
    }
}

The last step is to create a web service called DataService.asmx with a web method called AddUser that takes a parameter called user.

[System.Web.Script.Services.ScriptService]
public class DataService : WebService
{
    [WebMethod]
    public bool AddUser(User user)
    {
        try
        {
            user.Add();
        }
        catch (Exception ex)
        {
            // Error logging can happen here.
            return false;
        }

        return true;
    }
}


Make sure you uncomment the line in the web service that allows the service to be called from scripts..for whatever reason I forget to do that a lot.

I was trying to walk the line between “simple enough to get my point across” and “complex enough to show value” for this example.   The key is that you can pass full objects from client code to .NET web service code with the use of JSON, and you can make asynchronous calls to web methods fairly easily using JQuery.

kick it on DotNetKicks.com

Parsing POP email messages

Posted by Jack Altiere on March 29th, 2010

I was recently tasked with coming up with a way to parse a pop email account and automatically save off the message and any attachments that came in the email.  While it didn’t sound like too bad of a task, I know from my limited experience that parsing MIME content can be a pain in the rear.  I thought it would be interesting to share what I came up with in a sample application.

First, I knew that I had no desire to reinvent the wheel and write my own MIME parser if I could find one that works.  After some searching and some trial and error I ended up finding a .NET library that seems to work great from here.  The full version of this library isn’t free, but the trial version is fully functional, it just rewrites the email subjects once in a while to tell you to buy the full version.  (as a side note, I will probably end up buying this product, it worked exactly like I wanted it to) 

Since I felt like showing this would go better if I had a sample app, I decided to write a little one page website that takes emails from an approved list of addresses, and posts any photo attachments in a little photo album.  I decided I wanted a SQL Server backend, and that I would just use LINQ to SQL for data access.  The plan is to just take the body of the email and make it the image caption and attach 1 image per email.   It would also be nice to resize the image if it’s too big.

First, the backend.  For the sake of simplicity I just created 2 tables…one to handle user validation and one to store the photos.  After creating the LINQ to SQL classes for these two tables, my .dbml design view looked like this:

dblayout

After that, I wanted to set up my mail parsing library.  Like I mentioned above, I just wrapped a 3rd party utility, so my code for this isn’t too complex.

public class MailParser
{
    private readonly string _popServer;
    private readonly string _username;
    private readonly string _password;
    private readonly IMessageProcessor _messageProcessor;

    public MailParser(IMessageProcessor messageProcessor)
    {
        _popServer = ConfigurationParser.GetAppSettingString("MailServer");
        _username = ConfigurationParser.GetAppSettingString("MailUserName");
        _password = ConfigurationParser.GetAppSettingString("MailPassword");
        _messageProcessor = messageProcessor;
    }

    public void ProcessMessages()
    {
        var messages = new List<IMail>();

        using (var pop3 = new Pop3())
        {
            pop3.Connect(_popServer);
            pop3.Login(_username, _password);

            foreach (var uid in pop3.GetAll())
            {
                // Add the email message to the list to be processed.
                var message = new MailBuilder().CreateFromEml(pop3.GetMessageByUID(uid));
                messages.Add(message);

                // Delete the message from the server.
                pop3.DeleteMessageByUID(uid);
            }
            pop3.Close(true);

            // We have snagged all of the messages from the server, now process them.
            foreach (var message in messages)
            {
                _messageProcessor.ProcessMessage(message);
            }
        }
    }

}

public interface IMessageProcessor
{
    void ProcessMessage(IMail message);
}

public class MessageProcessor : IMessageProcessor
{
    private readonly PhotoDBDataContext _db = new PhotoDBDataContext();

    public void ProcessMessage(IMail message)
    {
        var fromAddresses = message.From;
        var body = message.HtmlData ?? message.TextData;

        if (fromAddresses.Count == 0)
            return;

        // I only want to process emails from a list of valid email addresses.
        var address = (fromAddresses[0].Address.IsNullOrEmpty()) ? string.Empty : fromAddresses[0].Address;
        var user = ValidateUser(address);
        if (user == null)
            return;

        // If there are no attachments ignore the message.
        if (message.Attachments.Count == 0)
            return;

        // Process the attachments. (only supporting 1 attachment per email)
        var counter = 0;
        foreach (var att in message.Attachments)
        {
            if (counter > 0)
                break;

            // Make sure that the attachment is a valid image.
            if (!att.ContentType.MimeType.ToString().ToLower().Equals("image"))
                return;

            var photo = new Photo
                            {
                                Caption = body.Text,
                                DateUploaded = DateTime.Now,
                                UserID = user.UserID,
                                ImageData = att.Data,
                                ContentType = att.ContentType.ToString(),
                                FileName = att.FileName
                            };

            _db.Photos.InsertOnSubmit(photo);
            _db.SubmitChanges();

            counter ++;
        }
    }

    private User ValidateUser(string email)
    {
        var query = from u in _db.Users
                    where u.EmailAddress.Equals(email)
                    select u;

        return query.FirstOrDefault();
    }

}

The code should be fairly straight forward.  I created a message processing interface, because it is conceivable that I would want to reuse this and processes messages differently.  You may notice the ConfigurationParser references, that is just a class I wrote to wrap the access of configuration variables allowing me to load them strongly typed.   All I am doing is looping over the messages on the POP server, loading them into a list to process, and deleting the original message from the server.  I’ll throw out the standard disclaimer here and say that this is an example application!  I would definitely consider persisting messages into some sort of a queue to process before deleting them from the mail server if this were a production application.

Using LINQ to SQL it’s a snap to validate the user and make sure we’re only posting pictures from trusted email addresses. (I know, we would have to think about how to protect this against spoofing if this were a real app)  Notice how I’m also using the MIME type to make sure that we only accept image attachments.  Lastly, I’m only processing the first attachment to make sure to only accept one image per email, I did this because I’m using the message body as the caption of the photo.

Now that images are being scraped from the email account and stored in the database, I thought I’d close the loop on this sample application and put a quick web page up to display the album.   I created a new ASP.NET MVC 2 web application, and then went through the same steps as above to create my LINQ to SQL classes.  The first thing I wanted to do was create a strongly typed view.  The way I do this is to right-click in the HomeController.cs file and select Add View.   You will get a dialog like this one:

strongtypedview

All I did was name the view, select my LINQ to SQL generated Photo class, and choose List as the View content.  This basically says that the view will have access to a collection of photos.  It’s trivial to pull the list of photos out of the database with LINQ:

public ActionResult Index()
{
    var db = new PhotoDBDataContext();
    var photos = (from p in db.Photos
                  select p).ToList();

    ViewData.Model = photos;
    return View();
}

I wanted to do is to display an image straight from an MVC controller.  I’m not going to post all the code I used to accomplish this, but the short version: I modified a guide I found here.  One requirement that I still haven’t addressed is that I never resized the images.  Since I took the images straight from the POP account and put them in the database, I have no idea how big they really are.  Rather than go way off track and figure out how to do this, I used a method I read about here to resize my images from a byte array if needed.  Now I wanted to come up with a clever way to be able to thumbnail images on the fly, so I changed the default route in the global.asax file to look like this:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{photoID}/{thumbnail}", // URL with parameters
        new { controller = "Home", action = "Index", photoID = UrlParameter.Optional, thumbnail = false } // Parameter defaults
    );

}


What this allows me to do is use a URL like mysite.com/Home/Images/1 to show the full image and mysite.com/Home/Images/1/true if I want to show the thumbnail of the same image.  My controller method for the image creation looks like this:

public ActionResult Images(int photoID, bool thumbnail)
{
    var db = new PhotoDBDataContext();
    var photo = (from p in db.Photos
                 where p.PhotoID.Equals(photoID)
                 select p).SingleOrDefault();

    if (photo == null)
        throw new Exception("Photo not loaded");

    var bytes = (thumbnail)
                    ? ResizeFromStream(100, new MemoryStream(photo.ImageData.ToArray()), photo.FileName)
                    : photo.ImageData.ToArray();

    var image = bytes;
    var contentType = photo.ContentType;
    return this.Image(image, contentType);
}

The view ended up being trivial:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<BlogSamples.DisplayPhotos.Photo>>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Photo Album - Jaltiere.Com
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <div id="container">
        <ul>

        <% foreach (var item in Model) { %>

            <li>
            <a href="Home/Images/<%= Html.Encode(item.PhotoID) %>" target="_blank" style="background-image: url('Home/Images/<%= Html.Encode(item.PhotoID) %>/true')">
            <span><%= Html.Encode(item.Caption) %><br /><i>uploaded <%= Html.Encode(item.DateUploaded.ToShortDateString()) %></i></span></a>
            </li>

        <% } %>

        </ul>
    </div>

</asp:Content>

And with a little CSS magic…

body {
    text-align:center;
    font-family: tahoma, arial, sans-serif;
    font-size: 8pt;
}

#container {
    position:relative;
    width:770px;
    height:396px;
    margin:20px auto 0 auto;
    border:1px solid #aaa;
} 

ul {
    padding:0;
    margin:0;
    list-style-type:none;
}

li {
  display: inline;
  float: left;
  width: 101px;
  height: 101px;
  margin: 4px;
}

li a {
  display: block;
  width: 101px;
  height: 101px;
  background-position: center;
  background-repeat: no-repeat;
  text-decoration: none;
}

li { height: 115px; }
li a span {
  font-size: 9px;
  position: relative;
  top: 103px;
  color: #666;
  display: block;
  text-align: center;
}
li a:hover span { color: red; }

You get a functional photo album:

 gallery

This article kind of took off on me and turned out to be more MVC than POP mail parsing, but it was a fun little exercise.  Things to take away:

  1. I recommend the mail parsing library I used, I found it to be intuitive and easy to use.
  2. LINQ to SQL makes data access easy. (coming from a guy with a big stored procedure background)
  3. MVC is much more fun to work with than Webforms in my opinion.
  4. I freely admit that I am definitely not a designer, so my web layout is not very good.

kick it on DotNetKicks.com


Copyright © 2007 Jack Altiere. All rights reserved.