<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Zach Hunter&#039;s Busy Life</title>
	<atom:link href="http://www.zachhunter.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zachhunter.com</link>
	<description>Random Brain Drool</description>
	<lastBuildDate>Fri, 18 May 2012 23:10:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>ASP.NET 4.0 WCF RESTful Services – Part 2</title>
		<link>http://www.zachhunter.com/2012/05/wcf-restful-services-part-2/</link>
		<comments>http://www.zachhunter.com/2012/05/wcf-restful-services-part-2/#comments</comments>
		<pubDate>Fri, 18 May 2012 22:39:09 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=605</guid>
		<description><![CDATA[In the first part, we got a .NET 4.0 WCF Service (file-extension less, yep no .SVC in your service call) setup and running, and I showed how to call a basic &#8220;GET&#8221; service using jQuery&#8217;s $.getJSON() method. Now, we are going to explore allow the different RESTful methods GET, POST, PUT, and DELETE. The steps [...]]]></description>
			<content:encoded><![CDATA[<p>In the first part, we got a .NET 4.0 WCF Service (file-extension less, yep no .SVC in your service call) setup and running, and I showed how to call a basic &#8220;GET&#8221; service using jQuery&#8217;s $.getJSON() method.  Now, we are going to explore allow the different RESTful methods GET, POST, PUT, and DELETE.  The steps below are designed to work with the project created in Part 1 and they focus on show basic CRUD style services you would use in a Ajax application.  Everything is being written with Visual Studio 2010 and .NET 4.0.</p>
<h4>RESTful Methods ( GET / POST / PUT / DELETE )</h4>
<p>Before we get going, it&#8217;s important to remember the following rules when building WCF Services.</p>
<ol style="margin-top:15px;">
<li>The UriTemplate can only use parameters of type string</li>
<li>Uri Templates can have many forms, here are a few examples:
<p><strong>Sample Uri Templates for .svc-less function calls</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        [WebGet(UriTemplate = &quot;Products/{name}&quot;)]
        public Product GetProduct(string name)
        // URL = &quot;/InventoryService/Products/ProductXYZ&quot;

        [WebGet(UriTemplate = &quot;Products/Product({name})&quot;)]
        public Product GetProduct(string name)
        // URL = &quot;/InventoryService/Products/Product(ProductXYZ)&quot;

        [WebGet(UriTemplate = &quot;Products/API.Service?Product={name}&quot;)]
        public Product GetProduct(string name)
        // URL = &quot;/InventoryService/Products/API.Service?Product=ProductXYZ&quot;
</pre>
</li>
<li>When passing multiple objects, you must make the following changes:
<p><strong>WCF Service (Sending 1 object vs 2 objects)</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        //  PASS 1 Object.

        [WebInvoke(UriTemplate = &quot;Products/API.Service?Product={productName}&quot;, Method = &quot;POST&quot;)]
        public string APIGet(string productName, Product product1)

        // Passing 2 Objects or more.
        // Added &quot;BodyStyle = WebMessageBodyStyle.WrappedRequest&quot;.

        [WebInvoke(UriTemplate = &quot;Products/API.Service?Product={productName}&quot;, Method = &quot;POST&quot;, BodyStyle = WebMessageBodyStyle.WrappedRequest )]
        public string APIGet(string productName, Product product1, Product product2)
</pre>
<p><strong>jQuery Ajax Call (Sending 1 object vs 2 objects)</strong></p>
<pre class="brush: jscript; title: ; notranslate">
            // Common Objects to use in examples below
            var Product1 = {};
            Product1.Name = 'Name1';
            Product1.Description = 'Desc1';
            Product1.Price = 1.0;
            Product1.Quantity = 1;
            Product1.IsDiscontinued = false;

            var Product2 = {};
            Product2.Name = 'Name2';
            Product2.Description = 'Desc2';
            Product2.Price = 2.0;
            Product2.Quantity = 2;
            Product2.IsDiscontinued = false;

            //  PASS 1 Object.
            $.ajax({
                type: 'POST',
                url: '/InventoryService/Products/API.Service?Product=ProductXYZ',
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                data: JSON.stringify(Product1),  // Here we are sending the 1 object, no wrapper.
                success: function (response)
                {
                    // Do Something
                }
            });

            // Passing 2 Objects or more.

            // Here we created a new jsonRequest object that wraps our 2 objects we want to send to our service.
            jsonRequest = { 'product1': Product1, 'product2': Product2 };

            $.ajax({
                type: 'POST',
                url: '/InventoryService/Products/API.Service?Product=ProductXYZ',
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                data: JSON.stringify(jsonRequest),  // Here we are sending a object that wraps our 2 product objects.
                success: function (response)
                {
                    // Do Something
                }
            });
</pre>
</li>
</ol>
<h4>GET / POST / PUT / DELETE WCF Services and their jQuery Ajax Calls</h4>
<h4>GET Method</h4>
<p><strong>Service</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        [WebGet(UriTemplate = &quot;Products/{name}&quot;)]
        [OperationContract]
        public Product GetProduct(string name)
        {
            // Get a Product
        }
</pre>
<p><strong>jQuery Call</strong></p>
<pre class="brush: jscript; title: ; notranslate">
                    var name = 'ProductXYZ';

                    $.ajax({
                        type: 'GET',
                        url: '/InventoryService/Products/' + name,
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: '',
                        success: function (response)
                        {
                            // Do Something
                        }
                    });

                    // Alternative to $.ajax for a GET request is using $.getJSON.
                    $.getJSON('/InventoryService/' + name, '', function (result) { // Do Something });
</pre>
<p>This is probably the simplest service call to issue, but the amazing jQuery team made the process even easier with the getJSON() call that wraps up a ajax() GET request.  Notice the svc-less call above, there&#8217;s no ugly &#8220;.svc&#8221; telling your consumers&#8230; Hay, I&#8217;m using WCF!!!</p>
<h4>POST Method</h4>
<p><strong>Service</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        [WebGet(UriTemplate = &quot;Products/{name}&quot;, Method = &quot;POST&quot;)]
        [OperationContract]
        public Product GetProduct(string name, Product product)
        {
            // Insert New Product
        }
</pre>
<p><strong>jQuery Call</strong></p>
<pre class="brush: jscript; title: ; notranslate">
                    var name = 'ProductXYZ';
                    var Product = {};
                    Product.Name = 'ProductXYZ';
                    Product.Description = 'Product XYZ Description';

                    $.ajax({
                        type: 'POST',
                        url: '/InventoryService/Products/' + name,
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: JSON.stringify(Product),
                        success: function (response)
                        {
                            // Do Something
                        }
                    });
</pre>
<p>This has always been my go to method for sending data to a service, but according to a few RESTful people this method is only supposed to be used for inserts.  I&#8217;m not really sure how &#8220;firm&#8221; this rule is, so I decided to do all Inserts and Updates with the POST method, since I almost always handle this in the same function call in my DAL.  In addition to posting my Object to the service, I also include the primary key (&#8220;PK&#8221;) in the service path so I can use the IIS logs to show who touched a specific record.</p>
<h4>PUT Method</h4>
<p><strong>Service</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        [WebInvoke(UriTemplate = &quot;Products/{name}&quot;, Method = &quot;PUT&quot;)]
        [OperationContract]
        public Product GetProduct(string name)
        {
            // Update Product
        }
</pre>
<p><strong>jQuery Call</strong></p>
<pre class="brush: jscript; title: ; notranslate">
                    var name = 'ProductXYZ';
                    var Product = {};
                    Product.Name = 'ProductXYZ';
                    Product.Description = 'Product XYZ Description';

                    $.ajax({
                        type: 'PUT',
                        url: '/InventoryService/Products/' + name,
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: JSON.stringify(Product),
                        success: function (response)
                        {
                            // Do Something
                        }
                    });
</pre>
<p>I don&#8217;t use this much, but when I do the calls look exactly the same as a POST except for the change in request type.</p>
<h4>DELETE Method</h4>
<p><strong>Service</strong></p>
<pre class="brush: csharp; title: ; notranslate">
        [WebGet(UriTemplate = &quot;Products/{name}&quot;, Method = &quot;DELETE&quot;)]
        [OperationContract]
        public bool GetProduct(string name)
        {
            // Delete Product
        }
</pre>
<p><strong>jQuery Call</strong></p>
<pre class="brush: jscript; title: ; notranslate">
                    var name = 'ProductXYZ';

                    $.ajax({
                        type: 'DELETE',
                        url: '/InventoryService/Products/' + name,
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        data: '',
                        success: function (response)
                        {
                            // Do Something
                        }
                    });
</pre>
<p>Since I always like &#8220;confirmation&#8221; when something has been done, I always return a boolean from my delete services.  This allows me to confirm something was able to be deleted, if you expect to have various failure states you might want to consider using a string return type to provide a detailed &#8220;error&#8221; message whey the request failed (e.g. &#8220;Successfully Deleted&#8221;, &#8220;You don&#8217;t have permission.&#8221;, &#8220;Product is associated with other orders.&#8221;).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2012/05/wcf-restful-services-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET 4.0 WCF RESTful Services &#8211; Part 1</title>
		<link>http://www.zachhunter.com/2012/05/asp-net-4-0-wcf-restful-service/</link>
		<comments>http://www.zachhunter.com/2012/05/asp-net-4-0-wcf-restful-service/#comments</comments>
		<pubDate>Fri, 11 May 2012 22:06:50 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=580</guid>
		<description><![CDATA[Details, details, details&#8230; I just spend a few days moving over to svc-less WCF services with a ASP.NET 4.0 web application, and boy was it fun&#8230; The overall setup is pretty easy, once you&#8217;ve painfully gone through the process &#8220;a few&#8221; times. Since this is something I&#8217;ll no be doing by default on all new [...]]]></description>
			<content:encoded><![CDATA[<p>Details, details, details&#8230; I just spend a few days moving over to svc-less WCF services with a ASP.NET 4.0 web application, and boy was it fun&#8230;  The overall setup is pretty easy, once you&#8217;ve painfully gone through the process &#8220;a few&#8221; times.  Since this is something I&#8217;ll no be doing by default on all new projects, I thought this would make a great write-up tutorial.  During my discovery and learning phase, I found a bunch of helpful blog posts but nothing was 100% and there was lots of those &#8220;important&#8221; bits missing.  Since most of my projects consume JSON, I plan to do a 4 part series on setting up a Web Application to support WCF services that will be called via jQuery.</p>
<p>Enough with the background, let&#8217;s start by creating a new &#8220;ASP.NET Web Application&#8221;.</p>
<p><a href="http://www.zachhunter.com/wp-content/uploads/RESTfulWCF_Image1.png" rel="lightbox[580]" title="Starting a ASP.NET Web Application"><img src="http://www.zachhunter.com/wp-content/uploads/RESTfulWCF_Image1-300x207.png" alt="What project to choose in VS 2010" title="Starting a ASP.NET Web Application" width="300" height="207" class="alignnone size-medium wp-image-589" /></a></p>
<ol>
<li>Remove everything inside the Scripts folder.</li>
<li>Right Click on Project, and choose &#8220;Manage NuGet Packages&#8230;&#8221;
<p>	Hopefully your familiar with NuGet, it&#8217;s a package manager  for Visual Studio and you can install it by going to Tools -> Extension Manager&#8230; -> Online Gallery -> Download &#8220;NuGet Package Manager&#8221;.  This is the most popular extension and it allows you to quickly add bits to your projects (e.g. <em>Install jQuery, and be notified when a new version is available.</em>).<br />
	<br/></p>
</li>
<li>Use search to install the following NuGet Packages.
<ul>
<li>jQuery </li>
<li>JSON-js json2</li>
</ul>
<p><a href="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_NuGet.png" rel="lightbox[580]" title="NuGet Installed Packages"><img src="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_NuGet-300x188.png" alt="Required NuGet Packages" title="NuGet Installed Packages" width="300" height="188" class="alignnone size-medium wp-image-625" /></a><br />
	<br/>
	</li>
<li>Edit your &#8220;site.master&#8221; to and include your new scripts:
<pre class="brush: xml; title: ; notranslate">
	   &lt;script src=&quot;Scripts/jquery-1.7.2.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	   &lt;script src=&quot;Scripts/jquery-ui-1.8.19.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	   &lt;script src=&quot;Scripts/jquery.validate.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	</pre>
</li>
<li>Also in the &#8220;site.master&#8221;, edit your asp:Menu to include 4 pages called Part1 &#8211; Part4:
<pre class="brush: xml; title: ; notranslate">
                &lt;asp:Menu ID=&quot;NavigationMenu&quot; runat=&quot;server&quot; CssClass=&quot;menu&quot; EnableViewState=&quot;false&quot; IncludeStyleBlock=&quot;false&quot; Orientation=&quot;Horizontal&quot;&gt;
                    &lt;Items&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/Default.aspx&quot; Text=&quot;Home&quot;/&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/Part1.aspx&quot; Text=&quot;Part 1&quot;/&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/Part2.aspx&quot; Text=&quot;Part 2&quot; /&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/Part3.aspx&quot; Text=&quot;Part 3&quot; /&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/Part3.aspx&quot; Text=&quot;Part 4&quot; /&gt;
                        &lt;asp:MenuItem NavigateUrl=&quot;~/About.aspx&quot; Text=&quot;About&quot; /&gt;
                    &lt;/Items&gt;
                &lt;/asp:Menu&gt;
	</pre>
<p>	** We are only going to use Part1.aspx right now, but I plan on 4 posts on this topic.<br/>
	</li>
<li>Add 4 new &#8220;Web Form using Master Page&#8221; to the project called <strong>Page1.aspx</strong>, <strong>Page2.aspx</strong>, <strong>Page3.aspx</strong>, <strong>Page4.aspx</strong>.<br/>** These will match the named used in the navigation menu in the site.master.<br/></li>
<li>Add a new folder to the root of the project called Service.</li>
<li>Add a new &#8220;AJAX-enabled WCF Service&#8221; to the Service folder called &#8220;InventoryService.svc&#8221;.
<ul>
<li>Note, this will add the following references to your project.
<pre class="brush: xml; title: ; notranslate">
	     System.Runtime.Serialization
	     System.ServiceModel
	     System.ServiceModel.Web
	</pre>
</li>
<li>It will also add the following lines to your Web.config
<pre class="brush: xml; title: ; notranslate">
	  &lt;system.webServer&gt;
		 &lt;modules runAllManagedModulesForAllRequests=&quot;true&quot;/&gt;
	  &lt;/system.webServer&gt;

	  &lt;system.serviceModel&gt;
		&lt;behaviors&gt;
		  &lt;endpointBehaviors&gt;
			&lt;behavior name=&quot;RESTfulWCF.Service.Service1AspNetAjaxBehavior&quot;&gt;
			  &lt;enableWebScript /&gt;
			&lt;/behavior&gt;
		  &lt;/endpointBehaviors&gt;
		&lt;/behaviors&gt;
		&lt;serviceHostingEnvironment aspNetCompatibilityEnabled=&quot;true&quot;
		  multipleSiteBindingsEnabled=&quot;true&quot; /&gt;
		&lt;services&gt;
		  &lt;service name=&quot;RESTfulWCF.Service.Service1&quot;&gt;
			&lt;endpoint address=&quot;&quot; behaviorConfiguration=&quot;RESTfulWCF.Service.Service1AspNetAjaxBehavior&quot;
			  binding=&quot;webHttpBinding&quot; contract=&quot;RESTfulWCF.Service.Service1&quot; /&gt;
		  &lt;/service&gt;
		&lt;/services&gt;
	  &lt;/system.serviceModel&gt;
	</pre>
</li>
<li>Change the &#8220;system.serviceModel&#8221; section of your web.config to the following.
<pre class="brush: xml; title: ; notranslate">
	    &lt;system.serviceModel&gt;
	        &lt;serviceHostingEnvironment aspNetCompatibilityEnabled=&quot;true&quot;/&gt;
	        &lt;standardEndpoints&gt;
	            &lt;webHttpEndpoint&gt;
	                &lt;standardEndpoint name=&quot;&quot; helpEnabled=&quot;true&quot; automaticFormatSelectionEnabled=&quot;true&quot;/&gt;
	            &lt;/webHttpEndpoint&gt;
	        &lt;/standardEndpoints&gt;
	    &lt;/system.serviceModel&gt;
	</pre>
<h3>Web.Config Key Points</h3>
<pre class="brush: jscript; title: ; notranslate">
	// This allows your services to run under your sites app pool, giving access
	// to your HttpContext.
	aspNetCompatibilityEnabled=&quot;true&quot;
	</pre>
<pre class="brush: jscript; title: ; notranslate">
	// See below, this allows you to type &lt;service&gt;/help to get information on your service
	helpEnabled=&quot;true&quot;
	</pre>
<pre class="brush: jscript; title: ; notranslate">
	// This is AWESOME, this tag allows your service to respond in any format you
	// specify in your request (e.g. XML, JSON, etc...).
	automaticFormatSelectionEnabled=&quot;true&quot;
	</pre>
<p><br/><br />
** One last item to note, every time you add an additional AJAX service, it will edit your web.config and put back in the bad configuration.  I strongly suggest you make a backup of your web.config, incase you run into problems in the future!!!
	</li>
<li>Manually add a project reference to <strong>System.ServiceModel.Activation</strong>.</li>
</ul>
</li>
<li>At this point, your project in solution explorer should look like this:
<p><a href="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_3.png" rel="lightbox[580]" title="Solution Explorer"><img src="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_3-136x300.png" alt="Items Included in Solution Explorer" title="Solution Explorer" width="136" height="300" class="alignnone size-medium wp-image-626" /></a>
	</li>
<li>Now, open InventoryService.svc and make the following changes:
<ul>
<li>Erase everything and add the following C# code:
<pre class="brush: csharp; title: ; notranslate">
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace RESTfulWCF.Service
{
    [ServiceContract(Namespace = &quot;&quot;)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class InventoryService
    {
        [WebGet(UriTemplate = &quot;Part1&quot;)]
        [OperationContract]
        public string Part1GetRequest()
        {
            return &quot;I did work&quot;;
        }
    }
}
	</pre>
<p>In the code above, we are mapping the function &#8220;Part1GetRequest&#8221; to the name &#8220;Part1&#8243;.  This will allow us to call the service with the following syntax &#8220;/InventoryService/Part1&#8243; using a GET request.<br/></p>
</li>
</ul>
</li>
<li>Add a route to call the service without referencing a &#8220;.svc&#8221; file.<br />
	<em>Open Global.asax and replace your Applicaiton_Start with the following.</em></p>
<pre class="brush: csharp; title: ; notranslate">
        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup
            RouteTable.Routes.Add(new ServiceRoute(&quot;InventoryService&quot;, new WebServiceHostFactory(), typeof(Service.InventoryService)));
        }
	</pre>
</li>
<li>Now we are ready to create a jQuery test call, open &#8220;Page1.aspx&#8221; in Source View:
<p>	<em>Erase everything and add the following HTML code</em></p>
<pre class="brush: jscript; title: ; notranslate">
&lt;%@ Page Title=&quot;&quot; Language=&quot;C#&quot; MasterPageFile=&quot;~/Site.Master&quot; AutoEventWireup=&quot;true&quot; CodeBehind=&quot;Part1.aspx.cs&quot; Inherits=&quot;RESTfulWCF.Part1&quot; %&gt;
&lt;asp:Content ID=&quot;Content1&quot; ContentPlaceHolderID=&quot;HeadContent&quot; runat=&quot;server&quot;&gt;
&lt;/asp:Content&gt;
&lt;asp:Content ID=&quot;Content2&quot; ContentPlaceHolderID=&quot;MainContent&quot; runat=&quot;server&quot;&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        $(document).ready(function ()
        {
            $('#doWork').click(function ()
            {
                $.getJSON('/InventoryService/Part1', '', function (result) { alert(result); });
            });
        });
    &lt;/script&gt;
    &lt;h2&gt;
        ASP.NET 4.0 WCF RESTful Demo - Part 1
    &lt;/h2&gt;
    &lt;p&gt;
        &lt;input type=&quot;button&quot; id=&quot;doWork&quot; value=&quot;Issue GET Request&quot; /&gt;
    &lt;/p&gt;
&lt;/asp:Content&gt;
	</pre>
<p>We are able to use the <strong>$.getJSON()</strong> jQuery function because we applied the &#8220;WebGet&#8221; attribute to the WCF function &#8220;Part1GetRequest()&#8221;.<br/></p>
</li>
<li>Launch the application and navigate to &#8220;Page 1&#8243;.  Click on the &#8220;Issue GET Request&#8221; button and you should see the followign results:
<p><a href="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_jQueryTest.png" rel="lightbox[580]" title="jQuery RESTful Service Call"><img src="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_jQueryTest-300x207.png" alt="jQuery Demo Results" title="jQuery RESTful Service Call" width="300" height="207" class="alignnone size-medium wp-image-627" /></a></p>
</li>
<li>To get a list of all the functions your service offers, pass the &#8220;/help&#8221; parameter to your service.
<p><a href="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_Help.png" rel="lightbox[580]" title="WCF RESTful Service Service List"><img src="http://www.zachhunter.com/wp-content/uploads/RESTful_Demo_Part1_Help-300x84.png" alt="List of all WCF Service Accessible by Passing /help to the Service" title="WCF RESTful Service Service List" width="300" height="84" class="alignnone size-medium wp-image-628" /></a></p>
</li>
</ol>
<p>As noted, here is the project I built above following all the steps one-by-one.<br />
&nbsp;&nbsp;&nbsp;&nbsp;>>&nbsp;<a href='http://www.zachhunter.com/wp-content/uploads/RESTfulWCF.zip'>ASP.NET 4.0 RESTful Web Application Project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2012/05/asp-net-4-0-wcf-restful-service/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making an Editiable Table (CRUD) with jQuery</title>
		<link>http://www.zachhunter.com/2012/04/crud-my-table-rows/</link>
		<comments>http://www.zachhunter.com/2012/04/crud-my-table-rows/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 21:56:33 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=505</guid>
		<description><![CDATA[I&#8217;ve been working on a form that needs to support a unknown number of rows, that the user will either enter 1-by-1 or bulk upload. Adding a few rows to a table is pretty easy in HTML, but as the rows increase page starts to slow down and the UI can become overwhelming with HTML [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a form that needs to support a unknown number of rows, that the user will either enter 1-by-1 or bulk upload.  Adding a few rows to a table is pretty easy in HTML, but as the rows increase page starts to slow down and the UI can become overwhelming with HTML input controls.  I decided to test a few concepts to determine what would best fit my form, I started with doing rows of input controls, followed by trying to use jqGrid plug-in.  I really liked jqGrid, but as I tried to get everything working I found myself having to &#8220;work around&#8221; lots of issues (read forum, apply fix, something else breaks, repeat), so I gave up after making the solution working 90% in jqGrid because the code was already a lot more complex than what I wanted.  In the end, I decided that building my own table editor that supported CRUD with jQuery.  In addition to following the KISS rule, I also had a list of goals I wanted to include.</p>
<h2>Solution Goals</h2>
<ol style="margin-left: 20px;">
<li>Allow users to add 1 to 2,000 rows</li>
<li>Keep the page quick when working with 500+ rows</li>
<li>Make all edits in memory</li>
<li>Create a Undo/Cancel button to undo a edit</li>
<li><strong>Capture dynamic HTML TABLE row contents for use in a server side postback</strong></li>
<li>(Not in DEMO) Enable validation for rows in Edit Mode</li>
<li>(Not in DEMO) Enable default values for manually added rows</li>
</ol>
<p><em>All of the goals above were in the final solution and 95% of the work is done client-side in ~300 lines of jQuery &#038; JavaScript code.  I choose to use jQuery templates for the rows, since it offers a simple model for merging data/HTML along with some advanced features to perform logic in how elements are rendered (e.g. If my Cross object has a Status set, it will display an alert icon on the row and notify the user something in wrong).  Since most of these other features were case specific, I left them out of the demo to focus on doing the basic CRUD in HTML and how I got the dynamic rows back to ASP.NET</em></p>
<h2>Final Product</h2>
<p><a href="http://www.zachhunter.com/wp-content/uploads/HtmlTableEditModeActive.png" rel="lightbox[505]" title="Dynamic HTML Table in Edit Mode"><img class="alignnone size-full wp-image-515" title="Dynamic HTML Table in Edit Mode" src="http://www.zachhunter.com/wp-content/uploads/HtmlTableEditModeActive.png" alt="" width="847" height="149" /></a></p>
<p><em>My solution was designed to leverage ASP.NET, but all of the code below is 100% HTML.  You can take this code and apply it to any table and choose to leverage any server technology you want.  Part of step 5 is ASP.NET specific, but this shows a neat trick for getting the HTML table rows back to the server so you can access them in a traditional ASP.NET postback event.</em></p>
<h3>Step 1: Prerequisites (Accessible via CDN)</h3>
<ol style="margin-left: 20px;">
<li>jQuery</li>
<li>jQuery tmpl plug-in</li>
<li>JSON.org library</li>
</ol>
<pre class="brush: xml; title: ; notranslate">
    &lt;!-- jQuery on GOOGLE CDN --&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js&quot;&gt;&lt;/script&gt;
    &lt;!-- JSON.org on CDNJS CDN --&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js&quot;&gt;&lt;/script&gt;
    &lt;!-- jQuery tmpl() plug-in on ASPNET CDN --&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js&quot;&gt;&lt;/script&gt;
</pre>
<h3>Step 2: HTML Layout</h3>
<pre class="brush: xml; title: ; notranslate">
&lt;body&gt;
    &lt;h1&gt;
        CRUD My Table&lt;/h1&gt;
    &lt;!-- Table where we will perform CRUD operations, data loaded via jQuery tmpl() --&gt;
    &lt;table id=&quot;CRUDthisTable&quot; class=&quot;mediumTable&quot;&gt;
        &lt;thead&gt;
            &lt;tr class=&quot;rowHeader&quot;&gt;
                &lt;th&gt;&lt;/th&gt;
                &lt;th&gt;Change Type &lt;/th&gt;
                &lt;th&gt;Update Type &lt;/th&gt;
                &lt;th&gt;Customer Part &lt;/th&gt;
                &lt;th&gt;ROHM Part &lt;/th&gt;
                &lt;th&gt;Rank Start &lt;/th&gt;
                &lt;th&gt;Rank End &lt;/th&gt;
                &lt;th&gt;Price &lt;/th&gt;
                &lt;th&gt;UOM &lt;/th&gt;
                &lt;th&gt;Apply Date &lt;/th&gt;
                &lt;th&gt;Remarks &lt;/th&gt;
            &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;
    &lt;!-- jQuery tmpl() Templates --&gt;
    &lt;!-- Edit Rows --&gt;
    &lt;script id=&quot;editRowTemplate&quot; type=&quot;text/x-jquery-tmpl&quot;&gt;
        &lt;tr class=&quot;editRow&quot;&gt;
            &lt;td&gt;
                &lt;span id=&quot;cancel&quot; name=&quot;cancel&quot; tooltip=&quot;Cancel&quot; class=&quot;ui-icon ui-icon-close CancelRow&quot;&gt;Cancel&lt;/span&gt;
                &lt;span id=&quot;save&quot; name=&quot;save&quot; tooltip=&quot;Save&quot; class=&quot;ui-icon ui-icon-disk SaveRow&quot;&gt;Save&lt;/span&gt;
            &lt;/td&gt;
            &lt;td&gt;
                &lt;select id=&quot;field1&quot; name=&quot;field1&quot; class=&quot;changeType&quot;&gt;
                    &lt;option&gt;&lt;/option&gt;
                    &lt;option&gt;All&lt;/option&gt;
                    &lt;option&gt;Part&lt;/option&gt;
                    &lt;option&gt;Price&lt;/option&gt;
                &lt;/select&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;select id=&quot;field2&quot; name=&quot;field2&quot; class=&quot;updateType&quot;&gt;
                    &lt;option&gt;&lt;/option&gt;
                    &lt;option&gt;Add&lt;/option&gt;
                    &lt;option&gt;Update&lt;/option&gt;
                    &lt;option&gt;Delete&lt;/option&gt;
                &lt;/select&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field3&quot; name=&quot;field3&quot; class=&quot;customerPart required part&quot; value=&quot;${CustomerPart}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field4&quot; name=&quot;field4&quot; class=&quot;rohmPart validROHMpart part&quot; value=&quot;${ROHMPart}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field5&quot; name=&quot;field5&quot; class=&quot;rankStart rank&quot; value=&quot;${RankStart}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field6&quot; name=&quot;field6&quot; class=&quot;rankEnd rank&quot; value=&quot;${RankEnd}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field7&quot; name=&quot;field7&quot; class=&quot;price required number&quot; value=&quot;${Price}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;select  id=&quot;field8&quot; name=&quot;field8&quot; class=&quot;uomType required&quot;&gt;
                    &lt;option&gt;&lt;/option&gt;
                    &lt;option&gt;1&lt;/option&gt;
                    &lt;option&gt;1000&lt;/option&gt;
                &lt;/select&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field9&quot; name=&quot;field9&quot; class=&quot;applyDate required date&quot; value=&quot;${ApplyDate}&quot; /&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; id=&quot;field10&quot; name=&quot;field10&quot;class=&quot;remarks&quot; value=&quot;${Remarks}&quot; /&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/script&gt;
    &lt;!-- View Rows --&gt;
    &lt;script id=&quot;viewRowTemplate&quot; type=&quot;text/x-jquery-tmpl&quot;&gt;
        &lt;tr&gt;
            &lt;td style=&quot;width:50px;&quot;&gt;
                &lt;span id=&quot;edit&quot; name=&quot;edit&quot; title=&quot;Edit&quot; class=&quot;ui-icon ui-icon-pencil EditRow&quot;&gt;Edit&lt;/span&gt;
                &lt;span id=&quot;delete&quot; name=&quot;delete&quot; title=&quot;Delete&quot; class=&quot;ui-icon ui-icon-trash DeleteRow&quot;&gt;Delete&lt;/span&gt;
            &lt;/td&gt;
            &lt;td style=&quot;width:120px;&quot;&gt;${ChangeType}&lt;/td&gt;
            &lt;td style=&quot;width:120px;&quot;&gt;${UpdateType}&lt;/td&gt;
            &lt;td&gt;${CustomerPart}&lt;/td&gt;
            &lt;td&gt;${ROHMPart}&lt;/td&gt;
            &lt;td style=&quot;width:45px;&quot;&gt;${RankStart}&lt;/td&gt;
            &lt;td style=&quot;width:45px;&quot;&gt;${RankEnd}&lt;/td&gt;
            &lt;td&gt;${Price}&lt;/td&gt;
            &lt;td style=&quot;width:64px;&quot;&gt;${UOM}&lt;/td&gt;
            &lt;!-- **** TIP: Here we use a function to format the date mm/dd/yyyy --&gt;
            &lt;td style=&quot;width:80px;&quot;&gt;${FormatDate(ApplyDate)}&lt;/td&gt;
            &lt;td&gt;${Remarks}&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/script&gt;
&lt;/body&gt;
</pre>
<h3>Step 3: Example Loading Data ( NO CRUD Functionality )</h3>
<pre class="brush: jscript; title: ; notranslate">
        // Helper Function to Format Date in View Row
        function FormatDate(date)
        {
            return date.getMonth() + 1 + &quot;/&quot; + date.getDate() + &quot;/&quot; + date.getFullYear();
        }

        // After the DOM has loaded, take the sample data and inject it into the table using the View Row template.
        $(document).ready(function ()
        {
            // Sample Data - Could be returned via AJAX or could be manual rows added to the TABLE
            var crosses = [
            { &quot;ChangeType&quot;: &quot;All&quot;, &quot;UpdateType&quot;: &quot;Add&quot;, &quot;CustomerPart&quot;: &quot;1SS355TE-17&quot;, &quot;ROHMPart&quot;: &quot;1SS355TE-17&quot;, &quot;RankStart&quot;: &quot;&quot;, &quot;RankEnd&quot;: &quot;&quot;, &quot;Price&quot;: 0.0151, &quot;UOM&quot;: 1, &quot;ApplyDate&quot;: new Date(1335337200000), &quot;Remarks&quot;: &quot;&quot;, &quot;Status&quot;: null, &quot;StatusNote&quot;: null },
            { &quot;ChangeType&quot;: &quot;All&quot;, &quot;UpdateType&quot;: &quot;Add&quot;, &quot;CustomerPart&quot;: &quot;RB160M-60TR&quot;, &quot;ROHMPart&quot;: &quot;RB160M-60TR&quot;, &quot;RankStart&quot;: &quot;&quot;, &quot;RankEnd&quot;: &quot;&quot;, &quot;Price&quot;: 0.0605, &quot;UOM&quot;: 1, &quot;ApplyDate&quot;: new Date(1335337200000), &quot;Remarks&quot;: &quot;&quot;, &quot;Status&quot;: null, &quot;StatusNote&quot;: null },
            { &quot;ChangeType&quot;: &quot;All&quot;, &quot;UpdateType&quot;: &quot;Add&quot;, &quot;CustomerPart&quot;: &quot;RR264M-400TR&quot;, &quot;ROHMPart&quot;: &quot;RR264M-400TR&quot;, &quot;RankStart&quot;: &quot;&quot;, &quot;RankEnd&quot;: &quot;&quot;, &quot;Price&quot;: 0.031, &quot;UOM&quot;: 1, &quot;ApplyDate&quot;: new Date(1335337200000), &quot;Remarks&quot;: &quot;&quot;, &quot;Status&quot;: null, &quot;StatusNote&quot;: null },
            { &quot;ChangeType&quot;: &quot;All&quot;, &quot;UpdateType&quot;: &quot;Add&quot;, &quot;CustomerPart&quot;: &quot;1SR154-400TE25&quot;, &quot;ROHMPart&quot;: &quot;1SR154-400TE25&quot;, &quot;RankStart&quot;: &quot;&quot;, &quot;RankEnd&quot;: &quot;&quot;, &quot;Price&quot;: 0.0309, &quot;UOM&quot;: 1, &quot;ApplyDate&quot;: new Date(1335337200000), &quot;Remarks&quot;: &quot;&quot;, &quot;Status&quot;: null, &quot;StatusNote&quot;: null },
            { &quot;ChangeType&quot;: &quot;All&quot;, &quot;UpdateType&quot;: &quot;Add&quot;, &quot;CustomerPart&quot;: &quot;RF071M2STR&quot;, &quot;ROHMPart&quot;: &quot;RF071M2STR&quot;, &quot;RankStart&quot;: &quot;&quot;, &quot;RankEnd&quot;: &quot;&quot;, &quot;Price&quot;: 0.0638, &quot;UOM&quot;: 1, &quot;ApplyDate&quot;: new Date(1335337200000), &quot;Remarks&quot;: &quot;&quot;, &quot;Status&quot;: null, &quot;StatusNote&quot;: null}];

            if (crosses) {
                $(&quot;#viewRowTemplate&quot;).tmpl(crosses).appendTo(&quot;#CRUDthisTable&quot;);
            }
        });
</pre>
<h2>CRUD Table &#8211; Data Loaded no CRUD Functions Activated</h2>
<p><a href="http://www.zachhunter.com/wp-content/uploads/CRUDTableBasic.png" rel="lightbox[505]" title="CRUD Table Basic - 100% HTML Only"><img class="alignnone size-large wp-image-542" title="CRUD Table Basic - 100% HTML Only" src="http://www.zachhunter.com/wp-content/uploads/CRUDTableBasic-1024x154.png" alt="Demo of 100% CRUD Table in HTML ( no persistance or CRUD features activated )" width="1024" height="154" /></a></p>
<p><em>** As you can see, I&#8217;m not using images links similar to the final product since I was aiming for simplicity.  If you want to use images, I suggest you use the jQuery UI icons as I did in the final product, they can easily be added to a span by adding two class values (e.g. <strong>class=&#8221;ui-icon ui-icon-close&#8221;</strong>).</em></p>
<h3>Step 4: Enable CRUD</h3>
<pre class="brush: jscript; title: ; notranslate">
        // Global Parameters
        var rowNum = 1;
        var rowRemovedNum;
        var rowRemovedContents;

        // Read a row in Edit Mode into a Cross Object
        function GetEditRowObject()
        {
            var row = $('#CRUDthisTable tbody tr.editRow');

            var cross = {};

            cross.ChangeType = row.find('.changeType').val();
            cross.UpdateType = row.find('.updateType').val();
            cross.CustomerPart = row.find('.customerPart').val();
            cross.ROHMPart = row.find('.rohmPart').val();
            cross.RankStart = row.find('.rankStart').val();
            cross.RankEnd = row.find('.rankEnd').val();
            cross.Price = row.find('.price').val();
            cross.UOM = row.find('.uomType').val();
            var dateString = row.find('.applyDate').val();
            cross.ApplyDate = new Date(dateString);
            cross.Remarks = row.find('.remarks').val();

            return cross;
        }

        // Read a row in View Mode into a Cross Object
        function GetViewRowObject(rowNum)
        {
            var row = $('#CRUDthisTable tbody tr').eq(rowNum);

            var cross = {};

            cross.ChangeType = row.find('td:eq(1)').text();
            cross.UpdateType = row.find('td:eq(2)').text();
            cross.CustomerPart = row.find('td:eq(3)').text();
            cross.ROHMPart = row.find('td:eq(4)').text();
            cross.RankStart = row.find('td:eq(5)').text();
            cross.RankEnd = row.find('td:eq(6)').text();
            cross.Price = row.find('td:eq(7)').text();
            cross.UOM = row.find('td:eq(8)').text();
            cross.ApplyDate = row.find('td:eq(9)').text();
            cross.Remarks = row.find('td:eq(10)').text();

            return cross;
        }

        // Read all rows into Cross Object Array
        function GetAllViewRowsAsCrossObjects()
        {
            var crossTableRows = [];

            $('#CRUDthisTable tbody tr').each(function (index, value)
            {
                var row = GetViewRowObject(index);
                crossTableRows.push(row);
            });

            return crossTableRows;
        }

        // Check if any rows are in Edit Mode
        function IsExistingRowInEditMode()
        {
            var rowsInEditMode = $('#CRUDthisTable tbody tr.editRow').length;

            if (rowsInEditMode &gt; 0) {
                alert('You have a row in Edit mode, please save or cancel the row changes before you continue.');
                return true;
            }

            return false;
        }

        // After the DOM has loaded, bind the CRUD events
        $(document).ready(function ()
            // Events
            $('.AddRow').click(function ()
            {
                if (IsExistingRowInEditMode())
                    return;

                rowRemovedNum = 0;
                rowRemovedContents = null;

                var data = { data: 1 };
                var output = $(&quot;#editRowTemplate&quot;).tmpl(data).html()

                $('#CRUDthisTable tbody').prepend('&lt;tr class=&quot;editRow&quot;&gt;' + output + '&lt;/tr&gt;');
                var $rowEdit = $('#CRUDthisTable tbody tr.editRow');

                $('#CRUDthisTable tbody tr:first')[0].scrollIntoView();
            });

            $('.EditRow').live('click', function (e)
            {
                if (IsExistingRowInEditMode())
                    return;

                var row = $(this).parent().parent().parent().children().index($(this).parent().parent());

                var data = GetViewRowObject(row);

                var output = $(&quot;#editRowTemplate&quot;).tmpl(data).html()

                rowRemovedNum = row;
                rowRemovedContents = $('#CRUDthisTable tbody tr').eq(row).html();

                $('#CRUDthisTable tbody tr').eq(row).after('&lt;tr class=&quot;editRow&quot;&gt;' + output + '&lt;/tr&gt;');

                var $editRow = $('#CRUDthisTable tbody tr.editRow');

                var changeType = $editRow.find('.changeType');
                $(changeType).val(data.ChangeType);

                var updateType = $editRow.find('.updateType');
                $(updateType).val(data.UpdateType);

                var uomType = $editRow.find('.uomType');
                $(uomType).val(data.UOM);

                $('#CRUDthisTable tbody tr').eq(row).remove();
            });

            $('.SaveRow').live('click', function (e)
            {
                var savedData = GetEditRowObject();

                var row = $(this).parent().parent().parent().children().index($(this).parent().parent());

                var output = $(&quot;#viewRowTemplate&quot;).tmpl(savedData).html();

                $('#CRUDthisTable tbody tr').eq(row).remove();

                var tableRows = $('#CRUDthisTable tbody tr').length;

                if (tableRows == 0 || row == 0) {
                    $('#CRUDthisTable tbody').prepend('&lt;tr&gt;' + output + '&lt;/tr&gt;');
                }
                else {
                    $('#CRUDthisTable tbody tr').eq(row).before('&lt;tr&gt;' + output + '&lt;/tr&gt;');
                }
            });

            $('.CancelRow').live('click', function (e)
            {
                var row = $(this).parent().parent().parent().children().index($(this).parent().parent());

                $('#CRUDthisTable tbody tr').eq(row).remove();

                if (rowRemovedContents)
                    $('#CRUDthisTable tbody tr').eq(row).before('&lt;tr&gt;' + rowRemovedContents + '&lt;/tr&gt;');

                rowRemovedContents = null;
            });

            $('.DeleteRow').live('click', function (e)
            {
                e.preventDefault;
                $(this).parent().parent().remove();
            });
        });
</pre>
<p><a href="http://www.zachhunter.com/wp-content/uploads/CRUDTableBasicWithAdd.png" rel="lightbox[505]" title="CRUD Table with All Features Activated"><img class="alignnone size-large wp-image-545" title="CRUD Table with All Features Activated" src="http://www.zachhunter.com/wp-content/uploads/CRUDTableBasicWithAdd-1024x197.png" alt="Table is shows the results of clicking the Add New Row in the Table Footer" width="1024" height="197" /></a></p>
<h3>Step 5: Ajax POST Table Contents to the Server (before button event)</h3>
<p>There is a ton of ways to do this, but my goal was to allow users to edit the table and when they were all done with all their edits they could hit &#8220;Save&#8221; and everything would then be written to the DB.  Since ASP.NET doesn&#8217;t give you access to dynamic table rows, I bound a AJAX post event to the &#8220;Save&#8221; button that sends the table contents to the server, stores in cache, and then uses the cache in the traditional postback &#8220;Save&#8221; event.</p>
<pre class="brush: jscript; title: ; notranslate">
        // After the DOM has loaded, bind the ASP.NET save button
        $(document).ready(function ()
            $('#&lt;%= btnSave.ClientID %&gt;').click(function (e) {
                return PostTable();
            });
        }

        // Post all rows to the server and put into Cache
        function PostTable()
        {
            // Normally I'll get the ID from the QueryString, but it could also be grabbed from a hidden element in the form.
            var crossId = 1;
            var jsonRequest = { crosses: GetAllViewRowsAsCrossObjects(), crossId: crossId };

            $.ajax({
                type: 'POST',
                url: 'Demo.aspx/CacheTable',
                data: JSON.stringify(jsonRequest),
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                success: function (data, text)
                {
                    return true;
                },
                error: function (request, status, error)
                {
                    return false;
                }
            });
        }
</pre>
<p><strong>Important Note:</strong> If you want to access a page method via jQuery $.ajax(), then you must make the function static and pass the case sensitive parameters with the expected data type(s) in the ajax call.</p>
<pre class="brush: csharp; title: ; notranslate">
    public partial class Demo: System.Web.UI.Page
    {
        private static string _cacheKey = &quot;CacheTable_&quot; + HttpContext.Current.User.Identity.Name;

        [WebMethod]
        public static void CacheTable(List&lt;Cross&gt; crosses, int crossId)
        {
            if (crosses != null &amp;&amp; crosses.Count &gt; 0)
            {
                HttpContext.Current.Cache.Remove(_cacheKey);
                HttpContext.Current.Cache.Insert(_cacheKey, crosses, null, DateTime.Now.AddSeconds(3600), Cache.NoSlidingExpiration);
            }
        }
    }

    // Custom Data Transfer Object (DTO)
    public class Cross
    {
        public string ChangeType { get; set; }
        public string UpdateType { get; set; }
        public string CustomerPart { get; set; }
        public string ROHMPart { get; set; }
        public string RankStart { get; set; }
        public string RankEnd { get; set; }
        public double Price { get; set; }
        public int UOM { get; set; }
        public DateTime ApplyDate { get; set; }
        public string Remarks { get; set; }
        public string Status { get; set; }
        public string StatusNote { get; set; }
    }
</pre>
<p><a href='http://www.zachhunter.com/wp-content/uploads/CRUDmyTable.zip'>Working Demo of using jQuery to allow CRUD edits to a HTML TABLE.</a></p>
<p><strong>ASP.NET Note</strong> <em>**If you run into issues on the amount of rows you can postback to the server in ASP.NET via AJAX &#038; JSON, you&#8217;ll need to edit your &#8220;maxJsonLength&#8221; in your web.config.</em></p>
<pre class="brush: xml; title: ; notranslate">
    &lt;system.web.extensions&gt;
        &lt;scripting&gt;
            &lt;webServices&gt;
                &lt;jsonSerialization maxJsonLength=&quot;2097152&quot;/&gt;
            &lt;/webServices&gt;
        &lt;/scripting&gt;
    &lt;/system.web.extensions&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2012/04/crud-my-table-rows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Password Generator and Callsign Spelling with C#</title>
		<link>http://www.zachhunter.com/2011/06/password-and-callsign-spelling-generator/</link>
		<comments>http://www.zachhunter.com/2011/06/password-and-callsign-spelling-generator/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 20:08:41 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=483</guid>
		<description><![CDATA[If you need help building a random password, you should check out pctools.com random password generator. It&#8217;s great, it gives you a lot of options and you can have it generate a list of 50 passwords with their callsign spellings in seconds. I&#8217;ve found the callsign spelling to be very helpful for remembering and recognizing [...]]]></description>
			<content:encoded><![CDATA[<p>If you need help building a random password, you should check out <a href="http://www.pctools.com/guides/password/">pctools.com</a> random password generator.  It&#8217;s great, it gives you a lot of options and you can have it generate a list of 50 passwords with their callsign spellings in seconds.  I&#8217;ve found the callsign spelling to be very helpful for remembering and recognizing all the characters in a new password I generate.  I liked this solution so much, I decided port this concept over to C# with a set of helpers.  This can be used anywhere you want to generate a password, I am currently using it in a ASP.NET LOB app to suggest and show better passwords options.</p>
<p><strong>Generating Random Passwords</strong></p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;

public static class StringHelper
{
    // Shared Static Random Generator
    private static readonly Random CommonRandom = new Random();

    public static string GenerateRandomPassword(int passwordLength, bool canRepeatCharacters = false)
    {
        char[] chars = &quot;$%#@!*abcdefghijklmnopqrstuvwxyz1234567890?;:ABCDEFGHIJKLMNOPQRSTUVWXYZ^&amp;&quot;.ToCharArray();

        string randomPassword = string.Empty;

        for (int l = 0; l &lt; passwordLength; l++)
        {
            int x = CommonRandom.Next(1, chars.Length);

            if (canRepeatCharacters || !randomPassword.ToCharArray().Any(ch =&gt; ch == chars[x]))
                randomPassword += chars[x].ToString();
            else
                l--;
        }

        return randomPassword;
    }

    public static List&lt;string&gt; GenerateRandomPasswords(int quantity, int passwordLength = 8)
    {
        List&lt;string&gt; passwords = new List&lt;string&gt;();

        for (int i = 0; i &lt; quantity; i++)
        {
            passwords.Add(GenerateRandomPassword(passwordLength));
        }

        return passwords;
    }
}
</pre>
<p>There are a few options on the generator, like not repeating a character and configuring the password length.  In addition to the main method, I also have a helper that also returns a list of multiple passwords, to return in a list to give your users options.</p>
<p>Important note, Random() is not very random when your making quick consecutive calls.  If you want to call Random() in a loop, you should move your instance of the Random() class to the outside to prevent duplicate seeds, which will result in duplicate passwords.</p>
<pre class="brush: csharp; title: ; notranslate">
    public static string GetCallsignSpelling(string password)
    {
        if (string.IsNullOrEmpty(password))
            return string.Empty;

        Dictionary&lt;char, string&gt; callsigns = new Dictionary&lt;char, string&gt;()
            {
                {'$',&quot;Dollar Symbol&quot;},
                {'%',&quot;Percent Symbol&quot;},
                {'#',&quot;Number Symbol&quot;},
                {'@',&quot;At Symbol&quot;},
                {'!',&quot;Exclamation Symbol&quot;},
                {'*',&quot;Asterisk Symbol&quot;},
                {'a',&quot;alpha&quot;},
                {'b',&quot;bravo&quot;},
                {'c',&quot;charlie&quot;},
                {'d',&quot;delta&quot;},
                {'e',&quot;echo&quot;},
                {'f',&quot;foxtrot&quot;},
                {'g',&quot;golf&quot;},
                {'h',&quot;hotel&quot;},
                {'i',&quot;india&quot;},
                {'j',&quot;juliet&quot;},
                {'k',&quot;kilo&quot;},
                {'l',&quot;lima&quot;},
                {'m',&quot;mike&quot;},
                {'n',&quot;november&quot;},
                {'o',&quot;oscar&quot;},
                {'p',&quot;papa&quot;},
                {'q',&quot;quebec&quot;},
                {'r',&quot;romeo&quot;},
                {'s',&quot;sierra&quot;},
                {'t',&quot;tango&quot;},
                {'u',&quot;uniform&quot;},
                {'v',&quot;victor&quot;},
                {'w',&quot;whiskey&quot;},
                {'x',&quot;xray&quot;},
                {'y',&quot;yankee&quot;},
                {'z',&quot;zulu&quot;},
                {'1',&quot;One&quot;},
                {'2',&quot;Two&quot;},
                {'3',&quot;Three&quot;},
                {'4',&quot;Four&quot;},
                {'5',&quot;Five&quot;},
                {'6',&quot;Six&quot;},
                {'7',&quot;Seven&quot;},
                {'8',&quot;Eight&quot;},
                {'9',&quot;Nine&quot;},
                {'0',&quot;Zero&quot;},
                {'?',&quot;Question Symbol&quot;},
                {';',&quot;SemiColon Symbol&quot;},
                {':',&quot;Colon Symbol&quot;},
                {'A',&quot;ALPHA&quot;},
                {'B',&quot;BRAVO&quot;},
                {'C',&quot;CHARLIE&quot;},
                {'D',&quot;DELTA&quot;},
                {'E',&quot;ECHO&quot;},
                {'F',&quot;FOXTROT&quot;},
                {'G',&quot;GOLF&quot;},
                {'H',&quot;HOTEL&quot;},
                {'I',&quot;INDIA&quot;},
                {'J',&quot;JULIET&quot;},
                {'K',&quot;KILO&quot;},
                {'L',&quot;LIMA&quot;},
                {'M',&quot;MIKE&quot;},
                {'N',&quot;NOVEMBER&quot;},
                {'O',&quot;OSCAR&quot;},
                {'P',&quot;PAPA&quot;},
                {'Q',&quot;QUEBEC&quot;},
                {'R',&quot;ROMEO&quot;},
                {'S',&quot;SIERRA&quot;},
                {'T',&quot;TANGO&quot;},
                {'U',&quot;UNIFORM&quot;},
                {'V',&quot;VICTOR&quot;},
                {'W',&quot;WHISKEY&quot;},
                {'X',&quot;XRAY&quot;},
                {'Y',&quot;YANKEE&quot;},
                {'Z',&quot;ZULU&quot;},
                {'^',&quot;Caret Symbol&quot;},
                {'&amp;',&quot;Ampersand Symbol&quot;}
            };

        char[] wordCharacters = password.ToCharArray();

        string callsignSpelling =
            wordCharacters.Aggregate(string.Empty,
                                         (current, passwordCharacter) =&gt;
                                         current + (callsigns[passwordCharacter] + &quot; - &quot;)).TrimEnd(' ', '-');

        return callsignSpelling;
    }
</pre>
<p>The spelling is done using a Key/Value dictionary, and iterating over each character of the password one-by-one.</p>
<p>The result of using these two helpers is below.</p>
<p><a href="http://www.zachhunter.com/wp-content/uploads/RandomPasswordGenerator_CallsignSpelling_Screenshot.png" rel="lightbox[483]" title="Random Password Generator and Callsign Spelling Output with ASP.NET"><img src="http://www.zachhunter.com/wp-content/uploads/RandomPasswordGenerator_CallsignSpelling_Screenshot.png" alt="" title="Random Password Generator and Callsign Spelling Output with ASP.NET" width="434" height="405" class="aligncenter size-full wp-image-484" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/06/password-and-callsign-spelling-generator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JSON to HTML Form Using jQuery dForm Plug-in</title>
		<link>http://www.zachhunter.com/2011/06/json-to-html-form-using-jquery-dform-plug-in/</link>
		<comments>http://www.zachhunter.com/2011/06/json-to-html-form-using-jquery-dform-plug-in/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 19:19:40 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=478</guid>
		<description><![CDATA[In a previous posts, I&#8217;ve showed how to go from a JSON array of objects/values, to a HTML table. This is great when you want to display a bunch of data in column and rows, but what happens if you want to interact with the data. No problem, there is the jQuery dForm plug-in for [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous posts, I&#8217;ve showed how to go from a JSON array of objects/values, to a HTML table.  This is great when you want to display a bunch of data in column and rows, but what happens if you want to interact with the data.  No problem, there is the <a href="https://github.com/daffl/jquery.dform">jQuery dForm plug-in</a> for that.  In order to generate the form, you&#8217;ll need to redesign your server side / inline objects to provide the required rendering data for dForms.  It&#8217;s pretty straight forward and there is a ton of options with the plug-in, <a href="http://neyeon.com/p/jquery.dform/doc/files2/examples-txt.html">see here</a>.</p>
<p><strong>Demo Screenshot</strong></p>
<p><a href="http://www.zachhunter.com/wp-content/uploads/jQuery-dForm-Demo-Screenshot.png" rel="lightbox[478]" title="jQuery dForm Demo Screenshot"><img src="http://www.zachhunter.com/wp-content/uploads/jQuery-dForm-Demo-Screenshot.png" alt="" title="jQuery dForm Demo Screenshot" width="640" height="787" class="alignnone size-full wp-image-479" /></a></p>
<p>In the image above, we use an inline object that will feed the dForm &#8220;buildForm()&#8221; method.  I&#8217;m using a static value here, but you could have easily setup dForm to load the data remotely using ajax.</p>
<p>Here is the <a href='http://www.zachhunter.com/wp-content/uploads/jQuery_dForm_Demo.zip'>jQuery dForm 0.1.3 Plug-in Demo</a> used in the screenshot above, which includes everything you need to get up and running fast.  If you have problems making dForm work, make sure you have included &#8220;ALL&#8221; the dForm libraries.  The dForm.js file has dependencies on the other libraries, if you don&#8217;t load the correct libraries, you&#8217;ll end up with a blank form.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/06/json-to-html-form-using-jquery-dform-plug-in/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reusable ASP.NET MessageBox UserControl</title>
		<link>http://www.zachhunter.com/2011/06/asp-net-messagebox-usercontrol/</link>
		<comments>http://www.zachhunter.com/2011/06/asp-net-messagebox-usercontrol/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 18:38:38 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=462</guid>
		<description><![CDATA[All systems need a way to share status messages with a user, without giving them feedback they don&#8217;t what has or what will happen. There are so many different ways to send an alert (modal window, JavaScript alert, inline HTML, etc&#8230;), regardless of what you use it always help to be consistent. I built this [...]]]></description>
			<content:encoded><![CDATA[<p>All systems need a way to share status messages with a user, without giving them feedback they don&#8217;t what has or what will happen.  There are so many different ways to send an alert (modal window, JavaScript alert, inline HTML, etc&#8230;), regardless of what you use it always help to be consistent.  I built this control based on a few different ideas/examples a long time ago, and I seem to find more uses for it all the time.  You can call it from the server or from the client using JavaScript, making it the perfect single solution &#8220;notification&#8221; solution.</p>
<p>Here is an example of what it looks like.</p>
<p><a href="http://www.zachhunter.com/wp-content/uploads/ASPNET_UserControl_MessageBox.png" rel="lightbox[462]" title="ASP.NET MessageBox User Control Screenshot"><img src="http://www.zachhunter.com/wp-content/uploads/ASPNET_UserControl_MessageBox.png" alt="ASP.NET MessageBox User Control Screenshot" title="ASP.NET MessageBox User Control Screenshot" width="930" height="313" class="alignnone size-full wp-image-468" /></a></p>
<p><em>** The text after the heading, is the code that was used to trigger the message box.</em></p>
<p>The control is pretty straight forward, on the server it works by &#8220;re-injecting&#8221; the rendered control when you call Show<type> function.  Since the control does not use viewstate, every time you post back to the server and call show again, the last message disappears and the new message is displayed.  If you want the message to disappear &#8220;automatically&#8221; after a few seconds, you can can set the timeout in milliseconds.  On the client (via JavaScript), you can create a simple function that will provide access to throwing alerts from the client without a postback.</p>
<p><strong>Client Side Example</strong></p>
<pre class="brush: jscript; title: ; notranslate">
    &lt;script type=&quot;text/javascript&quot;&gt;
        function ShowSuccess(message) {
            $alert = $('#MBWrapper1');

            $alert.removeClass().addClass('MessageBoxInterface');
            $alert.children('p').remove();
            $alert.append('&lt;p&gt;' + message + '&lt;/p&gt;').addClass('successMsg').show().delay(8000).slideUp(300);
        }
    &lt;/script&gt;
</pre>
<p><strong>Server Side Example</strong></p>
<pre class="brush: csharp; title: ; notranslate">
    public partial class _Default : System.Web.UI.Page
    {
        protected void Success_Click(object sender, EventArgs e)
        {
            MessageBox1.ShowSuccess(&quot;Success, page processed.&quot;, 5000);
        }
    }
</pre>
<p><a href='http://www.zachhunter.com/wp-content/uploads/ASPNET_UserControl_MessageBox_FullDemo.zip'>ASP.NET MessageBox User Control &#8211; Full Working Demo</a></p>
<p>Download and try the demo, if you like what you see&#8230;  Here is what you need to include to make the control work in your project.</p>
<ul>
<li>MessageBox User Control (ASMX &#038; CS)</li>
<li><a href="http://code.jquery.com/">jQuery </a></li>
<li>IMessageBox.css stylesheet</li>
<li>All the graphics from the Images folder</li>
</ul>
<p><em>** Note: If you move the images into a different directory, you&#8217;ll need to update the CSS to use the correct path to the images.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/06/asp-net-messagebox-usercontrol/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ASP.NET Lists Elements and Client Side Updates</title>
		<link>http://www.zachhunter.com/2011/06/asp-net-lists-elements-and-client-side-updates/</link>
		<comments>http://www.zachhunter.com/2011/06/asp-net-lists-elements-and-client-side-updates/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 20:03:39 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=455</guid>
		<description><![CDATA[A common issue I see people run into with Web Forms is the inability for client side changes to LIST elements (ListBox, DropDownList, etc&#8230;) to be passed back during POSTBACK. This is due to the how the viewstate is assigned/process, and there is no simple &#8220;hack&#8221; to bypass this. As for other non-list elements that [...]]]></description>
			<content:encoded><![CDATA[<p>A common issue I see people run into with Web Forms is the inability for client side changes to LIST elements (ListBox, DropDownList, etc&#8230;) to be passed back during POSTBACK.  This is due to the how the viewstate is assigned/process, and there is no simple &#8220;hack&#8221; to bypass this.  As for other non-list elements that typically implement a Text property, this isn&#8217;t an issue.  Here are 3 common ways to get around the limitation in seeing changes to your LIST elements that were made on the client using jQuery/JavaScript.</p>
<p><strong>1. Create a hidden field (that has a text property)</strong></p>
<pre class="brush: xml; title: ; notranslate">
&lt;select size=&quot;5&quot; id=&quot;users&quot;&gt;
    &lt;option value=&quot;Kelly&quot;&gt;Kelly&lt;/option&gt;
    &lt;option value=&quot;Kylee&quot;&gt;Kylee&lt;/option&gt;
    &lt;option value=&quot;Nathan&quot;&gt;Nathan&lt;/option&gt;
&lt;/select&gt;

&lt;input type=&quot;hidden&quot; id=&quot;userList&quot; runat=&quot;server&quot; value=&quot;Kelly,Kylee,Nathan&quot;/&gt;
</pre>
<p>Here is how you would add/parse the client side change.</p>
<pre class="brush: jscript; title: ; notranslate">
var $users = $('#users');
var $usersList = $('#usersList');

$users.append($('&lt;option&gt;&lt;/option&gt;').val('New Entry Value').html('New Entry Text'));

var newUserList = '';
var $options = $('#users').children('option');

$.each($options, function(index, value) {
	newUserList = newUserList + $options[index].value + ',';
}); 			

$usersList.val(newUserList.substr(0, newUserList.length-1));
</pre>
<p><em>** In this example, you maintain a hidden input element that matches the items in the select list.  When you change the select list in JavaScript, you change the value of the hidden element.  During post back, you read and parse this list to make your updates.<br />
</em></p>
<p><strong>2.  Wrap your lists in an update panel</strong></p>
<pre class="brush: xml; title: ; notranslate">
&lt;asp:UpdatePanel ID=&quot;UpdateRoles&quot; runat=&quot;server&quot;&gt;
    &lt;ContentTemplate&gt;
        &lt;table&gt;
            &lt;tr&gt;
                &lt;td style=&quot;height: 180px; vertical-align: top;&quot;&gt;
                    Active Roles&lt;br /&gt;
                    &lt;asp:ListBox ID=&quot;lstAdd&quot; runat=&quot;server&quot; Width=&quot;300px&quot; OnSelectedIndexChanged=&quot;lstAdd_SelectedIndexChanged&quot; Rows=&quot;10&quot;&gt;&lt;/asp:ListBox&gt;
                &lt;/td&gt;
                &lt;td style=&quot;height: 180px&quot;&gt;
                    &lt;asp:Button ID=&quot;AddRole&quot; runat=&quot;server&quot; Text=&quot;-&gt;&quot; OnClick=&quot;AddRole_Click1&quot; /&gt;
                    &lt;br /&gt;
                    &lt;asp:Button ID=&quot;RemoveRole&quot; runat=&quot;server&quot; Text=&quot;&lt;-&quot; OnClick=&quot;RemoveRole_Click&quot; /&gt;
                &lt;/td&gt;
                &lt;td style=&quot;height: 180px; vertical-align: top;&quot;&gt;
                    InActive Roles&lt;br /&gt;
                    &lt;asp:ListBox ID=&quot;lstRemove&quot; runat=&quot;server&quot; Width=&quot;300px&quot; OnSelectedIndexChanged=&quot;lstRemove_SelectedIndexChanged&quot; Rows=&quot;10&quot;&gt;&lt;/asp:ListBox&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/table&gt;
    &lt;/ContentTemplate&gt;
&lt;/asp:UpdatePanel&gt;
</pre>
<p>Here are the events that are fired when you click the Add / Remove buttons the move items between the lists.</p>
<pre class="brush: csharp; title: ; notranslate">
        protected void AddRole_Click1(object sender, EventArgs e)
        {
            if (lstAdd.SelectedIndex &gt; -1)
            {
                lstRemove.Items.Add(lstAdd.SelectedItem);
                lstAdd.Items.RemoveAt(lstAdd.SelectedIndex);
            }
        }

        protected void RemoveRole_Click(object sender, EventArgs e)
        {
            if (lstRemove.SelectedIndex &gt; -1)
            {
                lstAdd.Items.Add(lstRemove.SelectedItem);
                lstRemove.Items.RemoveAt(lstRemove.SelectedIndex);
            }
        }
</pre>
<p><em><br />
** You could fire the events using any type of event, in the sample I highlighting a item in one of the two lists and click Add/Remove to switch the items between the lists.</em></p>
<p><strong>3. Post back using Ajax</strong></p>
<p>This is currently my preferred approach, since it ride on top of jQuery Ajax and follows my normal design approach to building widgets (ajax load / add / edit / delete).  Using this approach you can do real-time updates as they edit the list, or you can post back your entire form including all your list changes without a post back.  There are so many options when you start using ajax calls to pass data back and forth between the client and server.</p>
<p>My example below is using a WCF service, you can also use ASMX to do this in earlier versions of .NET.  This solution has a lot more steps, but it really encompasses a whole &#8220;form submit&#8221; vs. propagating your LIST changes to the server.</p>
<p>To start, I also build some simple objects to pass between the client &#038; server.  The objects go both ways and are defined as a DataContract in C#.</p>
<pre class="brush: csharp; title: ; notranslate">
    [DataContract]
    public class Member
    {
        [DataMember]
        public int MemberId;

        [DataMember]
        public string CustomerCode;

        [DataMember]
        public string DelToCode;
    }

    [DataContract]
    public class Rule
    {
        [DataMember]
        public int RuleId;

        [DataMember]
        public string Name;

        [DataMember]
        public bool Enabled;

        [DataMember]
        public List&lt;Member&gt; Members;
    }
</pre>
<p>One we have an opject to pass, we define a method that will use this object.</p>
<pre class="brush: csharp; title: ; notranslate">
    [OperationContract]
    [WebInvoke(
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.WrappedRequest)
    ]
    bool UpdateRule(Rule rule);

    public bool UpdateRule(Rule rule)
    {
        // Do Update Using Object
    }
</pre>
<p>Next we build a form that will be used with our server, everything on the form can be build during page load or it can be populate via Ajax.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;fieldset class=&quot;withborder&quot; id=&quot;manageRule&quot;&gt;
&lt;legend&gt;Rule Update&lt;/legend&gt;
&lt;ol&gt;
	&lt;li&gt;
		&lt;label class=&quot;left&quot;&gt;
			Rule ID&lt;em&gt;*&lt;/em&gt;&lt;/label&gt;
		&lt;input type=&quot;text&quot; class=&quot;medium disabled&quot; id=&quot;ruleId&quot;&gt;
	&lt;/li&gt;
	&lt;li&gt;
		&lt;label class=&quot;left&quot;&gt;
			Name&lt;em&gt;*&lt;/em&gt;&lt;/label&gt;
		&lt;input type=&quot;text&quot; class=&quot;medium&quot; maxlength=&quot;5&quot; id=&quot;ruleName&quot;&gt;
	&lt;/li&gt;
	&lt;li&gt;
		&lt;label class=&quot;left&quot;&gt;
			Enabled&lt;em&gt;*&lt;/em&gt;&lt;/label&gt;
		&lt;input type=&quot;checkbox&quot; class=&quot;checkBox&quot; id=&quot;ruleEnabled&quot; checked=&quot;checked&quot;&gt;
	&lt;/li&gt;
	&lt;li&gt;
		&lt;label class=&quot;left&quot;&gt;
			Assigned&lt;em&gt;*&lt;/em&gt;&lt;/label&gt;
		&lt;div&gt;
			&lt;div class=&quot;dropZone available&quot;&gt;
				&lt;ul class=&quot;connectedSortable ui-sortable&quot; id=&quot;available&quot; style=&quot;&quot;&gt;
					&lt;li id=&quot;MemberId_1&quot; class=&quot;ui-state-highlight&quot;&gt;Red&lt;/li&gt;
					&lt;li id=&quot;MemberId_2&quot; class=&quot;ui-state-highlight&quot;&gt;Green&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
			&lt;div class=&quot;dropZone included&quot;&gt;
				&lt;ul class=&quot;connectedSortable ui-sortable&quot; id=&quot;included&quot; style=&quot;&quot;&gt;
					&lt;li id=&quot;MemberId_3&quot; class=&quot;ui-state-highlight&quot;&gt;Blue&lt;/li&gt;
					&lt;li id=&quot;MemberId_4&quot; class=&quot;ui-state-highlight&quot;&gt;Yellow&lt;/li&gt;
					&lt;li id=&quot;MemberId_5&quot; class=&quot;ui-state-highlight&quot;&gt;Orange&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;
		&lt;/div&gt;
	&lt;/li&gt;
	&lt;li style=&quot;text-align: right;&quot;&gt;
		&lt;input type=&quot;button&quot; value=&quot;Update Rule&quot; text=&quot;Add&quot; id=&quot;updateRule&quot;&gt;
	&lt;/li&gt;
&lt;/ol&gt;
&lt;/fieldset&gt;
</pre>
<p>Finally, we put it all together with JavaScript function that uses <a href="http://jquery.com/">jQuery </a>and <a href="http://www.json.org/">JSON.org&#8217;s</a> libraries to build and transfer data between the client and sever.</p>
<pre class="brush: jscript; title: ; notranslate">
    function UpdateRule() {
        var rule;

        rule.RuleId = parseInt($('#ruleId').val());
        rule.Name = $('#ruleName').val();
        rule.Enabled = $('#ruleEnabled').is(':checked');

        var $includedMembers = $('#included &gt; li');

        rule.Members = [];

        // This is where you parse / add the values of your list (listbox, li, etc...)
        if ($includedMembers.length &gt; 0) {
            $.each($includedMembers, function (index, value) {
                var id = $includedMembers[index].id.replace('MemberId_', '');
                var name = $includedMembers[index].firstChild.data.split(' - ');
                var member = { 'CustomerCode': name[0], 'DelToCode': name[1], 'MemberId': id };
                rule.Members.push(member);
            });
        }

        $.ajax({
            url: '/Service/ExampleWCFService.svc/UpdateRule',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            type: 'POST',
            data: JSON.stringify({ 'rule': rule }),
            success: function (rule) {
                // Do Something On Success
            }
        });
    }
</pre>
<p><em>** Don&#8217;t forget, you could have your service store this data in the cache/session/etc&#8230; if you don&#8217;t want to store it real-time.  In my sample, I send the whole form to be process and not just the list.  This gets rid of the entire post back process.<br />
</em></p>
<p>Each has it&#8217;s own unique requirements, the only one I tend not to use anymore is #2 since it requires the addition of the ASP.NET Ajax Library.  Having an additional library and added content in a project for this one feature isn&#8217;t worth it to me.  I know the library has got more compact, but in general it&#8217;s quite heavy (size wise), and since I already &#8220;always&#8221; include jQuery there really isn&#8217;t a need for this baggage.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/06/asp-net-lists-elements-and-client-side-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JSON to CSV</title>
		<link>http://www.zachhunter.com/2011/06/json-to-csv/</link>
		<comments>http://www.zachhunter.com/2011/06/json-to-csv/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 19:23:39 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=422</guid>
		<description><![CDATA[I created a helper a few months back that used DATA URIs to download JSON to CSV, but due to IE&#8217;s implementation of DATA URIs (or lack of), it does not work for IE (all versions). Here is the same helper that will just convert the data, which you can use anyway you want (example: [...]]]></description>
			<content:encoded><![CDATA[<p>I created a helper a few months back that used DATA URIs to download JSON to CSV, but due to IE&#8217;s implementation of DATA URIs (or lack of), it does not work for IE (all versions).  Here is the same helper that will just convert the data, which you can use anyway you want (example: in a popup, to display in a modal window, etc&#8230;).</p>
<pre class="brush: xml; title: ; notranslate">
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Demo - Covnert JSON to CSV&lt;/title&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;http://code.jquery.com/jquery-latest.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;https://github.com/douglascrockford/JSON-js/raw/master/json2.js&quot;&gt;&lt;/script&gt;

    &lt;script type=&quot;text/javascript&quot;&gt;
		// JSON to CSV Converter
        function ConvertToCSV(objArray) {
            var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
            var str = '';

            for (var i = 0; i &lt; array.length; i++) {
                var line = '';
                for (var index in array[i]) {
                    if (line != '') line += ','

                    line += array[i][index];
                }

                str += line + '\r\n';
            }

            return str;
        }

		// Example
        $(document).ready(function () {

			// Create Object
            var items = [
				  { name: &quot;Item 1&quot;, color: &quot;Green&quot;, size: &quot;X-Large&quot; },
				  { name: &quot;Item 2&quot;, color: &quot;Green&quot;, size: &quot;X-Large&quot; },
				  { name: &quot;Item 3&quot;, color: &quot;Green&quot;, size: &quot;X-Large&quot; }];

			// Convert Object to JSON
			var jsonObject = JSON.stringify(items);

			// Display JSON
            $('#json').text(jsonObject);

			// Convert JSON to CSV &amp; Display CSV
            $('#csv').text(ConvertToCSV(jsonObject));
        });
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;
        JSON&lt;/h1&gt;
    &lt;pre id=&quot;json&quot;&gt;&lt;/pre&gt;
    &lt;h1&gt;
        CSV&lt;/h1&gt;
    &lt;pre id=&quot;csv&quot;&gt;&lt;/pre&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Here is the output using the script and above.</p>
<h1>
        JSON</h1>
<h3>Created with &#8220;JSON.stringify()&#8221; function from <a href="https://github.com/douglascrockford/JSON-js/raw/master/json2.js">json.org</a>.</h3>
<pre id="json">[{"name":"Item 1","color":"Green","size":"X-Large"},{"name":"Item 2","color":"Green","size":"X-Large"},{"name":"Item 3","color":"Green","size":"X-Large"}]</pre>
<h1>
        CSV</h1>
<h3>Created with &#8220;ConvertToCSV()&#8221; function I created above.</h3>
<pre id="csv">Item 1,Green,X-Large
Item 2,Green,X-Large
Item 3,Green,X-Large
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/06/json-to-csv/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Compare SubSonic Objects (Columns) for Differences</title>
		<link>http://www.zachhunter.com/2011/05/compare-subsonic-objects-columns-for-differences/</link>
		<comments>http://www.zachhunter.com/2011/05/compare-subsonic-objects-columns-for-differences/#comments</comments>
		<pubDate>Wed, 25 May 2011 22:04:10 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[C# Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=408</guid>
		<description><![CDATA[Awhile back I needed a way to quickly compare a set of SubSonic v2.2 objects ( data properties ) for differences. Since the two source rows of data would be created at different times and have different primary keys, I needed a way to selectively compare columns/properties. My solution, was a function called &#8220;ColumnsAreEqual&#8221; that [...]]]></description>
			<content:encoded><![CDATA[<p>Awhile back I needed a way to quickly compare a set of SubSonic v2.2 objects ( data properties ) for differences.  Since the two source rows of data would be created at different times and have different primary keys, I needed a way to selectively compare columns/properties.  My solution, was a function called &#8220;ColumnsAreEqual&#8221; that I added to &#8220;RecordBase.cs&#8221; that compares each property value of two SubSonic Objects, while allowing you to set a list of columns/properties to exclude. </p>
<pre class="brush: csharp; title: ; notranslate">
        /// &lt;summary&gt;
        /// Compare values of two SubSonic objects for differences.  You can also pass an exclusion list
        /// of columns/properties to exclude,  like a primary key or CreatedOn date.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;comparableObject&quot;&gt;Object to Compare&lt;/param&gt;
        /// &lt;param name=&quot;ignoreColumnList&quot;&gt;Comma separated list of ColumnNames to ignore&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public bool ColumnsAreEqual(T comparableObject, string ignoreColumnList = null)
        {
            if (comparableObject == null)
                return false;

            // If ignore list is set, build array of column names to skip
            string[] ignoreColumnNames = new string[] {};
            if (ignoreColumnList != null &amp;&amp; ignoreColumnList.IndexOf(',') &gt; 0)
            {
                ignoreColumnNames = ignoreColumnList.Split(',');
            }

            foreach (TableSchema.TableColumnSetting setting in columnSettings)
            {
                // If there are columns to ignore, check the current ColumnName against ignore list and skip.
                if (ignoreColumnNames.Length &gt; 0)
                {
                    bool ignored = false;

                    foreach (string ignoreColumnName in ignoreColumnNames)
                    {
                        if (ignoreColumnName.Trim().ToLower() == setting.ColumnName.ToLower())
                        {
                            ignored = true;
                            break;
                        }
                    }

                    // If this is a ignore column, skip.
                    if (ignored)
                    {
                        continue;
                    }
                }

                var before = setting.CurrentValue;
                var after = comparableObject.GetColumnValue&lt;object&gt;(setting.ColumnName);

                // If both are null, then they are equal
                if (before == null &amp;&amp; after == null)
                    continue;

                // If one is null then they are not equal
                if (before == null || after == null)
                    return false;

                // Compare two non-null objects
                if (!before.Equals(after))
                    return false;
            }

            return true;
        }

// Example Usage
bool areEqual = before.Packaging.ColumnsAreEqual(after.Packaging,&quot;PackagingId,CreatedOn,ModifiedOn&quot;);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/05/compare-subsonic-objects-columns-for-differences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optional Column Updates with your Stored Procedures</title>
		<link>http://www.zachhunter.com/2011/05/optional-column-updates-with-your-stored-procedures/</link>
		<comments>http://www.zachhunter.com/2011/05/optional-column-updates-with-your-stored-procedures/#comments</comments>
		<pubDate>Wed, 25 May 2011 21:14:43 +0000</pubDate>
		<dc:creator>Zach</dc:creator>
				<category><![CDATA[SQL Development]]></category>

		<guid isPermaLink="false">http://www.zachhunter.com/?p=397</guid>
		<description><![CDATA[Recently, I needed a way to quickly update some bulk data based on a part number&#8230; I started by building 2 stored procedure that each updated different columns, but a few minutes later I realized I was going to need at least 2 more permutations of my update procedure since there were more columns combinations [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I needed a way to quickly update some bulk data based on a part number&#8230;  I started by building 2 stored procedure that each updated different columns, but a few minutes later I realized I was going to need at least 2 more permutations of my update procedure since there were more columns combinations I needed to update.  I didn&#8217;t want to maintain a bunch of SP for different types of updates, I just wanted a handy update SP that would update a column/field with data when I passed it in or ignored it if left it blank/null.</p>
<p>I came up with a T-SQL Optional Update Parameter solution, which is based on using the &#8220;COALESCE&#8221; function along with <strong>typed</strong> null values.  Normally, you pass in a bunch of values and it returns the first non null value, but&#8230;  There is a hidden gem, you can pass in typed null values and it will return null&#8230;  Knowing this, I created the code below.</p>
<pre class="brush: sql; title: ; notranslate">
-- CREATE DEMO TABLE
CREATE TABLE [dbo].[Product](
	[PartNumber] [nvarchar](20) NULL,
	[Description] [nchar](20) NULL,
	[Comments] [nchar](20) NULL
) ON [PRIMARY];

GO

-- DEMO TABLE DATA
PRINT '';
PRINT 'INSERT SAMPLE DATA';
PRINT '---------------------------------------------------------- '
INSERT INTO [PRODUCT] VALUES (N'PART1', N'PART 1 Description', N'PART 1 Comment');

GO

-- CREATE DEMO PROCEDURE
CREATE PROCEDURE [dbo].[spProduct_Update]
	@PartNumber AS NVARCHAR(20),
	@Description AS NCHAR(20),
	@Comments AS NCHAR(20)
AS
BEGIN
	DECLARE @BEFORE AS NVARCHAR(200);
	DECLARE @AFTER AS NVARCHAR(200);

	SELECT @BEFORE = 'BEFORE: ' + [PartNumber] + '  |  ' + [Description] + '  |  ' + [Comments] FROM [Product] WHERE [PartNumber] = @PartNumber;

	UPDATE [Product]
		SET [Description] = COALESCE(@Description,[Description]),
			[Comments] = COALESCE(@Comments,[Comments])
	WHERE [PartNumber] = @PartNumber;

	SELECT @AFTER = ' AFTER: ' + [PartNumber] + '  |  ' + [Description] + '  |  ' + [Comments] FROM [Product] WHERE [PartNumber] = @PartNumber;

	PRINT @BEFORE;
	PRINT @AFTER;

END

GO

-- Fails : Both values are non-typed null values
PRINT '';
PRINT '';
PRINT 'FAIL = COALESCE(null,null)';  --2 non-typed null value

GO

DECLARE @MyField AS NVARCHAR(50);
SET @MyField = COALESCE(null, null);
PRINT @MyField;

GO

-- Pass : The second value is a typed null value
PRINT '';
PRINT '';
PRINT 'PASS = COALESCE(null,&lt;typed null parameter&gt;)';  --1 non-typed null value, 1 typed null value

GO

DECLARE @MyField AS NVARCHAR(50);
DECLARE @MyTypedParameter AS NVARCHAR(50);
SET @MyField = COALESCE(null, @MyTypedParameter);
PRINT @MyField;

GO

-- Using the COALESCE with a typed parameter to create an optional &quot;column&quot; update.
PRINT '';
PRINT '---------------------------------------------------------- '
PRINT 'NO UPDATES';
EXEC spProduct_Update 'PART1', null, null;

PRINT '';
PRINT '---------------------------------------------------------- '
PRINT 'UPDATE DESCRIPTION ONLY';
EXEC spProduct_Update 'PART1', 'PART 1 *** UPDATE DESCRIPTION ***', null;

PRINT '';
PRINT '---------------------------------------------------------- '
PRINT 'UPDATE COMMENTS ONLY';
EXEC spProduct_Update 'PART1', null, 'PART 1 *** UPDATE COMMENT ***';

PRINT '';
PRINT '---------------------------------------------------------- '
PRINT 'UPDATE DESCRIPTION &amp; COMMENTS';
EXEC spProduct_Update 'PART1', '*** UPDATE BOTH ***', '*** UPDATE BOTH ***';

-- DELETE DEMO PROCEDURE
DROP PROCEDURE [dbo].[spProduct_Update];

GO

-- DELETE DEMO TABLE
DROP TABLE [dbo].[Product];

GO
</pre>
<p>In a nutshell, we can only use COALESCE with typed nullable values&#8230; this means COALESCE(null,null,null) will fail because null is not a defined type, but COALESCE(@nullvalue, @nullvalue, @nullvalue) will work since we had to declare a type of @nullvalue [e.g. DECLARE @nullvalue AS nvarchar(20)]</p>
<pre class="brush: plain; title: ; notranslate">
INSERT SAMPLE DATA
----------------------------------------------------------
(1 row(s) affected)

FAIL = COALESCE(null,null)
Msg 4127, Level 16, State 1, Line 3
At least one of the arguments to COALESCE must be a typed NULL.

PASS = COALESCE(null,&lt;typed null parameter&gt;)

----------------------------------------------------------
NO UPDATES

(1 row(s) affected)
BEFORE: PART1  |  PART 1 Description    |  PART 1 Comment
 AFTER: PART1  |  PART 1 Description    |  PART 1 Comment      

----------------------------------------------------------
UPDATE DESCRIPTION ONLY

(1 row(s) affected)
BEFORE: PART1  |  PART 1 Description    |  PART 1 Comment
 AFTER: PART1  |  PART 1 *** UPDATE DE  |  PART 1 Comment      

----------------------------------------------------------
UPDATE COMMENTS ONLY

(1 row(s) affected)
BEFORE: PART1  |  PART 1 *** UPDATE DE  |  PART 1 Comment
 AFTER: PART1  |  PART 1 *** UPDATE DE  |  PART 1 *** UPDATE CO

----------------------------------------------------------
UPDATE DESCRIPTION &amp; COMMENTS

(1 row(s) affected)
BEFORE: PART1  |  PART 1 *** UPDATE DE  |  PART 1 *** UPDATE CO
 AFTER: PART1  |  *** UPDATE BOTH ***   |  *** UPDATE BOTH ***
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zachhunter.com/2011/05/optional-column-updates-with-your-stored-procedures/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

