Archive for category jQuery

Executing long running process from a web site

I recently had to build a report which accepts one xls excel file, churns through a bunch the data looking stuff up on other systems and performing calculations, then spits out another xls excel sheet the other end. The whole process takes about 15 to 20 minutes to run and at present is a simple command line application which accepts a couple of parameters (input and output filenames) and I fire up manually- obviously a situation which is no good moving forward.

All our internal business systems are web forms/ mvc running from local IIS boxes so ideally I would like to add a screen where the user can submit their xls file, hit go, and then get the result back 15/ 20 minutes later- but I don’t want to tie up one of the threads in the aspnet worker thread pool for the entire duration. Some Googling revealed the best approach appears to be to write a windows service which hosts the long running process then get the web app to call across to that to kick off the task.

Implementation

This is to be a standard Windows Service which will run my long running process, hosting a WCF service which the website can use to call into it with. If you;ve not done this before, you can follow the steps on the MSDN ; msdn.microsoft.com/en-us/library/ms733069.aspx.

Create your WCF Service which will respond to requests from the website. In my instance I wanted to be able to start the operation, passing a byte[] containing the xls file, request status updates, then finally request the resulting xls file, again as a byte[]. For the sake of this example, the WCF service is the one which is doing all the work with regards spawning the worker thread and tracking updates from the actual worker class, and the worker class is a type called “Calculator”.

    using System.ServiceModel;
    [ServiceContract(Namespace = "http://Moneybarn.VIVS.FleetRevaluation")]
    public interface IMyWCFService
    {
        [OperationContract]
        string Start(byte[] excel_file, string user_name);

        [OperationContract]
        Progress GetProgress();

        [OperationContract]
        byte[] GetResult();
    }

    using System.Threading;
    public class MyWCFService: IMyWCFService
    {
        private static string CurrentUserInstance;
        private static Calculator MyCalculatorInstance;
        private static Progress LastUpdate;
        private static Thread WorkerThread;
        private static bool IsComplete;
        private static string LastError;
        private static byte[] FinishedFile;

        public string Start(byte[] excel_file, string user_name)
        {
            if (WorkerThread == null)
            {
                CurrentUserInstance = user_name;
                MyCalculatorInstance = new Calculator(excel_file);

                MyCalculatorInstance.OnProgress += new OnProgressEventHandler(MyCalculatorInstance_OnProgress);
                MyCalculatorInstance.OnComplete += new OnCompleteEventHandler(MyCalculatorInstance_OnComplete);
                MyCalculatorInstance.OnError += new OnErrorEventHandler(MyCalculatorInstance_OnError);

                WorkerThread = new Thread(new ThreadStart(MyCalculatorInstance.Start));
                WorkerThread.Start();

                return null; // no news is good news!
            }
            else
            {
                return "Instance already running for user " + CurrentUserInstance;
            }
        }

        public Progress GetProgress()
        {
            return LastUpdate;
        }

        public string GetError()
        {
            return LastError;
        }

        public byte[] GetResult()
        {
            if (IsComplete)
            {
                byte[] buff = FinishedFile;

                MyCalculatorInstance = null;
                WorkerThread = null;
                CurrentUserInstance = string.Empty;
                LastUpdate = null;
                FinishedFile = null;
                IsComplete = false;

                return buff;
            }
            else
                return null;
        }

        private void MyCalculatorInstance_OnError(string error)
        {
            LastError = error;
        }

        private void MyCalculatorInstance_OnComplete(byte[] the_file)
        {
            FinishedFile = the_file;
            IsComplete = true;
        }

        private void MyCalculatorInstance_OnProgress(int stage, float percent)
        {
            LastUpdate = new Progress() { 
                Stage = stage, 
                Percent = (int)(percent * 100) 
            };
        }
    }

Add a new class called ProjectInstaller- this will handle registering your service with Windows

    using System.ComponentModel;
    using System.Configuration.Install;
    using System.ServiceProcess;

    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "MyWindowsService";  // change this!
            Installers.Add(process);
            Installers.Add(service);
        }
    }

Add the actual service body; add a new “Windows Service” file to the project. This is the meat of the service, and contains no real logic- it’s only job is to fire up the ServiceHost for your WCF service.

    using System.ServiceModel;
    using System.ServiceProcess;

    public class MyWindowsService : ServiceBase
    {
        public ServiceHost serviceHost = null;

        public MyWindowsService()
        {
            // Name the Windows Service
            ServiceName = "MyWindowsService";
        }

        public static void Main()
        {
            ServiceBase.Run(new MyWindowsService());
        }

        // Start the Windows service.
        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }

            // The type of your WCF service
            serviceHost = new ServiceHost(typeof(MyWCFService));

            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }

Finally there is a little bit of config to pop into the app.config for the WCF endpoints- I’ve created a custom binding here to allow me to receive larger files over the WCF call than the default limits allow (in this case, up to 10 meg);

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="bigWSHttpBinding" 
                 maxBufferPoolSize="10485760" maxReceivedMessageSize="10485760"> <!-- 10 MB limit -->
          <readerQuotas maxDepth="10485760" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="MyWCFServiceBehavior"
        name="Demo.MyWCFService">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="bigWSHttpBinding"
          contract="Demo.IMyWCFService" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/MyWCFService/service" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyWCFServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

I also created a couple of little batch files which I mark as “Copy to output directory” for installing and removing the service;

rem install.bat
c:\windows\microsoft.net\Framework\v4.0.30319\InstallUtil MyWindowsService.exe
net start MyWindowsService
rem remove.bat
net stop MyWindowsService
c:\windows\microsoft.net\Framework\v4.0.30319\InstallUtil MyWindowsService.exe /u

That’s the Windows service part built. You can now build, and jump to the bin output folder and run the install.bat file from the command line- with any luck (more likly with a little debugging!) you will be up and running. The second part is even easier;

Jump over to your web app, add a service reference to the url of the base address from your app config above then it’s just a matter of exposing those web service methods so that you can call them from your page with an ajax call- so in MVC I created a controller with Start, GetProgress & GetResult methods which returned JsonResults called straight from the client with jQuery.

2 Comments

Recursive jQuery Drop Down Menu’s

Following on from my previous post about drop downs, I recently expanded the code to allow for sub menus- as many levels deep as you would like.

The Code:

$(document).ready(function () { // Shawsons' Teeny-Tiny Recursive Drop Downs!
    $('.drop-down-menu>li>ul').hide().mouseleave(function () {
        $('.highlighted', this).removeClass('highlighted');
        $(this).hide();
    });
    $('.drop-down-menu li>a').mouseenter(function () {
        var menu_root = $(this).parent().parent();
        $('ul', menu_root).hide();
        $('.highlighted', menu_root).removeClass('highlighted');
        $('>ul', $(this).addClass('highlighted').parent()).show();
    }).mouseleave(function (o) {
        if ($(this).parent().has($(o.relatedTarget)).length < 1) {
            $('ul', $(this).parent()).hide();
        }
    });
});

The Markup:

<ul class="drop-down-menu">
        <li>Drop Down Menu - Demo Title : </li>
        <li><a href="">Menu 1</a>
            <ul>
                <li><a href="a.htm">a</a></li>
                <li><a href="b.htm">b</a></li>
                <li><a href="c.htm">c &raquo;</a>
                    <ul>
                        <li><a href="c-a.htm">c-a</a></li>
                        <li><a href="c-b.htm">c-b &raquo;</a>
                          <ul>
                              <li><a href="c-b-a.htm">c-b-a</a></li>
                              <li><a href="c-b-b.htm">c-b-b &raquo;</a>
                                  <ul>
                                      <li><a href="c-b-b-a.htm">c-b-b-a</a></li>
                                  </ul>
                              </li>
                          </ul>
                        </li>
                        <li><a href="c-c.htm">c-c</a></li>
                    </ul>
                </li>
            </ul>
        </li>
        <li><a href="">Menu 2</a>
            <ul>
                <li><a href="d.htm">d</a></li>
                <li><a href="e.htm">e</a></li>
                <li><a href="f.htm">f</a></li>
            </ul>
        </li>
    </ul>

Some CSS:


.drop-down-menu { display:block; }
.drop-down-menu li { float:left; padding: 8px; }
.drop-down-menu>li>a { padding:8px; }
.drop-down-menu li ul  
{
    position:absolute; 
    background-color:#fff; 
    border: 1px solid #999;
    border-radius: 0px 7px 7px 7px; -moz-border-radius:0px 7px 7px 7px; -webkit-border-radius:0px 7px 7px 7px;
    padding:5px; 
    width: 50px;
}
.drop-down-menu li ul a {
   display:block;
   width:50px;
}
.drop-down-menu li ul li ul 
{
    margin-left:50px;
    margin-top: -20px;
}
.drop-down-menu li ul li { float:none; }
.drop-down-menu li ul li a { color:#000; }
.drop-down-menu li ul a.highlighted { background-color:#F68833; }

Demo :

 

2 Comments

Adding cross browser consistent keyboard short-cuts to your website

I wanted to employ keyboard short cuts to a frequently used internal web app used within the company- Pinch o’ the proverbial piss I thought- I’ll just use access keys! I’ve used them before on front facing sites for accessibility- but when I actually came to document these keys for the users I realised that support across different browsers is a mess;

IE Alt + {key}then hit return
Firefox Alt + Shift + {key}
Chrome Alt + {key} (the most sensible implementation, in my opinion)

IE also seems to refuse to aknowlege the links unless they are currently visible, and as the options I was short cutting existed in drop down menus this was no good, as they existing in bulleted lists which are “display:none” until the user mouses-over the menu bar (using my tiny drop down menu code)!

So to get around this I wrote some jQuery which standardises the short cuts- note this is no good for normal accessibility uses as it’s a new key combo which none of the browsers use, so without documentation no one will know- but for my use on an internal system it’s perfect.

I took the decision to make all the short cuts Ctrl+Alt+{key}, and wanted to keep using the accesskey attribute on my links rather than introduce another mechanism for dictating which keys triggered what- I also wanted to ensure if the link had a javascript onclick handler, instead of navigating away, we respect the handler and simply trigger that. Here’s the code;

$(document).keydown(function(e) {
	if (e.ctrlKey && e.altKey && e.which >= 65 && e.which <= 122) {
		e.preventDefault();
		
		var key = String.fromCharCode(e.which);
		var the_link = $("a[accesskey=" + key.toLowerCase() + "]");
		
		if (typeof(the_link) != 'undefined') {
			// does this link have a javascript assigned click handler, or do we simply send the user to the links href value?
			var events = $.data( $(the_link).get(0), 'events' );
			if (typeof(events) != 'undefined') {
				if (typeof(events.click) != 'undefined') {
					$(the_link).click();
					return;
				}
			}
			window.location = $(the_link).attr('href');
		}
	}
});

1 Comment

Quick & Tiny jQuery Drop Down Menus

Note: this has been superseded by the recursive drop down menu script.

The Code:

$(document).ready(function () { // Shawsons' Teeny-Tiny Drop Downs!
    $('.drop-down-menu li ul').hide().mouseleave(function () {
        $(this).hide();
    });
    $('.drop-down-menu>li>a').mouseenter(function () {
        $('ul', $(this).parent().parent()).hide();
        $('ul', $(this).parent()).show();
    }).mouseleave(function (o) {
        if ($(this).parent().has($(o.relatedTarget)).length < 1) {
            $('ul', $(this).parent()).hide();
        }
    });
});

The Markup:

<ul class="drop-down-menu">
        <li>Available Actions : </li>
        <li><a href="">Menu 1</a>
            <ul>
                <li><a href="a.htm">a</a></li>
                <li><a href="b.htm">b</a></li>
                <li><a href="c.htm">c</a></li>
            </ul>
        </li>
        <li><a href="">Menu 2</a>
            <ul>
                <li><a href="d.htm">d</a></li>
                <li><a href="e.htm">e</a></li>
                <li><a href="f.htm">f</a></li>
            </ul>
        </li>
    </ul>

Some CSS:

.drop-down-menu { display:block; }
.drop-down-menu li { float:left; padding: 8px; }
.drop-down-menu li a { padding:8px; }
.drop-down-menu li ul  
{
    position:absolute; 
    background-color:#fff; 
    border: 1px solid #999;
    border-radius: 0px 7px 7px 7px; -moz-border-radius:0px 7px 7px 7px; -webkit-border-radius:0px 7px 7px 7px;
    padding:5px; 
}
.drop-down-menu li ul li { float:none; }
.drop-down-menu li ul li a { color:#000; }
.drop-down-menu li ul li:hover { background-color:#F68833; }

2 Comments

jqZoomage jQuery component

I’ve built a simple jQuery plugin for use on a website I’m building and am in the process of submitting it to the jQuery plugins website. It’s a simple zoom panel, allowing your users to mouse over portions of your small image, to see a close up view. Ideal for use on product details page or similar.

Screenshot

Installation

Just add a reference to the script at the bottom of your page (where all your js should be anyway!)- as shown in the demo, this is a basic example;

$(window).ready(function() {
	$("#dinky-img").zoomage({
		zoomedImageContainer: "#big-img",
		zoomedImageUrl: "big-image.gif",
		stayActiveOnMouseOut: false,
		zoomedImageStartsCentered: true
	});
});

There are a couple of styles which are required for the view finder, and the mask which goes over the image (allowing you to customise the look)- add these rules to your style sheet somewhere;

#zoomage-view-finder { border: 1px solid #fff; }
.zoomage-view-finder-surround { background-color:#fff; opacity:0.7; }

As a general point, it’s best to run the script in a $(window).load() rather than the standard $(document).load(), as this ensures that all the images are loaded before the script begins, otherwise the script runs and grabs the width() and height() of the image to work out ratios, but these get returned as 0′s! More info on this can be found on the stack overflow issue about this

Configuration

zoomedImageContainer * Required *
Default Value : “#zoom-image-container”
This is the jQuery selector for the div which will act as the close up view for your image.

zoomedImageUrl * Required *
Default Value : “”
This is the URL of the zoomed image file. I generally use images 3 times larger than the original, however there isn’t a limit. The scale ratio is calculated on load.

stayActiveOnMouseOut
Default Value : false
If this is set to true, the view finder will continue to show in it’s last position even when the mouse pointer is moved off of the image. If false, the view finder will disappear on mouse out.

zoomedImageStartsCentered
Default Value : true
Indicates that, on load, the zoomed image view shows the center of the image.

centerOnMouseOut
Default Value : true
If true, on mouse out, the zoomed view will return to the center of the zoomed image.

Live Demo

You can check out a real life working version of it here!

Tested across all the major modern browsers (IE9/ FF4/ Chrome10)- give me a shout if you spot an issue.

Download

Current Version 1.2 – 2011-09-10
Unminified Development Version
Minified Production Version

Licence

This plugin is available for use under the MIT licence. For more info see http://codeblog.shawson.co.uk/storage/jquery.zoomage/licence.txt

jQuery Plugin Site Link

The official jQuery Plugin catalogue link for this plugin is http://plugins.jquery.com/project/jqZoomage

11 Comments

Random Band Generator!

Just a quick post to mention that I’ve uploaded the Random Band Generator- just a bit of fun I boshed together built for a mate… check it out here.

No Comments

More Manic Spaceman (8weekgame) documentation done

I promised I would, and I’m finally getting round to documenting the rest of the classes I wrote for my javascript platformer I built for the 8weekgame competition, as well as putting up the sourcecode. There’s still a few more to do, which I shall bash out through the course of the rest of the week. Check them out at www.shawson.co.uk/codeblog/8-week-game-competition/

No Comments

KnockoutJS/ jQuery tmpl with jQuery Validate

Quick post; I found tonight that my jquery validate was letting my knockoutjs viewModel.save() method run, even if the form wasn’t valid. This turned out to be because you need to set “uniqueName: true” on any form fields you want validated. Eg

<input data-bind="value: ChargedShipping, uniqueName: true" class="required number"/>

1 Comment

Using JQueryUI combobox() with KnockoutJS

This is something I had a great deal of trouble with, but in the end the solution was simple. Basically when using the combobox() autocomplete drop down in jQueryUI (in prototype at time of writing) along side KnockoutJS I found changing your selection in the drop down list didn’t update the viewModel in knockout as expected. This is because knockoutjs attached itself to the change() event of the drop down, and jqueryUI wasn’t raising this event when it changed the drop down. This is easily fixed by adding an event handler to thre jqueryUI combobox which forces the event to be called when the user selects a new option;

$("select").combobox({
            selected: function(event, ui) { 
                $(ui.item.parentNode).change();
            }
        });

Thanks go out to the “Rob on programming” blog, which helped me get my head around what was going on in the events in combobox.

2 Comments

MVC with MVVM using Knockout.js

Previously, on Shawson.co.uk..

see “Creating an Order/ Order Details style view using ASP.net MVC2 & Entity Framework 4″

So following on from my last MVC post I posed my question to Scott Hanselman himself via email, and he took the time to write me a very helpful response;

Interesting solution. Good job getting it working.
Take a look at maybe using some cleaner JS on the client…check out my last podcast on Knockout and check out this demo: http://knockoutjs.com/examples/contactsEditor.html
The pod cast he’s refering to is here.  The contacts editor example he pointed me to is exactly what I’m trying to do here.  This implementation would totally resolve my issue as you are no longer binding directly to the entity framework objects- I could instead create simple cut down DTO’s for the sale and it’s associated sale lines and serialise it to JSON then use Knockout (an open source javascript library which deals with clientside binding of UI elements to a data structure, like your ViewModel represented as JSON) to deal with all the client-side binding and editing before posting the data back as JSON.  I shall post again once I have something up and working.

6 Comments