<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7240109143089619921</id><updated>2011-12-31T20:35:48.541-08:00</updated><category term='Google Maps'/><category term='Vista'/><category term='Sobel Computer Vision WPF Edge detection blur filter computer graphics'/><category term='Each MVC Razor extension method Phil+Haack'/><category term='Slides'/><category term='Watin web gui test mstest unit testing'/><category term='Gadget'/><category term='Dynamic-Linq'/><category term='Javascript'/><category term='Soloppgang'/><category term='Custom actionresult mvc datacontract'/><category term='Sobel Edge operator Computer vision'/><category term='Douglas Crockford'/><category term='Personlig'/><category term='ASP.NET MVC Route visualizer routing dll visual studio tool'/><category term='Ecmascript 5'/><category term='ASP.NET MVC og jQuery Grid'/><category term='ytelse'/><category term='Solnedgang'/><category term='Asynchronous MVC controllers'/><category term='Unit test javascript tdd mstest qunit'/><category term='Embedded files MVC 3 Razor Views Image Javascript CSS'/><category term='MVC ActionMethodSelectorAttribute Controllers'/><category term='DOM'/><category term='Mashup'/><category term='Statens Kartverk'/><category term='C# Javascript unit test'/><category term='createDocumentFragment'/><category term='AutoDisplayAttribute PostSharp C# Attribute DisplayAttribute'/><category term='The Good parts'/><category term='NKSilverMashup'/><category term='temavalg'/><category term='Sol'/><category term='ES5'/><category term='Filters Treshold Wpf C# Iterative Optimal'/><category term='Scriptaculous'/><category term='Iterative optimal treshold selection wpf tresholding image algorithms c#'/><category term='MvcContrib TestHelper unit test Mvc 3 Controller'/><category term='Slider Script.aculo.us'/><category term='WORM NOIS kart.nois.no Samferdselsetaten'/><category term='CS'/><category term='Silverlight'/><category term='Sample'/><category term='Histogram equalization.'/><category term='Måne'/><title type='text'>Coding Grounds</title><subtitle type='html'>Compilation of different programming 
projects I amuse myself with.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-6139564347902344057</id><published>2011-12-31T20:05:00.001-08:00</published><updated>2011-12-31T20:33:13.575-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Each MVC Razor extension method Phil+Haack'/><title type='text'>Razor extension method Each</title><content type='html'>It is possible to augment razor views with not only helpers, but also razor extension methods. &lt;br /&gt;&lt;br /&gt;In this example, an extension method which will take a template and from this template generate a rendered result of a list of the IEnumerable of items passed in for the extension method will be presented. It is named Each and was created by Phil Haack.&lt;br /&gt;&lt;br /&gt;I will present the source code quickly to just repeat Phil Haack's code. Let's first add a new class called IndexedItemModel: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;&lt;br /&gt;namespace TestActionMethodSelectorAttribute.Extensions&lt;br /&gt;{&lt;br /&gt;    public class IndexedItem&amp;lt;TModel&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        public IndexedItem(int index, TModel item)&lt;br /&gt;        {&lt;br /&gt;            this.Index = index;&lt;br /&gt;            this.Item = item; &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int Index { get; private set; }&lt;br /&gt;        public TModel Item { get; private set; }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let's add the extension method next: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.WebPages;&lt;br /&gt;&lt;br /&gt;namespace TestActionMethodSelectorAttribute.Extensions&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    public static class RazorCollectionExtensions&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        public static HelperResult Each&lt;TItem&gt;(this IEnumerable&amp;lt;TItem&amp;gt; items,&lt;br /&gt;            Func&amp;lt;IndexedItem&amp;lt;TItem&amp;gt;, HelperResult&amp;gt; template)&lt;br /&gt;        {&lt;br /&gt;            return new HelperResult(&lt;br /&gt;                writer =&gt;&lt;br /&gt;                {&lt;br /&gt;                    for (int i = 0; i &lt; items.Count(); i++)&lt;br /&gt;                    {&lt;br /&gt;                        template(new IndexedItem&amp;lt;TItem&amp;gt;(i, items.ElementAt(i))).WriteTo(writer);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;An example of its usage is shown next in a view: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;@{&lt;br /&gt;    ViewBag.Title = "Home Page";&lt;br /&gt;&lt;br /&gt;    var cars = new []&lt;br /&gt;    {&lt;br /&gt;       new { name = "Audi", color = "Blue", make = "A4" },&lt;br /&gt;       new { name = "BMW", color = "Black", make = "M5" },&lt;br /&gt;       new { name = "Volvo", color = "Red", make = "240" },&lt;br /&gt;       new { name = "Renault", color = "Black", make = "19" }     &lt;br /&gt;    }; &lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@cars.Each(@&amp;lt;li&amp;gt;Car is an @item.Item.name @item.Item.make of color @item.Item.color&amp;lt;/li&amp;gt;)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Take note of the "magic" @item property in use here. What we see here in effect is a convenient way to iterate over a list of objects, in this case an array of anonymous objects which we call "cars" and we just add in some car objects to this array using a collection initializer. Then we output this list with our new Each method which is a razor extension method and specify our template. You need to prefix the first letter in the parenthesis with the @ sign, then use @item to refer to the object. In our Each method we use IndexedModel type for each item in the list. This got both an index and an Item of type TModel (TItem) passing in our item type, in this case the anonymous type that constitutes the "cars" object.&lt;br /&gt;&lt;br /&gt;Thanks to Phil Haack for this nice method! I like this Each method a lot. No need to write that long @foreach razor helper any more. This also should fit nicely into linq expressions like: &lt;br /&gt;@Model.MyList.Where(myItem =&gt; myItem.Age &amp;gt; 19).Each(@&lt;br /&gt;&amp;lt;li&amp;gt;@item.Name &amp;lt;/li&amp;gt;)&lt;br /&gt; to output a list of the name propery for all people above 19 years old in our Model.MyList property, just to take an example.&lt;br /&gt;&lt;br /&gt;This nice method was presented by Phil Haack here: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://channel9.msdn.com/events/mix/mix11/FRM03"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note for those viewing this video, not everything went smooth for Phil Haack in this demonstration, however there were lots of "hidden gems" he presented there at the MIX11 conference in Las Vegas. &lt;br /&gt;&lt;br /&gt;Disclaimer: I added this blog post to extract the source code from his demo into an easily available sample. &lt;br /&gt;&lt;br /&gt;It should be relatively easy now to start creating Razor extension methods as an alternative to HTML helpers and Razor html helpers in MVC by taking a look at this example. Note the use of HelperResult and WriteTo (corresponding Response.Write in ASP.NET).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-6139564347902344057?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/6139564347902344057/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/razor-extension-method-each.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6139564347902344057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6139564347902344057'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/razor-extension-method-each.html' title='Razor extension method Each'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4005569275658231738</id><published>2011-12-30T17:16:00.001-08:00</published><updated>2011-12-30T17:35:46.152-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC Route visualizer routing dll visual studio tool'/><title type='text'>Analyzing routing in your MVC application</title><content type='html'>Routing and ASP.NET MVC woes !!! &lt;br /&gt;&lt;br /&gt;So you have created a MVC application and worked on it a bit, and now your Global.asax contains calls to a setup of your RouteCollection that has got complex logic inside it and now you need to understand your routing better and perhaps fix that particular scenario where routing does not seem to work (keep in mind for instance that the first match algorithm is used when using your MVC routing table). How to understand those routes in a better way without staring at your code. How about interpreting it at realtime using a runtime debugger for just that case. First off, download the &lt;br /&gt;ASP.NET MVC Routing Debugger Visualizer tool. &lt;br /&gt;&lt;br /&gt;Go to the following url: &lt;br /&gt;http://visualstudiogallery.msdn.microsoft.com/2993e666-4534-49c8-807f-e8bffcaee7e0&lt;br /&gt;&lt;br /&gt;Keep in mind that this should be easily installed in Visual Studio 2010 using the Tools =&gt; Extension Manager dialog in DevEnv. &lt;br /&gt;&lt;br /&gt;Now we need to "patch" your system to allow this tool to work. &lt;br /&gt;&lt;br /&gt;First off edit the devenv.exe.config file to allow loading remote sources: &lt;br /&gt;Open the file&lt;br /&gt;C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.config&lt;br /&gt;&lt;br /&gt;Inside the runtime xml element node add the following: &lt;br /&gt;&amp;lt;loadFromRemoteSources enabled="true" /&amp;gt;&lt;br /&gt;&lt;br /&gt;Just to double check, check that the dll is added to the following folder: &lt;br /&gt;C:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers&lt;br /&gt;&lt;br /&gt;There should now be a file called MvcRouteVisualizer.dll in this folder, this is the library which constitutes the ASP.NET MVC Route debugger visualizer tool. &lt;br /&gt;&lt;br /&gt;Start the MVC application with debugging turned on and add a breakpoint in a MVC controller action, I tested this tool out with the HomeController About action in my basic templated ASP.NET MVC application for instance. Hit Ctrl+D+Q (quickwatch) and add a watch to the System.Web.Routing.RouteTable.Routes object (which is a collection of the routes to monitor for our app) and hit the available magnify icon button to the right of the value column of our watch window in our debugger. &lt;br /&gt;&lt;br /&gt;If all now went well, you should have this nifty tool to display the routes in our MVC app. This way, if the routing seem to have gone berserk and you cant understand why your nice routing table is not correctly set up, MVC Route visualizer routing tool comes to your rescue. &lt;br /&gt;&lt;br /&gt;Here is a screenshot of this great tool, happy coding! &lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-Qsa-V9tZJx8/Tv5m29NMWqI/AAAAAAAAAJk/kn3cCZn3dm4/s1600/mvcroutevisualizer.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 94px;" src="http://4.bp.blogspot.com/-Qsa-V9tZJx8/Tv5m29NMWqI/AAAAAAAAAJk/kn3cCZn3dm4/s320/mvcroutevisualizer.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5692100073371753122" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4005569275658231738?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4005569275658231738/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/blog-post.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4005569275658231738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4005569275658231738'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/blog-post.html' title='Analyzing routing in your MVC application'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-Qsa-V9tZJx8/Tv5m29NMWqI/AAAAAAAAAJk/kn3cCZn3dm4/s72-c/mvcroutevisualizer.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-2796279302278080887</id><published>2011-12-28T18:45:00.000-08:00</published><updated>2011-12-28T19:00:31.663-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Custom actionresult mvc datacontract'/><title type='text'>Creating custom ActionResult</title><content type='html'>It is possible to inherit the ActionResult class and create a custom ActionResult. &lt;br /&gt;The following class creates a new kind of ActionResult for spewing out the serialized string of an inputted data contract instance. &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Mvc;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;&lt;br /&gt;namespace TestActionMethodSelectorAttribute.ActionResult&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    public class DataContractSerializedResult : System.Web.Mvc.ActionResult&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        private object data;&lt;br /&gt;&lt;br /&gt;        public DataContractSerializedResult(object data)&lt;br /&gt;        {&lt;br /&gt;            this.data = data;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public override void ExecuteResult(ControllerContext context)&lt;br /&gt;        {&lt;br /&gt;            var response = context.HttpContext.Response;&lt;br /&gt;            response.ContentType = "text/xml";&lt;br /&gt;            DataContractSerializer serializer = new   DataContractSerializer(data.GetType());&lt;br /&gt;            serializer.WriteObject(response.OutputStream, data); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You will need to add a reference to the System.Runtime.Serialization assembly and namespace. We use DataContractSerializer to serialize the object to a string value. The stream in use is the context.HttpContext.Response.OutputStream, where context is the ControllerContext (current). &lt;br /&gt;&lt;br /&gt;It is required to set the ContentType to "text/xml" to output xml. &lt;br /&gt;&lt;br /&gt;Usage, adding a test method to homecontroller (ignore Hungarian notation, this is for demonstration purposes..) : &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;   public DataContractSerializedResult About2()&lt;br /&gt;        {&lt;br /&gt;            return new DataContractSerializedResult(&lt;br /&gt;                new AgeNameDataContract&lt;br /&gt;                {&lt;br /&gt;                     Age = 93,&lt;br /&gt;                     Name = "Gamla Olga"&lt;br /&gt;                });&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then we get the xml outputted of the data contract passed in: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-Z1sSaOU8NRU/TvvWAgTzNsI/AAAAAAAAAJM/y425FssO3hk/s1600/datacontract.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 177px;" src="http://3.bp.blogspot.com/-Z1sSaOU8NRU/TvvWAgTzNsI/AAAAAAAAAJM/y425FssO3hk/s320/datacontract.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5691377858274080450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The morale of the story, to create a new kind of ActionResult: &lt;br /&gt;&lt;br /&gt;- inherit from ActionResult &lt;br /&gt;- implement abstract method ExecuteResult&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-2796279302278080887?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/2796279302278080887/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/creating-custom-actionresult.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2796279302278080887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2796279302278080887'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/creating-custom-actionresult.html' title='Creating custom ActionResult'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Z1sSaOU8NRU/TvvWAgTzNsI/AAAAAAAAAJM/y425FssO3hk/s72-c/datacontract.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-1317318084187819262</id><published>2011-12-28T18:00:00.000-08:00</published><updated>2011-12-28T18:06:30.465-08:00</updated><title type='text'>Timing your MVC Actions</title><content type='html'>Add the following attribute to your MVC actions to view the timing of your mvc actions using System.Diagnostics.Stopwatch class. &lt;br /&gt;&lt;br /&gt;This is another filter attribute example.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Mvc;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;&lt;br /&gt;namespace TestActionMethodSelectorAttribute.Attributes&lt;br /&gt;{&lt;br /&gt;    public class StopwatchAttribute : ActionFilterAttribute&lt;br /&gt;    {&lt;br /&gt;        private Stopwatch _stopWatch;&lt;br /&gt;&lt;br /&gt;        public StopwatchAttribute()&lt;br /&gt;        {&lt;br /&gt;            _stopWatch = new Stopwatch(); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public override void OnActionExecuting(ActionExecutingContext filterContext)&lt;br /&gt;        {&lt;br /&gt;            _stopWatch.Start(); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public override void OnActionExecuted(ActionExecutedContext filterContext)&lt;br /&gt;        {&lt;br /&gt;            _stopWatch.Stop();&lt;br /&gt;            var response = filterContext.HttpContext.Response;&lt;br /&gt;            response.AddHeader("X-elapsed-milliseconds", _stopWatch.ElapsedMilliseconds.ToString()); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Usage (homecontroller): &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;        [Stopwatch] &lt;br /&gt;        public ActionResult About()&lt;br /&gt;        {&lt;br /&gt;            return View();&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is nice to output the elapsed time in millisecond in the http headers, since we then easily can monitor the values outside Visual Studio, in our browser: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-v5GacoT72ko/TvvK3Unj_lI/AAAAAAAAAJA/sdNWpFF2ZXA/s1600/stopwatch.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/-v5GacoT72ko/TvvK3Unj_lI/AAAAAAAAAJA/sdNWpFF2ZXA/s320/stopwatch.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5691365605889015378" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-1317318084187819262?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/1317318084187819262/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/timing-your-mvc-actions.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/1317318084187819262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/1317318084187819262'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/timing-your-mvc-actions.html' title='Timing your MVC Actions'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-v5GacoT72ko/TvvK3Unj_lI/AAAAAAAAAJA/sdNWpFF2ZXA/s72-c/stopwatch.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-8789441513348995931</id><published>2011-12-28T17:27:00.000-08:00</published><updated>2011-12-28T17:33:21.037-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC ActionMethodSelectorAttribute Controllers'/><title type='text'>Using ActionMethodSelectorAttribute in MVC</title><content type='html'>If you want an MVC controller action to be only available for Ajax methods, use theAjaxMethodSelectorAttribute. Inherit this abstract class to create the attribute AjaxOnlyAttribute below and tag this attribute with your method: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Mvc;&lt;br /&gt;&lt;br /&gt;namespace TestActionMethodSelectorAttribute.Attributes&lt;br /&gt;{&lt;br /&gt;    public class AjaxOnlyAttribute : ActionMethodSelectorAttribute&lt;br /&gt;    {&lt;br /&gt;        public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)&lt;br /&gt;        {&lt;br /&gt;            return controllerContext.HttpContext.Request.IsAjaxRequest(); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Usage (testing the attribute out in HomeController): &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;        &lt;br /&gt;        [AjaxOnly] &lt;br /&gt;        public ActionResult About()&lt;br /&gt;        {&lt;br /&gt;            return View();&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If the current request is not an AjaxRequest, a Http 404 is returned. The attribute [HttpPost] and [HttpGet]is inherited from the ActionMethodSelectorAttribute. They also implement the abstract method IsValidForRequest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-8789441513348995931?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/8789441513348995931/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/using-actionmethodselectorattribute-in.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8789441513348995931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8789441513348995931'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/using-actionmethodselectorattribute-in.html' title='Using ActionMethodSelectorAttribute in MVC'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-5112569818378905307</id><published>2011-12-25T20:30:00.001-08:00</published><updated>2011-12-25T21:38:49.323-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Asynchronous MVC controllers'/><title type='text'>Asynchronous MVC controllers end to end example</title><content type='html'>=== PREAMBLE ===&lt;br /&gt;&lt;br /&gt;My intended audience: &lt;br /&gt;&lt;br /&gt;1) You are a programmer or articial being understanding code (probably the former)&lt;br /&gt;2) You work with ASP.NET MVC&lt;br /&gt;3) You must take in use asynchronous processing to handle a slow and time consuming&lt;br /&gt;   MVC action and want to learn how to implement an AsyncController. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If this is the case, please read on! &lt;br /&gt;&lt;br /&gt;== PREAMBLE === &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I guess many of you know how to create an ordinary MVC controller inheriting from System.Web.Mvc.Controller class, but what about creating an Asynchronous MVC controller?&lt;br /&gt;&lt;br /&gt;It is possible to opt-in asynchronous controllers in MVC out of the box of the MVC framework. This will be a code sample of how this is possible. The goal of the asynchronous controller will be to provide better scalability, especially for complex calculations that take long which are accessed by many simultaneous users. Beware though, the standard synchronous design is easier to relate to and will be suitable in many standard scenarios. Asynchronous controllers should only be applied where there is a good reason to expect bottlenecks to be present in the code and in a real production environment. &lt;br /&gt;&lt;br /&gt;Moving on to the asynchronous controller. Instead of inheriting from the controller class, inherit from the System.Web.Mvc.AsyncController class in MVC. The following code shows how to create an asynchronous controller. &lt;br /&gt;&lt;br /&gt;Code sample follows: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Mvc;&lt;br /&gt;using System.Threading;&lt;br /&gt;&lt;br /&gt;namespace SubstitutePartInCompositionContainer.Controllers&lt;br /&gt;{&lt;br /&gt;    public class TestAsyncController : AsyncController&lt;br /&gt;    {&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;        [AsyncTimeout(60000)] &lt;br /&gt;        public ActionResult IndexAsync()&lt;br /&gt;        {&lt;br /&gt;            AsyncManager.OutstandingOperations.Increment();&lt;br /&gt;            ThreadPool.QueueUserWorkItem((s) =&gt;&lt;br /&gt;                {&lt;br /&gt;                    ServiceReference1.NewsServiceClient client =&lt;br /&gt;                     new ServiceReference1.NewsServiceClient();&lt;br /&gt;              &lt;br /&gt;                    TempData["news"] = client.GetSomeNews("Steinkjer"); &lt;br /&gt;                    AsyncManager.OutstandingOperations.Decrement(); &lt;br /&gt;                }, null); &lt;br /&gt;&lt;br /&gt;            return View();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public ActionResult IndexCompleted()&lt;br /&gt;        {&lt;br /&gt;            ViewBag.DateStamp = DateTime.Now;&lt;br /&gt;            ViewBag.News = TempData["news"] as string; &lt;br /&gt;            return View(); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The class in this example is called TestAsyncController. It inherits from the AsyncController class. The class contains two action methods which is called IndexAsync and IndexCompleted. In general, for every asynchronoous MVC action, there must be two method suffixed with Async and Completed, just like every controller must be suffixed with Controller (part of the design by contract conventions in MVC). &lt;br /&gt;&lt;br /&gt;I put the attribute [AsyncTimeout(60000)] here, it is possible to specify in milliseconds how long an async timeout should be allowed to execute before timing out. It is also possible to use the attribute [NoAsynctimeout] instead. &lt;br /&gt;&lt;br /&gt;Further on, I use the static method ThreadPool.QueueUserWorkItem to add an asynchronous call in the current Thread Pool. I use the AsyncManager.OutstandingOperations.Increment() and corresponding Decrement() methods to keep track of the pending asynchronous calls. AsyncManager is part of System.Web.Mvc.Async namespace. This book keeping is required for correctly arriving at the Complete method that will receive the asynchronous result. For convenience, I move the result to the TempData dictionary. This will be available for me in the Complete method in my controller. Since the data I get is a string, I just copy it to the ViewBag (dynamic object) and this is then just displayed in the MVC view Index.cshtml in the folder TestAsync. &lt;br /&gt;&lt;br /&gt;Here is the service contract for the NewsService used (WCF service): &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.ServiceModel;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace TestServices&lt;br /&gt;{&lt;br /&gt; &lt;br /&gt;    [ServiceContract]&lt;br /&gt;    public interface INewsService&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        [OperationContract(AsyncPattern=true)]&lt;br /&gt;        IAsyncResult BeginGetSomeNews(string city, AsyncCallback callback, &lt;br /&gt;         object asyncState);&lt;br /&gt;&lt;br /&gt;        string EndGetSomeNews(IAsyncResult result);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the WCF service tags the operation BeginGetSomeNews with the AsyncPattern equals set to true to allow asynchronous execution. Not only will the IIS service not receive a blocking call, the service itself is also run asynchronous in this case. The WCF service also got a pair of methods this time prefixed with Begin and End. Only the Begin method is attributed with [AsyncPattern=true], the end method is not even attributed with OperationItem attribute without any overloads. This is because the end method is just a callback for the Begin method. As in asynchronous programming, the Begin method starts by receiving its parameters, followed by AsyncCallback callback, object asyncState paramteters. The End method returns string in this case and also receives such an object. &lt;br /&gt;&lt;br /&gt;The service implementation looks like this: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.ServiceModel;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Threading;&lt;br /&gt;&lt;br /&gt;namespace TestServices&lt;br /&gt;{&lt;br /&gt;   &lt;br /&gt;    public class NewsService : INewsService&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        public IAsyncResult BeginGetSomeNews(string city, AsyncCallback callback, &lt;br /&gt;         object asyncState)&lt;br /&gt;        {&lt;br /&gt;            Thread.Sleep(3000); //simulate some sleep &lt;br /&gt;            return new&lt;br /&gt;              CompletedAsyncResult&lt;string&gt;("Here are some news for " + city); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public string EndGetSomeNews(IAsyncResult result)&lt;br /&gt;        {&lt;br /&gt;            var resultFromAsync = result as CompletedAsyncResult&lt;string&gt;; &lt;br /&gt;            return resultFromAsync.Data; &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I use a class called CompletedAsyncResult, this looks like this (MSDN is the source):&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Threading;&lt;br /&gt;&lt;br /&gt;namespace TestServices&lt;br /&gt;{&lt;br /&gt;    &lt;br /&gt;    public class CompletedAsyncResult&lt;T&gt; : IAsyncResult&lt;br /&gt;    {&lt;br /&gt;        T data;&lt;br /&gt;&lt;br /&gt;        public CompletedAsyncResult(T data)&lt;br /&gt;        { this.data = data; }&lt;br /&gt;&lt;br /&gt;        public T Data&lt;br /&gt;        { get { return data; } }&lt;br /&gt;&lt;br /&gt;        #region IAsyncResult Members&lt;br /&gt;        public object AsyncState&lt;br /&gt;        { get { return (object)data; } }&lt;br /&gt;&lt;br /&gt;        public WaitHandle AsyncWaitHandle&lt;br /&gt;        { get { throw new Exception("The method or operation is not implemented."); } }&lt;br /&gt;&lt;br /&gt;        public bool CompletedSynchronously&lt;br /&gt;        { get { return true; } }&lt;br /&gt;&lt;br /&gt;        public bool IsCompleted&lt;br /&gt;        { get { return true; } }&lt;br /&gt;        #endregion&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Then, I just added a Service Reference to the WCF class library containing my service to generate a proxy or service agent to access my WCF service in my controller, as seen in the first code.&lt;br /&gt;&lt;br /&gt;Important GOTCHAS about asynchronous MVC controllers: &lt;br /&gt;&lt;br /&gt;&lt;ul type="square"&gt;&lt;br /&gt;&lt;li&gt; There is no explicit call between the Async and Completed method in the MVC controller inheriting from AsyncController. This is code by design or contract.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; We must "help" MVC keep track of the outstandingoperations for the AsyncManager in our code. When the counter turns to zero again, the async operation decrementing the value last will call its Complete method.. Use AsyncManager throughout. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Google blogger does not handle generic arguments well, but the CompletedAsyncResult object takes string as a generic type argument in my demo code here. It could be a complex type such as a data contract. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; There are many more methods of achieving this, this is just one example.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-5112569818378905307?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/5112569818378905307/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/asynchronous-mvc-controllers.html#comment-form' title='2 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5112569818378905307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5112569818378905307'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/12/asynchronous-mvc-controllers.html' title='Asynchronous MVC controllers end to end example'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-3511419842905122121</id><published>2011-09-16T20:21:00.001-07:00</published><updated>2011-09-16T20:32:26.041-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Embedded files MVC 3 Razor Views Image Javascript CSS'/><title type='text'>Simple access of embedded resources in DLLs in MVC views</title><content type='html'>I was working with embedded views in a DLL in a MVC Razor 3 project today and I had to be able to refer to embedded Javascript .js files, images (jpg and png) and css files in the precompiled views. To make this work I tagged the files as Embedded Resource in my project, compiled the project into a dll and in the other mvc project which used the dll I could get it to fetch the embedded resources easily adding a new MVC controller action.&lt;br /&gt;&lt;br /&gt;The mvc controller action looks like this:&lt;br /&gt;&lt;br /&gt;The code below goes into the Home controller, ContentFile action method, which&lt;br /&gt;returns a FileStreamResult below.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;        public FileStreamResult ContentFile(string id)&lt;br /&gt;        {&lt;br /&gt;            string resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames().ToList().FirstOrDefault(f =&amp;gt; f.EndsWith(id));&lt;br /&gt;            return new FileStreamResult(Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName), GetMIMEType(id));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private string GetMIMEType(string fileId)&lt;br /&gt;        {&lt;br /&gt;            if (fileId.EndsWith(".js"))&lt;br /&gt;            {&lt;br /&gt;                return "text/javascript";&lt;br /&gt;            }&lt;br /&gt;            else if (fileId.EndsWith(".css"))&lt;br /&gt;            {&lt;br /&gt;                return "text/stylesheet";&lt;br /&gt;            }&lt;br /&gt;            else if (fileId.EndsWith(".jpg"))&lt;br /&gt;            {&lt;br /&gt;                return "image/jpeg";&lt;br /&gt;            }&lt;br /&gt;            return "text";&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To use this in the views, write this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="/Home/ContentFile/test.js"&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;link rel="Stylesheet" href="/Home/ContentFile/blue.css"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;img src="/Home/ContentFile/forest.jpg" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To load up an embedded resource we look into the executing dll, which instead should perhaps load a specified assembly if necessary, and then GetManifestResourceStream and retrieving the matching resource name passed in. The MIME type must be set and is resolved by looking at the resource name passed in.&lt;br /&gt;&lt;br /&gt;So the morale is that if you want to load a content file from a DLL in a MVC view, use a controller action and return a FileStreamResult and then load up the content file by writing the route to the ContentFile action.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-3511419842905122121?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/3511419842905122121/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/simple-access-of-embedded-resources-in.html#comment-form' title='4 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/3511419842905122121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/3511419842905122121'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/simple-access-of-embedded-resources-in.html' title='Simple access of embedded resources in DLLs in MVC views'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4036277375020661150</id><published>2011-09-11T15:05:00.000-07:00</published><updated>2011-09-11T15:29:45.072-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Watin web gui test mstest unit testing'/><title type='text'>Testing out the WatiN unit testing</title><content type='html'>WatiN, or "Web application testing in .Net", is based on a similar package for Ruby on Rails called WatiR. This is a browser automation package that gives the ability to run say a MsTest where you open up an url in Internet Explorer 6,7,8 or 9 or Firefox 2 or 3, then locate a gui element in a web page by its id and write in some text, if it is  textbox and click a button. This is making it possible easily write GUI tests for web applications running in an IE or FireFox environment, covering most users. WatiN also gives logging options and makes it possible to create screenshots and so on. &lt;br /&gt;&lt;br /&gt;Lets start with a equivalent "Hello world" unit test using WatiN.&lt;br /&gt;&lt;br /&gt;First off, create a new Mvc 3 Web Application, select Internet Application as the template, choose to add a unit test. Check that you got &lt;i&gt;Nuget&lt;/i&gt; insstalled.&lt;br /&gt;&lt;br /&gt;Then write in the Nuget console:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt; Install-Package WatiN&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will download the necessary DLL files to the unit test project and add to its references. These DLL files are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Interop.SHDocVw  - Mark in the references this DLL and choose Embed Interop Types to false.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;WatiN.Core&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;WatinUnitTest&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Now add a unit test or basic unit test and then write the following test method &lt;br /&gt;inside your test class: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestLogInToMrs()&lt;br /&gt;        {&lt;br /&gt;            string targetServer = "http://mrx.hex.no"; &lt;br /&gt;            using (var browser = new IE(targetServer))&lt;br /&gt;            {&lt;br /&gt;&lt;br /&gt;                LogintoCerebralParese(targetServer, browser);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void LogintoCerebralParese(string targetServer, IE browser)&lt;br /&gt;        {&lt;br /&gt;            browser.ShowWindow(WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle.ShowMaximized);&lt;br /&gt;            browser.Link(l =&gt; l.Url == targetServer + "/CerebralPareseRegister").Click();&lt;br /&gt;            browser.TextField(t =&gt; t.Name == "ctl00$ContentPlaceHolderMain$RoleComboBox").SetAttributeValue("readonly", "");&lt;br /&gt;            browser.TextField(t =&gt; t.Name == "ctl00$ContentPlaceHolderMain$RoleComboBox").TypeText("Registeransvarlig");&lt;br /&gt;            browser.Button("ContentPlaceHolderMain_LoginButton").Click();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this example, an instance of an IE object is instantiated inside the using block. The url specified in the constructor argument is requested. Then the unit test &lt;br /&gt;maximizes the window, then it will search on the login page for a Link object (basically searching for the A tags) by url matching CerebralPareseRegister.&lt;br /&gt;It will then look for a TextField, again using a lambda overload (Linq is supported in WatIN, which is written in C#), overriding its readonly html property using the SetAttributeValue method and setting readonly to empty string, unlocking the readonly textbox. Then it writes in "Registeransvarlig" (a role in my test scenario) in the textfield, using the TypeText method with the argument passed into the text box. The last line looks for a button, i.e. an input tag element with id equal to the passed in argument and invokes the click method which will click the button.&lt;br /&gt;&lt;br /&gt;The test then will check that it is possible to login to this registry. Without giving out to much details to our global audience, we got web registries which there will be about 50 registries later and this single test will test logging into a single registry (CerebralPareseRegistry). We would then probably test all 50 registries and verify that we can log in to the different registries. The Internet Explorer browser is not thread safe and therefore there is a risk that unit tests running in parallel will crash the IE browser. The good thing then, is that when using the IE browser in these parallel tests, they will run in STA (Single thread apartment) and therefore it will avoid the possible crash. An optimization is in the TestInitialize method use the same IE object and then dispose it in the TestComplete method. Instead, use a single IE object per test to keep thread safety. This will increase the test time. The good thing is that these automated web gui tests can be run in automatic mode and for example runned every night in the nightly build. The WatiN framework makes it therefore possible to do full integration unit tests using browser automation so that you can verify that the web application is working for the end user for its core functionality, such as log in to a web application, perform a search and so on. &lt;br /&gt;&lt;br /&gt;The WatiN tests should be testing the core end-user functionality. The different parts of your web application, for example a MVC 3 application, should also have unit tests of their own. &lt;br /&gt;&lt;br /&gt;As I have suggested in previous posts, the MvcContrib TestHelper should be used when testing Controllers and their actions in MVC 3. Unit tests in javascript can use the helper class of Stephen Walther. The views can also use the Razor Single File Generator to tests their views. Finally testing the DAL layer Entity Framework supports testing POCO objects using the Seed function if you use Entity Framework Objects. &lt;br /&gt;&lt;br /&gt;WatiN supports a multitude of functionality and this blogpost just wanted to mention it.&lt;br /&gt;&lt;br /&gt;Check out the http://watin.org website to see the documentation of WatiN and download the package, if you do not want to use Nuget. WatiN is open source and therefore fully customizable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4036277375020661150?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4036277375020661150/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/testing-out-watin-unit-testing.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4036277375020661150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4036277375020661150'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/testing-out-watin-unit-testing.html' title='Testing out the WatiN unit testing'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-6596844387623735333</id><published>2011-09-06T15:19:00.000-07:00</published><updated>2011-09-08T15:16:20.548-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MvcContrib TestHelper unit test Mvc 3 Controller'/><title type='text'>Adventures with the MvcContrib TestHelper</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Unit testing a MVC Controller&lt;/span&gt;&lt;br /&gt;When unit testing a MVC controller, stop reinventing the wheel and take a look at the MvcContrib TestHelper. Add a reference to the MvcContrib.TestHelper.dll and unit testing different functionality of your controller and its actions should be a walk in the park. Yes, using Moq to build up a mocked object is possible, but since MvcContrib TestHelper supports much of the needed functionality, why not start using it?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How to start using the MvcContrib TestHelper?&lt;/span&gt;&lt;br /&gt;Download the MvcContrib TestHelper with the MvcContrib release package from this location: &lt;a href="http://mvccontrib.codeplex.com/releases"&gt;Mvc Contrib&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Install the MVC contrib zipped file. Actually there is no installer, just a bunch of DLL files. It is the file MvcContrib.TestHelper.dll that you are interested in. Add this dll as a reference to the Visual Studio 2010 test project in your solution (remember to add this file to your solution by saying "Copy to output folder" and modify your WiX scripts, if needed), then create a new basic unit test or unit test and at the top add the using statement: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using MvcContrib.TestHelper; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Verify that the view result is returned and view name and model type matches in a unit test for a MVC action &lt;/h4&gt; &lt;br /&gt;Given that we have modified the Index mvc view to be strongly typed by a class Bird in our Models folder, the following code can verify in a single assertion that the returned ActionResult is a ViewResult, that the rendered view name is "Index" and that the model, that is the strongly type that the view is associated with is a given type as follows: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void IndexTestViewResult()&lt;br /&gt;        {&lt;br /&gt;            var controller = new HomeController();&lt;br /&gt;            ActionResult result = controller.Index();&lt;br /&gt;            result.AssertViewRendered().ForView("Index").WithViewData&lt;Bird&gt;(); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First off, I just new my controller I want to test, HomeController in this case. &lt;br /&gt;Then using the extension methods in MvcContrib.TestHelper I call AsserViewRendere() which just asserts that ActionResult is of type ViewResult. Further, I check with the ForView extension method (take note of the chaining going on here) that the view name is Index. The third part of this single assert checks that the View data is of type Bird. &lt;br /&gt;&lt;br /&gt;In this particular example, make note that my Index method looks like the following in my HomeController:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt; public class HomeController : Controller&lt;br /&gt;    {&lt;br /&gt;        public ActionResult Index()&lt;br /&gt;        {&lt;br /&gt;            ViewBag.Message = "Welcome to ASP.NET MVC!";&lt;br /&gt;&lt;br /&gt;            return View("Index", new Bird { SpeciesName = "Crow",&lt;br /&gt; CanFly = true, WeightInGrams = 400, WingspanInCentimetres = 80 });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;       .&lt;br /&gt;       .&lt;br /&gt;       .&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Obviously the Bird class is just a simple sample in this case.. The second argument &lt;br /&gt;could be assigned to variable called model and passed in for cleaner code. The point I want to make here is that when you return a ViewResult, specifically specify the View Name explicitly, as this then can be verified with the ForView extension method in a unit test. &lt;br /&gt;&lt;br /&gt;For more advanced controller tests there are lots of functionality in MvcTestContrib.TestHelper DLL to help out. Do not reinvent the wheel to get started with unit testing your controllers, use MvcContrib TestHelper!&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Towards more complex controller action tests in MVC&lt;/h4&gt;&lt;br /&gt;Just to get started with a custom HttpContext, I wanted to test out the TestControllerBuilder class in MvcContrib.TestHelper. With this class, I adjust the unit test for the index action method a bit: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;       [TestMethod]&lt;br /&gt;        public void IndexTestViewResult()&lt;br /&gt;        {&lt;br /&gt;            TestControllerBuilder builder = new TestControllerBuilder();&lt;br /&gt;            var controller = builder.CreateController&lt;HomeController&gt;(); &lt;br /&gt;            builder.HttpContext.Cache["test"] = "test1"; &lt;br /&gt;            builder.InitializeController(controller); &lt;br /&gt;            ActionResult result = controller.Index();&lt;br /&gt;            result.AssertViewRendered().ForView("Index").WithViewData&lt;Bird&gt;(); &lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;Now, I use the TestControllerBuilder class to create a controller of type HomeController. The builder is then tested out with setting the HttpContext.Cache to a test key-value pair. Further on, the line above instantiates the HomeController by using the CreateController static generic factory method by passing in the home controller as a generic type argument. Then the controller is initialized with the TestControllerBuilder. The unit test passes. Obviously, this just show how the HttpContext can be mocked using the TestControllerBuilder. &lt;br /&gt;&lt;br /&gt;One important note here is the strange error I got thrown at me when running the test the first time. &lt;br /&gt;&lt;br /&gt;&lt;i&gt;Test method TestMvcContribUnitTests.Tests.Controllers.HomeControllerTest.IndexTestViewResult threw exception: &lt;br /&gt;System.InvalidOperationException: Unable to create a factory.  Be sure a mocking framework is available.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;To avoid this error and get the test to pass, add also a reference to a mocking framework. By glancing into the code at the Mvc Contrib Codeplex page, I see that Rhino Mocks and Moq is the two mocking frameworks with support for TestHelper in MvcContrib. Since I have worked most with Moq, I just added a reference to Moq.dll (copy a reference to the Moq.dll assembly file, copy local set to true), and then the test passed. &lt;br /&gt;&lt;br /&gt;This now, shows how to get a HttpContext which can be adjusted (Request, Response, Cache and so on), using Moq and MvcContrib TestHelper. The developer can then focus on the task at hand when it comes to unit test, namely to write efficiently unit tests that are relevant and not reinvent the wheel to get HttpContext up and running in Moq, without using MvcContrib TestHelper. &lt;br /&gt;&lt;br /&gt;I will look into additional adventures of using MvcContrib TestHelper. If there are other use-case scenarios that should be presented, it would be nice to know.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-Y7KHOkmAohs/Tma8645iuII/AAAAAAAAAIw/rq4-YjtlZkA/s1600/testcontrollerbuilder.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 153px;" src="http://2.bp.blogspot.com/-Y7KHOkmAohs/Tma8645iuII/AAAAAAAAAIw/rq4-YjtlZkA/s320/testcontrollerbuilder.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5649410502475036802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Testing a RedirectToAction inside a mvc controller action&lt;/h4&gt;&lt;br /&gt;To test the redirection of an action inside a mvc controller action, use the &lt;br /&gt;following:&lt;br /&gt;&lt;br /&gt;Suppose we have return the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;..&lt;br /&gt;  return RedirectToAction("About"); &lt;br /&gt;..&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The test can then verify that we are returning a RedirectToActionResult and that &lt;br /&gt;the controller action's name is "About" as follows: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;..&lt;br /&gt;result.AssertActionRedirect().ToAction("About");&lt;br /&gt;..&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In case we return a RedirectToActionResult with overload: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;..&lt;br /&gt;    return RedirectToAction("About", "Home"); &lt;br /&gt;..&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To test this we can write:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;..&lt;br /&gt;   result.AssertActionRedirect().ToController("Home").ToAction("About"); &lt;br /&gt;..&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Testing the routing in an MVC application&lt;/h4&gt;&lt;br /&gt;To test out the routes in your MVC application, the following unit test is served as an example using MvcContrib TestHelper: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void RouteTestHomeIndex()&lt;br /&gt;        {&lt;br /&gt;            var routeTable = RouteTable.Routes;&lt;br /&gt;            routeTable.Clear(); &lt;br /&gt;            routeTable.MapRoute(null, "{controller}/{action}/{id}",&lt;br /&gt;                new { controller= "Home", action= "Index", &lt;br /&gt;                 id = UrlParameter.Optional    });&lt;br /&gt;&lt;br /&gt;            "~/Home/Index".ShouldMapTo&lt;HomeController&gt;(action =&gt; action.Index());&lt;br /&gt;            "~/Home/About".ShouldMapTo&lt;HomeController&gt;(action =&gt; action.About()); &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;First line of the unit tests grabs a reference to the RouteTable.Routes property, defined in the System.Web.Routing namespace. The routetable is then cleared and then&lt;br /&gt;the MapRoute method adds a route definition to test. We set up the default route using the MapRoute method. Then we test the two routes "~/Home/Index" and "~/Home/About". These two values are strings and MvcContrib TestHelper has extension method which will check that the route specified in the string maps to a controller using the ShouldMapTo extension method with a generic argument specifying the controller, and in the parameter the action method of the contorller is specifed. Actually, controller =&gt; controller.Index is probably a better lambda argument here. &lt;br /&gt;&lt;br /&gt;This shows that testing out routes are simple using MvcContrib TestHelper. Just use the string extension methods to test out which controller and which method a certain route should take.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-iW2eJHy4VvA/Tmk9RAG1pJI/AAAAAAAAAI4/3ER0iSzP67M/s1600/unitests.PNG"&gt;&lt;img style="float:left; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://1.bp.blogspot.com/-iW2eJHy4VvA/Tmk9RAG1pJI/AAAAAAAAAI4/3ER0iSzP67M/s320/unitests.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5650114569808749714" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-6596844387623735333?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/6596844387623735333/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/adventures-with-mvccontrib-testhelper.html#comment-form' title='3 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6596844387623735333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6596844387623735333'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/adventures-with-mvccontrib-testhelper.html' title='Adventures with the MvcContrib TestHelper'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-Y7KHOkmAohs/Tma8645iuII/AAAAAAAAAIw/rq4-YjtlZkA/s72-c/testcontrollerbuilder.PNG' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4605101613116846129</id><published>2011-09-05T17:07:00.000-07:00</published><updated>2011-09-06T05:51:58.308-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C# Javascript unit test'/><title type='text'>Additional methods in the unit testing of Javascript</title><content type='html'>&lt;span style="font-weight:bold;"&gt;More methods to the unit testing of javascript&lt;/span&gt;&lt;br /&gt;I am building upon the great example of unit testing in javascript by Stephen Walther, and will now present additional methods to the JavascriptUnitTestingFramework.js file he presented.&lt;br /&gt;&lt;br /&gt;Let me first list up the new contents: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;var assert = {&lt;br /&gt;&lt;br /&gt;    areEqual: function (expected, actual, message) {&lt;br /&gt;        if (expected !== actual) {&lt;br /&gt;            throw new Error("Expected value " + expected&lt;br /&gt;                + " is not equal to " + actual + ". " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    areNotEqual: function (expected, actual, message) {&lt;br /&gt;        if (expected === actual) {&lt;br /&gt;            throw new Error("Expected value " + expected&lt;br /&gt;                + " is equal to " + actual + ". " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    isTrue: function (actual, message) {&lt;br /&gt;        if (!actual) {&lt;br /&gt;            throw new Error("The provided actual value" + actual + " is not evaluating to true. " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    isNull: function (actual, message) {&lt;br /&gt;        if (actual != null) {&lt;br /&gt;            throw new Error("The provided actual value " + actual + " must be null. " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    isNotNull: function (actual, message) {&lt;br /&gt;        if (actual == null) {&lt;br /&gt;            throw new Error("The provided actual value " + actual + "must be not null." + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    isFalse: function (actual, message) {&lt;br /&gt;        if (actual) {&lt;br /&gt;            throw new Error("The provided actual value " + actual + " must be false.   " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    isInstanceOfType: function (actual, type, message) {&lt;br /&gt;        if ((actual instanceof type) == false) {&lt;br /&gt;            throw new Error("The provided actual value " + actual + " is not an instance of type  " + type + ". " + message);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    referenceEquals: function (actual, expected, message) {&lt;br /&gt;        if (actual !== expected) {&lt;br /&gt;            throw new Error("The provided actual and expected values does not point to the same object. Actual is " + actual + " and expected is " + expected + " " + message); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I have added much of the methods of the Assert class in C#. The Assert class have static methods such as ReferenceEquals, IsTrue, IsFalse, AreNotEqual and so on and these methods have now been added above.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lets continue with the javascript unit tests using this js file. &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;//At the start of the file for your javascript unit tests &lt;br /&gt;//add a reference to the unit testing reference file JavascriptUnitTestingFramework.js&lt;br /&gt;//Use the reference element and three slashes. &lt;br /&gt;&lt;br /&gt;function testAddNumbers() {&lt;br /&gt;    // Act&lt;br /&gt;    var result = addNumbers(1, 3);&lt;br /&gt;    &lt;br /&gt;    // Assert&lt;br /&gt;    assert.areEqual(4, result, "addNumbers did not return right value!");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testFactorial() {&lt;br /&gt;    var result = factorial(5);&lt;br /&gt;    assert.areEqual(120, result, "factorial did not return righ value!");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testIsTrue() {&lt;br /&gt;    assert.isTrue(110 &gt; 0, "This must evaluate to true for the test to pass.");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testIsNull() {&lt;br /&gt; var city = null; &lt;br /&gt; assert.isNull(city, "Must be null");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testIsNotNull() {&lt;br /&gt;    var city =  { name: "London" };&lt;br /&gt;    assert.isNotNull(city, "Must be not null");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testIsFalse() {&lt;br /&gt;   var actual = 4 &gt; 5; &lt;br /&gt;   assert.isFalse(actual, "The expression must evaluate to false.");&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testIsInstanceOfType() {&lt;br /&gt;    assert.isInstanceOfType(new String("mystring"), String, "The provided actual value must be an instance of type String.");&lt;br /&gt;    assert.isInstanceOfType([1, 2, 3, 4], Array, "The provided value must be an&lt;br /&gt;instance of an array.");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testAreNotEqual() {&lt;br /&gt;    assert.areNotEqual("abc", "abbc", "Provided expected value and actual value are not equal");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testAreEqual() {&lt;br /&gt;    assert.areEqual("def", "def", "The two provided values does not agree."); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testReferenceEquals() {&lt;br /&gt; var a = { city: "Manchester" };&lt;br /&gt; // var c = { country: "Ireland" }; &lt;br /&gt; var b = a;&lt;br /&gt; assert.referenceEquals(a, b, "The two objects does not point to the same object."); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;The unit tests written in C# then looks like this: &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestFactorial()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;&lt;br /&gt;            jsHelper.ExecuteTest("testFactorial");&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestIsTrue()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testIsTrue");   &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestIsNull()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testIsNull");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestIsNotNull()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testIsNotNull");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestAreEqual()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testAreEqual");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestIsFalse()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testIsFalse");      &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestIsInstanceOfType()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testIsInstanceOfType");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestAreNotEqual()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testAreNotEqual");&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TestMethod]&lt;br /&gt;        public void TestReferenceEquals()&lt;br /&gt;        {&lt;br /&gt;            var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;            jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;            jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;            jsHelper.LoadFile("MathTest.js");&lt;br /&gt;            jsHelper.ExecuteTest("testReferenceEquals");&lt;br /&gt;&lt;br /&gt;        } &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok, so as the methods above show that much of the action should take place in the TestInitialize method. I will leave that to figure out for yourself, basically the methods will have some similar Arrange for the individual unit tests. &lt;br /&gt;&lt;br /&gt;So what we now have is a basic way of performing unit tests against javascript using MSTest with methods such as AreNotEqual, AreEqual, IsNull, IsNotNull, ReferenceEquals, IsTrue, IsFalse that are available when doing ordinary C# unit tests. &lt;br /&gt;&lt;br /&gt;Using Stephen Walter's solution makes the client code developer focus at the task at hand at writing &lt;span style="font-style:italic;"&gt;Javascript code&lt;/span&gt; and companion unit test. I would not suggest that you unit test the jQuery based javascript "Gui code", since you need to have a document loaded (with companion DOM tree). Instead, what you should unit test of your javascript code would be your custom logic which is kind of independent of the "GUI" and as such is suitable to doing unit tests and TDD. I find myself now using these unit tests as a quick way of performing TDD with javascript. When developing the factorial function for example, I could verify that the code I was writing by remembering my university days of how a factorial function was indeed spot on by executing a unit test. These unit tests are alsovery convenient to modify and executes very quickly, outside any browser and web server. &lt;br /&gt;&lt;br /&gt;I will now include a zipped file that contains a Visual Studio 2010 solution with a test project that shows how the unit tests are for javascript code is running under MSTest. You will need Microsoft Visual Studio 2010 with support for test projects to open up the solution, this is not supported in Visual Studio 2010 Express.. Many thanks to Stephen Walther for making the unit testing in javascript possible! &lt;br /&gt;&lt;br /&gt;Download the zipped solution with the javscript unit testing framework and companion unit tests in C¤ / javscript here right here from 2Shared drop location:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.2shared.com/file/nKhBvkbL/MvcApplication1.html"&gt;Download zipped solution here of this article [zip]&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Unit testing in Javascript done the right way!&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-1vAFiSt-M8g/TmYXU5vJpUI/AAAAAAAAAIo/WJImg60ao-I/s1600/unitests.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://1.bp.blogspot.com/-1vAFiSt-M8g/TmYXU5vJpUI/AAAAAAAAAIo/WJImg60ao-I/s320/unitests.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5649228430446273858" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4605101613116846129?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4605101613116846129/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/additional-methods-in-unit-testing-of.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4605101613116846129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4605101613116846129'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/additional-methods-in-unit-testing-of.html' title='Additional methods in the unit testing of Javascript'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-1vAFiSt-M8g/TmYXU5vJpUI/AAAAAAAAAIo/WJImg60ao-I/s72-c/unitests.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4640838351011126640</id><published>2011-09-04T15:37:00.000-07:00</published><updated>2011-09-06T05:21:45.175-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unit test javascript tdd mstest qunit'/><title type='text'>Unit testing of javascript in MVC 3 application</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Goal: Unit testing the javascript code&lt;/span&gt;&lt;br /&gt;In todays modern web applications, unit testing all your layers should be a goal. Often a developer unit tests the C#-code, so why only write unit tests for the server code, when the client code (such as javascript) is just as important? The end user uses both, and if there are custom logic in your javascript the code should definately have its own unit tests. In this article I will explain my own little adventure into looking at the possibilities I have to unit test my javascript code. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Initial spin&lt;/span&gt;&lt;br /&gt;I have trying to resolve the issue of how to proper unit test javascript code in a MVC application the latest days. Basically I initially started out with the idea of definining which javascript code I would like to load and which unit test I would like to run. I ended up creating a test solution which was essentially working, but I did not like the end result. The good part was that I was using the &lt;a href='http://docs.jquery.com/QUnit'&gt;QUnit&lt;/a&gt; unit testing framework that much of jQuery is based upon. I basically wrote the necessary code to define the javascript and the unit tests to run and I then looped through the list to launch off the browser to display results from QUnit. Yes, this works and yes it uses the elegant QUnit framework - but there are several negative sides of this &lt;i&gt;browser launcher&lt;/i&gt; approach. The really negative part is that these browser launched tests needs non-automatic supervision. The tester must inspect the results in the browser and there is really a lot of dependendency going on. We need a working browser and web server, so this is not a general unit test. I was striving to find the solution, and in general I wanted to use MS Test, i.e. I wanted to define ordinary unit tests that were "javascript flavored". Before venturing too deep into this seemingly mess, I discovered that somebody else already had thought of this. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Stephen Walter to the rescue&lt;/span&gt;&lt;br /&gt;In his &lt;a href='http://stephenwalther.com/blog/archive/2010/12/20/integrating-javascript-unit-tests-with-visual-studio.aspx'&gt;blog article&lt;/a&gt;, &lt;i&gt;Stephen Walter&lt;/i&gt; explains how to do the proper unit test &lt;br /&gt;with MsTest, which is just what I wanted. Best of all, since we now can use MsTest this will support automatic running of unit tests and fits nicely into MSBuild and the rest of the test infrastructure. Finally the javascript code can be put under control! What I then did was read through Stephen Walter's article and test out his complementary solution. It worked perfectly out of the box, and I do not see much changes that needs to be done to make this suit perfect into MVC 3 as Stephen Walter already shows the solution in such an application. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Summing up the article of Steven Walter&lt;/span&gt;&lt;br /&gt;I just want to confirm to the rest of the interested party that Steven Walter's solution to unit tests in javascript is working perfectly. I will present his solution in summary form next. First of all, the unit test project added to the MVC &lt;br /&gt;project that should have tests for javascript must have a reference to the Microsoft Script Control. This is an ActiveX COM component. The addon can be downloaded using the link next: &lt;a href='http://www.microsoft.com/download/en/details.aspx?id=1949'&gt;Microsoft Script Control 1.0&lt;/a&gt;. Once this DLL has been added to the unit test project, you want to add a &lt;i&gt;unit test&lt;/i&gt;. This will not be a &lt;i&gt;basic unit test&lt;/i&gt;, as this kind of test does not have a &lt;i&gt;TestContext&lt;/i&gt;, which will be needed. Second, add a folder called helpers, and add Stephen Walter's helper class for running the javascript code. The javascript code and javascript unit test will not run in a browser envrironment, but use the ScriptControl class. This will behind the scenes actually use the JScript engine which means that the browser in effect we test is Internet Explorer 8. This will actually suit our needs, since the loading of the additional libraries such as jQuery to support cross browser support should also be needed. The plumbing code to set up the ScriptControl with the correct .js library files I would suggest is set up in the TestInitialize method of your unit test, and it should call a common method, preferably also in Helpers folder to load up the "default" jquery javascript files once javascript code that uses jQueryis to be tested. Beware of the ordering of loading the js files. The js files should be as default be built using build type content (we will load up these files using "loose files"). The path pointing to the js files should point to the javascript files in the Content/Scripts folder. In general, javascript that should be tested and be available for the views should in general reside in the Content/Scripts folder for a MVC application. The tests written in javascript is in Steven Walters example put in a folder called JavascriptTests in the test project. This looks like a good practice. In general, the folder structure under Content/Scripts should somehow match the folder structure under JavascriptTests, once one gets more javascript tests added. &lt;br /&gt;&lt;br /&gt;In Steven Walther's article there is a specific step of setting up the test settings for the javascript code to deploy a folder for the javascript code during the execution of the test. This step should be carefully read, since the tests needs to find the javascript files during the testexecution. Basically, a .testsetting file needs to be added to the solution to make this possible, so I just refer to the article. &lt;br /&gt;&lt;br /&gt;Let me present the helper class which Steven Walter created for instantiating and initializing the ScriptControl instance. &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;   public class JavaScriptTestHelper : IDisposable {&lt;br /&gt;&lt;br /&gt;        private ScriptControl _sc;&lt;br /&gt;        private TestContext _context;&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// You need to use this helper with Unit Tests and not &lt;br /&gt;        /// Basic Unit Tests because you need a Test Context&lt;br /&gt;        /// &lt;/summary&gt;&lt;br /&gt;        /// &lt;param name="testContext"&gt;Unit Test Test Context&lt;/param&gt;&lt;br /&gt;        public JavaScriptTestHelper(TestContext testContext) {&lt;br /&gt;            if (testContext == null) {&lt;br /&gt;                throw new ArgumentNullException("TestContext");&lt;br /&gt;            }&lt;br /&gt;            _context = testContext;&lt;br /&gt;&lt;br /&gt;            _sc = new ScriptControl();&lt;br /&gt;            _sc.Language = "JScript";&lt;br /&gt;            _sc.AllowUI = false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// Load the contents of a JavaScript file into the &lt;br /&gt;        /// Script Engine.&lt;br /&gt;        /// &lt;/summary&gt;&lt;br /&gt;        /// &lt;param name="path"&gt;Path to JavaScript file&lt;/param&gt;&lt;br /&gt;        public void LoadFile(string path) {&lt;br /&gt;            var fileContents = File.ReadAllText(path);&lt;br /&gt;            _sc.AddCode(fileContents);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// Pass the path of the test that you want to execute.&lt;br /&gt;        /// &lt;/summary&gt;&lt;br /&gt;        /// &lt;param name="testMethodName"&gt;JavaScript function name&lt;/param&gt;&lt;br /&gt;        public void ExecuteTest(string testMethodName) {&lt;br /&gt;            dynamic result = null;&lt;br /&gt;            try {&lt;br /&gt;                result = _sc.Run(testMethodName, new object[] { });&lt;br /&gt;            } catch {&lt;br /&gt;                var error = ((IScriptControl)_sc).Error;&lt;br /&gt;                if (error != null) {&lt;br /&gt;                    var description = error.Description;&lt;br /&gt;                    var line = error.Line;&lt;br /&gt;                    var column = error.Column;&lt;br /&gt;                    var text = error.Text;&lt;br /&gt;                    var source = error.Source;&lt;br /&gt;                    if (_context != null) {&lt;br /&gt;                        var details = String.Format("{0} \r\nLine: {1} Column: {2}", source, line, column);&lt;br /&gt;                        _context.WriteLine(details);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                throw new AssertFailedException(error.Description);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Dispose() {&lt;br /&gt;            _sc = null;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The JavascriptTestHelper class of Steven Walter basically news up a ScriptControl class and contains two methods to load a javscript file (.js) and then exceute the test. Of course, several javascript files can be added. Note that the ScriptControl instance which is a COM object needs to be nulled when disposing the object.&lt;br /&gt;&lt;br /&gt;Ok, so this is the class that will be used when writing the [TestMethod] in C# for the javascript test. Basically we must arrange the test using this testhelper to load up the .js files, and then use the test helper to execute the javascript test. The test method name must be added also to the ScriptController instance before starting up. &lt;br /&gt;&lt;br /&gt;Every javascript unit test will of course in essence be written in Javascript, the C# based unit test is just a wrapper, the really interesting part is as always in Javscript when it comes to the client code. So each javascript class will then refer to a utility library. Steven Walther gives a very simple example of  such a library, which is nothing more than providing a AreEqual function. The unit test written in javascript will then refer to this "library", using the ///&lt;reference path="..." /&gt;&lt;br /&gt;syntax. This library will be in the base path of he JavascriptTests folder for now. The path must point to this JavascriptUnitTestLibrary.js file. The AreEqual method is really simple and the addition of more methods to support different errors should be a overcoming task. I will myself try out addind more such methods. The sad part is that this code does not use QUnit to support more function that Steven Walter's AreEqual metod, but this method covers very much of the needed functionality. I will soon add more examples of unit testing functions soon into this file. &lt;br /&gt;&lt;br /&gt;Here is the JavascriptUnitTestLibrary.js file: &lt;br /&gt;&lt;br /&gt;var assert = {&lt;br /&gt;&lt;br /&gt;    areEqual: function (expected, actual, message) {&lt;br /&gt;        if (expected !== actual) {&lt;br /&gt;            throw new Error("Expected value " + expected&lt;br /&gt;                + " is not equal to " + actual + ". " + message);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}; &lt;br /&gt;&lt;br /&gt;The little library does nothing more than define an object with a single method areEqual which will throw an error. The script controller will in the helper class &lt;br /&gt;catch this error and then rethrow it into an AssertFailedException, which MSTest will then recognize and we are getting our fancy detection of errors in Javascript that MSTest will see! Elegant! &lt;br /&gt;&lt;br /&gt;So the only thing next when it comes to the javascript unit test is to write the test and use this utility library. Lets add a new test for demonstrational purposes to the addTwoNumbers method Steven Walther was presenting in this article, the factorial of a number, let's put this additional code to MathTest.js (the reference line at the top should only be listed once).&lt;br /&gt;&lt;br /&gt;MathTest.js: &lt;br /&gt;&lt;br /&gt;/// &lt;reference path="JavaScriptUnitTestFramework.js"/&gt;&lt;br /&gt;function testFactorial() {&lt;br /&gt;    var result = factorial(5);&lt;br /&gt;    assert.areEqual(120, result, "factorial did not return righ value!"); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This test will then assert that the factorial of five is equal to 120 (check with your calculator!). The MathTest.js file is added to the JavascriptTests folder. &lt;br /&gt;&lt;br /&gt;Ok, so next up is then writing the unit test, add a new unit test to the test project &lt;br /&gt;and then write the following: &lt;br /&gt;&lt;br /&gt;  [TestMethod]&lt;br /&gt;  public void TestFactorial()&lt;br /&gt;  {&lt;br /&gt;    var jsHelper = new JavaScriptTestHelper(this.TestContext);&lt;br /&gt;    jsHelper.LoadFile("JavaScriptUnitTestFramework.js");&lt;br /&gt;    jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");&lt;br /&gt;    jsHelper.LoadFile("MathTest.js");&lt;br /&gt;    jsHelper.ExecuteTest("testFactorial");&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;If you can't understand why the code in the JavascriptTests are references as seemingly being in the same folder as the unit test (which is one folder up), this is handled by the testsettings file added previously. Refer to Steven Walthers article. &lt;br /&gt;&lt;br /&gt;The test method in my file, UnitTest1.cs is then newing up the test helper class &lt;br /&gt;and make note, passes in the testcontext of my unit test, which is why a basic unit&lt;br /&gt;test will not suffice in this case. Then the ordering of loading the js files is&lt;br /&gt;important. First the unit test framework js file is added. Then the javascript&lt;br /&gt;code is added which will be tested. Next up the javascript code that contains the &lt;br /&gt;javascript based test is added. If your javascript code uses a lot of jQuery libraries, additional js files should be added before the user provided javascript &lt;br /&gt;code. The ordering is as previously mentioned important, and the paths should be correct. Basically one wants to go up three levels of the current directory and then go into the Scripts or Content/Scripts folder to the target .js file. I really suggest that the Scripts folder should be the place that custom javascript is added and that the .js files that the user creates should be in sub folders here. The base directory of the Scripts folder should only contain the jquery libraries and similar, not the user based code, as this is not very scalable as the web project grows.. &lt;br /&gt;&lt;br /&gt;Finally the ExecuteTest is called and the parameter provided is the name of the javascript test. &lt;br /&gt;&lt;br /&gt;I also of course had to add the factorial function in the Math.js. This code looks like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function factorial(n) {&lt;br /&gt;    if (n &gt; 1) {&lt;br /&gt;        return n * factorial(n - 1);&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;        return 1; &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This factorial function uses recursion to return the factorial of a number. The code is almost the same as a C# based function for the factorial. &lt;br /&gt;&lt;br /&gt;Then I just ran the unit test with Ctrl+R and Ctrl+T and saw it pass in the test results. Great stuff Steven Walther! I believe this is the correct way to do unit tests in javascript, i.e. not using QUnit. &lt;br /&gt;&lt;br /&gt;The next obvious task is to implement more code to Steven Walther's JavascriptUnitTestLibrary.js file. This should be a near future task I will look into. &lt;br /&gt;&lt;br /&gt;I have looked at other parts of unit testing MVC applications. Unit testing controllers are actually very good supported, as these are ordinary classes, which requests can be mocked. The unit testing of views is possible using the RazorSingleFileGenerator or RazorGenerator extension (although many means that unit testing a MVC view should be avoided). &lt;br /&gt;&lt;br /&gt;One open issue is how to unit test a MVC 3 Razor helper, I will look into this perhaps using RazorSingleFileGenerator extension in the near future.. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-kQEiA80YDr4/TmQOuDQOEPI/AAAAAAAAAIg/FQRU2NS8ii0/s1600/javascriptunittest.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 198px;" src="http://1.bp.blogspot.com/-kQEiA80YDr4/TmQOuDQOEPI/AAAAAAAAAIg/FQRU2NS8ii0/s320/javascriptunittest.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5648656016939553010" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4640838351011126640?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4640838351011126640/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/towards-improved-unit-testing-of.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4640838351011126640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4640838351011126640'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/09/towards-improved-unit-testing-of.html' title='Unit testing of javascript in MVC 3 application'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-kQEiA80YDr4/TmQOuDQOEPI/AAAAAAAAAIg/FQRU2NS8ii0/s72-c/javascriptunittest.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4167230552273368751</id><published>2011-08-05T18:04:00.001-07:00</published><updated>2011-08-05T19:55:12.888-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AutoDisplayAttribute PostSharp C# Attribute DisplayAttribute'/><title type='text'>Automatic DisplayAttribute using PostSharp</title><content type='html'>&lt;h2&gt;The Problem&lt;/h2&gt;&lt;br /&gt;I worked with a MVC 3 web application the other day and was asked to translate the properties to Norwegian. The MVC 3 views are written in Razor view engine and the models are set to DataContract classes. These classes consists of multiple properties and each property needs to have a DisplayAttribute where the Name property is set to the text to display. An overload of the DisplayAttribute is to provide the type of a Resource file (public) followed by the Name attribute, which will in this case be the Resource key inside the Resource file. &lt;br /&gt;&lt;br /&gt;After translating large DataContract classes with many DataMember properties, I thought this was a very tedious process. Another challenge was that I got runtime&lt;br /&gt;exceptions when opening the MVC 3 view in a browser just to see an exception being &lt;br /&gt;thrown at me because the resource file did not have a matching resource key which &lt;br /&gt;should be tied to a property by given Name in the DisplayAttribute. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Attributes being difficult&lt;/h2&gt;&lt;br /&gt;The source of this problem is actually that Attributes in C# cannot define the Resource key directly, but by a string literals. The reason for this is limitations in the types supported in the parameters of a attribute. The ResourceType of the DisplayAttribute is set to the Resource file Type (the resx file is actually a class, inspect the designer.cs file to see its structure). The Name attribute is as previously mentioned a string literal, hardly very refactoring friendly. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Finding a solution&lt;/h2&gt;&lt;br /&gt;In another project at my work we have used PostSharp to aid in such repetitive tasks, where each property or class needs to be tagged with attributes in a certain pattern. I created a test project and implemented a PostSharp attribute / aspect called AutoDisplayAttribute. This attribute is set on the class level and will decorate all properties with a required display attribute and a resource key set to the property name. The client of this aspect can enforce lookup in the Resource File which means an error will be raised if there are no matching Resource key. The default behavior of this aspect is to avoid setting the DisplayAttribute if no matches are found in the Resource File specified (forceLookup). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Download ILSpy and SharpCrafter's PostSharp&lt;/h2&gt;&lt;br /&gt;I also used ILSpy to inspect the results in the DLL file of my test project, and the properties were all decorated with my desired DisplayAttribute. ILSpy is free software and is similar to Reflector. The tool is very useful to inspect metadata for DLL files and disassemble them to reveal the source code.  &lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.sharpdevelop.net/ILSpy.ashx"&gt;ILSpy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you have not used PostSharp earlier, you need to download the setup from SharpCrafters. The version I used is PostSharp version 2.1 CTP 3. The download page should be available here: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sharpcrafters.com/downloads/postsharp-2.1/ctp-3"&gt;PostSharp 2.1 Community Edition CTP 3&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The PostSharp.dll file must be added in the References to your test project to test out the source code I will present next. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The source code for the AutoDisplayAttribute&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;The source code for the AutoDisplayAttribute follows below. &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint" style="font-size:10pt;font-family:TimesGaramond,Verdana"&gt;&lt;br /&gt;&lt;br /&gt;        // We set up multicast inheritance so  the aspect is automatically added to children types.&lt;br /&gt;        [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]&lt;br /&gt;        [Serializable]&lt;br /&gt;        public sealed class AutoDisplayAttribute : TypeLevelAspect, IAspectProvider&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;            private Type _resourceType;&lt;br /&gt;            private bool _forceLookUp; &lt;br /&gt;&lt;br /&gt;            public AutoDisplayAttribute(Type resourceType, bool forceLookup = false) : base()&lt;br /&gt;            {&lt;br /&gt;                _resourceType = resourceType;&lt;br /&gt;                _forceLookUp = forceLookup; &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // This method is called at build time and should just provide other aspects.&lt;br /&gt;            public IEnumerable&lt;AspectInstance&gt; ProvideAspects(object targetElement)&lt;br /&gt;            {&lt;br /&gt;                Type targetType = (Type)targetElement;           &lt;br /&gt;                var targetTypeProperties = GetTargetTypeProperties(targetType).Distinct(); &lt;br /&gt;                    &lt;br /&gt;                // Add a Display attribute to every relevant property.&lt;br /&gt;                foreach (PropertyInfo property in targetTypeProperties)&lt;br /&gt;                {                    &lt;br /&gt;                    if (!property.IsDefined(typeof(NotAutoDisplayAttribute), false) &amp;&amp; &lt;br /&gt;                        !property.IsDefined(typeof(DisplayAttribute), false))&lt;br /&gt;                    {&lt;br /&gt;                        if ((!_forceLookUp) &amp;&amp; (_resourceType.GetProperty(property.Name) == null))&lt;br /&gt;                        {&lt;br /&gt;                            continue;&lt;br /&gt;                        }&lt;br /&gt;                        CustomAttributeIntroductionAspect introduceDisplayAspect = &lt;br /&gt;CreateDisplayAttributeIntroductionAspect();&lt;br /&gt;                        InitDisplayAttributeForProperty(introduceDisplayAspect, property);&lt;br /&gt;                        yield return new AspectInstance(property, introduceDisplayAspect);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            private void InitDisplayAttributeForProperty(CustomAttributeIntroductionAspect introduceDisplayAspect, PropertyInfo property)&lt;br /&gt;            {&lt;br /&gt;                introduceDisplayAspect.CustomAttribute.NamedArguments.Add("ResourceType", _resourceType);&lt;br /&gt;                introduceDisplayAspect.CustomAttribute.NamedArguments.Add("Name", property.Name);              &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            private static PropertyInfo[] GetTargetTypeProperties(Type targetType)&lt;br /&gt;            {&lt;br /&gt;                return targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            private static CustomAttributeIntroductionAspect CreateDisplayAttributeIntroductionAspect()&lt;br /&gt;            {&lt;br /&gt;                CustomAttributeIntroductionAspect introduceDisplayAspect =&lt;br /&gt;                    new CustomAttributeIntroductionAspect(&lt;br /&gt;                        new ObjectConstruction(typeof(DisplayAttribute).GetConstructor(Type.EmptyTypes)));&lt;br /&gt;                return introduceDisplayAspect;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [AttributeUsage(AttributeTargets.Property)]&lt;br /&gt;        public sealed class NotAutoDisplayAttribute : Attribute&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;AutoDisplayAttribute code explained&lt;/h2&gt;&lt;br /&gt;The class above generates the DisplayAttribute for properties inside the &lt;br /&gt;class the AutoDisplayAttribute is applied on, which is the Attribute which is used to lookup the string to display for a given property. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;The TypeLevelAspect is the parent class for AutoDisplayAttribute and the class also &lt;br /&gt;implements the IAspectProvider interface. The interface consists of the public method ProvideAspects which will return an IEnumerable of AspectInstance. All these supportive classes and interface is part of the PostSharp API which is used in the code to provide the "magic" post-compilation code executed right during/after the default compilation process. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Talk and embrace&lt;/h2&gt;&lt;br /&gt;I like this AutoDisplayAttribute a lot. The aspect will definately be a time saver. If you set forceLookup to true on all classes that should have translated properties (usually data contracts), excluding the properties tagged with NotAutoDisplayAttribute, you will get compilation errors when the Resource lookup defined in a Display(Name="MyProperty", ResourceType=typeof(MyResourceType)], which is a huge benefit compared to having run time exceptions thrown at you when the display lookup fails. To fix such an exception, add the resource key and associated resource value in the resource file and build again. If the build went fine, the display attributes are set up. When you refactor a property (i.e. rename), the AutoDisplayAttribute will indirectly require that the resource key is also refactored. To avoid this, it is possible to rather stick to adding the DisplayAttribute manually, but try to keep up this when having DataContract classes with many properties that must be translated and displayed using a resource file. Instead, when having AutoDisplayAttribute on all data contracts and forcing lookup, the compilation errors will guide you to keep the lookup process in a "type-safe" manner, requiring that for each property name there must be a resource key with the same case-sensitive name. In addition, this attribute / aspect is a huge time saver and when the data contracts are tagged with this attribute, it merely consists of adding the [AutoDisplay(typeof(MyResource), forceLookup:true)] tag at the class (instead of lots of [Display(..)] attributes polluting your data contract.. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Use-case of this attribute&lt;/h3&gt;&lt;br /&gt;A minimalistic example follows. &lt;br /&gt;&lt;br /&gt;Consider this data contract class. Note the AutoDisplayAttribute at the top of the class.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt; [AutoDisplay(typeof(Resource1), forceLookup:true)] &lt;br /&gt;    public class TestModel&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        public DateTime? BirthDate { get; set; }&lt;br /&gt;&lt;br /&gt;        public string FirstName { get; set; } &lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lets follow up with a simple razor view sample&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;@Html.LabelFor(model =&gt; model.BirthDate) &lt;br /&gt;@Html.TextBoxFor(model =&gt; model.BirthDate, new { id = "dtpBirthDate" }) &lt;br /&gt;&lt;br /&gt;@Html.LabelFor(model =&gt; model.FirstName)&lt;br /&gt;@Html.TextBoxFor(model =&gt; model.FirstName, new { id = "tbFirstName" }) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Of course, this attribute is very general and can be used in other frameworks &lt;br /&gt;than MVC 3. When running the application, the labels should now use the value from the Resource file by given resource key. &lt;br /&gt;&lt;br /&gt;Please note that the forceLookup is set default to false. To enforce lookup and letting the compiler aiding you that the resource file do indeed have the resource key, set the forceLookup to true explicitly. &lt;br /&gt;&lt;br /&gt;In the end, a screen shot from ILSpy to show the magic revealed. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-lTMYcSrLKi4/Tjyg0qIEwXI/AAAAAAAAAIM/oNnZxfw8G-s/s1600/ilspy.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 249px;" src="http://1.bp.blogspot.com/-lTMYcSrLKi4/Tjyg0qIEwXI/AAAAAAAAAIM/oNnZxfw8G-s/s320/ilspy.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5637557660082815346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Download sample solution here: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://tore.aurstad.net/TestDisplayCustomAttributeMvc3.zip"&gt;Download sample MVC 3 solution with AutoDisplayAttribute implementation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Regards, Tore Aurstad&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4167230552273368751?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4167230552273368751/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/08/automatic-displayattribute-using.html#comment-form' title='3 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4167230552273368751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4167230552273368751'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/08/automatic-displayattribute-using.html' title='Automatic DisplayAttribute using PostSharp'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-lTMYcSrLKi4/Tjyg0qIEwXI/AAAAAAAAAIM/oNnZxfw8G-s/s72-c/ilspy.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4075053536825610723</id><published>2011-07-17T08:39:00.000-07:00</published><updated>2011-07-17T08:46:38.336-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Slides'/><category scheme='http://www.blogger.com/atom/ns#' term='ES5'/><category scheme='http://www.blogger.com/atom/ns#' term='CS'/><category scheme='http://www.blogger.com/atom/ns#' term='Ecmascript 5'/><title type='text'>Slides about Ecmascript 5 arrays</title><content type='html'>I am publishing some slides about Ecmascript 5 arrays written in Norwegian in this article. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://tore.aurstad.net/EcmaScript 5 Arrays.ppt"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4075053536825610723?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4075053536825610723/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2011/07/slides-about-ecmascript-5-arrays.html#comment-form' title='2 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4075053536825610723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4075053536825610723'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2011/07/slides-about-ecmascript-5-arrays.html' title='Slides about Ecmascript 5 arrays'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-927327319416986183</id><published>2010-12-30T16:40:00.000-08:00</published><updated>2010-12-30T17:01:46.973-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Histogram equalization.'/><title type='text'>Histogram equalization</title><content type='html'>I have added histogram equalization to the Image Algorithms demo. This method scans through an image, inspecting each pixel and creates a histogram. If a pixel p_q of grayscale intensity g_q is found at location (x,y), the Histogram H is incremented at position g_q for all grayscale levels L = 0 .. G-1, where G = 256 for grayscale images. A cumulative histogram is then calculated and the resulting pixel value is the ratio between the cumulative histogram and the total amounts of pixels in the image multiplied with G - 1. &lt;br /&gt;&lt;br /&gt;More formally.&lt;br /&gt;&lt;br /&gt;ALGORITHM - Histogram equalization.&lt;br /&gt;&lt;br /&gt;1. For an NxM image of G gray levels, create an array H (histogram) of length G initialized with default intensity value 0. &lt;br /&gt;&lt;br /&gt;2. Form the image histogram. Scan every pixel and increment relevant position in the histogram H. If pixel p has intensity g_p, perform:&lt;br /&gt;H[g_p] = H[g_p + 1. &lt;br /&gt;&lt;br /&gt;3. Form the cumulative image histogram H_c. Set: &lt;br /&gt;H_c[0] = H[0]&lt;br /&gt;H_c[p] = H_c[p-1] + H[p] for all pixel intensities p where p = 0,1,2... G-1&lt;br /&gt;&lt;br /&gt;4. Rescan the image and calculate the corrected intensity, which it output. &lt;br /&gt;Let T[p] = round(((G-1)/(N*M)) * H_c[p]. For a pixel of intensity p in the image &lt;br /&gt;at position x,y, use T[p] to find the correct adjusted value.&lt;br /&gt;&lt;br /&gt;5. Display image results. &lt;br /&gt;&lt;br /&gt;END.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note about step 4. Use the (double) cast when doing the math.. In general, histogram equalization is all about creating a Histogram of an image, then form a cumulative histogram, and then use the ratio between the total amount of pixels N*M and multiply with the cumulative histogram H_c[p] and then multiply with (G-1), usually 255.. This will set the most luminous pixels in the image near full intensity, will the less luminous pixels towards zero intensity, increasing the dynamic range and contrast in the image.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note about the demo, I have added also Hough transform (tested some basic images) and &lt;br /&gt;filters for displaying histogram of the histogram equalization. Test them out. Hough transform shown the sinusoidal images in the parameter space and should be considered as not finished code. &lt;br /&gt;&lt;br /&gt;A demonstration follows. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MFfxHf2W1dA/TR0p8eYE_cI/AAAAAAAAAEc/GVR66aDkWJY/s1600/imagefilters1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 296px;" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/TR0p8eYE_cI/AAAAAAAAAEc/GVR66aDkWJY/s320/imagefilters1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5556643634168004034" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is equalized to:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MFfxHf2W1dA/TR0qqVhQILI/AAAAAAAAAEk/lqq1lNyCRo0/s1600/imagefilters2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 281px;" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/TR0qqVhQILI/AAAAAAAAAEk/lqq1lNyCRo0/s320/imagefilters2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5556644422064545970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Download the demo here: &lt;br /&gt;&lt;a href="http://tore.aurstad.net/ImageAlgorithmsDemo.zip"&gt;Image algorithms demo [2,7 Mb zip] &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;To summarize, to understand histogram equalization is to consider the cumulative histogram and scale this with the ratio with the total amount of pixels multiplied with 255 (G-1).. The result is that the brightest pixels are moved towards full intensity 255 and the darkest pixels are moved towards 0, increasing the contras and dynamic range.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-927327319416986183?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/927327319416986183/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/histogram-equalization.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/927327319416986183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/927327319416986183'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/histogram-equalization.html' title='Histogram equalization'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MFfxHf2W1dA/TR0p8eYE_cI/AAAAAAAAAEc/GVR66aDkWJY/s72-c/imagefilters1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-5809540510652955408</id><published>2010-12-28T19:03:00.000-08:00</published><updated>2010-12-28T19:09:40.679-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Filters Treshold Wpf C# Iterative Optimal'/><title type='text'>Test out iterative optimal treshold algorithm on images?</title><content type='html'>&lt;blockquote&gt;Merry Xmas&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MFfxHf2W1dA/TRqlL-YCwfI/AAAAAAAAAEU/CkRYes3oF3Y/s1600/bloodDiff.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 220px; height: 320px;" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/TRqlL-YCwfI/AAAAAAAAAEU/CkRYes3oF3Y/s320/bloodDiff.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5555934715455914482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tore.aurstad.net/ImageAlgorithmsDemo.zip"&gt;Image algorithms demo [2,6 MB zip]&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-5809540510652955408?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/5809540510652955408/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/test-out-iterative-optimal-treshold.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5809540510652955408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5809540510652955408'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/test-out-iterative-optimal-treshold.html' title='Test out iterative optimal treshold algorithm on images?'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MFfxHf2W1dA/TRqlL-YCwfI/AAAAAAAAAEU/CkRYes3oF3Y/s72-c/bloodDiff.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-3299343196465989157</id><published>2010-12-28T17:04:00.000-08:00</published><updated>2010-12-28T18:45:03.768-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Iterative optimal treshold selection wpf tresholding image algorithms c#'/><title type='text'>Iterative optimal tresholding</title><content type='html'>&lt;script type="text/javascript" language="javascript" src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" language="javascript" src="http://google-code-prettify.googlecode.com/svn/trunk/src/lang-css.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;function addLoadEvent(func) {&lt;br /&gt;  var oldonload = window.onload;&lt;br /&gt;  if (typeof window.onload != 'function') {&lt;br /&gt;    window.onload = func;&lt;br /&gt;  } else {&lt;br /&gt;    window.onload = function() {&lt;br /&gt;      if (oldonload) {&lt;br /&gt;        oldonload();&lt;br /&gt;      }&lt;br /&gt;      func();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;addLoadEvent(prettyPrint);&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;/* Pretty printing styles. Used with prettify.js. */&lt;br /&gt;&lt;br /&gt;.str { color: #080; }&lt;br /&gt;.kwd { color: #008; }&lt;br /&gt;.com { color: #800; }&lt;br /&gt;.typ { color: #606; }&lt;br /&gt;.lit { color: #066; }&lt;br /&gt;.pun { color: #660; }&lt;br /&gt;.pln { color: #000; }&lt;br /&gt;.tag { color: #008; }&lt;br /&gt;.atn { color: #606; }&lt;br /&gt;.atv { color: #080; }&lt;br /&gt;.dec { color: #606; }&lt;br /&gt;pre.prettyprint { padding: 2px; border: 1px solid #888; }&lt;br /&gt;&lt;br /&gt;@media print {&lt;br /&gt;  .str { color: #060; }&lt;br /&gt;  .kwd { color: #006; font-weight: bold; }&lt;br /&gt;  .com { color: #600; font-style: italic; }&lt;br /&gt;  .typ { color: #404; font-weight: bold; }&lt;br /&gt;  .lit { color: #044; }&lt;br /&gt;  .pun { color: #440; }&lt;br /&gt;  .pln { color: #000; }&lt;br /&gt;  .tag { color: #006; font-weight: bold; }&lt;br /&gt;  .atn { color: #404; }&lt;br /&gt;  .atv { color: #060; }&lt;br /&gt;}&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have tested out and implemented another filter in my image algorithms demo. I follow the Iterative (optimal) treshold selection algorithm from the "Image Processing, Analysis and Machine Vision" book from my Computer Vision course, which I took when studying to my Master of Science (Siv. ing datateknikk) degree at NTNU, Trondheim. It is a simple algorithm, consisting of these steps. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div  style="font-family:trebuchet ms;"&gt;ALGORITHM - Iterative optimal tresholding.&lt;br /&gt;&lt;br /&gt;GOAL: Separate an image into two regions, background and foreground.&lt;br /&gt;DEFINITIONS: Background is pixels&lt;br /&gt;which got intensity below the current treshold, calculated in the algorithm's iterations. Foreground pixels got intensity above the current treshold.&lt;br /&gt;&lt;br /&gt;STEPS:&lt;span style="font-family: trebuchet ms;font-size:85%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;pre style="font-family: trebuchet ms;"&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;1.Calculate the initial average of the current treshold value. Set this value to the&lt;br /&gt;average of the &lt;span style="font-style: italic;"&gt;four corner pixels average value.&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div style="font-family: trebuchet ms;font-family:trebuchet ms;" &gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;2. Traverse the image. If a pixel is above the current treshold value, it is added to the sum of object pixels&lt;br /&gt;(foreground pixels). Incremement the count of foreground pixels. Also, vice versa for the background pixels. Add to the sum of background pixels and increment the background pixels if the pixel's intensity is below the treshold value.&lt;br /&gt;&lt;br /&gt;3. Calculate the average of the background average and object (foreground average) and set this to the next treshold value.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: trebuchet ms;font-family:trebuchet ms;" &gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;4. If not the next treshold is the same as current treshold, iterate the image again, but now set current treshold to next treshold. When the next and current treshold is same, the treshold calculated is the optimal treshold value. End iteration or break at 100 iterations.&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family: trebuchet ms;font-family:trebuchet ms;font-size:85%;" class="Apple-style-span"  &gt;&lt;br /&gt;5. After calculation is complete, display result. Set the object pixels to full pixel intensity (255). Background&lt;br /&gt;pixels are set to 0, creating a binary image showing foreground and background.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: italic; font-family: georgia; color: rgb(255, 153, 0);"&gt;&lt;blockquote&gt;&lt;span style="color: rgb(102, 0, 0);"&gt;It took five iterations to calculate the iterative optimal treshold value for the infamous Lenna image, calculated to be 162 in pixel intensity. For an average picture one would expect the value to be above 140 - 180, if the picture is grayscale image with good contrast.&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;code&gt;&lt;span style="color: rgb(51, 102, 255);font-size:180%;" &gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;Result:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRqR_EzDSmI/AAAAAAAAAEM/KhkeXoRpj9E/s1600/treshold.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 311px;" src="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRqR_EzDSmI/AAAAAAAAAEM/KhkeXoRpj9E/s320/treshold.jpg" alt="" id="BLOGGER_PHOTO_ID_5555913603120581218" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="prettyprint"&gt;&lt;span&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;IMPLEMENTATION - OptimalTresholdFilter.cs &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="prettyprint"&gt;&lt;span&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace ImageAlgorithms.Filters.Treshold&lt;br /&gt;{&lt;br /&gt;  public class OptimalTresholdFilter : ImageFilterBase&lt;br /&gt;  {&lt;br /&gt;&lt;br /&gt;      int objectPixelSum = 0;&lt;br /&gt;      int backgroundPixelSum = 0;&lt;br /&gt;      int currentTresholdValue = 0;&lt;br /&gt;      int nextTresholdValue = 0;&lt;br /&gt;      int objectPixelsCount = 0;&lt;br /&gt;      int backgroundPixelCount = 0;&lt;br /&gt;&lt;br /&gt;      public OptimalTresholdFilter()&lt;br /&gt;      {&lt;br /&gt;          Header = "Optimal treshold filter";&lt;br /&gt;          FilterType = FilterTypeEnum.TresholdFilter;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public override void FilterProcessImage(int width, int height)&lt;br /&gt;      {&lt;br /&gt;          //base.FilterProcessImage(width, height);&lt;br /&gt;&lt;br /&gt;          //Read first four pixels (edges of image)&lt;br /&gt;          //Calculate the average of object pixels and background pixels&lt;br /&gt;          //Let avg+1 = average of background pixels and object pixels&lt;br /&gt;          //if avg+1 and avg is the same, stop, else continue.    &lt;br /&gt;          CalculateAverage(width, height, 0);&lt;br /&gt;          DisplayTresholdImage(width, height);           &lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void DisplayTresholdImage(int width, int height)&lt;br /&gt;      {&lt;br /&gt;          for (int i = 0; i &amp;lt; width; i++)&lt;br /&gt;          {&lt;br /&gt;              for (int j = 0; j &amp;lt; height; j++)&lt;br /&gt;              {&lt;br /&gt;                  int position = (j*width) + i;&lt;br /&gt;                  if (TemporaryImageData[i, j] &amp;gt; nextTresholdValue)&lt;br /&gt;                  {                  &lt;br /&gt;                      ResultingImageData[position] = 255;&lt;br /&gt;                  }&lt;br /&gt;                  else&lt;br /&gt;                  {&lt;br /&gt;                      ResultingImageData[position] = 0;                                             &lt;br /&gt;                  }&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;        &lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void CalculateAverage(int width, int height, int iteration)&lt;br /&gt;      {&lt;br /&gt;          InitFilterIteration();&lt;br /&gt;          CheckInitialStep(width, height, iteration);&lt;br /&gt;          TraverseImageBackgroundForeground(width, height, iteration);&lt;br /&gt;          CheckPixelCounts();&lt;br /&gt;          CalculateNextTreshold();&lt;br /&gt;          if (nextTresholdValue != currentTresholdValue &amp;amp;&amp;amp; iteration &amp;lt; 100)&lt;br /&gt;          {&lt;br /&gt;              currentTresholdValue = nextTresholdValue;&lt;br /&gt;              CalculateAverage(width, height, iteration + 1);&lt;br /&gt;          }   &lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void CalculateNextTreshold()&lt;br /&gt;      {&lt;br /&gt;          nextTresholdValue = ((objectPixelSum / objectPixelsCount) +&lt;br /&gt;         (backgroundPixelSum / backgroundPixelCount)) / 2;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void TraverseImageBackgroundForeground(int width, int height, int iteration)&lt;br /&gt;      {&lt;br /&gt;          for (int i = 0; i &amp;lt; width; i++)&lt;br /&gt;          {&lt;br /&gt;              for (int j = 0; j &amp;lt; height; j++)&lt;br /&gt;              {&lt;br /&gt;                  if (TemporaryImageData[i, j] &amp;gt; currentTresholdValue)&lt;br /&gt;                  {&lt;br /&gt;                      AddToObjectPixels(i, j);&lt;br /&gt;                  }&lt;br /&gt;                  else&lt;br /&gt;                  {&lt;br /&gt;                      if (iteration &amp;gt; 0)&lt;br /&gt;                      {&lt;br /&gt;                          AddToBackgroundPixels(i, j);&lt;br /&gt;                      }&lt;br /&gt;                  }&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void AddToBackgroundPixels(int i, int j)&lt;br /&gt;      {&lt;br /&gt;          backgroundPixelSum += TemporaryImageData[i, j];&lt;br /&gt;          backgroundPixelCount++;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void AddToObjectPixels(int i, int j)&lt;br /&gt;      {&lt;br /&gt;          objectPixelSum += TemporaryImageData[i, j];&lt;br /&gt;          objectPixelsCount++;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void CheckInitialStep(int width, int height, int iteration)&lt;br /&gt;      {&lt;br /&gt;          if (iteration == 0)&lt;br /&gt;          {&lt;br /&gt;              backgroundPixelSum = (TemporaryImageData[0, 0] + TemporaryImageData[width - 1, 0] +&lt;br /&gt;                  TemporaryImageData[0, height - 1] +&lt;br /&gt;TemporaryImageData[width - 1, height - 1]);&lt;br /&gt;              backgroundPixelCount = 4;&lt;br /&gt;              currentTresholdValue = backgroundPixelSum / backgroundPixelCount;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void CheckPixelCounts()&lt;br /&gt;      {&lt;br /&gt;          objectPixelsCount = Math.Max(1, objectPixelsCount);&lt;br /&gt;          backgroundPixelCount = Math.Max(1, backgroundPixelCount);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      private void InitFilterIteration()&lt;br /&gt;      {&lt;br /&gt;          backgroundPixelCount = 0;&lt;br /&gt;          objectPixelsCount = 0;&lt;br /&gt;          backgroundPixelSum = 0;&lt;br /&gt;          objectPixelSum = 0;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Download the latest version of the algorithms demo (v1.1.) to test out the optimal treshold filter. As you can see in the code above, the class inherits from ImageFilterBase, which handles some of the "logistics" around the image filter (loading the filter and showing the result).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-3299343196465989157?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/3299343196465989157/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/iterative-optimal-tresholding.html#comment-form' title='0 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/3299343196465989157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/3299343196465989157'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/iterative-optimal-tresholding.html' title='Iterative optimal tresholding'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MFfxHf2W1dA/TRqR_EzDSmI/AAAAAAAAAEM/KhkeXoRpj9E/s72-c/treshold.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4782768842047917447</id><published>2010-12-27T19:46:00.000-08:00</published><updated>2010-12-27T20:02:27.770-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sobel Computer Vision WPF Edge detection blur filter computer graphics'/><title type='text'>Image filter algorithms demo is updated!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MFfxHf2W1dA/TRlhIkfHkrI/AAAAAAAAAEE/MXfIACNNH-U/s1600/havana2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 316px; height: 320px;" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/TRlhIkfHkrI/AAAAAAAAAEE/MXfIACNNH-U/s320/havana2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5555578415199261362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MFfxHf2W1dA/TRlgJ0UrI0I/AAAAAAAAAD8/iR_BiYrqy6U/s1600/havana.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 314px; height: 320px;" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/TRlgJ0UrI0I/AAAAAAAAAD8/iR_BiYrqy6U/s320/havana.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5555577337118663490" /&gt;&lt;/a&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MFfxHf2W1dA/TRlgJ0UrI0I/AAAAAAAAAD8/iR_BiYrqy6U/s1600/havana.jpg"&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRldqOLg2bI/AAAAAAAAAD0/YerfsF8TPwI/s1600/lenna.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 276px;" src="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRldqOLg2bI/AAAAAAAAAD0/YerfsF8TPwI/s320/lenna.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5555574595280492978" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRldqOLg2bI/AAAAAAAAAD0/YerfsF8TPwI/s1600/lenna.jpg"&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;Download the newest source code?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4782768842047917447?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4782768842047917447/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/image-filter-algorithms-demo-is-updated.html#comment-form' title='2 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4782768842047917447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4782768842047917447'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/image-filter-algorithms-demo-is-updated.html' title='Image filter algorithms demo is updated!'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MFfxHf2W1dA/TRlhIkfHkrI/AAAAAAAAAEE/MXfIACNNH-U/s72-c/havana2.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-2698478413411701233</id><published>2010-12-25T19:22:00.000-08:00</published><updated>2010-12-27T19:42:57.003-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sobel Edge operator Computer vision'/><title type='text'>Image algorithms demo</title><content type='html'>&lt;div&gt;At last an update to my blog! This has been a busy year for me with my work, I am now a developer in Helse Midt-Norge IT since May, earlier this year I worked as an independent consultant for Artsdatabanken (NTNU). I work with WPF and C# mainly presently.&lt;br /&gt;&lt;br /&gt;I will now present a new hobby project of mine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;This WPF application demo of image algorithms demonstrates different techniques towards&lt;br /&gt;blur, sharpen, edge detection and other filtering techniques, all relying on the general concept of Convolution in image processing. 8-bits level grayscale images (256 levels, 1 bpp) are supported. &lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRa17z3M1mI/AAAAAAAAADg/vMAGwXEUcAA/s1600/blurdifference.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 259px; height: 320px;" src="http://4.bp.blogspot.com/_MFfxHf2W1dA/TRa17z3M1mI/AAAAAAAAADg/vMAGwXEUcAA/s320/blurdifference.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5554827229546731106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have worked with an image algorithms demo the last days. The&lt;br /&gt;demo is a small WPF application that demonstrates image algorithms used in&lt;br /&gt;edge detection. See the link below to download the zip file that contains&lt;br /&gt;the Microsoft Visual Studio 2010 project with source code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Examples of edge operators are sobel edge operator and Prewitt, Laplacian, Roberts and&lt;br /&gt;Horizontal and Vertical Sobel, blur difference operator, shown above. There are additional&lt;br /&gt;filters included.&lt;br /&gt;&lt;br /&gt;The resulting images can be inverted. The application works with 8-bit grayscale images  (256 levels). The BitmapSource class must be able to import the image (BMP or GIF should work).&lt;br /&gt;&lt;br /&gt;Right now the demo is in v1.1. I will add more features soon. There are a few issues with double-edges, noise and normalization in the demo, but I hope I will complete the demo in a more stable version later. Feel free to unzip the zip file linked below and provide comments of the code. Perhaps you can add new features to my code and discuss optimizations, corrections? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will state that already there is very little code to make a new filter, so this source code could be used as a basis for developing filters for applications needing to provide basic blur, sharpen and edge detection capabilities. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MFfxHf2W1dA/TRa3fiUqp5I/AAAAAAAAADo/D9y7ku5o5aw/s1600/lenasobel.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 194px;" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/TRa3fiUqp5I/AAAAAAAAADo/D9y7ku5o5aw/s320/lenasobel.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5554828942825400210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;i&gt;Sobel operator, horisontal komponent (3x3 convolution kernel).&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Comment: &lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Download newest version of  ImageAlgorithmsDemo WPF Application here [v1.1.]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://tore.aurstad.net/ImageAlgorithmsDemo.zip"&gt;Image algorithms v1.1&lt;/a&gt; (Zip-fil, ca. 2,4 MB compressed) &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Last update 28th of December 2010.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Future stuff:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;improve the speed of the filtering &lt;/li&gt;&lt;li&gt;support greater than 8 bpp (e.g. RGB)&lt;/li&gt;&lt;li&gt;support more operators. Canny edge and more advanced filters are desired&lt;/li&gt;&lt;li&gt;improve code, add tests to the test project&lt;/li&gt;&lt;li&gt;even friendlier GUI, more feedback and information&lt;/li&gt;&lt;li&gt;document code&lt;/li&gt;&lt;li&gt;share code with the community when v2.0 is done. &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The goal is that this demo should be a good starter demo of edge analysis in digital image algorithms, that can be used in courses at universities and the likes. The demo demonstrates pixel manipulation in WPF-application and filtering also with up to date .NET 4.0 code. Often one only finds C or C++ code when looking for these kinds of algorithms.. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Comments? &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-2698478413411701233?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/2698478413411701233/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/image-algorithms-demo.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2698478413411701233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2698478413411701233'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/12/image-algorithms-demo.html' title='Image algorithms demo'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MFfxHf2W1dA/TRa17z3M1mI/AAAAAAAAADg/vMAGwXEUcAA/s72-c/blurdifference.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-8482644456658932118</id><published>2010-02-13T20:11:00.000-08:00</published><updated>2010-02-13T20:47:10.070-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dynamic-Linq'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC og jQuery Grid'/><title type='text'>ASP.NET MVC og jQuery Grid</title><content type='html'>Jeg har testet ASP.NET MVC i Visual Web Developer Express og jQuery Grid. Det er kraftig teknologi som gir gode muligheter for å jobbe strukturert med utvikling i ASP.NET MVC (et rammeverk og paradigme som oppfordrer til strukturert og modularisert webutvikling, optimert mot TDD, test-drevet utvikling), samtidig som man vha. jQuery og jQuery grid kan vise data i en grid.&lt;br /&gt;&lt;br /&gt;Jeg vil begynne med å vise et skjermbilde av hva som testløsningen min inneholder.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_MFfxHf2W1dA/S3d5PoetplI/AAAAAAAAACo/1XmD2CB1qOg/s1600-h/mvc_jquery_grid.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 142px;" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/S3d5PoetplI/AAAAAAAAACo/1XmD2CB1qOg/s320/mvc_jquery_grid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5437948384544400978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;- ASP.NET MVC er en ny teknologi som ASP.NET kan benytte for å tilby en mer strukturert måte å jobbe på. Man går vekk fra code-behind og rammeverket er meget &lt;br /&gt;datasentrisk. Man har en oppkobling, gjerne til Sql Server (.mdf filer og tilsvarende), altså MS-SQL, hvor man definerer raskt en datamodell. Man bruker så Linq-to-sql for å generere klasser for datalag for å jobbe mot dataene. Videre har man både Model og Model-View klasser etter behov, samt .aspx filer er "View". Partielle view er av typen MVC Web User control (.ascx filer). &lt;br /&gt;&lt;br /&gt;For de som har jobbet lenge i ASP.NET vet man farene ved store prosjekter. Det blir fort spaghettikode og monolittisk kode. MVC tvinger en til å jobbe strukturert og modulrisert, samt unngår spaghetti på en mye mer streng måte enn standard ASP.NET. &lt;br /&gt;&lt;br /&gt;En stor ulempe med MVC i ASP.NET er mangelen på en skikkelig grid-kontroll m.m., da vanlige ASP.NET kontroller ikke nødvendigvis vil virke i MVC.. &lt;br /&gt;&lt;br /&gt;Jeg har derfor testet ut jQuery Grid som er en meget bra måte å erstatte ASP.NET GridView. Best av alt, denne javascript baserte kontrollen kan benyttes i MVC-baserte løsninger!&lt;br /&gt;&lt;br /&gt;Bortsett fra å tilby interesserte en nedlasting kan jeg kort si hva jQuery Grid er for noe. Det er en javascript plugin til jQuery og en klientbasert kontroll som er lik ASP.NET GridView, men har innebygd støtte for Ajax m.m. &lt;br /&gt;&lt;br /&gt;Det tar en tid til å venne seg til å implementer en jQuery Grid. Man har ikke drag and drop på denne komponenten. Men det går temmelig raskt å få opp en løsning. I mitt demoprosjekt har jeg benyttet meg at Dynamisk Linq, som Scott Guthrie (en av de prinsipielle arkitektene bak ASP.NET) har laget. Dere finner implementasjonen i klassen Dynamic.cs. Jeg har i mitt testprosjekt laget en servermetode som spør en tabell i en .mdf fil om innholdet i tabellen Countries, som har alle hovedsteder og land i verden. Videre har jeg laget en Country dataklasse automagisk med Linq-To-Sql. I min HomeController (Controller er C-en i MVC) har jeg en Index funksjon som henter opp tabelldataene vha. Ajax og Json. Testfunksjonen min håndterer både paginering og sortering av databasen og json-dataene overføres tilbake til klienten, som viser dem i jQuery Griden. Denne kontrollen abonnerer på data fra server-side funksjonen som returnerer et ActionResult av type JsonResult.&lt;br /&gt;&lt;br /&gt;MVC har en læringskurve og det er noe vanskelig å forstå hva alt dette er vits i å sette seg inn i. Men det vil spare en utvikler i ASP.NETfor mye arbeid, da det støtter TDD og unit testing på en mye bedre måte enn ASP.NET. Endelig går det an å utvikle nettsider profesjonelt og dele opp oppgaver til testere og verifisere at det man lager faktisk virker. Dette har vært enklere i applikasjonsutvikling enn i webutvikling, men med ASP.NET MVC så er det like enkelt å lage unit tester som for f.eks. WPF og WCF.. &lt;br /&gt;&lt;br /&gt;Ulempen med MVC er som sagt at vanlige ASP.NET serverkontroller ikke er vanligvis støttet. Men jQuery og jQuery Grid er sentral i MVC. Man har kontroller som er mer klient-orienterte enn de klassiske ASP.NET server-kontrollene. Med Json som kommunikasjon er det minimalt med data som går mellom klienten og serveren. Serveren leverer selvsagt data fortsatt ut til klient, men klienten "drar" dataene fra serveren oftere. Dermed blir det oftere requests, men disse er mindre i størrelse..&lt;br /&gt;&lt;br /&gt;Dette gjør det mulig å utvikle webapplikasjoner som er repsonsive og tillater et vell av interaksjon. MVC i ASP.NET er en alternativ modell til Silverlight og den lekre jQuery Grid viser at dette er absolutt tilfelle. &lt;br /&gt;&lt;br /&gt;I mitt demoprosjekt så er paginering og sortering støttet. Jeg har ikke testet enda hvordan man får til redigering i jQuery Grid eller har templates for celler, column reordering og annen avansert funksjonalitet, men dette er altså støttet i jQuery Grid. Dere finner jQuery Grid lett med et kjapt søkt med Google. Jeg anbefaler å sjekke ut vedlagte .zip fil for å se hele koden..&lt;br /&gt;&lt;br /&gt;Til slutt før lenken til nedlastingen, så legger jeg ved koden for server-funksjonen i ASP.NET MVC som gir paginering og sortering. Den benytter som sagt Scott Guthrie sin Dynamic Linq klasse, som gir noen tilleggsfunksjoner som spytter inn SQL i linq-spørringer og gir det man trenger for akkurat dette..&lt;br /&gt;&lt;br /&gt;&lt;code class="prettify"&gt;&lt;br /&gt;  public ActionResult DynamicGridData&lt;br /&gt;    (string sidx, string sord, int page, int rows)&lt;br /&gt;        {&lt;br /&gt;            var context = new GeografiTestDbDataContext();&lt;br /&gt;            int pageIndex = Convert.ToInt32(page) - 1;&lt;br /&gt;            int pageSize = rows;&lt;br /&gt;            int totalRecords = context.Countries.Count();&lt;br /&gt;            int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);&lt;br /&gt;&lt;br /&gt;            var countries = context.Countries.OrderBy(sidx + " " + sord)&lt;br /&gt;              .Skip(pageIndex * pageSize)&lt;br /&gt;              .Take(pageSize);&lt;br /&gt;&lt;br /&gt;            var jsonData = new&lt;br /&gt;            {&lt;br /&gt;                total = totalPages,&lt;br /&gt;                page = page,&lt;br /&gt;                records = totalRecords,&lt;br /&gt;                rows = (&lt;br /&gt;                  from c in countries&lt;br /&gt;                  select new&lt;br /&gt;                  {&lt;br /&gt;                      i = c.Id,&lt;br /&gt;                      cell = new string[] {&lt;br /&gt;          c.Id.ToString(), c.Capital, c.Country1 &lt;br /&gt;        }&lt;br /&gt;                  }).ToArray()&lt;br /&gt;            };&lt;br /&gt;            return Json(jsonData);&lt;br /&gt;        }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Linq-spørringene over virker ikke uten at man har Dynamics.cs filen som Scott Guthrie har laget, 81 kB stor. Her er det masse extension methods som gjør det mulig å spørre databasen inne i Linq-spørringer.. Dynamic Linq er helt vilt bra for de som tenker på hvordan det faktisk virker.. &lt;br /&gt;&lt;br /&gt;Til slutt, slik ser .aspx filen ut hvor man lager et jQuery Grid objekt:&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;        jQuery(document).ready(function() {&lt;br /&gt;&lt;br /&gt;            jQuery("#list").jqGrid({&lt;br /&gt;                url: '/Home/DynamicGridData/',&lt;br /&gt;                datatype: 'json',&lt;br /&gt;                mtype: 'GET',&lt;br /&gt;                colNames: ['Uniktnummer', 'Hovedstad', 'Land'],&lt;br /&gt;                colModel: [&lt;br /&gt;             { name: 'Id', index: 'Id', width: 120, align: 'left' },&lt;br /&gt;             { name: 'Capital', index: 'Capital', width: 120, align: 'left' },&lt;br /&gt;             { name: 'Country1', index: 'Country1', width: 220, align: 'left' }&lt;br /&gt;             ],&lt;br /&gt;                pager: jQuery('#gridpager'),&lt;br /&gt;                pgtext: "Side {0} av {1}",&lt;br /&gt;                pginput: true,&lt;br /&gt;                recordpos: 'left',&lt;br /&gt;                rowNum: 20,&lt;br /&gt;                width: 900,&lt;br /&gt;                multiSelect:true,&lt;br /&gt;                hidegrid: false,&lt;br /&gt;                rowList: [5, 10, 20, 50],&lt;br /&gt;                sortname: 'Id',&lt;br /&gt;                sortorder: "asc",&lt;br /&gt;                viewrecords: true,&lt;br /&gt;                imgpath: '/scripts/themes/redmond/images',&lt;br /&gt;                caption: 'Hovedsteder i ulike land. Demotest.'&lt;br /&gt;            });&lt;br /&gt;        });         &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Man ser i json-egenskapen url hvordan jQuery Griden kobles mot server metoden &lt;br /&gt;Index i HomeController.cs, som er tilgjengelig i route /Home/Index. MVC er litt &lt;br /&gt;spesielt for ASP.NET utviklere, men etter å ha brukt det kun noen få dager ser &lt;br /&gt;jeg vesentlige fordeler med det. En ulempe er at det kan bli litt vanskeligere på &lt;br /&gt;klienten siden, men implementasjonen på server siden blir mye mer strukturert. Utfordringene ligger i at ferdige komponenter som ASP.NET GridView ikke er tilgjengelig. Skal man bruke MVC må man lære seg javascript godt og benytte jQuery&lt;br /&gt;og nye komponenter. Dette er noe av den mest spennende teknologien, sammen med Linq, som Microsoft har laget på år og dag.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Visual Studio 2008 løsning:&lt;br /&gt;Last ned prosjekt [Zip-fil, 711 kB] &lt;a href="http://tore.aurstad.net/TestMVC1/TestJqueryGrid2.zip"&gt;her&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Framgangsmåte for å kjøre mitt demoprosjekt:&lt;br /&gt;1. Lagre zip fil på C:\minmappe&lt;br /&gt;2. Pakk ut zip fil fra pkt 1.&lt;br /&gt;3. Dobbeltklikk på .sln fil og se at Visual Studio laster..&lt;br /&gt;4. Når pkt 3. er ferdig, trykk på knappen F5 på tastaturet ditt.&lt;br /&gt;5. Be amazed.&lt;br /&gt;&lt;br /&gt;:o)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-8482644456658932118?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/8482644456658932118/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/aspnet-mvc-og-jquery-grid.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8482644456658932118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8482644456658932118'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/aspnet-mvc-og-jquery-grid.html' title='ASP.NET MVC og jQuery Grid'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MFfxHf2W1dA/S3d5PoetplI/AAAAAAAAACo/1XmD2CB1qOg/s72-c/mvc_jquery_grid.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-6839476543799451867</id><published>2010-02-06T17:29:00.000-08:00</published><updated>2010-02-06T17:36:06.060-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Douglas Crockford'/><category scheme='http://www.blogger.com/atom/ns#' term='The Good parts'/><title type='text'>Godbiten Javascript</title><content type='html'>Javascript er et fantastisk herlig programmeringsspråk. &lt;br /&gt;&lt;br /&gt;Her er grunnene til at jeg liker javascript:&lt;br /&gt;- Ingen klasser! Alt er objekter.&lt;br /&gt;- Dynamisk tolket språk som ikke er strengt typet, full fleksibilitet mht utvidelse.&lt;br /&gt;- Intet behov for generics eller innviklede mønstre for å oppnå det javascript &lt;br /&gt;  greier på en elegant måte.&lt;br /&gt;- Det programmeringsspråket i verden flest mennesker har tilgang til, nemlig som &lt;br /&gt;  en tolker i en nettleser.&lt;br /&gt;- Innebygd støtte for lambda-uttrykk og avansert funksjonalitet som Javascript har &lt;br /&gt;  arvet fra Scheme. &lt;br /&gt;- Det herligste, mest elegante språket i verden!&lt;br /&gt;&lt;br /&gt;Jeg håper Ecmascript 5 ikke lager en stor bloatware ut av Javascript, men at språket &lt;br /&gt;sin nette eleganse og enkelhet bevares som i dag. Det er nettopp enkelheten og &lt;br /&gt;fleksibiliteten som gjør Javascript så kraftig. &lt;br /&gt;&lt;br /&gt;Jeg anbefaler å se videoene av Douglas Crockford på Yahoo! sin video side. &lt;br /&gt;&lt;br /&gt;Spesielt følgende video anbefales!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=hQVTIJBZook"&gt;JavaScript: The Good Parts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Javascript har selvsagt sine "flaws" også og Douglas Crockford går gjennom disse på en hysterisk morsom måte. (Man må være innvidd i denne bransjen for å sette pris på slike ting da..).&lt;br /&gt;&lt;br /&gt;Mvh Tore A&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-6839476543799451867?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/6839476543799451867/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/godbiten-javascript.html#comment-form' title='0 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6839476543799451867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/6839476543799451867'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/godbiten-javascript.html' title='Godbiten Javascript'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-4374236194665126549</id><published>2010-02-06T15:49:00.000-08:00</published><updated>2010-02-06T17:10:41.101-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='DOM'/><category scheme='http://www.blogger.com/atom/ns#' term='ytelse'/><category scheme='http://www.blogger.com/atom/ns#' term='createDocumentFragment'/><title type='text'>Raskere Javascript med document-fragments?</title><content type='html'>Jeg har undersøkt litt om man får kjøre raskere Javascript vha. document-fragments. Sentralt i denne teknikken er å benytte document.createDocumentFragment(). Dette er en "construct" eller byggekloss som tillater en å klargjøre store modifikasjoner i HTML DOM treet i en operasjon. Dermed slipper man "reflow", dvs. at nettleseren forsøker å tegne opp html dom treet, hver gang man setter inn et nytt element.&lt;br /&gt;&lt;br /&gt;Jeg har testet teknikken ved å lage en Javascript kode som regner ut tiden det tar i antall millisekunder å sette inn 1000 elementer i et HTML nedtrekksliste, etter først å ha slettet 1000 elementer, hvis nødvendig, i samme nedtrekksliste. Enten ved å bruke document-fragments, eller ved å direkte manipulere HTML dom treet for hver iterasjon. Resultatene viser seg at effekten er mindre enn mange andre tester har vist, men det er størst effekt i Internet Explorer. IE er helt klart også den nettleseren med dårligst Javascript-ytelse for akkurat dette.&lt;br /&gt;&lt;br /&gt;Resultatene ble som følger (målt i antall millisekunder, mindre er bedre=raskere!):&lt;br /&gt;With Fragment Without Fragment&lt;br /&gt;IE 8.0 608 1070&lt;br /&gt;Firefox 3.6 77 100&lt;br /&gt;Safari 4.0 69 74&lt;br /&gt;Opera 10.5 77 76&lt;br /&gt;Chrome 4.0 87 92&lt;br /&gt;&lt;br /&gt;Resultatene er etter kjøring av Javascript som setter inn 1000 elementer og sletter hvis nødvendig de 1000 elementene først og hvert case er kjørt 10 ganger og tatt gjennomsnitt av. IE 8.0 er nesten dobbelt så rask med document-fragment teknikken som uten. Likevel er IE 8.0 i sin egen liga i å være tregere enn de andre nettleserne. Som man ser av tallene over er Safari 4.0 9x-10x raskere med fragment teknikken. Safari 4.0 er mer enn 12x raskere enn IE 8.0 uten fragment teknikken. Safari er forøvrig den raskeste browseren, både med og uten document-fragment. Opera, Safari og Chrome viser små hastighetendringer med document-fragment. Opera 10.5 er faktisk litt raskere uten.. Chrome og Safari har små bedringer, ca. 5-10% raskere. Etter Safari er Opera raskest, Chrome og Firefox er ganske jevne. Chrome er tregere enn Firefox med document-fragment, men kjøringen uten document-fragment viser at Chrome er raskere enn Firefox 3.6. Firefox har ca. 30% raskere utførelse med document-fragment.&lt;br /&gt;&lt;br /&gt;Konklusjonen må derfor være at document-fragment må absolutt brukes. IE 8.0 er meget treg i sin Javascript-ytelse og doblingen i hastighet (100% raskere) er nødvendig å utføre. Er du opptatt av hastigheten til webapplikasjonene dine i IE 8.0 er document-fragment meget viktig å bemerke seg med andre ord. For de andre nettleserne er det Firefox 3.6som er mest følsom for document-fragment, med 30% raskere utførelse. De andre browserne har 10-5% økning i raskere utførelse, men for dette caset hadde Opera 10.5 Alpha -1 til -5% økning i hastighet.. Safari er forøvrig den aller raskeste nettleseren. Det at Safari 4.0 skal med en slik enkel test med HTML DOM manipulasjon i javascript være mellom 9x-12x raskere enn IE 8.0: Dette er for dårlig Microsoft! Hvis IE 9 skal bli tatt seriøst som en nettleser og tatt i betraktning Microsoft sine enorme finansielle muskler, må de seriøst fikse Javascript hastigheten sin. Er du på utkikk etter den aller raskeste browseren gir denne testen en klar indikasjon på at JS-ytelsen i Safari er best. Opera og Chrome er hakk i hæl, Firefox sist av disse fire, men langt foran IE 8.0. Det skal nevnes at Opera 10.5 Alpha er en Alpha-versjon og kanskje kan nå opp til Safari 4.0.4 sine høyder i nær framtid..&lt;br /&gt;&lt;br /&gt;Jeg har i Google Docs Spreadsheet laget et diagram på ytelsen:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_MFfxHf2W1dA/S24M_GPg7RI/AAAAAAAAACg/vALh5b6q3us/s1600-h/docfragchart.jpg"&gt;&lt;img style="WIDTH: 320px; HEIGHT: 229px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5435296078429744402" border="0" alt="" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/S24M_GPg7RI/AAAAAAAAACg/vALh5b6q3us/s320/docfragchart.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Legg merke til den dramatisk raskere utførelsen i IE 8.0 med document-fragment. Ikke alle nettlesere har spesiell stor ytelsesforbedring, ca. 5-30%, med Firefox som den nettleseren som nyter best av å benytte document-fragment.&lt;br /&gt;&lt;br /&gt;Her er testen vist under kjøring i Google Chrome 4.0:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/S24Mgsx_mSI/AAAAAAAAACY/YG_0RqNvWjY/s1600-h/chrome_test.jpg"&gt;&lt;img style="WIDTH: 320px; HEIGHT: 302px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5435295556198963490" border="0" alt="" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/S24Mgsx_mSI/AAAAAAAAACY/YG_0RqNvWjY/s320/chrome_test.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Jeg vil nå oppsummere resultatene fra denne testen:&lt;br /&gt;- Kjører man IE 8.0 må nesten document.createDocumentFragment() benyttes når store&lt;br /&gt;HTML DOM manipulasjoner kjører i nettleseren, pga IE 8.0 sin dårlige hastighet.&lt;br /&gt;- IE 8.0 er 9x-12x tregere enn Safari 4.0.4 i JS-ytelse. Dette er ikke bra Microsoft..&lt;br /&gt;- For de andre nettleserne er det også bra å bruke document.createDocumentFragment(), forbedringen er 5-30%, men Opera hadde ikke noen ytelsesforbedring..&lt;br /&gt;- Generelt sett, benytt document-fragment likevel, evt. unngå det for Opera med&lt;br /&gt;oppdaging av klientens nettleser..&lt;br /&gt;- Testen viser at Safari 4.0.4. er aller raskest, Opera 10.5 og Chrome 4.0 er hakk i hæl. Firefox 3.6 er nest tregest, men milevis foran IE 8.0 i JS-ytelse.&lt;br /&gt;&lt;br /&gt;For de som ønsker å teste ut selv, kan de laste ned en zippet versjon av løsningen som jeg laget i Visual Web Developer Express 2008 her:&lt;br /&gt;&lt;a href="http://tore.aurstad.net/TestJSSpeed/TestJSSpeed.zip"&gt;Document Fragment Demo Test Solution&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For å teste gjør følgende:&lt;br /&gt;1. Pakk ut .zip filen&lt;br /&gt;2. Åpne .sln filen&lt;br /&gt;3. Når Visual Studio er startet, trykk F5 for å starte.&lt;br /&gt;&lt;br /&gt;Klikk på de to knappene for å kjøre tester med document-fragment i ulike nettlesere.&lt;br /&gt;&lt;br /&gt;Da skulle vel Microsoft-utviklere der ute ha noen pekepinner om hvor skoen trykker i&lt;br /&gt;JS-ytelse for neste versjon av IE 9.x! De øvrige nettleserne er mindre følsomme for document.createFragment() men man bør unngå reflow inne i iterasjoner i javascript, eller spesifisere det enklere på en måte som er optimert for hastighet. Problemet ligger her i at nettleseren ønsker å holde GUI-visuelt oppdatert hele tiden. I en iterasjon er ikke det nødvendigvis en god teknikk for en nettleser. Klienten vil jo helst ha innholdet sitt og starte å jobbe videre, nettlesere er jo som kjent single-threaded miljø når det kommer til GUI. Da bør nettlesere unngå reflow inne i iterasjonen og først starte med en reflow rett etter en slik for-loop slik at man slipper å gjøre rene hacks for å få nettleseren til å være rask og responsiv.&lt;br /&gt;&lt;br /&gt;Jeg limer inn javascript-koden her til slutt:&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;///Runs a desired function, returns amount of millisecond the function took to perform before completing.&lt;br /&gt;function timedFunction(func) {&lt;br /&gt;if (typeof func == 'function') {&lt;br /&gt;var startTime = (new Date()).getTime();&lt;br /&gt;func();&lt;br /&gt;var endTime = (new Date()).getTime();&lt;br /&gt;return (endTime - startTime);&lt;br /&gt;} //if&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function generate_thousand_option_elements_in_dropdown_with_document_fragment() {&lt;br /&gt;var optionsFragment = document.createDocumentFragment();&lt;br /&gt;var ddltest = document.getElementById("ddlTest");&lt;br /&gt;var len = 0;&lt;br /&gt;while (len = ddltest.options.length) {&lt;br /&gt;ddltest.options[len-1] = null;&lt;br /&gt;} &lt;br /&gt;for (var i = 1; i &lt;= 1000; i++) { var optiontoadd = document.createElement("option"); optiontoadd.value = i; optiontoadd.appendChild(document.createTextNode("Option " + i)); optionsFragment.appendChild(optiontoadd); } ddltest.appendChild(optionsFragment); } var withoutFragmentTest = 0; function generate_thousand_option_elements_in_dropdown_without_document_fragment() { withoutFragmentTest++; var ddltest = document.getElementById("ddlTest"); var len = 0; while (len = ddltest.options.length) { ddltest.options[len-1] = null; } &lt;br /&gt;for (var i = 1; i &lt;= 1000; i++) { var optiontoadd = document.createElement("option"); optiontoadd.value = i; optiontoadd.appendChild(document.createTextNode("Option " + i)); ddltest.appendChild(optiontoadd); } }generate_thousand_option_elements_in_dropdown_without_document_fragment var withFragmentTest = 0; function testDocumentFragment() { withFragmentTest++; var resultRun = timedFunction(generate_thousand_option_elements_in_dropdown_with_document_fragment); if (resultRun != 'undefined') { var resultParagraphNode = document.createElement("p"); var resultParagraphTextNode = document.createTextNode("Ran test #"+ withFragmentTest + " with document fragment. Test took: " + resultRun + " milliseconds."); resultParagraphNode.appendChild(resultParagraphTextNode); document.getElementById("resultList").appendChild(resultParagraphNode); } //if }&lt;br /&gt;testDocumentFragment () function testWithoutDocumentFragment() { var resultRun = timedFunction(generate_thousand_option_elements_in_dropdown_without_document_fragment); if (resultRun != 'undefined') { var resultParagraphNode = document.createElement("p"); var resultParagraphTextNode = document.createTextNode("Ran test #" + withoutFragmentTest + " without document fragment. Test took: " + resultRun + " milliseconds."); resultParagraphNode.appendChild(resultParagraphTextNode); document.getElementById("resultList").appendChild(resultParagraphNode); } } testWithoutDocumentFragment &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mvh Tore Aurstad&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-4374236194665126549?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/4374236194665126549/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/raskere-javascript-med-document.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4374236194665126549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/4374236194665126549'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/02/raskere-javascript-med-document.html' title='Raskere Javascript med document-fragments?'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MFfxHf2W1dA/S24M_GPg7RI/AAAAAAAAACg/vALh5b6q3us/s72-c/docfragchart.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-7981298170878248458</id><published>2010-01-27T17:18:00.000-08:00</published><updated>2010-01-27T17:37:40.686-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sample'/><category scheme='http://www.blogger.com/atom/ns#' term='Scriptaculous'/><category scheme='http://www.blogger.com/atom/ns#' term='Slider Script.aculo.us'/><title type='text'>Slider-kontroll på web</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/S2DoHq11WvI/AAAAAAAAACQ/WKNfo29C0Fg/s1600-h/slider1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 129px;" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/S2DoHq11WvI/AAAAAAAAACQ/WKNfo29C0Fg/s320/slider1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5431596369065630450" /&gt;&lt;/a&gt;&lt;br /&gt;Jeg har testet ut Scriptaculous, som er et javascript bibliotek myntet på gui og effekter i gui. Det har blant annet en slider kontroll, som jeg har laget et testprosjekt for. Slideren ser meget elegant ut og er vel så god som den som &lt;br /&gt;Silverlight kan tilby. Best av alt er at man har tilgang til HTML DOM-treet og lett kan lese ut og sette verdier til Slideren.&lt;br /&gt;&lt;br /&gt;For å laste ned testprosjektet, last ned &lt;a href="http://tore.aurstad.net/Slider/TestSliderScriptaculous.zip"&gt;her&lt;/a&gt; [ZIP-fil,101kB].&lt;br /&gt;&lt;br /&gt;Start prosjektet på følgende måte:&lt;br /&gt;* Pakk ut Zip-filen TestSliderScriptaculous.zip i en midlertidig mappe.&lt;br /&gt;* Åpne denne mappen og dobbeltklikk på .sln filen.&lt;br /&gt;* Når Visual Studio er lastet (Jeg har anvendt Visual Web Developer 2008 Express):&lt;br /&gt;* Trykk på F5 for å snurre film.&lt;br /&gt;* Standard nettleser skal så åpne og man presenteres siden Default.aspx hvor jeg har &lt;br /&gt;  implementert testprosjektet.&lt;br /&gt;&lt;br /&gt;Øverst i denne artikkelen ser du et skjermbilde hvordan slideren ser ut. Like elegant som den du ser i Mac OS X, eller hva? Slideren er selvsagt interaktiv. Klikk og dra på slider handelen (håndtaket) og slipp for å sette en verdi for slideren. For dette testprosjektet har jeg satt 0 og 100 som verdiintervallet og alle titallsverdier som diskrete verdier. Hvis man ikke setter noen verdier her vil man med slideren spesifisere en verdi mellom 0 og 1 som et flyttall.&lt;br /&gt;&lt;br /&gt;Dette er en meget kraftig måte å presentere en slider på i web. Man benytte denne kontrollen i for eksempel en Ajax-aktivert Web 2.0. applikasjon, for eksempel for å sette en tallverdi, e.g. 0 til 100 prosent gjennomsiktighet i en bilde-applikasjon eller parametere inn til et filter i en bilde-applikasjon.&lt;br /&gt;&lt;br /&gt;Script.aculo.us inneholder nok mange andre godbiter, jeg har ikke fått testet ut rammeverket noe mye enda. Sliderkontrollen var meget lett å få til å virke, det tok meg kun 2-3 timer å få ferdigstilt testprosjektet. Om noen kjenner andre gode demoer av Script.aculo.us, si i fra. Litt kjapt nettsøk viser at det er tonnevis av demoer der ute.&lt;br /&gt;&lt;br /&gt;Dette testprosjektet inneholder Script.aculo.us i Script mappen, som er rett og slett noen få .js filer.&lt;br /&gt;&lt;br /&gt;Script.aculo.us nettside (inkluderer nedlasting):&lt;br /&gt;&lt;a href="http://script.aculo.us"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-7981298170878248458?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/7981298170878248458/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/01/slider-kontroll-pa-web.html#comment-form' title='1 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/7981298170878248458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/7981298170878248458'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/01/slider-kontroll-pa-web.html' title='Slider-kontroll på web'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MFfxHf2W1dA/S2DoHq11WvI/AAAAAAAAACQ/WKNfo29C0Fg/s72-c/slider1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-7157884218921493109</id><published>2010-01-07T16:41:00.000-08:00</published><updated>2010-01-07T17:03:09.262-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WORM NOIS kart.nois.no Samferdselsetaten'/><title type='text'>Stor suksess med tidligere prosjekt hos NOIS!</title><content type='html'>&lt;div style="background-color:darkorange;font-family:'Trebuchet MS',Verdana;color:charcoal"&gt;Jeg søkte nettopp på nettet etter 'NOIS' og 'WORM' som er et akronym for 'Web Office Resource Management'. Jeg kom over en artikkel skrevet av Thor Hestnes i InnoDesign med tittel "Hull i veien? Klag på nettet!". Den tar for seg Samferdselsetaten i Oslo sin webløsning WORM, som er skrevet av meg når jeg jobbet som konsulent i NOIS i 10 måneder. Nå viser det seg at Samferdselsetaten har hatt stor glede av denne webløsningen! Ikke verst!&lt;br /&gt;&lt;br /&gt;Løsningen er publisert her:&lt;br /&gt;&lt;a href="http://melding.samferdselsetaten.oslo.kommune.no/"&gt;http://melding.samferdselsetaten.oslo.kommune.no/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Artikkelen er så rosende og full av lovord om webapplikasjonen jeg laget at jeg nesten datt av stolen :-)&lt;br /&gt;&lt;br /&gt;Løsningen er laget med ASP.NET, programmert i VB.NET og Javascript er anvendt en god del.&lt;br /&gt;&lt;br /&gt;Litt skryt kan man bare se her!&lt;br /&gt;&lt;br /&gt;"Hull i veien? Klag på nettet!&lt;br /&gt;Thor Hestnes &lt;br /&gt;02.09.2009 20:11 &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;Noe i veien der du ferdes i Oslo?&lt;br /&gt;Meld fra til samferdselsetaten på nettet!&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Samferdsels-etaten i Oslos satsing på en tettere kommunikasjon med byens borgere, er online. Etatens kundetorg på nettet er i ferd med å bli en suksess etter bare noen måneders drift.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Ved hjelp av Norconsult Informasjonssystemers WinMap-baserte, skreddersydde meldingssystem kan Oslos innbyggere nå på en enkel måte gå inn på nettet og melde fra om kommunale samferdselsproblemer som opptar dem. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Ekstraservice, det er samferdselsetaten det&lt;br /&gt;&lt;br /&gt;Men ikke bare det, forteller etatens prosjektleder Stein Arild Sandnes: ― Folk kan også følge med om noe fysisk blir gjort med «klagen». Det være seg reparasjoner av hull i veien, gatelys, signalanlegg, eller brøyting, strøing, salting osv. Denne ekstraservicen er vi ganske alene om på kommunalt plan. Selvbetjeningen innfører en mye tettere brukerdialog og fremmer bedre tilfredshet med kommunens tjenester.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Ambisiøs orm&lt;br /&gt;&lt;br /&gt;WORM heter programnyvinningen. Web Office Resource Management står det for og beskriver egentlig godt ambisjonen med kommunens satsing. Systemet er nemlig ment å være mye mer enn bare et meldingssystem. I WORM ligger også moduler for planlegging av graving, asfaltering, mindre byggearbeider osv. Det er med andre ord et oppfølgings-, kontroll- og beslutningsstøttesystem for kommunen. Et system som de kan bruke til å styre og utnytte ressursene bedre med.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;Kartbasert nettløsning&lt;br /&gt;&lt;br /&gt;― Det hele startet i 2005, forteller Sandnes. ― Etaten ønsket et nytt meldingssystem for å kunne forbedre kommunikasjonen med publikum og entreprenørene som utfører arbeidet på vegne av kommunen. Etaten bestemte seg for å bruke et kartsystem som informasjonsbærer for å gjøre brukerdialogen og oppfølgingen enklest mulig. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Valget falt på NOIS (Norconsult Informasjonssystemer) som utviklingspartner og WinMap som kartmotor i løsningen.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;― Ved å klikke deg inn på den veiviserbaserte kartapplikasjonen på etatens nettside velger du først meldingstypen fra en meny, forklarer Sandnes og prøver å tegne et bilde av hvordan systemet fungerer. ― Dernest spesifiserer du nøyaktig hvor på kartet problemet ligger, gir en kort beskrivelse av hva saken dreier seg om, og klikker til slutt meldingen direkte til etatens kundetorg. Her blir de løpende behandlet i henhold til gitte behandlingsregler og formidlet til rette ansvarlige i etaten, som til slutt utsteder arbeidsordre til avtalefestet entreprenør som utfører oppdraget. Alt er helt dynamisk.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Genialt enkelt, helt enkelt&lt;br /&gt;&lt;br /&gt;― Når jobben så er gjort er det entreprenørens plikt å gå inn på det samme systemet og endre status slik at det røde merket på kartet endres til grønn, som beskriver at jobben er utført. Noe også publikum kan se, poengterer Sandnes. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Og alle hjerter gleder seg… Ja, for dette har i følge Sandnes ført til mange konstruktive tilbakemeldinger fra publikum i løpet av vinteren og våren. Og samtidig positive erfaringer for samferdselsetaten.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Synliggjør arbeidet&lt;br /&gt;&lt;br /&gt;Nesten 2800 meldinger ble registrert i løpet av 3 ½ måned i vinter. Mye snøfall voldte selvsagt mange henvendelser. Nesten 1800 dreide seg om brøyting, ca 600 rapporterte om hull i veien… &lt;br /&gt;&lt;br /&gt;― Systemet gir oss mye mer korrekt innrapportering og det synliggjør jobben som gjøres av entreprenørene, fortsetter Stein Arild Sandnes. ― Med oversiktlig statistikk kan vi enkelt sammenstille og kontrollere arbeidsområder og tiltak.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Lønnsom pionervirksomhet&lt;br /&gt;&lt;br /&gt;― Systemet er ganske komplisert med avansert filtreringslogikk, fortsetter han. ― Det ligger en stor applikasjon rundt kartmotoren. Systemet er unikt. Det er rett og slett pionervirksomhet det vi gjør. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;― Men det fungerer utmerket. Vi har nesten ikke hatt nedetid siden oppstarten. Og publikumstilbakemeldingen er veldig bra. De er imponert over ekstraservicen vi gir dem. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;― For kommunens del får vi nå en mye bedre totaloversikt og sparer ressurser både på den ene og andre måten, mener Sandnes. ― Effektiviteten og kontrollen er bedret betraktelig. Ikke minst ved enkel gjenfinning av informasjon og gjennom verdifull statistikk. For kontrollseksjonen, som er en hyppig bruker av systemet, er det betydelig enklere å følge opp og kontrollere at tingene utføres i henhold til kontrakt.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Enklere hverdag&lt;br /&gt;&lt;br /&gt;― Kundetorget som til daglig jobber mest med meldingssystemet, har for øvrig fått fordelen av kun én applikasjon å forholde seg til. Et stort pluss og en drastisk bedring av situasjonen, slutter Stein Arild Sandnes og ser frem til å tilfredsstille enda flere, nye behov som underveis har dukket opp. &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Mandatet er nemlig utviklet ytterligere etter de gode resultatene. Oslos ansatte og borgere kan forhåpentlig vente seg en stadig enklere hverdag…"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Må si meg fornøyd med en slik omtale.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Og det er visst mer skryt i vente, les bare Aftenposten... &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.aftenposten.no/nyheter/oslo/article3317321.ece"&gt;http://www.aftenposten.no/nyheter/oslo/article3317321.ece&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Det har visst blitt bedre veger i Oslo, blant annet pga. meg.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-7157884218921493109?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/7157884218921493109/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2010/01/stor-suksess-med-tidligere-prosjekt-hos.html#comment-form' title='0 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/7157884218921493109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/7157884218921493109'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2010/01/stor-suksess-med-tidligere-prosjekt-hos.html' title='Stor suksess med tidligere prosjekt hos NOIS!'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-2660151173780095842</id><published>2009-12-28T07:42:00.000-08:00</published><updated>2010-01-02T19:42:51.508-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Måne'/><category scheme='http://www.blogger.com/atom/ns#' term='Solnedgang'/><category scheme='http://www.blogger.com/atom/ns#' term='Soloppgang'/><category scheme='http://www.blogger.com/atom/ns#' term='Sol'/><category scheme='http://www.blogger.com/atom/ns#' term='Vista'/><category scheme='http://www.blogger.com/atom/ns#' term='Gadget'/><title type='text'>Sol Måne : Windows Vista Sidebar gadget</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MFfxHf2W1dA/S0ASNmUeZsI/AAAAAAAAACI/aoRILGfF8w8/s1600-h/sunmoonv13_2.jpg"&gt;&lt;img style="cursor: pointer; width: 152px; height: 196px;" src="http://3.bp.blogspot.com/_MFfxHf2W1dA/S0ASNmUeZsI/AAAAAAAAACI/aoRILGfF8w8/s320/sunmoonv13_2.jpg" alt="" id="BLOGGER_PHOTO_ID_5422353976188102338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;v1.3 tilgjengelig.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_MFfxHf2W1dA/SzjZs5SKoAI/AAAAAAAAABM/ehhg-Oar1rc/s1600-h/sunmoonscreenshot.jpg"&gt;&lt;img style="width: 150px; height: 223px;" id="BLOGGER_PHOTO_ID_5420321516854878210" alt="" src="http://4.bp.blogspot.com/_MFfxHf2W1dA/SzjZs5SKoAI/AAAAAAAAABM/ehhg-Oar1rc/s320/sunmoonscreenshot.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Versjon 1.3:&lt;/strong&gt;&lt;br /&gt;Hei, da er fiks laget hvor tallet 0 paddes foran dager og måneder med verdi mindre enn 10 mot SunRise metoden. Fikset også en feil i switch for visning av ikon for månefase, case "Waning gibbous".&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tore.aurstad.net/SunMoonGadgetv11/SunMoonGadgetv13.gadget"&gt;&lt;br /&gt;Sol Måne gadget v 1.3.&lt;/a&gt;&lt;br /&gt;Last ned versjon 1.3 nå over. Samme installasjonsmetode som for v1.2.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Versjon 1.2:&lt;/strong&gt;&lt;br /&gt;Hei, da er fiks laget for automatisk oppdatering av data for gadget og ny versjon laget.&lt;br /&gt;Gadget vil hente nye data fra Yr.no sin &lt;em&gt;Sunrise&lt;/em&gt; web service metode en gang i timen!&lt;br /&gt;Last ned versjon 1.2 nå.&lt;br /&gt;&lt;br /&gt;Installasjonen er på samme måte som for versjon 1.1., velg 'Erstatt' eller 'Oppgrader' når installasjonen av gadget spør deg om du vil oppgradere, i tilfelle du har lastet ned v1.1. tidligere.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Last ned Sol Måne v1.2. gadget for Windows Vista Sidebar!&lt;br /&gt;&lt;a href="http://tore.aurstad.net/SunMoonGadgetv11/SunMoonGadgetv12.gadget"&gt;&lt;br /&gt;Sol Måne gadget v 1.2.&lt;/a&gt; &lt;/h4&gt;&lt;h4&gt;Last ned Sol Måne v1.1. gadget for Windows Vista Sidebar!&lt;br /&gt;&lt;a href="http://tore.aurstad.net/SunMoonGadgetv11/SunMoonGadgetv11.gadget"&gt;&lt;br /&gt;Sol Måne gadget v 1.1.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Installasjonsprosedyre:&lt;br /&gt;&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;Last ned filen over ved å høyreklikke og velge 'Lagre mål som...'&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Åpne mappen til filen du nettopp lastet ned (SunMoonGadgetv11.zip)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Endre filnavnet til å et etternavn (file extension) som ender på .gadget&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Dobbeltklikk på filen i Windows Explorer for å starte installasjonsprogrammet&lt;br /&gt;for å legge til gadget.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I Windows Vista / Windows 7 Sidebar, klikk på pluss symbolet.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Velg den nylig installerte gadget blant øvrige gadgets med teksten 'Sol Måne' .&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;Etter installasjonen har gjort seg ferdig er filene installert som en undermappe til mappen:&lt;br /&gt;%userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Gadget skal nå være valgbar i gadget-utvalgssiden:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzjVRpMY6CI/AAAAAAAAAA8/5L8R5T8gP2E/s1600-h/sunmoongadget.jpg"&gt;&lt;img style="width: 320px; height: 168px;" id="BLOGGER_PHOTO_ID_5420316650632701986" alt="" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzjVRpMY6CI/AAAAAAAAAA8/5L8R5T8gP2E/s320/sunmoongadget.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Det første man må gjøre etter å ha installert, er å sette opp lokalisering for å få vist riktig informasjon. Klikk på skiftenøkkel symbolet for å åpne innstillingene og skriv så inn lokaliseringen du befinner deg på og ønsker å vise informasjon for. Dette vil se slik ut på siden for innstillinger av gadget (settings.html):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_MFfxHf2W1dA/SzjWJYpsy-I/AAAAAAAAABE/7QA4WdPozFg/s1600-h/sunmoonsettings.jpg"&gt;&lt;img style="width: 174px; height: 320px;" id="BLOGGER_PHOTO_ID_5420317608264911842" alt="" src="http://4.bp.blogspot.com/_MFfxHf2W1dA/SzjWJYpsy-I/AAAAAAAAABE/7QA4WdPozFg/s320/sunmoonsettings.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I eksempelet vist på bildet over er Oslo satt opp som lokalisering for gadget. Breddegrad og lengdegrad hentes med web service kall mot Google Maps, som søker opp stedsnavnet og viser samtidig i et kart lokalisering som er skrevet inn. &lt;/p&gt;&lt;p&gt;Måten dette hentes ut på i Javascript vises i følgende javascript-kode:&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;function geoCodeAddress(address) {&lt;br /&gt;var geocoder = new GClientGeocoder();&lt;br /&gt;geocoder.getLatLng(address, function(point) {&lt;br /&gt;if (!point) {&lt;br /&gt;alert("Lokaliseringsøk returnerte tomt resultat!");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt;map.setCenter(point, 10, G_NORMAL_MAP);&lt;br /&gt;lblLatitude.innerHTML = map.getCenter().lat().toFixed(2);&lt;br /&gt;lblLongitude.innerHTML = map.getCenter().lng().toFixed(2);&lt;br /&gt;return point;&lt;br /&gt;} //if-else&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;(Syntax coloring: Google Prettify &lt;a href="http://code.google.com/p/google-code-prettify/downloads/list"&gt;http://code.google.com/p/google-code-prettify/downloads/list&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I koden over anvendes metoden &lt;em&gt;getLatLng&lt;/em&gt; i klassen &lt;strong&gt;GClientGeocoder&lt;/strong&gt; i Google Maps&lt;br /&gt;API-et og address parameteret til funksjonen er en enkel tekststreng som er den&lt;br /&gt;teksten man skriver inn i tekstboksen. Man søker så opp lokaliseringen vha. &lt;em&gt;getLatLng&lt;/em&gt; kallet og setter point objektet i den anonyme delegatfunksjonen til sentrum av Google Maps kartet (GMap2) objekt. Dette er en meget brukervennlig funksjonalitet for en bruker for å skrive inn sin lokalisering og samtidig se kjapt at programmet har oppfattet hvor man befinner seg. I tillegg slipper man spesialtilfeller hvor man setter en beliggenhet som ikke har et unikt stedsnavn, ved at man ser at kartet tar feil, da anbefaler jeg å skrive inn et annet stedsnavn som er rett i nærheten som er unikt. Det som gjøres i innstillingssiden for gadget er å sette lengdegrad og breddegrad for denne gadgeten. Klokkeslettet som gadget benytter er alltid satt til nå (new Date() i Javascript med andre ord). &lt;/p&gt;&lt;p&gt;&lt;strong&gt;I versjon 1.2. vil en fix komme som setter opp en timeout på en time s.a. man får oppdatert gadgeten en gang i timen.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Jeg har implementert gadget så den benytter data basert på web services fra Yr.no og Google Maps. Gadgeten heter &lt;em&gt;Sol Måne&lt;/em&gt; og viser et ikon for månefase for gjeldende dag for en gitt beliggenhet, som brukeren setter opp ved å gå på innstillingene for gadgeten.&lt;br /&gt;I tillegg vises klokkeslettet for tiden månen og solen går opp og ned. Programmet håndterer midnattsol og mørketid for soloppgang og solnedgang. Man kan når man vil endre sin beliggenhet s.a. man får oppdaterte klokkeslett tider for sol opp og ned og måne opp og ned. Dette er en nyttig gadget som alltid gir deg tilgang til disse tidene. Det kan godt hende jeg legger inn enda mer informasjon som &lt;em&gt;Sunrise &lt;/em&gt;metoden tilbyr i versjon 1.3 og evt. fixer som trengs.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Google Maps API nøkkel - justering trengs?&lt;/strong&gt;&lt;br /&gt;I tillegg så er det satt en fast Google Maps API nøkkel i gadget (for localhost). Opplever du at du ikke får satt beliggenheten riktig pga. feil Google Maps, så må duendre API-nøkkel ved å gå til installasjonsmappen (Astropage.gadget for meg):&lt;br /&gt;&lt;br /&gt;%userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\Astropage.gadget&lt;br /&gt;&lt;br /&gt;Endre så api nøkkelen i settings.html, søk etter 'key' i denne filen. Google Maps API nøkkel får du tak i her:&lt;/p&gt;&lt;p&gt;&lt;a href="http://code.google.com/intl/no/apis/maps/signup.html"&gt;http://code.google.com/intl/no/apis/maps/signup.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Merk dog at testing har vist at dette ikke er nødvendig å gjøre dog, utvikling og testing er gjort i Windows Vista.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ActiveX teknologi i gadget&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;1. Når man lager gadget i Windows sidebar må man ofte ta i bruk ActiveX. XmlHttpRequest kall benytter ActiveX objektet MsXml2.XMLHTTP. Dette lar en gadget foreta Ajax kall. &lt;/p&gt;&lt;p&gt;2. Når man lagrer en fil for gadget i Windows sidebar benyttes ADODB.Stream som også er et ActiveX objekt .&lt;/p&gt;&lt;p&gt;3. Når man skal parse Xml filen som resultatet &lt;em&gt;SunRise&lt;/em&gt; metoden returnerer er lagret i benyttes ActiveX objektet Microsoft.XMLDOM. &lt;/p&gt;&lt;p&gt;Følgende javascript kode i gadgeten viser alle disse tre ActiveX objektene i bruk:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;function displayWeatherDataSunrise(selectedLatitude, selectedLongitude) {&lt;br /&gt;var xmlhttp = false;&lt;br /&gt;var now = new Date();&lt;br /&gt;try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }&lt;br /&gt;catch (e) { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }&lt;br /&gt;var dateString = now.getFullYear().toString() + "-" + (now.getMonth() + 1).toString() + "-" +&lt;br /&gt;now.getDate().toString();&lt;br /&gt;&lt;br /&gt;var url =&lt;br /&gt;"http://api.yr.no/weatherapi/sunrise/1.0/?lat=" + selectedLatitude + ";lon=" +&lt;br /&gt;selectedLongitude + ";date=" + dateString;&lt;br /&gt;&lt;br /&gt;//lblMoonphase.innerHTML = dateString;&lt;br /&gt;&lt;br /&gt;//xmlhttp.setRequestHeader("Content-type", "image/gif");&lt;br /&gt;xmlhttp.open("GET", url, true);&lt;br /&gt;now.setFullYear(2009, 1, 1);&lt;br /&gt;xmlhttp.setRequestHeader("If-Modified-Since", now);&lt;br /&gt;var ret;&lt;br /&gt;xmlhttp.onreadystatechange = function() {&lt;br /&gt;if (xmlhttp.readyState == 4) {&lt;br /&gt;if (xmlhttp.status == 200) {&lt;br /&gt;//Display the results.&lt;br /&gt;ret = xmlhttp.responseText;&lt;br /&gt;//document.body.style.backgroundColor = 'yellow';&lt;br /&gt;try {&lt;br /&gt;var path = "astrodata.xml";&lt;br /&gt;var stream = new ActiveXObject("ADODB.Stream");&lt;br /&gt;stream.type = 1; //Binary&lt;br /&gt;stream.open();&lt;br /&gt;stream.write(xmlhttp.responseBody);&lt;br /&gt;//Create if needed and overwrite if necessary&lt;br /&gt;stream.SaveToFile(System.Gadget.path + "\\" + path, 2);&lt;br /&gt;stream.close();&lt;br /&gt;xmlDoc = new ActiveXObject("Microsoft.XMLDOM");&lt;br /&gt;xmlDoc.async = false;&lt;br /&gt;xmlDoc.onreadystatechange = readAstroData;&lt;br /&gt;xmlDoc.load(System.Gadget.path + "\\" + path);&lt;br /&gt;} catch (e) {&lt;br /&gt;// Handle error here&lt;br /&gt;document.write("Error occurred: " + e);&lt;br /&gt;}&lt;br /&gt;//document.body.style.backgroundColor = 'green';&lt;br /&gt;} //if&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;xmlhttp.send(null);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;code class="prettyprint"&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-2660151173780095842?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/2660151173780095842/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/sol-mane-gadget-laget.html#comment-form' title='4 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2660151173780095842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/2660151173780095842'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/sol-mane-gadget-laget.html' title='Sol Måne : Windows Vista Sidebar gadget'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_MFfxHf2W1dA/S0ASNmUeZsI/AAAAAAAAACI/aoRILGfF8w8/s72-c/sunmoonv13_2.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-8359180356485091457</id><published>2009-12-26T15:52:00.000-08:00</published><updated>2010-01-02T19:42:09.705-08:00</updated><title type='text'>Værradar-gadget for Vista og Windows 7</title><content type='html'>Siste oppdatering:&lt;br /&gt;Fant endelig ut hvordan man får unngått at IE 8 cacher s.a. XmlHttpRequest ikke oppdateres for GET-kall, med følgende triks:&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;xmlhttp.open("GET", url, true);&lt;br /&gt;now.setFullYear(2009, 1, 1);&lt;br /&gt;xmlhttp.setRequestHeader("If-Modified-Since", now);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Dette sørger for at caching nå endelig unngås i gadgeten. Nå er det kun to bilder som stadig overskrives med nyeste data fra Yr.no og man får alltid nyeste tilgjengelige data pga caching endelig er slått av! Trikset over sender en request header i XmlHttpRequest kallet. Kravet til verdien for If-Modified-Since er at det er en dato som er tidligere enn nå. Jeg har satt denne til 1. januar 2009 (litt random, så lenge den er historisk så fungerer cachingen med at den endelig SLÅS AV.&lt;br /&gt;&lt;br /&gt;Dermed får man oppdaterte værradar-data, slik som ungdommen liker..&lt;br /&gt;&lt;br /&gt;Jeg har oppdatert gadgeten WeatherGadgetYr til versjon 1.2 som dere nå kan laste ned&lt;br /&gt;under. Dermed så er gadgeten ferdig laget, men er det ønsker om videreutvikling av den, si i fra!&lt;br /&gt;&lt;br /&gt;Mvh Tore Aurstad&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:2px;"&gt;Last ned WeatherGadgetYr som jeg har laget fra direkte link her:&lt;br /&gt;&lt;b&gt;&lt;a href="http://tore.aurstad.net/WeatherGadgetYr/WeatherRadarYr12.gadget"&gt;&lt;br /&gt;Værradar gadget versjon 1.2.&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Installasjonsprosedyre: &lt;/strong&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Last ned filen fra lenken over (høyreklikk og lagre mål som i IE8).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Gå til mappen du lastet ned filen, som er en zip fil.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Døp om filen til en fil som har filetternavn .gadget&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Dobbeltklikk på .gadget filen for å starte installasjonsprosedyren av gadget.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Et alternativ er å heller gjør dette:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Last ned filen fra lenken over (høyreklikk og lagre mål som i IE8).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Gå til mappen du lastet ned filen, som er en zip fil.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Pakk ut innholdet til mappen: %userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\WeatherRadarYr.gadget&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Etter å ha installert, klikk på "+"-knappen i Windows Sidebar i Vista (Windows 7 har en annen måte å gjøre dette på, men støtter også gadgets!) og velg så gadgeten.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/SzaxaxZSnqI/AAAAAAAAAA0/nWPxOQRbqB0/s1600-h/wradar_sidebar4.jpg"&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/SzaxaxZSnqI/AAAAAAAAAA0/nWPxOQRbqB0/s1600-h/wradar_sidebar4.jpg"&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;img style="width: 237px; height: 320px;" id="BLOGGER_PHOTO_ID_5419714275081100962" alt="" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/SzaxaxZSnqI/AAAAAAAAAA0/nWPxOQRbqB0/s320/wradar_sidebar4.jpg" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Gadgeten kan lett velges blant alle gadgeter på systemet. Dette er testet i Windows Vista.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;For å legge den til, velg &lt;strong&gt;Værradar Yr.no &lt;/strong&gt;gadgeten. Ikonet som vises er av radardomen&lt;br /&gt;til værradaren Radar Rissa i Midt-Norge.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzavoSP30YI/AAAAAAAAAAk/5I-mryo0tBw/s1600-h/wradar_sidebar2.jpg"&gt;&lt;img style="width: 320px; height: 245px;" id="BLOGGER_PHOTO_ID_5419712308215009666" alt="" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzavoSP30YI/AAAAAAAAAAk/5I-mryo0tBw/s320/wradar_sidebar2.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;em&gt;Værradardata vises som i Gadget i Windows Vista Sidebar. Flyout vises til venstre,&lt;br /&gt;som aktiveres når man klikker på Gadgeten. Klikker man på flyout igjen så lukkes&lt;br /&gt;flyout. For å redigere innstillinger klikker man på skiftenøkkel ikonet som for alle&lt;br /&gt;andre Gadgets. &lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/SzawAPCF49I/AAAAAAAAAAs/k_4HJb06O9M/s1600-h/wradar_sidebar3.jpg"&gt;&lt;img style="width: 246px; height: 320px;" id="BLOGGER_PHOTO_ID_5419712719668765650" alt="" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/SzawAPCF49I/AAAAAAAAAAs/k_4HJb06O9M/s320/wradar_sidebar3.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;em&gt;Det er mulig å velge blant mange værradarstasjoner og om man &lt;/em&gt;&lt;br /&gt;&lt;em&gt;vil hente en animasjon eller et stillbilde som viser nyeste værradardata.&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzapgvsejcI/AAAAAAAAAAc/Nay0S2sqAfs/s1600-h/wradar_sidebar.jpg"&gt;&lt;img style="width: 141px; height: 178px;" id="BLOGGER_PHOTO_ID_5419705581610896834" alt="" src="http://1.bp.blogspot.com/_MFfxHf2W1dA/SzapgvsejcI/AAAAAAAAAAc/Nay0S2sqAfs/s320/wradar_sidebar.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;em&gt;Gadgeten docker inn i sidebar sømløst.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Last ned WeatherGadgetYr som jeg har laget fra direkte link her:&lt;br /&gt;&lt;b&gt;&lt;a href="http://tore.aurstad.net/WeatherGadgetYr/WeatherRadarYr.gadget"&gt;&lt;br /&gt;Værradar gadget versjon 1.1.&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;Lisensen er GPL Open Source. Gi meg gjerne&lt;br /&gt;beskjed om når du bruker Gadgeten og tilbakemeldinger om evt. feil og forslag&lt;br /&gt;til forbedringer. Filen .gadget i lenken over er rett og slett en .zip fil&lt;br /&gt;med et spesielt fil etternavn og inneholder all HTML og Javascript som inngår.&lt;br /&gt;Du kan gjerne se innholdet til gadgeten hvis du går til filmappen:&lt;br /&gt;&lt;br /&gt;%userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\WeatherRadarYr.gadget\radarImages&lt;br /&gt;&lt;br /&gt;Jeg har benyttet Visual Web Developer 2008 Express til å utvikle. Det er mulig å hente ned templates for å utvikle gadgets, men jeg utviklet gadgeten stegvis. Det er sikkert slik at når man har laget en gadget så blir den neste mye enklere å lage. Det er lite som må til av kode for å lage en HTML/Javascript gadget og eneste kravet er at man er noenlunde stø i Javascript og forstår litt om HTML og HTML Document Object Model (DOM).&lt;br /&gt;&lt;br /&gt;Jeg har laget en Gadget som kan benyttes i Windows Sidebar som viser værradar data fra web-servicen The Weather API som benyttes på &lt;a href="http://www.yr.no/"&gt;http://www.yr.no/&lt;/a&gt; . Gadgeten er testet i Windows Vista, men skal også virke i Windows 7. Med denne gadgeten kan man på en enkel måte få vist værradar data fra Yr.no i Windows Sidebar.&lt;br /&gt;&lt;br /&gt;Du kan lese om The Weather API sin dokumentasjon av funksjonaliteten for å hente ut&lt;br /&gt;bilde eller animert bilde av nyeste værradardata fra DNMI og NRK her:&lt;br /&gt;&lt;a href="http://api.yr.no/weatherapi/radar/1.2/documentation"&gt;WeatherAPI Radar 1.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Gadget.xml, manifestfilen ser slik ut:&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;gadget&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;name&amp;gt;Værradar Yr.no&amp;lt;/name&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;namespace&amp;gt;tore.aurstad.net&amp;lt;/namespace&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;version&amp;gt;1.1.0.0&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;author name="Tore Aurstad"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;info url="http://tore.aurstad.net" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/author&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;copyright&amp;gt;© 2007&amp;lt;/copyright&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;description&amp;gt;Viser værradar-data for alle regioner av Norge som dekkes helt eller delvis&lt;br /&gt;&lt;br /&gt;av vær-radarer. Klikk på minatyrbildet for å vise siste oppdaterte værbilde for din&lt;br /&gt;&lt;br /&gt;region i Norge. Det er også mulig å vise animasjoner og værradar for hele Norden.&lt;br /&gt;&lt;br /&gt;&amp;lt;/description&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hosts&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;host name="sidebar"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;base type="HTML" apiVersion="1.0.0" src="weatherradar_yr.html" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;platform minPlatformVersion="1.0" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;permissions&amp;gt;Full&amp;lt;/permissions&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/host&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/hosts&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;icons&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;icon width="32" height="32" src="weatherradar.jpg" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/icons&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;defaultImage src="weatherradar.jpg" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/gadget&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I manifest filen over spesifiserer man en host av type HTML i sidebar (name) og&lt;br /&gt;setter src lik en hmtl fil weathergadget_yr.html. Dette er hoved html-filen i gadgeten. Denne filen vil&lt;br /&gt;sette opp gadgeten vha. Javascript og linke opp til to html filer settings.html og&lt;br /&gt;flyout.html. En settings fil viser GUI-et for å konfigurere gadgeten, altså det som vises når man velger skiftenøkkelen på en gadget. En flyout fil vises når man klikker på et element i gadgeten.&lt;br /&gt;&lt;br /&gt;Dette settes altså opp i javascript slik:&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;System.Gadget.settingsUI = "settings.html";&lt;br /&gt;System.Gadget.Flyout.file = "flyout.html";&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Denne koden skal inn i en script blokk for javascript og kalles når hoved html-filen&lt;br /&gt;er lastet.&lt;br /&gt;&lt;br /&gt;I denne gadgeten oppstod det et behov for å lagre bildefilene som returneres fra web services. Det er to bildefiler som lagres, en som viser et stillbilde som vises i sidebar og et bilde som viser et stillbilde eller et animert bilde i større størrelse i flyout visningen når man klikker på gadgeten. Opplever du at gadgeten ikke oppdaterer likevel værradardataene, må du tømme cachen for nettleseren. Dette skal nå dog være håndtert.&lt;br /&gt;&lt;br /&gt;For å skrive data i samme mappe som gadgeten, dvs. lagre bildene benyttes ADODB.Stream ActiveXObject. I tillegg benyttes et annet ActiveXObject, XmlHttpRequest eller Ajax om du vil. Funksjonen som henter opp værdataene er skrevet helt i Javascript og ser slik ut:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;function displayWeatherRadarData() {&lt;br /&gt;         var xmlhttp = false;&lt;br /&gt;         var now = new Date();&lt;br /&gt;         try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }&lt;br /&gt;         catch (e) { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }&lt;br /&gt;         var url =&lt;br /&gt;         "http://api.yr.no/weatherapi/radar/1.2/?radarsite=" + selectedRadarSite + ";type=" +"Image" + ";width=174";&lt;br /&gt;         //xmlhttp.setRequestHeader("Content-type", "image/gif");&lt;br /&gt;         xmlhttp.open("GET", url, true);&lt;br /&gt;         var ret;&lt;br /&gt;         xmlhttp.onreadystatechange = function() {&lt;br /&gt;             if (xmlhttp.readyState == 4) {&lt;br /&gt;                 if (xmlhttp.status == 200) {&lt;br /&gt;                     try {&lt;br /&gt;                        var path = "radarData_small.gif";&lt;br /&gt;                        var stream = new ActiveXObject("ADODB.Stream");&lt;br /&gt;                        stream.type = 1; //Binary&lt;br /&gt;                        stream.open();&lt;br /&gt;                        stream.write(xmlhttp.responseBody);&lt;br /&gt;                         //Create if needed and overwrite if necessary&lt;br /&gt;&lt;br /&gt;                        stream.SaveToFile(System.Gadget.path + "\\" + path, 2);&lt;br /&gt;                        stream.close();&lt;br /&gt;                     } catch (e) {&lt;br /&gt;                         // Handle error here&lt;br /&gt;                         document.write("Error occurred: " + e);&lt;br /&gt;                     }&lt;br /&gt;                     radarImg.src = "radarData_small.gif";&lt;br /&gt;                 } //if&lt;br /&gt;             }&lt;br /&gt;         }&lt;br /&gt;         xmlhttp.send(null);&lt;br /&gt;     }&lt;br /&gt; &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Javascript koden over demonstrerer både hvordan man skriver til fil i mappen til en gadget vha. ADODB.Stream objektet og hvordan man gjør et grunnleggende XmlHttpRequest&lt;br /&gt;for å hente asynkront data over internett. Dette kan nok benyttes til mer generelt å hente opp data asynkront fra ulike REST-baserte providere. Best av alt det virker.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Oppdatert informasjon: &lt;/strong&gt;&lt;br /&gt;Cachingen ser ut som den ikke er mulig å slå av for bildene i gadget, uten at&lt;br /&gt;man lagrer hvert minutt et nytt navn på radarbildet til flyouten. Alle bilder&lt;br /&gt;blir nå lagret i undermappen radarImages hver gang man aksesserer den for å se&lt;br /&gt;radardata. Hvis man ofte bruker gadgeten kan man med andre ord slette bildene i mappen:&lt;br /&gt;&lt;br /&gt;%userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\WeatherRadarYr.gadget\radarImages&lt;br /&gt;&lt;br /&gt;Hvert bilde tar litt plass, er det en animasjon tar et bilde rundt ca. 1 MB. Dermed kan man greit slette radarbildene etterhvert. Jeg skal legge inn funksjonalitet for å slette cachen (alle .gif filene som er i radarImages mappen) etterhvert i innstillingene for gadgeten.&lt;a href="http://tore.aurstad.net/WeatherGadgetYr/WeatherGadgetYr.gadget"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-8359180356485091457?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/8359180356485091457/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/vrradar-gadget-for-vista-og-windows-7.html#comment-form' title='5 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8359180356485091457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8359180356485091457'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/vrradar-gadget-for-vista-og-windows-7.html' title='Værradar-gadget for Vista og Windows 7'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MFfxHf2W1dA/SzaxaxZSnqI/AAAAAAAAAA0/nWPxOQRbqB0/s72-c/wradar_sidebar4.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-5654174410937622388</id><published>2009-12-20T19:44:00.000-08:00</published><updated>2009-12-20T21:24:36.274-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Statens Kartverk'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='NKSilverMashup'/><category scheme='http://www.blogger.com/atom/ns#' term='Mashup'/><category scheme='http://www.blogger.com/atom/ns#' term='Google Maps'/><title type='text'>NKSilverlight - Mashup</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/_MFfxHf2W1dA/Sy70P2Fel1I/AAAAAAAAAAU/OaECq6oqK4c/s1600-h/NKSilvermashup1.png"&gt;&lt;img style="WIDTH: 320px; HEIGHT: 246px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5417535954826991442" border="0" alt="" src="http://2.bp.blogspot.com/_MFfxHf2W1dA/Sy70P2Fel1I/AAAAAAAAAAU/OaECq6oqK4c/s320/NKSilvermashup1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;NKSilverlight er en mashup som kombinerer Google Maps, Statens kartverkdata, Silverlight og Javascript for å presentere kartdata for Norge med flere lag samtidig i en nettleser.&lt;/p&gt;&lt;p&gt;NKSilverlight står for Norgeskart Silverlight. Mashupen over er dog ikke bare en Silverlight applikasjon, til venstre ser man et tradisjonell HTML Div element som viser Google Maps. Google Maps er her en viewer for Statens Kartverk sine data. Man kunne forsåvidt bruke Microsoft Virtual Earth også for samme effekt. Vha. IsWindowLess satt til true i silverlight og css absolutt posisjonering klarer man å vise HTML og Silverlight side ved side. Kommunikasjonen mellom de to gjøres med standard HTML Bridge i Silverlight, HtmlWindow.Page.Invoke.&lt;/p&gt;&lt;p align="left"&gt;Jeg har laget en mashup som baserer seg på data fra Statens Kartverk og har en kort omtale&lt;br /&gt;av tilgjengelige data her: &lt;a href="http://www.statkart.no/?module=Articles;action=Article.publicShow;ID=14165"&gt;http://www.statkart.no/?module=Articles;action=Article.publicShow;ID=14165&lt;/a&gt;&lt;a href="http://www.statkart.no/?module=Articles;action=Article.publicShow;ID=14165"&gt;module=Articles;action=Article.publicShow;ID=14165&lt;/a&gt;&lt;br /&gt;Mashupen bruker Google Maps på web som &lt;em&gt;Viewer &lt;/em&gt;og kartdataene fra Statens Kartverk lastes inn i Mashupen som GTileLayerOverlay objekter i GMap2 objektet, mye av koden er i Javascript og kan leses hvis man velger &lt;em&gt;View Source &lt;/em&gt;i Mashupen. Jeg anbefaler for teknisk interesserte å lese om GTileLayerOverlay her: &lt;a href="http://code.google.com/intl/no/apis/maps/documentation/overlays.html#Tile_Layer_Overlays"&gt;http://code.google.com/intl/no/apis/maps/documentation/overlays.html#Tile_Layer_Overlays&lt;/a&gt;&lt;br /&gt;I tillegg har Mashupen brukt Silverlight 3 for å gi et interessant GUI som lar en mikse de ulike lagene som Statens Kartverk tilbyr for de ulike &lt;em&gt;Cache-tjenestene sine. &lt;/em&gt;Man kan med en Slider kontroll styre opacity, altså gjennomsiktighet fra 0 til 100 prosent for de ulike lagene. Ønsker man å vise f.eks. to lag så kan man slå på 50 prosent på begge. Dermed er det mulig å kombinere&lt;br /&gt;sjøkart og topografiske kart for Norge i Google Maps. Dette er mye bedre kart enn standardkartet til Google Maps som man fort vil synes er nakent i forhold. Statens kartverk dekker kun Norge, med unntak av det siste laget som er et europakartlag. Bruk avkrysningsboksene for kjapt å sette opacity til 0 eller 100 (skru lag av og på). Jeg har zippet hele prosjektet, som jeg har laget i Visual Web Developer Express 2008 som et Silverlight Application 3 prosjekt for de av dere som vil se på koden. Dette er en mashup som kun er et demoprosjekt, det er ikke optimert eller testet ut nøye. Det er morsomt å se at man kan slå sammen kartdata fra Statens Kartverk på en så grei måte, det tok meg kun noen få timers arbeid å lage Mashupen. Jeg vil også gjerne kombinere mashupen med data fra andre leverandører som Yr.no, f.eks. snødybde m.m. Er du interessert i disse temaene som meg er det kjempefint å få litt tilbakemelding, kanskje vi kan samarbeide om mashuper og mulige prosjekter rundt dette?&lt;br /&gt;&lt;/p&gt;&lt;p align="left"&gt;Til slutt er det kanskje interessant å laste ned prosjektet også som en zippet fil for Visual Studio 2008 Express Silverlight application prosjektet og se en live demo av mashupen. &lt;/p&gt;&lt;p align="left"&gt;Nedlasting av NKSilverlight prosjektet [ZIP, 253 kb]: &lt;/p&gt;&lt;p align="left"&gt;&lt;/p&gt;&lt;p align="left"&gt;&lt;/p&gt;&lt;p align="left"&gt;&lt;a href="http://tore.aurstad.net/NKSilverMashup/NKSilverMashup.zip"&gt;http://tore.aurstad.net/NKSilverMashup/NKSilverMashup.zip&lt;/a&gt;&lt;/p&gt;&lt;p align="left"&gt;Instruksjoner: Pakk ut filene, åpne NKSilverMashup.sln Solution filen, høyreklikk på NKSilverMashupTestpage.html filen i NKSilverMashup.web og velg &lt;em&gt;Set as Start Page&lt;/em&gt;.&lt;br /&gt;Trykk så på F5 for å snurre film. Du vil få opp NKSilverMashup omtrent som i skjermbildet over, man starter på lokalisering Steinkjer og viser 50% Topografisk Norgeskart 2 WMS og&lt;br /&gt;50% Sjøkart Hoveserien 2 WMS data i Google maps utsnittet man ser. &lt;/p&gt;&lt;p align="left"&gt;Har du ønsker om å videreutvikle prosjektet er det fint om du kan kreditere meg i tillegg. Jeg vil også gjerne ha beskjed om dette først. Hvis du ønsker å stille spørsmål om prosjektet, gi gjerne tilbakemelding, gjerne nedenfor eller en e-post til: &lt;a href="mailto:tore.aurstad@ntebb.no"&gt;tore.aurstad@ntebb.no&lt;/a&gt; . &lt;/p&gt;&lt;p align="left"&gt;En genial ting med denne mashupen er at den består kun av en .HTML fil og en .XAP fil for Silverlight prosjektet, altså kun to filer. Data hentes som sagt av Statens Kartverk og vieweren er Google maps. Dermed er dette prosjektet en mashup, altså benytter seg av eksterne tjenester. Det blir spennende å se om det går an å teste og videreutvikle mashupen til også vise andre ting. Google maps har en spennende og rik API som er interessant å eksperimentere med. &lt;/p&gt;&lt;p align="left"&gt;Til slutt og ikke minst, LIVE DEMO! Klikk på lenken nedenfor:&lt;br /&gt;&lt;a href="http://tore.aurstad.net/NKSilverMashup/NKSilverMashupTestPage.html"&gt;http://tore.aurstad.net/NKSilverMashup/NKSilverMashupTestPage.html&lt;/a&gt;&lt;/p&gt;&lt;p align="left"&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-5654174410937622388?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/5654174410937622388/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/nksilvermashup-laget.html#comment-form' title='3 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5654174410937622388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5654174410937622388'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/nksilvermashup-laget.html' title='NKSilverlight - Mashup'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MFfxHf2W1dA/Sy70P2Fel1I/AAAAAAAAAAU/OaECq6oqK4c/s72-c/NKSilvermashup1.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-8366697072150956123</id><published>2009-12-20T19:42:00.001-08:00</published><updated>2009-12-20T19:43:38.932-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='temavalg'/><title type='text'>Hva skal bloggen inneholde?</title><content type='html'>Bloggen vil inneholde informasjon primært om teknologi, mer spesifikt .NET prosjekter og web-teknologi som jeg har gjennomført og gjerne ønsker diskusjon rundt. I tillegg kan det bli litt personlig informasjon om meg selv og noen bilder, men fokus på bloggen er primært teknologi.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-8366697072150956123?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/8366697072150956123/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/hva-skal-bloggen-inneholde.html#comment-form' title='0 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8366697072150956123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/8366697072150956123'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/hva-skal-bloggen-inneholde.html' title='Hva skal bloggen inneholde?'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-1927904654209084984</id><published>2009-12-20T19:28:00.000-08:00</published><updated>2009-12-20T20:09:02.953-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Personlig'/><title type='text'>Litt informasjon om bloggen</title><content type='html'>Hensikten med denne bloggen er å spesielt presentere mine interesser og dele dem med andre globalt sett. Det vil være en god del innlegg på engelsk etterhvert, men de innleggene som kun nok vil interesse nordmenn vil foregå på norsk.&lt;br /&gt;&lt;br /&gt;Jeg er en 31 år gammel programmerer som jobber i Trondheim. Jeg er født og oppvokst i Steinkjer i Nord-Trøndelag og har studert allmenne fag her. I ungdommen (er jeg ikke ung enda da?) drev jeg mye med fotball og svømming. Jeg studerte tre år på Lade ulike emner i realfag, mye matematikk og informatikk. Også emner i fysikk og noe i statistikk. Jeg måtte avtjene min førstegangstjeneste i 2000 og hadde et interessant år i HMK Garden i Rekognoseringstroppen. Jeg brukte så kun fire år på å få tatt min grad Sivilingeniør i datateknikk, sommeren 2005. Videre jobbet jeg etter studiene med ulike prosjekter for ulike og tok også en del etterutdanning innenfor fag i Linux og systemadministrasjon. Jeg fikk min første jobb i Kongsberg Spacetec i Tromsø mai 2006 og jobbet her et halvt år. En arbeidsgiver med mange spennende prosjekter og jeg jobbet med NASA og ESA. Etterhvert gikk det dog opp for meg at jeg ville fortsette og jobbe og bo i Trøndelag og jeg fikk så jobb i Norconsult IS i Trondheim. Her jobbet jeg for første gang med .NET teknologi og etter å ha jobbet med mye Linux-systemer og åpen programvare så var det egentlig en grei retur til .NET teknologi og Visual Studio. Jeg jobbet her i 10 måneder som konsulent på oppdrag og drev mye med ASP.NET, Javascript og Geomedia WebMap, samt Oracle. Etterpå fikk jeg jobb hos Lydia AS i Trondheim og har jobbet der i 2 år. Her har jeg jobbet med .NET teknologi igjen, Windows Presentation Foundation (WPF) og ASP.NET, Javascript og WCF, all .NET programmering i hovedsaklig C#.NET. Jeg kjenner også VB.NET men liker helst å bruke C#.NET. For tiden så er jeg formelt ansatt i Lydia AS fram til 31. mars 2010 og jeg er på utkikk etter en ny arbeidsgiver, helst i Trondheim og som kan tilby stilling til meg. Jeg håper at jeg med min gode formelle utdanning og etterhvert varierte bakgrunn kan være interessant for en ny arbeidsgiver i Trondheim til nyåret 2010.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-1927904654209084984?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/1927904654209084984/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/litt-informasjon-om-bloggen.html#comment-form' title='0 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/1927904654209084984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/1927904654209084984'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/litt-informasjon-om-bloggen.html' title='Litt informasjon om bloggen'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7240109143089619921.post-5181675279746529487</id><published>2009-12-20T19:27:00.000-08:00</published><updated>2009-12-20T19:28:04.985-08:00</updated><title type='text'>Bloggen opprettet</title><content type='html'>Dette er en test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7240109143089619921-5181675279746529487?l=toreaurstad.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toreaurstad.blogspot.com/feeds/5181675279746529487/comments/default' title='Legg inn kommentarer'/><link rel='replies' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/bloggen-opprettet.html#comment-form' title='2 Kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5181675279746529487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7240109143089619921/posts/default/5181675279746529487'/><link rel='alternate' type='text/html' href='http://toreaurstad.blogspot.com/2009/12/bloggen-opprettet.html' title='Bloggen opprettet'/><author><name>Tore Aurstad</name><uri>http://www.blogger.com/profile/04987676273327898993</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_MFfxHf2W1dA/S0APtqkHYYI/AAAAAAAAABg/AA1fGTpdzco/S220/tore.JPG'/></author><thr:total>2</thr:total></entry></feed>
