Parsing/Reading a PDF file with C# and Asp.Net to text

PDFs are a very ubiquitous and useful file type, but they can be a pain to work with programatically

PDFs are extensively used in my organization, and people always want programs that will extract information from them. It can be very difficult to get the information they want due to the strange format, but sometimes it's a necessity. Here is how to get a PDF into text, from there you are on your own!

download the necessary files

There are always more than one way to skin a cat when it comes to programming, but the easiest way I have found for PDFs is to use the fantastic, open-source project PDFBox. The download is good for all sorts of platforms, but you only need a few parts to use it with Asp.Net and C#.

*Now keep in mind the version numbers I show here may change, but the process should stay the same.

what you need

  • Just a few things, pull the following files into your bin:
    • FontBox-0.1.0-dev.dll
    • IKVM.GNU.Classpath.dll
    • IKVM.Runtime.dll
    • PDFBox-0.7.3.dll

  • Now just make sure you add a couple references in your project, it is a bit of a strange process, so follow it closely. First, add this reference:
    • IKVM.GNU.Classpath

  • Then build the project, as the next reference requires the previous to be built. So you then add this reference:
    • PDFBox-0.7.3

  • Then build again - once again, there may be a better way to do this, but this is what the documentation said and it worked, so I won't mess with it. Now all you need to do is make sure you add the following using statements to any code file that needs to use the parser:
    using org.pdfbox.pdmodel;
    using org.pdfbox.util;

all set, now use it

This quick snippet shows how to use the program to take in a pdf file and output it to a .txt file.  The inputs are simply the string 'pdf_in' which is the path to a PDF to parse, and the string 'txt_out' which is the path to the output text file. You can easily modify it to take in a Stream of some sort or something else like using a FileUpload or output some other way, but this should get the idea across.
public void parsePDF(string pdf_in, string txt_out)
{
    StreamWriter sw = new StreamWriter(txt_out, false);
    try
    {
        sw.WriteLine();
        sw.WriteLine(DateTime.Now.ToString());
        PDDocument doc = PDDocument.load(pdf_in);
        PDFTextStripper stripper = new PDFTextStripper();
        sw.Write(stripper.getText(doc));
    }
    catch (Exception ex) { Response.Write(ex.Message); }
    finally
    {
        sw.Close();
        sw.Dispose();
    }
}

And there you have it, your PDF is now a (most likely, ugly and difficult to parse) text file with your PDF data in it; now it's up to you to figure out how to use it. As you will see, PDFs can (not always) be very strange in how they come out as text, tables will often be in odd order and such and it is a new adventure each time to engineer an effective and acurate parsing scheme that is very case-specific. Normally I would offer a download, but these files are pretty big, so I will leave it to the guys at SourceForge.

Inserting New Items Into a Table : 'REAL' AJAX with Asp.Net Series

Add a new item into the table and database and have it immediately sortable, pageable, etc without any postback

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

This is probably the hardest part about a full CRUD (Create, Read, Update, Delete) system, but as we have already covered 'RUD', it's time to hit the 'C'. First of all, we have to break down what will be happening, both on the client-side, and the server side, then it will be easier to dissect.
  1. User pulls up a 'New Entry' dialogue (client)
  2. User enters information and it is validated (client*)
  3. Valid information is sent to the server (client)
  4. Server attempts to add in new item (server)
  5. Server spits back status update (server)
  6. status update is displayed (client)
  7. item is added into the visible table (client)
  8. input fields are cleared and the input dialogue is hidden (client)

The * above denotes that while in this example we are doing only client-side validation, it is in your best interest to add in some server side as well (keep in mind that this example will not work without javascript, so it is not robust and does not 'gracefully' degrade).

As you can see, most of the heavy lifting here is done on the client side, with the dedicated server doing just a couple things.

set up the entry dialogue

First I am adding a couple divs which will be clicked to open the dialogue:

insert.aspx

<div class="button triggerNew">New Entry</div>


In the CSS, you can see that these will render like buttons:

demo.css
.button 
{ 
    width: 100px; 
    font-weight: bold; 
    border: outset 2px blue; 
    padding: 1px; 
    text-align: center; 
    color: Blue; 
}
.button:hover 
{ 
    border-style: inset; 
    cursor: pointer; 
    padding: 2px 0 0 2px; 
}

To go with the whole ajax feel, I am setting up the entry in a modal popup; you probably noticed the class 'triggerNew' which isn't really a css class, but it will be used to by jQuery to hook into any elements that have that class and tie them to the modal. To do that first we must include the jquery.jqModal plugin (which IMO is the best modal plugin as it is minimalist and customizable as well as easy to use) in our masterpage.
demo.master

<script type="text/javascript" src="js/jquery.jqModal.js"></script>


As for the modal popup, here is the markup:

<div class="jqmWindow" id="new">
  <h3 class="modal_header">
    <div class="working">working...</div>
    <a href="#" class="x jqmClose">X</a>
    Add New Entry
  </h3>
  <div class="pad">
    <div class="left">
      <h4>
        <asp:RequiredFieldValidator ID="rfvFirst" ControlToValidate="txtFirst" CssClass="right"
          ErrorMessage="required" runat="server" ValidationGroup="new" />
        First Name
      </h4>
      <input type="text" ID="txtFirst" runat="server" />
    </div>
    <div class="left">
      <h4>
        <asp:RequiredFieldValidator ID="rfvLasst" ControlToValidate="txtLast" CssClass="right"
          ErrorMessage="required" runat="server" ValidationGroup="new" />
        Last Name
      </h4>
      <input type="text" ID="txtLast" runat="server" />
    </div>
    <div class="left">
      <h4>
        <asp:RegularExpressionValidator ID="regAge" ControlToValidate="txtAge" CssClass="right"
          ErrorMessage="1-3 digits" runat="server" Display="dynamic" ValidationGroup="new" />
        <asp:RequiredFieldValidator ID="rfvAge" ControlToValidate="txtAge" CssClass="right"
          ErrorMessage="required" runat="server" Display="dynamic" ValidationGroup="new" />
        Age
      </h4>
      <input type="text" ID="txtAge" runat="server" />
    </div>
    <div class="summary">
      <div id="submit" class="button">Submit</div>
    </div>
  </div>
</div>


Now there is a lot going on there. First of all, I used the Asp.Net validators as we are most familiar with them, and they play nicely with jQuery. Also, I am not using asp:TextBoxes at all, I am sticking with the basic input boxes. But, because I am using the Asp.Net Validators, I still need to include runat="server" with each input that I Validate; this also means that they will get weird Asp.Net IDs and not the exact ones I assign them. All I am doing here is making sure all the fields have values, and that age is a diget with 1-3 digits (yes, someone can be 999 in this system...).

In addition, the css class 'jqmClose' class is included in a link: this will automatically be assigned to close the modal window by jqModal.

I also put an additional 'working' element in there so the user can see that dialogue while the program is running its magic.

But as it stands now, we can't even see that popup, get the validators to fire or submit any sort of data. Here comes the jQuery.

work the jQuery magic

Here is the script, it is explained in the comments:
//assign all 'triggerNew' elements to open the modal dialogue
$('#new').jqm({ trigger: false }).jqmAddTrigger($('.triggerNew'));

//attach this event to the clicking of the 'submit' div
$("#submit").click(function() {
    //will not do anything if the validators don't check out
    //Page_ClientValidate('ValidationGroup') is an Asp.Net generated function
    if (!Page_ClientValidate('new')) { return false; }
    else {
        // get the values from the textboxes into an array
        // notice that this is using .ClientID to get the strange Asp.Net ID assigned to it
        var vals = [
            $("#<%= txtFirst.ClientID %>"),
            $("#<%= txtLast.ClientID %>"),
            $("#<%= txtAge.ClientID %>")
        ];
        // do the ajax post
        $.post(
            //function is at
            "ajax_functions/insert.aspx",
            //send the values frorm the vals object
            { first: vals[0].val(), last: vals[1].val(), age: vals[2].val() },
            function(data) {
                //output the return data
                $("#report").html(data);
                // the class 'success' was sent back if it worked...
                var success = (data.toString().substring(12, 19) == "success");
                //add the new data into the table so the user can see it if it was successful
                if (success) {
                    oTable.fnAddData([
                    vals[0].val(),
                    vals[1].val(),
                    vals[2].val(),
                    '&nbsp;'
                ]);
                    //clear the textboxes
                    $(vals).each(function() { $(this).val('') });
                }
                //hide the modal now that it's done
                $('#new').jqmHide();
            }
        );
    }
});

Note that this will not allowed items added since the last postback to be deleted/edited, that is why the last cell simpy gets an '&nbsp;'. Keep in mind that it is possible, just beyond the scope of this tutorial.

Also, in a ghetto form of error reporting, I passed the css class which will either be 'error' on error, or 'success' otherwise.  We can use that to decide whether or not to post the new data into the table and to clear the inputs.  This will catch any errors that we did not already account for.

Really all that remains is the server-side part, we need to make the page that is called: "ajax_functions/insert.aspx" to handle the inputs passed.

server-side functions

Notice this time that we used a $.post() method, which sends the stated values and returns something - in this case, we are having it return a chunk of html which will tell us what happened with the server, and it will be pushed into the 'report' div. Here is our server operations:

ajax_functions/insert.aspx.cs
using System;

public partial class ajax_functions_insert : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        demoDataContext db = new demoDataContext();
        try
        {
            // get all the new values
            string first = Request.Form[0];
            string last = Request.Form[1];
            int age = Convert.ToInt32(Request.Form[2]);

            //make a new person
            person p = new person()
            {
                first_name = first,
                last_name = last,
                age = age
            };

            //insert them into the db
            db.persons.InsertOnSubmit(p);
            db.SubmitChanges();

            //if it was all successful
            Response.Write("<div class='success'>" + first + " " + last + " [" + age + "] inserted</div>");
        }
        // this will catch all the errors and output an error message if caught
        catch (Exception ex) 
        {
            Response.Write("<div class='success'>Error: " + ex.Message +"</div>");
        }
    }
}

As usual, this is the easy part. Now you have a full working CRUD system, with some pretty good error catching as such with absolutely no postbacks! Ajax is fun and can be quite useful, I hope these tutorials helped make it a little more accessible to some Asp.Net devs, I know I learned a lot making them.

« Deleting

Use and Manipulate Asp.Net Validators with jQuery and/or Javascript

Asp.Net has some great validation included - no need to learn new validation, just grab them with client-side scripting

The problem I found when going into jQuery validation, is that they mostly seem to assume that you can have more than one form on your page; which, for us Asp.Net devs, is not the case. After some digging, I figured out how to use the current validators which I am already familiar with (RegularExpressionValidator, RequiredFieldValidator, etc.) and just hook into them with javascript; no need to reinvent the wheel. It is very easy, and we don't lose the server-side validation that is so great with the Asp.Net validators (if you call on it that is).

want to make a certain validator(s) fire?

Let's say I have a RequiredFieldValidator named 'rfvFirst' and I want it to test for validation on the click event of the element with id 'some_link'. With jQuery, this is what I would do:
$("#some_link").click(function() {
    ValidatorValidate($("#<%= rfvFirst.ClientID %>")[0]);
});

Now, the ErrorMessage of 'rfvFirst' will show if it is not valid - it will behave just as if you tried to submit the form, but just for that validator itself. Notice that I am using <%= rfvFirst.ClientID %> which will pull the crazy Asp.Net id that is produced in Asp.net which is often something strange like 'ctl00_ContentPlaceHolder1_rfvFirst'.  Now, if you want to use a class or something else to select the Validators, that is fine too.  This will fire all of the Validators that have the CssClass 'fire':
$(".fire").each(function() {
    ValidatorValidate($(this)[0]);
});

want to have a button/link cause validation and only work if the page is valid?

For this, you need to make sure your validators each have a ValidationGroup set. In this example I am attaching it to a button with id 'submit' and the ValidationGroup 'new'. Simply attach the click event to Page_ClientValidate() method:
$("#submit").click(function() {
    return Page_ClientValidate('new');
});

This was the only method I found that actually returned something that could be used to tell if the page was valid (I am far from a JS pro). There is likely more ways to do this and I am interested in any that people have found!

want to stroll through the validators?

The are all held in an object (array) 'Page_Validators' and you can access it like any other array, looping or whatever. This will look through and output into the 'report' element the ids of all the Validators you have on your page:
for(var i=0,len=Page_Validators.length;i<len;++i){
    $("#report").append($(Page_Validators[i]).attr('id'));
    $("#report").append("<br />");
}

Finding web hosting reviews is the first step when you plan to build a website. It will help you ensure a great looking site.

Deleting Items From a Table : 'REAL' AJAX with Asp.Net Series

Delete an entry from the DB and remove the corresponding row from the table; plus an ajax loading indicator

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

GridView has an incredibly easy 'Delete' feature when used in conjunction with a DataSource, the problem is, that is requires a postback. Since we are going the ajax route, this is a no-go. Alternatively, we could wrap in in an UpdatePanel, but that is exactly what we are trying to avoid. Deleting is very easy, we use a lot of the same methods that were involved in fixing the sort on the last post and using the jQuery .ajax() method.

changes to the markup

First we have to add another column for deleting and stick a delete image in there, this is simple enough. I added unique ids to each row and each delete cell for jQuery to have something to hook on to, you could also add classes. The markup hasn't changed all too much:

delete.aspx

<asp:Repeater ID="rpt" runat="server" DataSourceID="lds">
  <HeaderTemplate>
    <table id="sort_table">
      <thead>
        <tr>
          <th>First</th><th>Last</th><th>Age</th><th></th>
        </tr>
      </thead>
      <tbody>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td id="frst<%#Eval("person_id")%>" class="editable">
        <%#Eval("first_name")%>
      
</td>
      <td id="last<%#Eval("person_id")%>" class="editable">
        <%#Eval("last_name")%>
      
</td>
      <td id="age_<%#Eval("person_id")%>" class="editable">
        <%#Eval("age")%>
      
</td>
      <td style="test-align:right;" id="del_<%#Eval("person_id")%>">
        <img src="images/delete_item.png" alt="delete" />
      </td>
    </tr>
  </ItemTemplate>
  <FooterTemplate>
    </tbody></table>
  </FooterTemplate>
</asp:Repeater>
<asp:LinqDataSource ID="lds" runat="server"
  ContextTypeName="demoDataContext" TableName="persons" />


We put the id on the cell itself and not the image because it will be easier to grab with dataTables, not to mention easier to click.

now for the js

First of all, you will notice if we leave the .dataTables() call the same as before, you can now 'sort' by the last column (the delete column), that isn't right, we have to pass some parameters to our 'dataTables()' method to make sure that column gets ignored:
oTable = $("#sort_table").dataTable({
    "aoColumns": [null, null, null, { "bSortable": false}]
});

Also notice that we decided to store the resulting table in 'oTable' just like the last lesson. Remember that this is because the sortable data is not kept in the table itself, but in an associated array, which we will need later.

Now, using the same method as last time, we will grab the position of the clicked item, attempt the ajax call, but instead of changing a value, we will delete a row. Normally, deleting a row in ajax is very simple, you grab the row by the id, and do a hide() or slideUp(), etc. - but that will not totally work here. Sure it would function, but since we are using sizing and paging, they wouldn't reflect the changes: if you had 30 items in your table, and you were 'showing 10 of 30' items, and you deleted one the normal way, it would still say 'showing 10 of 30 items' when in fact, you are only now showing 9 of 29 items, and the problem then just compounds. The brilliant minds who wrote the dataTables plugin built in ways to get around this.

First thing, we get the position of the clicked item (which all have 'del_' as an id prefix) and store that:
var pos = oTable.fnGetPosition(this);

As well as the id of the cell as we need the corresponding 'person_id' that is contained there:
var del = $(this);

Then we simply call the .ajax() method in jQuery:
$.ajax({
    type: "POST",
    url: "ajax_functions/delete.aspx",
    data: "person_id=" + del.attr('id').replace('del_', ''),
    success: function() {
        $("#report").addClass("success").html("Person Deleted");
        oTable.fnDeleteRow(pos[0]);
    }
});

And that is where the magic happens. It was indicated that this was of type 'POST', the url that it is sent to (we will get to that in a moment), and the POST query that was sent (the delete cell's id, minus the 'del_' prefix). Then, on success, we simply output some feedback to the user into a new div with the id of 'report' - nothing special there. But on the next line, we use the 'oTable' that we stored earlier that has all of the sortable data, and call the included function 'fnDeleteRow' with the position that we collected earlier, and that is what deletes the row. The finished javascript looks like this:

delete.aspx
var oTable;
var aPos;
var editedCell;
$(function() {
    $("td[id^='del_']").addClass("pointer").click(function(event) {
        var pos = oTable.fnGetPosition(this);
        var del = $(this);
        $.ajax({
            type: "POST",
            url: "ajax_functions/delete.aspx",
            data: "person_id=" + del.attr('id').replace('del_', ''),
            success: function() {
                $("#report").addClass("success").html("Person Deleted");
                oTable.fnDeleteRow(pos[0]);
            }
        });
    });
    $(".editable").click(function() {
        aPos = oTable.fnGetPosition(this);
        editedCell = $(this);
    }).editInPlace({
        url: "ajax_functions/update.aspx",
        params: "ajax=yes",
        value_required: true,
        default_text: "click to edit",
        success: function() {
            var data = oTable.fnGetData(aPos[0]);
            data[aPos[1]] = editedCell.html();
        }
    });
    oTable = $("#sort_table").dataTable({
        "aoColumns": [null, null, null, { "bSortable": false}]
    });
});

backend

Lastly is the easy part, to make the backend to "ajax_functions/delete.aspx" to handle the POST.

ajax_functions/delete.aspx.cs
using System;
using System.Linq;

public partial class ajax_functions_delete : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        demoDataContext db = new demoDataContext();
        try
        {
            System.Threading.Thread.Sleep(1000);
            // get the person_id of the person being deleted
            int person_id = Convert.ToInt32(Request.Form[0]);
            db.persons.DeleteOnSubmit(db.persons.First(x => x.person_id == person_id));
            db.SubmitChanges();

            Response.Write("deleted");
        }
        // this will catch all the errors and output them to the edited field
        catch (Exception ex) { Response.Write("Error: " + ex.Message); }
    }
}

This code is pretty simple. Since we specified the POST in the ajax() call in jQuery, we knew the first element of the POST was going to be the person_id, and that is used to delete it from the DB.
*NOTE* that I used a Thread.Sleep() in there which I NEVER recommend using. it is just there to illustrate the ajax loading indicator that was implemented into the masterpage, which is covered next.

ajax loading indicator

I snuck a new div into the masterpage with the id of 'working' and bound it to all jQuery ajax events with the following js:
demo.master
$(function() {
    $("#working").bind("ajaxSend", function() {
        $(this).show();
    }).bind("ajaxComplete", function() {
        $(this).hide();
    });
});

Now any time jQuery is doing ajax, there will be a little notification so the user knows your app is not quitting on them. All other times, that div will be hidden.

Now all that we have left is the ability to add new items.

Is Nick Stakenburg bullying his open-source 'competitor'

corporate scare tactics on a lower level?

Due to my recent affection for jQuery, I was looking around for a good tooltip framework. I found SimpleTip written by Craig Thompson and it is great! I noticed that there was a SimpleTip 2.0 link on the top and was pretty aggravated at what I saw:

Simpletip2 is now discontinued due to supposed copyright infringement

It was a good run, but unfortunately my own arrogance to the scope of this project led me to make some very bad decisions regarding the design of this site, most notably the copying of anothers layout for my own purposes. I gladly hold my hands up to the fact that, in my rush to provide others with a service, I neglected to think about what I was actually doing - infringing copyright.

I'd like to make one thing abunduntly clear about this whole situation, and that is that no code was ever "adapted, transformed or built upon" as per the terms of the license I supposidly infringed upon. My one and only mistake in this matter was utilising a, to use the term loosely, "competitors" design, and since I have neither the time nor the resources to fight a legal battle between myself and Nick, the project will henceforth be discontinued.

I take this as a life lesson, and hopefully those of you who read this will too, because this incident almost cost me something very valuable to me, my reputation.

Please direct all questions about this infringement to Nick Stakenburg and his Prototip2 project.

A log of all email transactions between me and Nick is available, strictly for reference purposes.

Well, I guess I should re-phrase, I wasn't upset at first, as I am all about following copyrights and such, but I became upset after I read the email transcript. Apparently, according to Nick Stakenburg a developer that charges for a similar Prototype plug-in (he gets no links from my page) Craig is infringing on his rights and he threatened him:
You either stop distributing the javascript or I will make sure you do through a different route, the latter comes with a pricetag.

Not only that, but he goes on to attack Craig's reputation, which is just not cool - as he is doing a great thing by releasing an open-source alternative to a commerical product; nothing unethical about it!

I will leave it to you if you want to read the transcript, but I highly recommend you do. The part that sticks out to me the most was from Nick:
The result of the code is the important thing, the code itself could be rearanged or coded in a different language, just like a translation on licensed text would not be allowed unless given permission. I could code Prototip for any framework and make the underlying code look different every time I go over it. If I did it in jquery I'd start from the ground up as well and end up with a similar result. When you look at the results it's clear that you've based the code on my API and ideas ending up with basically the same thing.

So, apparently, if the 'result' of software is the same as another, they are infringing upon the software itself, even though it may be completely different. Someone better let Open Office know, because they are in a world of hurt, considering this would be no different than if MS came after OO. Not to mention all those email apps and web browsers... almost the entire software industry is in legal trouble if Nick was writing the books. In fact, Nick seems to have released a product (that he charges for) that is amazingly similar to countless js image viewing plugins out there... isn't he breaking his own 'rules'?

Though the most brazen and ridiculous statement though comes at the end:
If you want to use your code for personal use while there is no alternative that works with jquery I'm okay with that but I can't give a green light on distribution.

The master of javascript distribution has spoken!

This is obviously a scare tactic used by Nick to frighten a 'competitor' who is encroachinig on his sales. Nick is jarred by the fact that someone has released a comparable (better?) product that his and it is free. It behaves somewhat the same, so obviously it was copied...

I could be wrong, I am no legal genius, but this seems like a big load of BS and Nick is trying scare tactics to get Craig to remove his competition. I hope Craig calls his bluff (I am assuming that Craig did in-fact not copy Nick's work, as he doesn't have the source).

In fact, isn't this the EXACT reason for the open-source community? Making free alternatives to commercial software that developers can dig in to? Collaboration of minds on software? This whole situation disgusts me. What does everyone else think?

Shout it kick it on DotNetKicks.com

Inline editing with DB write : 'REAL' AJAX with Asp.Net Series

Writing to the database inline without a postback, simple and effective

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

This is the first example of ajax I am showing with a write to the DB, and this will show just how easy it really is. I am building on the last post (GridView Sorting/Paging : 'REAL' AJAX with Asp.Net Series) which will explain where/how the data and display is set up.

Also, you will notice that the CSS changed a bit, that is because this plugin has a hover property that resets the backgorund of the td, and that gave a funky interface; now this can be taken care of with some jQuery magic pretty easily, but that is outside the scope of what this is trying to show.

load all of your js

I am still using jQuery and the extension dataTables but for this lesson I am using an additional plugin: inPlace. So now our script loading looks like this (notice I moved the script refs into the masterpage in this lesson):

demo.master

<script type="text/javascript"
  src="js/jquery.js"></script>
<script type="text/javascript"
  src="js/jquery.dataTables.js"></script>
<script type="text/javascript"
  src="js/jquery.inplace.js"></script>


decide what you want to be editable

Now, since we are using our Repeater table from the last example, we just modify if ever-so-slightly to make it editable, to do that, we just add the class 'editable' (or whatever you want it to be) to each td that we want to be editable. In addition to adding a class, we are going to add meaningful ids to each of the cells, each ID will contain:
  • First 4 Letters - What field is being edited
  • Following digits - 'person_id' that is being edited

if you are unsure as to why we are doing this, keep reading, it will become clear.

inline_edit.aspx

<asp:Repeater ID="rpt" runat="server" DataSourceID="lds">
  <HeaderTemplate>
    <table id="sort_table">
      <thead>
        <tr><th>First</th><th>Last</th><th>Age</th></tr>
      </thead>
      <tbody>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td id="frst<%#Eval("person_id")%>" class="editable">
        <%#Eval("first_name")%>
      
</td>
      <td id="last<%#Eval("person_id")%>" class="editable">
        <%#Eval("last_name")%>
      
</td>
      <td id="age_<%#Eval("person_id")%>" class="editable">
        <%#Eval("age")%>
      
</td>
    </tr>
  </ItemTemplate>
  <FooterTemplate>
    </tbody></table>
  </FooterTemplate>
</asp:Repeater>
<asp:LinqDataSource ID="lds" runat="server"
  ContextTypeName="demoDataContext" TableName="persons" />


make them editable

Now just add in a a little jQuery magic, and the fields will be editable:

inline_edit.aspx
$(function() {
    $("#sort_table").dataTable();
    $(".editable").editInPlace({
        url: "ajax_functions/update.aspx",
        params: "ajax=yes",
        value_required: true,
        default_text: "click to edit"
    });
});

You can look on the documentation for jquery.inplace.js for a further explanation, but what we declared there is that all items that have class 'editable' will now be editable; also, requests will get sent to 'ajax_functions/update.aspx' (which we haven't made yet) and we are requiring a value.

handling the ajax

Ok, so what is happening now, is if you click on a cell you will be able to edit it, and when you click off, or hit enter (you can edit these behaviors if you want), a POST will be sent to 'ajax_functions/update.aspx'. What is sent to the page is the following values:
  • update_value - the value you edited
  • element_id - the element id that was edited
  • original_html - value from before your edit

Now we only care about the first two in this example, but the third value could also be useful given the situation; possibly returning the old value if an error occurs? Also, it may be easier to see why we included both the field and the person_id in the ID of the <td>.

For handling, you could easily have seperate pages that only handle a certain element, i.e. ajax_functions/first_name.aspx for first_name, ajax_functions/last_name.aspx for last_name, etc. but I found that if you did it that way, you ended up writing the same code over and over - so what I did was combine it into a single update handling page. That is why I include 'what' is being updated in the id.

When you make your handling page, it is important that there is no html in it to start with - as the page text itself will be what is stuffed back into the area that you edited. This is the ENTIRE ajax_functions/update.aspx page:

ajax_functions/update.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="update.aspx.cs" Inherits=ajax_functions_update" %>


Anything we want to appear we will just dump out a Response.Write() for. Here is the handling code, I will explain afterwards:

ajax_functions/update.aspx.cs
using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;

public partial class ajax_functions_update : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        demoDataContext db = new demoDataContext();
        // this is unneccessary, but more efficient since there will 
        // be more than 1 db call, this uses the same connection
        SqlConnection con = new SqlConnection(
            ConfigurationManager
            .ConnectionStrings["demoConnectionString"].ConnectionString);

        try
        {
            // get the new value
            string newValue = Request.Form[0]; 
            // figure out what is being edited (remember, its the first 4 chars in the id)
            string what = Request.Form[1].Substring(0, 4);
            // get the person_id of the changing value (the remaining digits)
            int person_id = Convert.ToInt32(
                Request.Form[1].Substring(4, Request.Form[1].Length - 4));

            con.Open();
            // get the record you want to deal with
            person p = db.persons.First(x => x.person_id == person_id);

            // change the value depending on 'what' was sent
            switch (what)
            {
                case "frst": p.first_name = newValue; break;
                case "last": p.last_name = newValue; break;
                case "age_":
                    try { p.age = Convert.ToInt32(newValue); }
                    catch { throw new Exception("not an int"); }
                    break;
                default: throw new Exception("nothing saved");
            }
            db.SubmitChanges();
            con.Close();
            Response.Write(newValue);
        }
        // this will catch all the errors and output them to the edited field
        catch (Exception ex) { Response.Write("Error: " + ex.Message); }
        finally { con.Close(); }
    }
}

First off, the code simply sets the DataContext and opens a SqlConnection (it is explained why in the code). Then, we pull from the POST values from the Request. We pull 3 things from this:
  • person_id - 'person_id' that is being edited
  • what - what field is being edited
  • newValue - the new value for the update

Now is the easy part, get the 'person' to edit, run a switch on 'what' and and update it to 'newValue'. I caught all errors and output them to Response.Write() as that is all the user will be able to see. Also, whatever is written is returned so it integrated seamlessly.  What the user will see is 'Saving...' (unless you change the text or substitute an image) and when it is complete, they will see the new value in place of the old value (which is now written to the DB) as that is what was put in the Response.Write() (if there are no errors, otherwise they'll see the error message).

There you have it! A 'real' ajax inline update with asp.net, and it was as painless as can be! There are all sorts of other things you can do like apply a js function after the update has completed, add in a nice loading graphic instead of the text, etc. - fun to play around with.

Keep in mind with this, if a user (hacker) realizes how it works, they would be able to fabricate a POST to send to your page and update it how they see fit; so be sure you test, protect against that. In one of my apps that uses this. I make sure that the record being edited belongs to the user currently logged in before they can update.

Next will be deleting a row in this table with ajax.



but...

If I have 3 'people', with last names, 'a', 'b', and 'c', and edit 'b' to now be 'z', it will not sort correctly; 'z' will not be the last one in the table, it will still be 'c'. That is because the table data that does the sorting is not held within the table itself, but in an array of 'nodes'.

I left that as a seperate download because this part dives a little deeper into the relation of the sort/edit. What needs to be done is we have to go into the array that holds the nodes, and change the related data along with the represented data in the table.

how do I do that?

This one might require reading a few times, so bear with me. First you need to set the global variables we will be using:
var oTable;
var aPos;
var editedCell;

Then, you will need to store your table in memory:
oTable = $("#sort_table").dataTable();

Now you need to intercept the click in any editable field, and get the position of it in memory; also, we will store the edited cell into a variable as well:
$(".editable").click(function() {
    aPos = oTable.fnGetPosition(this);
    editedCell = $(this);
})

What is now in aPos is a 2-element array [int row_index, int cell_index]; editedCell is the cell that you just clicked. At this point we have all the necessary values to plug the data back in. So next we tack the '.editable()' on to the end of the previous 'click()' call and add a 'success' parameter that will fire on success of the edit. Here is the completed js:

inline_edit.aspx
var oTable;
var aPos;
var editedCell;
$(function() {
    $(".editable").click(function() {
        aPos = oTable.fnGetPosition(this);
        editedCell = $(this);
    }).editInPlace({
        url: "ajax_functions/update.aspx",
        params: "ajax=yes",
        value_required: true,
        default_text: "click to edit",
        success: function() {
            var data = oTable.fnGetData(aPos[0]); 
            data[aPos[1]] = editedCell.html();
        }
    });
    oTable = $("#sort_table").dataTable();
});

Now, the table will re-sort correctly, it's a little extra work, but the added benefit is worth it IMO. Here is the download with the extended functionality (it also has the next demo in it):

Shout it

GridView Sorting/Paging : 'REAL' AJAX with Asp.Net Series

Who knew this could be so easy... and FAST?

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

Ok, nothing too dramatic to start things off, we are going to make some tabled data sortable and pagable all without using a bit of postback. Not only that, but it is going to be incredibly easy!

First off we need the data that these demos will be working with, nothing complicated, just a simple SQL table 'person' that holds peoples' names and ages:

setup.sql
CREATE TABLE dbo.person (
person_id INT NOT NULL PRIMARY KEY IDENTITY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
age INT NOT NULL
);

Also included in the setup.sql file is some dummy data to populate it initially. We ill be using a Linq as our datasource throughout with a .dbml file named demo.dbml.

Next we need to display the data. Normally if I wanted to do paging, I would use a GridView, due to the fact is is already integrated. But that integration is sloooow, and requires a postback - we are ajax'ing here! What we are going to do will load all the data (which could be slower initially on large data sets) and use jQuery to take care of all of the lifting for us. So, it is much more efficient for us to use a Repeater. Without postbacks, all the advantages of a GridView quickly fade away. You will see how little markup you need:

sort_page.aspx

<asp:Repeater ID="rpt" runat="server" DataSourceID="lds">
  <HeaderTemplate>
    <table id="sort_table">
      <thead>
        <tr><th>First</th><th>Last</th><th>Age</th></tr>
      </thead>
      <tbody>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td><%#Eval("first_name")%></td>
      <td><%#Eval("last_name")%></td>
      <td><%#Eval("age")%></td>
    </tr>
  </ItemTemplate>
  <FooterTemplate>
    </tbody></table>
  </FooterTemplate>
</asp:Repeater>
<asp:LinqDataSource ID="lds" runat="server"
  ContextTypeName="demoDataContext" TableName="persons" />


That is all the markup it takes, no code-behind. Now just call the javascript magic of the combination of jQuery and the extension dataTables:

sort_page.aspx
$(function() {
    $("#sort_table").dataTable();
});

And just like that you have a full sortable (with flipping sorting images), filterable, sizable, pageable and 'pretty' table using a simple Repeater. Now, I guess this isn't truly ajax, as nothing is truly pulled from the data store after the initial pull, but I argue that it is *relatively* because if you were to use a GridView jumping pages would cost a postback each time.

This is just the introduction here, but it is to show you how incredibly easy it is to get real, time-saving ajax and it is not as intmidating as you think. Next I will be showing you how to do inline editing of this table.

Shout it Update »

'REAL' AJAX with Asp.Net (not Asp.Net AJAX) Series : Building a complete ajax CRUD system with Asp.Net

Am I the only one who feels guilty every time I throw an 'UpdatePanel' into my code?

We all know Asp.Net AJAX is technically ajax, but it generally passes one the main advantage of using ajax in the first place.

Sure ajax is slick for user interface, but where I feel it really helps is speed. For example, if you want to edit a row in a GridView, you can easily do this using the GridView, stick it in an UpdatePanel and poof... you have an 'ajax' interface. But, and this is a huge but, the *ENTIRE* GridView was actually pulled from the DataSource, not just the row you were using. Asp.Net AJAX is a great tool, but it sort of masks (nearly) complete postbacks as being asynchronous; which is extremely convenient for quick development, but does not really help in the realm of performance.

Basically, I look at Asp.Net AJAX as a lazy way to do 'ajax' - that's in quotes as it really isn't asynchronous. So, lately, I have been making it my mission to get familiar with jQuery and integrating *real* ajax into my projects; and the speed gains are extremely noticable and quite impressive! Now jQuery is not necessary, but I am waaay to lazy and unskilled to write raw JS to do what I want, plus people have already written amazing jQuery plugins to do tons of what I want; not to mention it is probably written better than I could do anyway.

So, I am going to be posting a series of Asp.Net with 'real' ajax tutorials and examples in the coming weeks. I am going to be recreating all the functionality that you can get out of a GridView normally with edit, delete, new, sort, page etc. - a full CRUD (Create, Read, Update, Delete) system; but it will all be true ajax and very fast. Here are the topics that will be covered:
So stay tuned, I think you will be really impressed with how easy, and how much faster 'real' ajax is.

Shout it kick it on DotNetKicks.com

How to use Google Code Prettify with BlogEngine.Net

Simple code coloring with this javascript library

From here on out you will notice that the code on my site will be formatted differently, and you won't know this, but it will be much easier for me to publish code. This is because I have implemented the google-code-prettify library which is freely available... and it is great! Getting it to work with BlogEngine is not too much of a hassle either; this is how I did it (there are unlimited ways to implement this, where to dave the files, etc.; this is just how I chose to).

place the files in a central location

I put mine in the root/js/ folder, just in case multiple themes were going to access it.

reference them from your site.master

I ended up putting this in the code-behind of my site.master as a precaution of where this file might (if ever) move in the future when I completely forgot how I did this. The nice thing about this is that it doesn't matter the relation to the JS, as it will always be found as long as the JS itself does not move.

site.master.cs
Page.ClientScript.RegisterClientScriptInclude(
  typeof(site), "jquery",
  ResolveUrl("~/js/prettify.js"));
Page.ClientScript.RegisterClientScriptInclude(
  typeof(site), "jquery", 
  ResolveUrl("~/js/lang-css.js"));
Page.ClientScript.RegisterClientScriptInclude(
  typeof(site), "jquery", 
  ResolveUrl("~/js/lang-sql.js"));

If you noticed, I did not load all the language JS files included in the download, that is because I don't plan on using them, but feel free if you are a lisp, vb, etc. developer.

reference your css

Now this I am referencing simply from the site.master itself. I placed the prettify.css file in the theme/naspinski/ directory of my site.

site.master

<link rel="Stylesheet" type="text/css" href="prettify.css" />

The reason I am not doing this in any sort of global way is the fact that different themes will likely want different prettify.css files. I will have to make sure there is a prettify.css file for each theme.

call the prettyPrint() method

Now simply call it with your 'body onload' (or jQuery, MooTools, Prototype, etc.).

site.master

<body onload="prettyPrint()" />


use it

Now that everything is all set up, you just need to put your code inside of some <pre> tags calling the required classes:

this code:

<pre class="prettyprint">
  List<Person> p2 = new List<Person>()
  {
    new Person(){Name = "A", City="New York", Id=100},
    new Person(){Name = "B", Id=101, State="WA"}
  };
</pre>


looks like:
List<Person> p2 = new List<Person>()
{
  new Person(){Name = "A", City="New York", Id=100},
  new Person(){Name = "B", Id=101, State="WA"}
};

**IMPORTANT**
Now, I noticed that the BlogEngine RTE liked to strip out line-breaks inside the <pre> tags so you will have to add the <br />s in there to break lines which you would normally not have to do, as well as any starting spaces with &nbsp;s. I noticed if I turned off JS while entering my post, that I did not have to do this; so I actually prefer to *not* use the rich text editor so I don't have to add the <br />s.

Now, if you look back up you see I specifically pulled a couple language scripts for use with SQL and CSS. The script as is will try to 'guess' the language you are using, but if you want to specify it you simply add it in the class declaration:

this code:

<pre class="prettyprint lang-sql">
CREATE TABLE dbo.person (
person_id INT NOT NULL PRIMARY KEY IDENTITY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
age INT NOT NULL
);
</pre>


looks like:
CREATE TABLE dbo.person (
person_id INT NOT NULL PRIMARY KEY IDENTITY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
age INT NOT NULL
);                

this code:

<pre class="prettyprint lang-css">
.code .comm { color:#444444; }
.code .var { color:#800000; }
.code .num { color:#0033CC; }
</pre>


looks like:
.code .comm { color:#444444; }
.code .var { color:#800000; }
.code .num { color:#0033CC; }        


And that's that. I use a customized prettify.css file that I made, so your results will be a bit different - if anyone wants it, just let me know.

Shout it kick it on DotNetKicks.com

Making a registration system with Asp.Net and Linq-to-SQL (part 3)

Now that it's all up and working, we can make it friendlier and add some cool AJAX effects

After part 2 the system works just fine, but I wanted to take it a step further.This will be the last entry in this series, which I will follow up with a tutorial on how to retrieve passwords and log the registered users in.

what are we going to accomplish?

Like I said before, the system works, this is just the frosting on the cake, we are going to add some jquery and use the MasterPage to make this more accessible to the users.

markup

On the MasterPage, I added quite a few things, and on the registration page I added one key element:

demo.master
<h1>
  <span class="right">
    <a href="default.aspx">Home</a>
    <a href="register.aspx" class="triggerRegister">Register</a>
  </span>
  Registration Demo
</h1>

<div><asp:ContentPlaceHolder id="body" runat="server" /></div>

<div id="footer">
  <a href="default.aspx">Home</a> |
  <a href="register.aspx" class="triggerRegister">Register</a>
</div>

<div class="jqmWindow" id="register">
  <h3>
    <asp:UpdateProgress ID="uppRegister" runat="server">
      <ProgressTemplate>
        <div class="status">working...</div>
      </ProgressTemplate>
    </asp:UpdateProgress>
    <a href="#" class="x jqmClose">X</a>
    Register
  </h3>
  <cc:register ID="ccRegister" runat="server" />
</div>

register.aspx
cc:register ID="reg" runat="server" in_page="true" />

First of all, you have to realize, since the <div id="register" ... > has a CSS class of 'jqmWindow, it will not be visible when the page loads. This is because it is going to be within a modal popup window. Also, you will notice that there is a <cc:register ... > control within. That is what causes the small change to register.aspx as the attribute 'in_page' is added.What this does is elimiate errors that may occur if two or more of these controls are on a single page, so the validators only validate the controls they are pertinant to. The code is in the Utils.cs file if you would like to examine it.

I am also using an UpdatePanel within the modal so the user is able to see their feedback; if it wasn't (or something similar) used, the modal would be hidden after postback.

Also, some links with the class 'triggerRegister' are added, these will be the links that will trigger the modal popup (using jqModal) with the following JS:

demo.master
$('#register').jqm({ trigger: false }).jqmAddTrigger($('.triggerRegister'));

And just that simply we made the registration available multiple ways across the entire project! If the user has javascript turned off, it will will still work just fine as we have a 'backup' register.aspx page that will handle the request.Ahh the beauty of jQuery.


« Part 1« Part 2