PicNet Custom Software Development

.Net and Javascript Development

GWT in a .Net environment

Posted on clock February 3, 2010 04:11 by author guido

Hi All,

As you know we have recently release the PicNet Mouse Eye Tracking service. This project is by far the largest Javascript centric application that PicNet has developed. This led us to do a lot of research on what technologies we would use for generating a maintainable javascript project.

We were restricted to having a .Net backend as that is what our existing infrastructure supports and its the technology where we live most comfortably. So the decision for the backend was simple, ASP.Net Mvc (w/ Spark View Engine) + NHibernate.

But now came the more complex decision of the client code (javascript). Do we stick to standard jquery code minified in our continous build? do we create our own bootstrapping js framework to easily allow OO in js? Do we leverage other such frameworks?

We ended up investigating a lot of different options but this article focuses on one of these which is GWT.

Javascript development is hard, anyone that tells you otherwise thinks javascript development is for creating roll over buttons. JS development is hard for various reasons.
  • The language is very flexible and it gives you all the rope in the world to ...
  • At the heart of the language is the function. This is a concept that is difficult for most OO devs to wrap their heads around
  • Performance is such a huge issue, compared to server languages
  • Code size (and design) is a big issue
  • Finally and most importantly is: The tools for javascript development are useless in comparison to other languages
The last item is huge. I mean with Java you use Eclipse or IntelliJ to manage your projects, builds, deployments, code analysis, error reporting, debugging, syntax highlighting, unit testing, code completion, refactoring, etc, etc, etc. For .Net you have Visual Studio giving the same support. Now try this as an experiment. Write a simple app in Java or .Net using notepad! That is what javascript development is like, regardless of language features, performance, etc. The tools issue is a killer.

GWT is a great framework and I would comfortably say, its the best framework for javascript development available. The reason it is the best framework is the fact that you can use good tools (Eclipse, IntelliJ, etc), it also removes alot of the Javascript hacky mentality required for writing fast javascript (but thats a secondary benefit in my opinion). Now for .Net developers learning to use Eclipse, etc is a bit of a pain but from a maintainability issue, if you were developing a solely javascript application it is definatelly worth the effort. HOWEVER!! Having a client (javascript) / server (.Net) application written in GWT / .Net has huge drawbacks. It is actually so painful that we finally decided to abandon the attempt.

How do you do it
Well our service is a very complex html page with a very large javascript component. The html file we generate using Spark View Engine. This lets us modularise the html into nice little controls that are easy to work with. This is where we encounter our first GWT hurdle. To use GWT you have to have the html in the hosted server, well that's not true you could compile the javascript and stick it in your ASP.Net application and not have html in Java however if you cannot use GWT in hosted mode it is not worth using (My own opinion).

What does this mean? Well, basically it means that you have to view the source of your html and copy into your GWT environment. Thats correct, change html you need to remember to copy paste into GWT env every time. We tried doing crazy things like having iframes pointing to the ASP.Net app from GWT environment with cross domain policies, etc but this always failed.

Ok, this is a huge maintenance issue, however if this were the only issue I think we still would have used GWT given its previously described benefits.

Second issue!! Talking to the server. This issue actually has a few parts, the first is serialisation. GWT offers a few optimised serialisation mechanisms such as XML and JSON (and a custom one). Since our application used plain strings for its communications, rolling up our own XmlHttpRequests from GWT was no problem (we do this for performance reasons). So this was no big issue at all. The second issue is authentication. To use our application you must be logged in so in development mode we had to add a hack that would recognise GWT development requests and simulate a user, Ughh!! Still not a huge issue but getting bigger. And finally the last issue is the fact that to use GWT with a .Net backlend in development you have to use a proxy server. No problem here is a great article describing how to set this up. Now it is difficult to describe the development process here but I will try.
  • Start the hosted mode server
  • Oh forgot to copy the new html
  • Copy the html
  • Restart hosted mode
  • Crash!!
  • Hughh?
  • Oh, a crash on the .net side
  • Done, try again
  • Hmmm yes it does look better with that border
So you get my pain?

So my conclusions. GWT is awesome!! Enough cannot be said about how good this toolkit is but it is still too painful to be a real alternative in a .net application.

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


XML Settings Files - No more web.config

Posted on clock September 10, 2009 02:28 by author guido

One of my pet hates is working on projects where previous developers have decided to dump all of their settings in the web.config file.  Some of the reasons why I dislike this practice is:

  • It looks horrible
  • You cannot modify settings at run time (it restarts the application)
  • You are mixing application deployment config info with your own configuration
  • Did I mention that it looks and smells horrible?
  • It is so simple to do it nicely

So now lets look at the nice way of doing this.

XML File

A settings file should look like this:


<ApplicationSettings>
<ConnectionString>server=servername;database=databaseName;</ConnectionString>
<AdministratorsGroup>Admin</AdministratorsGroup>
<MaxNumberOfAllowedConnections>500</MaxNumberOfAllowedConnections>
<Etc>true</Etc>
</ApplicationSettings>

Not like this (Did I mention ugly?):


<appSettings>
<add key="ConnectionString" value="server=servername;database=databaseName;" />
<add key="AdministratorsGroup" value="Admin" />
<add key="MaxNumberOfAllowedConnections" value="500" />
<add key="Etc" value="true" />
</appSettings>

So lets go ahead and assume that our settings file will look like the first one above.

Accessing Application Settings

Accessing settings like this:

int maxConnections = SystemSettings.Instance.MaxNumberOfAllowedConnections;

Is a million times nicer that accessing the like this:

int maxConnections = String.IsNullOrEmpty(ConfigurationSettings.AppSettings["MaxNumberOfAllowedConnections"]) ? 0 : Int32.Parse(ConfigurationSettings.AppSettings["MaxNumberOfAllowedConnections"]);

 

Basic Implementation

So now that I've made it easy to see how ugly the alternative is lets look at a simple implementation for this design.

using System;

using System.IO;

using System.Web;

using System.Xml.Serialization;

 

namespace Namespace {

[Serializable] public class ApplicationSettings {

private static readonly XmlSerializer serial = new XmlSerializer(typeof(ApplicationSettings));

 

    private static ApplicationSettings instance;

    public static ApplicationSettings Instance

{

           get

           {

               if (instance != null) return instance;

               string filename = HttpContext.Current.Server.MapPath("~/resources/settings.xml");

               using (StringReader sr = new StringReader(filename)) return instance = (ApplicationSettings) serial.Deserialize(sr);

           }

}

       public string ConnectionString { get; set;}

       public string AdministratorsGroup { get; set;}

       public int MaxNumberOfAllowedConnections { get; set;}

       public bool Etc { get; set;}

}

}

Allow Changes at Runtime

The above design is very tidy but it has a flaw that it does not allow changes to the settings file at run time.  To accomplish this we need

a file aware cache.  Lukily the ASP.Net cache is ideal for this.  So lets expand the above to take advantage of this.

 

using System;

using System.IO;

using System.Web;

using System.Web.Caching;

using System.Xml.Serialization;

 

namespace PicNet.FreeWeb.Settings {

[Serializable] public class ApplicationSettings {

private static readonly XmlSerializer serial = new XmlSerializer(typeof(ApplicationSettings));

    public static ApplicationSettings Instance

{

           get

           {

               Cache cache = HttpContext.Current.Cache;

               string filename = HttpContext.Current.Server.MapPath("~/resources/settings.xml");

               if (cache[filename] != null) return (ApplicationSettings) cache[filename];                

               CacheDependency dep = new CacheDependency(filename);                                     

               using (StringReader sr = new StringReader(filename)) {

                   ApplicationSettings appSettings = (ApplicationSettings) serial.Deserialize(sr);

                   cache.Insert(filename, appSettings, dep, DateTime.MaxValue, TimeSpan.MaxValue);

                   return appSettings;

               }

           }

}

       public string ConnectionString { get; set;}

       public string AdministratorsGroup { get; set;}

       public int MaxNumberOfAllowedConnections { get; set;}

       public bool Etc { get; set;}

}

}

 

Securing the Settings File

We may have sensitive data in this settings file such as passwords, etc.  This kind of information should obviously not be delivered to the web.  So how can we secure this.  Well, there are 3 main ways.

 

IIS

IIS can be set not to deliver xml files.  Or if you want just change the file name to settings.appsettings and then block the .appsettings filetype.

 

Web.config

This option is probably preferred to the IIS option as it will allow you to deploy to any server without having to remember to change IIS settings.  

To do this simply add the following handler to your web.config:


<add verb="*" path="*.xml" type="System.Web.HttpForbiddenHandler" validate="false"/>

Note: You will need to ensure that .xml files are being handled by the aspnet IIS handler.

 

 

Global.asax.cs

Finally and by far the best (in my opinion) is to hide the file by Filtering in Global.asax.cs

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)

{   

if (HttpContext.Current.Request.Url.LocalPath.IndexOf(".xml") >=0) { throw new SecurityException();}

...

}

Note: You will need to ensure that .xml files are being handled by the aspnet IIS handler.

 

That's it, and again, there is no good reason to have your settings in that decaying Web.config file.

 

Enjoy

 

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Sharing MVC Views Across Projects

Posted on clock August 12, 2009 04:25 by author guido

This is something I have been wanting to do for a while in the ASP.Net world however its not untill recently (with MVC) that this has been a 'clean' possibility. This article demonstrates how to do this.

Inspiration

At PicNet are always trying to deliver quality products at the cheapest possible cost to the user.  The way we do is is by having 'template' driven projects. This allows us to generate data access layers very quickly (see previous articles) and we also copy template web projects, windows projects, mobile projects that give us a good starting point.  We also levarage custom libraries heavily.  However we could never put any of the view code (aspx, ascx) in these libraries as it was just not clean.

Embedded Views

To store your shared views in a library project simply copy the view code (aspx, ascx, master) into your library project.  Please ensure that the view code compiles.  By this I mean that all references are still valid (without requiring Web.config namespaces).  Tools like Resharper will show wether the view is valid or not.  Then mark the view as an 'Embedded Resource'.  To do this just right click on the file name -> Properties and set the Buidl Action to 'Embedded Resource'.  You will then need to rebuild the project to embed the resource in the DLL.

 

The View Engine

Add the following View Engine to your library project.

 

/// <summary>

/// This class will read all embedded views in THIS dll and will dumpo them out to the

/// ~/tmp/Views directory.

/// </summary>

public class EmbeddedResourceViewEngine : WebFormViewEngine

{

    public EmbeddedResourceViewEngine() {            

        MasterLocationFormats = new[] {

            "~/Views/{1}/{0}.master",

            "~/Views/Shared/{0}.master",

            "~/tmp/Views/{0}.master"

        };

 

        ViewLocationFormats = new[] {

            "~/Views/{1}/{0}.aspx",

            "~/Views/{1}/{0}.ascx",

            "~/Views/Shared/{0}.aspx",

            "~/Views/Shared/{0}.ascx",

            "~/tmp/Views/{0}.aspx",

            "~/tmp/Views/{0}.ascx"

        };

        PartialViewLocationFormats = ViewLocationFormats;

 

        DumpOutViews();

    }

 

    private static void DumpOutViews()

    {

        IEnumerable<string> resources = typeof (EmbeddedResourceViewEngine).Assembly.GetManifestResourceNames().Where(name => name.EndsWith(".master") || name.EndsWith(".aspx") || name.EndsWith(".ascx"));

        foreach (string res in resources) { DumpOutView(res); }                

    }

 

    private static void DumpOutView(string res)

    {

        string rootPath = HttpContext.Current.Server.MapPath("~/tmp/Views/");

        if (!Directory.Exists(rootPath)) {

            Directory.CreateDirectory(rootPath);

        }

 

        Stream resStream = typeof (EmbeddedResourceViewEngine).Assembly.GetManifestResourceStream(res);

        int lastSeparatorIdx = res.LastIndexOf('.');

        string extension = res.Substring(lastSeparatorIdx + 1);

        res = res.Substring(0, lastSeparatorIdx);

        lastSeparatorIdx = res.LastIndexOf('.');

        string fileName = res.Substring(lastSeparatorIdx + 1);

 

        FileUtils.WriteFileContents(rootPath + fileName + "." + extension, resStream);

    }

}

 

 

This view engine simply gets the views that have been stored as embedded resources and dumps them out to the ~/tmp/Views directory.

 

Register the View Engine

In Global.asax.cs just add:

 

public static void RegisterCustomViewEngines(ViewEngineCollection viewEngines)  

{  

  viewEngines.Clear();  

  viewEngines.Add(new EmbeddedResourceViewEngine());  

}  

...

protected void Application_Start(object sender, EventArgs e)

{

  RegisterRoutes(RouteTable.Routes);

  RegisterCustomViewEngines(ViewEngines.Engines);

}

 

That's It

That's it all the embedded views now simply behave like shared views.

 

 

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd