Tag Archives: .NET

Creating Your Own Glimpse Plugin

Last weekend I created a Glimpse plugin for PetaPoco. It was surprisingly easy. In this post I’ll show you how to create your own.

Please note as Glimpse is still in Beta, this example may change. but I will endeavour to update the post when and if the interface changes. This plugin is based on Glimpse 0.81.

Here is the complete code for our first plugin.

    [GlimpsePlugin(ShouldSetupInInit=true)]
    public class MyFirstGlimpsePlugin : IGlimpsePlugin
    {
        private int MaxValue;

        public object GetData(HttpApplication application)
        {
            // Return the data you want to display on your tab
            var data = new List<object[]> {new[]{ "Column1", "Column2", "Column3" }};

            for (int i = 0; i < MaxValue; i++)
            {
                // Usually get your data from application.Context.Items
                data.Add(new object[] {"Data " + i, 10*i, DateTime.Now.AddHours(i)});
            }

            return data;
        }

        public void SetupInit(HttpApplication application)
        {
            // Perform an initialisation that needs to be done.
            // Run once at startup
            MaxValue = 5;
        }

        public string Name
        {
            get { return "MyFirstPlugin"; }
        }
    }

There are three parts.

1. The Name get accessor: This is the name of the tab.

2. SetupInit method: This method will run once when the Plugin is loaded. Perform any initialisation code here.

3. GetData method: This is where the action happens. All data returned from here will be serialized into JSON and sent to the client to be rendered by the Glimpse client side framework. How it is exactly rendered depends on whether you return arrays or objects or arrays of objects etc. Initial details for this can be found on the Protocol page. Usually you would put the data you need to display in the HttpContext.Items dictionary in part of your application. You can then pull the data out using the application variable provided to you in the GetData method.

For example

-> data goes in:  HttpContext.Current.Items[“test”] = “Some data”;

-> data comes out:  var testdata = application.Context.Items[“test”]

The following is rendered by Glimpse.

Glimpse-firstPlugin

As you will see, it doesn’t matter what data you put in what column as Glimpse will do its best to render the data in the most approriate way. If I change the GetData method to be:

        public object GetData(HttpApplication application)
        {
            // Return the data you want to display on your tab
            var data = new List<object[]> {new[]{ "Column1", "Column2", "Column3" }};

            for (int i = 0; i < MaxValue; i++)
            {
                // Usually get your data from application.Context.Items
                data.Add(new object[] {"Data " + i, 10*i, DateTime.Now.AddHours(i)});
            }

            var nestedData = new Dictionary<string, object>
                                 {
                                     {"NestKey1", "NestedValue"},
                                     {"NestKey2", 2 },
                                     {"NestKey3", DateTime.Now }
                                 };

            data.Add(new object[] { "Data Nested", 60, nestedData });

            return data;
        }

the following is rendered by Glimpse.

Glimpse-firstPlugin2

As you can see the Glimpse team have made it super easy to create your own plugin. It literally takes minutes.

Enjoy

Adam

A Glimpse into PetaPoco

Last week I blogged about upcoming performance statistics that enable you to see all the Sql’s that were executed by PetaPoco in the current request.

It was also just over a week ago that I learned about Glimpse from this Mix video by Scott Hanselman. And wow what an impact. Anthony van der Hoorn (@anthony_vdh) and Nik Molnar (@nikmd23) had created a wonderful diagnostics system for Asp.net MVC. Firebug for the server if you will.

I then wondered if I could somehow plug PetaPoco diagnostics into the display for Glimpse and it was unbelievably easy. Implementing a single interface was all it took. Less than 50 lines of code in total to produce the following results. I will show you how to create your own tab in a future post. Update: Creating Your Own Glimpse Plugin

petapoco_glimpse2

This gives a pretty clear display of exactly what queries were performed during the current request.

Another powerful feature of Glimpse is that it saves the last n (default 5) requests so it is indeed possible to get access to the Sql’s performed when posting data back to the server.

It really is a credit to the guys for a wonderful project which still hasn’t reached a V1.

My aim is to have both the integration to Glimpse and html source statistics available within the week but it all depends on whether the integration points make it into the main branch before hand.

Update (01/06/2011): This is now available as a package from NuGet called PetaPoco.Glimpse.

Until then, check out Glimpse (on NuGet as well) and support it by providing valuable feedback to the team.

Adam

Getting Back In Touch With SQL

I’ve always used native SQL for my applications. Approximately a year or so ago I finally decided to give NHibernate a look and see what all the hype was about. I gave it a test run on a new project as there is really nothing like real world requirements to show you what a tool is really made of.

It started off slowly, but was really enjoying the easy of which you could do inserts and updates. Even selects where pretty easy. At least at first.

As the system started to grow, the pain started. The queries were relatively straight forward, but the object graph needed to pull all the data together for a simple nested list was becoming convoluted to say the least. At once stage I think I spend almost a day trying to figure out a query, however at the time I was still learning so I knew there would be some pain but it was starting to become ridiculous.

Let me say though, I’m not entirely blaming NHibernate (or ORMS eg. EF) for the problems. The data interactions that I was trying to perform were pretty intense, with complex hierarchical relationships, but I knew there had to be a better way.

I started to switch most of the queries over to using session.CreateSqlQuery(sql) and using the AliasToBeanTransformer to project the query into a DTO that more closely represented how the data was to be displayed on the page.

It was at this time that CQRS was starting to gain some traction and it was all starting to make a lot of sense.

How you model the data is usually not how you need to display the data.

I couldn’t believe how simple everything was after separating the queries from the commands. It was definitely an “aha” moment!

I am currently not implementing CQRS in full (event sourcing, table per model, separate read store etc) but I think it is a great compromise.

I have started to put together a sample application of how I am doing Web Applications using CQRS-Lite and I will endeavour to blog about the details in the upcoming weeks. This will also include details on the new Micro-ORM PetaPoco that I have been helping Brad out on, and how much easier it has made things!

Adam

Dynamic Dot Less Css With Asp.net MVC 2

I have been having a look at the best way to theme a asp.net mvc website in the last few weeks. I heard about dot less css late last year but hadn’t had time to integrate it into a project until now.

Integrating dot less css is pretty easy by default, as shown on its home page however I wanted something that could be configured by application users. We want to be able to specify the link html tag like the following.

<link href="/public/css/sites.less" rel="stylesheet" type="text/css" />

There are few steps involved in the solution I have come up with so bare with me as I go through them. Firstly we’ll start with the web.config:

        <compilation>
            <buildProviders>
                <add extension=".lessx" type="System.Web.Compilation.PageBuildProvider" />
            </buildProviders>
        </compilation>

Insert the builderProviders block inside the compilation section. The compilation section will be under the system.web section. This will enable us to use code blocks in our lessx files.

Secondly, is the routing.

        //Special Route for css so that images are relative to it
        routes.MapRoute("css",
                           "public/css/{filename}.less",
                           new { controller = "Css", action = "Index” },
                           new[] { "eLearning.Controllers" });

This specifies that any url matching /public/css/{filename}.less should be routed to the CssController passing the filename as the parameter to the Index method.

    public class CssController : BaseController
    {
        [OutputCache(Duration = 10, VaryByParam = "")]
        public ActionResult Index(string filename)
        {
            if (string.IsNullOrEmpty(filename))
                throw new ArgumentException("A filename must be supplied");

            ViewData["baseColor"] = "#aabbcc";

            var less = RenderViewToString(filename + ".lessx", null);
            var css = LessCss.Generate(less, true);
            return Content(css, "text/css");
        }
    }

    public static class LessCss
    {
        public static string Generate(string less, bool minify)
        {
            var lessEngine = new EngineFactory();
            lessEngine.Configuration.MinifyOutput = minify;
            var output = lessEngine.GetEngine().TransformToCss(less, null);
            return output;
        }
    }

This is the css controller class. It receives the filename as the input, finds the corresponding .lessx file and returns the file with appropriate view data replaced. Is then takes the less formatted string and runs it through the dot less parser to return a css string. This is then returned to the browser with the appropriate content-type. One method I have not shown is the RenderViewToString() and how the .lessx file is located. This method is located on the base controller class that the css controller inherits from. I have also turned Caching on so that it will cache the result for 10seconds.

        protected string RenderViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindView(ControllerContext, viewName, null);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }


This method finds the .lessx file and returns the result as a string. Now usually the view engine will take controller name and method name and by convention look in the /Views/css/index.aspx file. It doesn’t quite make sense to put it in the views folder so I have overridden the default web forms view engine so that they can be placed in the /Public/Css folder. This can be configured to your liking (convention).

    public class CustomViewEngine : WebFormViewEngine
    {
        public CustomViewEngine()
        {
            var locs = new List<string>(base.ViewLocationFormats);
            locs.Add("~/Public/{1}/{0}"); //My personal choice
            locs.Add("~/Views/{1}/{0}");  //An alternative choice
            base.ViewLocationFormats = locs.ToArray();
        }
    }

Once your Custom View Engine has been overridden, you will need to add it to the ViewEngines.Engines collection in the application start method in the global.asax.cs.

        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new CustomViewEngine());

This will then allow us to write a *.lessx file like the following; you can also pass a strongly typed model to the .lessx file if you so wish in the same way you would to a regular aspx view.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

@basecolor: <%= ViewData["baseColor"] %>;

body {
    background: @basecolor;
}

Which will be rendered to the browser as:

body {
    background: #aabbcc;
}

And that’s it. I’m still working on the finer details but I am liking how it works at the moment. If you have any thoughts or suggestions, please leave a comment.

Adam

Fluent Validation Model Binder – Asp.net MVC

A few weeks ago I found the Fluent Validation framework by Jeremy Skinner. I needed to conditionally validate a model depending on an application setting. eg. Description field mandatory / not mandatory depending on the clients business requirements. I loved the simplicity of the framework and the separation from the model it provided.

Since then I have submitted a few patches for the framework, one of which is the Fluent Validation Model binder. Inspired by the Data Annotations Model binder, it works in much the same way. Once you have it set to your default model binder, it will validate any model which contains the specific attribute. This will become clear in the examples below.

Firstly lets take our model.


    [Validator(typeof(LineItemValidator))]
    public class LineItem
    {
        public int LineNumber { get; set; }
        public DateTime Date { get; set; }
        public string Description { get; set; }
        public decimal Net { get; set; }
        public decimal Tax { get; set; }
        public decimal Gross { get; set; }
    }

Attached to this simple LineItem class is a Validator attribute. This attribute is used by the Model Binder to locate the Class used for validation. Below I will define my LineItemValidator class which will hold the rules for the validation.


public class LineItemValidator : AbstractValidator<LineItem> { public LineItemValidator() { RuleFor(x => x.Description) .NotEmpty().When(x => Settings.DescriptionRequired) .And .Length(0, 30); RuleFor(x => x.Date) .GreaterThanOrEqualTo(DateTime.Today); RuleFor(x => x.Net) .GreaterThan(0); RuleFor(x => x.Gross) .GreaterThan(0) .And .Equal(y => (y.Net + y.Tax)) .WithName("Total Amount"); } }

As you can see the class must inherit from AbstractValidator<T> where T is the model you want to define the rules for. The first rule uses the conditional When clause where it will only validate that the field is NotEmpty when the Settings.DescriptionRequired boolean is true. Also, another thing is the complex validation taking place on the Gross field. Not only does it validate that it is greater than 0, but that the value is equal to the net + tax amount. This is very elegant indeed. I have also specified the ‘WithName’ clause which has also been integrated into the model binder so that if an error occurs with the gross field, the WithName value will be displayed when an error happens. This is extremely handy for language localization or when the name of the field on the Model is insufficient.

Wiring this Model binder up in the Application_start event in the global.asax.cs is as easy as this.


ModelBinders.Binders.DefaultBinder = new FluentValidationModelBinder(new AttributedValidatorFactory());

Note that we have to pass an instance of the AttributedValidatoryFactory into the Model Binder. This means if you have an alternate way of locating the Validator class other than via the attribute you can inherit from IValidatorFactory and create your own.

Now when a parameter of LineItem gets passed into a controller it will be validated against the model and all errors placed into the ModelState. This can then check the isValid property to determine if there are any errors and proceed accordingly.


        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(List<LineItem> lineItems)
        {
            if (ModelState.IsValid)
                return RedirectToAction("Edit");

            return View();
        }

And that’s it. I hope you enjoy using the Fluent Validation framework as much as I have and happy coding. For all you guys waiting for xVal integration, I will try and post a solution in the coming week.

Adam

Integrating xVal Validation with Linq-to-Sql

In a previous post I showed you how you can use xVal and the IDataErrorInfo class to add validation to your Asp.net MVC website. In this post I will extend that to Linq-to-Sql and the classes it generates.

The northwind database has a suppliers table. The info contained below is using that table with linq-to-sql.

After adding the table to the designer, a Supplier class gets constructed in the background. This class is a partial class which means we can add to it without changing the code auto-generated in the designer.cs file.

We can then create a partial class called Supplier inheriting from Custom Validation and add a MetadataType attribute to it. This attribute specifies the class for which use for validating the Supplier class.


[
MetadataType(typeof(SupplierValidation))] public partial class Supplier : CustomValidation { }

We can then create the SupplierValidation class specifying the properties of the Supplier class we would like to be validated. For instance here I only want to validate the ContactName and the ContactTitle of the Supplier.

    
public class SupplierValidation { [Required] public string ContactName { get; set; } [Required, Range(0, 10)] public string ContactTitle { get; set; } }

This specifies that both fields are required and that the ContactTitle cannot be more than 10 characters in length.

The other benefit of using the buddy class here is that if you need to regenerate a table in the linq-to-sql designer, you won’t lose your changes because they’re contained in a separate file.

From here when a Supplier gets passed to in as a parameter on a Controller action it will be validated using the rules in the Supplier Validation class.

Cheers,

Adam

Transforming one-to-many Sql into Nested Class

Back in the days of Classic ASP, when you had a one too many relationship displaying the data was pretty painful. You would do things like


var reference_number_old =
"$##%@"; while (recordsExist) { reference_number = String(rs(0)); if (reference_number_old != reference_number) { Response.Write(reference_number); reference_number_old = reference_number; } //Do more stuff }

Sooo very very painful, and that’s only grouping by one column (reference number).

Now however with OO programming and the advance of Linq there is a much nicer and easier way to deal with this Master-Detail type one-to-many relationship.

Lets see how we do it now, still using our own custom sql.

Firstly here is our class to represent our flat data straight out of the database.

        public class FlatCustomerAndOrders
        {
            public int ReferenceNumber { get; set; }
            public string Name { get; set; }
            public string Address { get; set; }
            public int OrderId { get; set; }
            public string ProductName { get; set; }
            public string Description { get; set; }
            public decimal Amount { get; set; }
        }

Even filling this class used to be a bit painful before Linq. You would have to create a connection, create a reader, then instantiate the FlatCustomerAndOrders class. Set the properties then add the object to a list while records could still be read. Here’s how I do it now.

        
DataContext dc = new DataContext(new SqlConnection(connString)); IEnumerable<FlatCustomerAndOrders> flat = dc.ExecuteQuery<FlatCustomerAndOrders>("select c.referencenumber, c.name," + "c.address, o.orderid, o.productname, o.description, o.amount from customers " + "c inner join orders o on c.referencenumber = o.referencenumber");

Thats its. We have our List of FlatCustomerAndOrders.

The next step is to organise the data so that the data is nested so its easy to display with just two foreach loops. The two classes:

        public class Customer
        {
            public int ReferenceNumber { get; set; }
            public string Name { get; set; }
            public string Address { get; set; }
            public List<Order> Orders { get; set; }
        }

        public class Order
        {
            public int OrderId { get; set; }
            public string ProductName { get; set; }
            public string Description { get; set; }
            public decimal Amount { get; set; }
        }

To fill these two class we do some clever Linq using the GroupBy method. Here’s the code.

        
IList<Customer> Customers = flat.GroupBy(cust => new { cust.ReferenceNumber, cust.Name, cust.Address }) .Select(c => new Customer() { ReferenceNumber = c.Key.ReferenceNumber, Name = c.Key.Name, Address = c.Key.Address, Orders = c.Select(o => new Order() { OrderId = o.OrderId, ProductName = o.ProductName, Description = o.Description, Amount = o.Amount }).ToList() }).ToList();

And that’s it. It may look like a bit of a mouthful but its quite simple really.

It just takes the flat list and applies the groupby method to it grouping by the three customer columns. It then builds a new list to fill the Orders property with.

Its then super easy to display the data like so.

       
foreach (Customer c in Customers) { //Display the customer details foreach (Order o in c.Orders) { //Display the orders for each customer } }

Well I hope this helps you as much as it has helped me.

Cheers

Schotime

Running ASP.NET MVC Applications Under IIS6

Yes…Finally…I have full control of my HTML again, but am still able to work with a great language like C#. MVC is here and its great. I’m absolutely loving it. But how the heck do you get it to work under IIS6. What if I want extensionless URL’s? Here is a few options for you.

Option 1:
Running IIS with Wildcard Application mapping.

This option allows extensionless URL’s but a what performance price. Every single request including images, files and css etc. will get passed through the aspnet_isapi.dll. For small sites this may not be a huge issue, but small sites soon because large sites and this then becomes an issue.

I’m not going to run through how to do this, because there are already some nice blogs about this and I don’t really recommend this option.

Option 2:
Running IIS with .mvc (or whatever you like) extensions.

I started out running my site (schotime.net) like this, however in the end I decided on Option 3.
URLs look like this.   /Home.mvc/Index   rather than /Home/Index  which is not that bad but again not as nice as the latter.

Anyways here’s how you set this up.
Firstly your global.asax.cs should look like this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCApplication1
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              
                "{controller}.mvc/{action}/{id}",                       
                new { controller = "Home", action = "Index", id = "" }  
            );

            routes.MapRoute(
                "Defaultest",                                           
                "Default.aspx",                                         
                new { controller = "Home", action = "Index", id = "" }  
            );

        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
            RouteTable.Routes.RouteExistingFiles = true;
        }
    }
}

This will get you started. All you need to do then is map the extension .mvc to the aspnet_isapi.dll in IIS under Home Directory -> Configuration -> Mappings or use an already mapped extension like .aspx and your mvc application should work.

Option 3:

This option requires the use of a clever isapi filter to rewrite the URLs.

I originally read an article on Bia Securities which uses the Isapi_rewrite 3rd party plugin however, Isapi_rewrite is not free so I thought I would find a suitable open source solution. Here it is: Ionic Rewriter -> http://www.codeplex.com/IIRF

It works in much the same way as the isapi_rewrite but will a few little differences. Once you download the IsapiRewrite4.dll, place the dll in a directory eg. C:\WINDOWS\system32\inetsrv\IIRF and run through the installation instructions included in the download (readme.txt) under Installation. Next comes the configuration. Firstly here is the IsapiRewrite4.ini configuration file ported from the Bia Securities article.

#RewriteLog  c:\temp\iirfLog.out

#RewriteLogLevel 3

RewriteRule ^/Default\.aspx /Home.mvc [I,L]

RewriteRule ^/$ /Home.mvc [I,L]

RewriteRule ^/([\w]+)$ /$1.mvc [I,L]

RewriteRule ^/(?!Content)([\w]*)/(.*) /$1.mvc/$2 [I,L]

The [I,L] stands for a case-insensitive match and to stop processing if the current rule is a match.

Important Note:

Any physical files that you directly linked to should not be routed. In my MVC folder system I store all of these files under the /Content directory. Wherever you store your files replace the text Content with the folder that your files reside. otherwise images, css etc. will fail to display.

Now all that’s left to do is to modify the global.asax.cs to support this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCApplication1
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }, // Parameter defaults
                new { controller = @"[^\.]*" }
            );

            routes.MapRoute(
                "Defaultmvc",                                               // Route name
                "{controller}.mvc/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" },     // Parameter defaults
                new { controller = @"[^\.]*" }
            );
        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

Note:  The line with this on it -> new { controller = @"[^\.]*" }   is very important. The routes won’t work without it.

And that’s it! You’re done.

Personally I like the last option but if you have no access to your hosting web server then Option 2 is probably the best.

Schotime

Dataset, Datatable to Json

After my previous posts about returning data to the client as a JSON object, I decided to have a go at returning a generic Datatable/Dataset. This however is not as easy as simple returning a Datatable in your code behind method or web service. There is a solution though and here it is.

If you break a Datatable down it is really only a List of Dictionary objects so that’s how we’ll approach this problem. This is compatible with .NET 2.0 and above, with the Ajax installed.

Below is the solution.

using System.Collections.Generic;
using System.Data;

public static class JsonMethods {
    private static List<Dictionary<string, object>>
        RowsToDictionary(DataTable table)
    {
        List<Dictionary<string, object>> objs =
            new List<Dictionary<string, object>>();
        foreach (DataRow dr in table.Rows)
        {
            Dictionary<string, object> drow = new Dictionary<string, object>();
            for (int i = 0; i < table.Columns.Count; i++)
            {
                drow.Add(table.Columns[i].ColumnName, dr[i]);
            }
            objs.Add(drow);
        }

        return objs;
    }

    public static Dictionary<string, object> ToJson(DataTable table)
    {
        Dictionary<string, object> d = new Dictionary<string, object>();
        d.Add(table.TableName, RowsToDictionary(table));
        return d;
    }

    public static Dictionary<string, object> ToJson(DataSet data)
    {
        Dictionary<string, object> d = new Dictionary<string, object>();
        foreach (DataTable table in data.Tables)
        {
            d.Add(table.TableName, RowsToDictionary(table));
        }
        return d;
    }
}

The static class JsonMethods exposes two public static methods and a private method. The public method ToJson() takes either a Dataset or a Datatable, and returns a Dictionary<string,object> object. The key to this class is the RowsToDictionary() method.

This method iterates through all the rows creating a dictionary entry for each column in the row using the column name as the key and storing the data value into the object. It then adds the Dictionary object to a List of Dictionary Objects and returns this to the ToJson() method. This Dictionary list is then added to another Dictionary object using the table name as the key. We’ll see how this all works together soon.

Lets have a look at the code behind now.

[System.Web.Script.Services.ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[System.Web.Services.WebMethod]
public static Dictionary<string, object> getTable()
{
    string sql = "select user_name, active_indicator, create_date from users";
    string connString = "database=db; server=localhost; user id=sa;";

    return JsonMethods.ToJson(GetDataTable(sql, connString));
}

private static DataTable GetDataTable(string sql, string connString)
{
    using (SqlConnection myConnection = new SqlConnection(connString))
    {
        using (SqlCommand myCommand = new SqlCommand(sql, myConnection))
        {
            myConnection.Open();
            using (SqlDataReader myReader = myCommand.ExecuteReader())
            {
                DataTable myTable = new DataTable();
                myTable.TableName = "mydt";
                myTable.Load(myReader);
                myConnection.Close();
                return myTable;
            }
        }
    }
}

So what I have above is two static methods. One is GetTable which is the one we will access from the client. The other is a generic method for loading a results set into a Datatable. Note how I have set the TableName property. You will see why soon.

So using the jMsAjax plugin as below will return the following JSON object.

$.jmsajax({
    type: "POST",
    url: "Default.aspx",
    method: "getTable",
    data: {},
    dataType: "msjson",
    success: function(data) {
        $(outputDT(data.mydt)).appendTo("body");
    }
});

Results (data):

{“mydt”:{“user_name”:”000001″,”active_indicator”:”Y”,”create_date”:”\/Date(1170892765197)\/”}, {“user_name”:”000002″,”active_indicator”:”Y”,”create_date”:”\/Date(1170892765197)\/”}]}

In the resulting data, the table name is the key to referencing the array of values. In this case we use ‘mydt’ as the key. In the success function on the client request you may also notice an outputDT function. This is a little helper function which takes a JSON Datatable and returns a the results in a table. This is very useful for debugging. Here is the client side code.

function outputDT(dataTable)
{
    var headers = [];
    var rows = [];

    headers.push("<tr>");
    for (var name in dataTable[0])
        headers.push("<td><b>"+name+"</b></td>");
    headers.push("</tr>");

    for (var row in dataTable)
    {
        rows.push("<tr>");
        for (var name in dataTable[row])
        {
            rows.push("<td>");
            rows.push(dataTable[row][name]);
            rows.push("</td>");
        }
        rows.push("</tr>");
    }            

    var top = "<table border='1'>";
    var bottom = "</table>";  

    return top + headers.join("") + rows.join("") + bottom;
}

So as you can see, its now very easy to return a Datatable or Dataset as a JSON object ready for use on the client.

Hope this is as useful for you as it is for me.

Cheers,

Schotime

jQuery Plugin for ASP.net Ajax (jMsAjax)

After my recent post on jQuery, JSON and dates in asp.net I decided that there must be a better solution so I set out writing my first jQuery plugin. And after a few hours I had it working to my delight.

It not only accepts a raw JSON object as input for method parameters, but safely parses and stringify’s the object using Crockford’s implementation (http://www.json.org/js.html). The syntax of the call doesn’t change if it is a “POST” or a “GET” as it is all handled inside the plugin. It also returns Dates without a problem.

I have add a Home page for the plugin at http://schotime.net/jMsAjax.aspx and also added it to the plugins pages on the jQuery website (http://plugins.jquery.com/project/jMsAjax).

Here is the basic syntax:

$.jmsajax({
    type: "POST",
    url: "jMsAjax.aspx",
    method: "getTime",
    data: { date_in: new Date() },
    success: function(data) {
        $("#div").html(String(data));
    }
});

You can find more information, a demo and the download at http://schotime.net/jMsAjax.aspx
Update: Just fixed the download page. Sorry for the inconvenience.

And at only 4kb + jQuery its significantly less size than MsAjax.

I hope this is as helpful to you as it is for me.

Schotime