Skip to content

Instantly share code, notes, and snippets.

@zdam
Created February 28, 2010 00:00
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save zdam/317069 to your computer and use it in GitHub Desktop.
Save zdam/317069 to your computer and use it in GitHub Desktop.
Use clojureCLR inside an asp.net MVC app
/*
* This is a litle tech demo to demonstrate using clojureCLR in a CLR web app.
*
* A custom IHttpHandler (ClojureHttpHandler) handles invocation of clojure code,
* and a custom IRouteHandler (ClojureRouteHandler) routes requests to the HttpHandler.
*
* See comments in the code for further detail.
*
* Cheers, zdam
* http://zimpler.com/blog/clojureclr-in-an-asp-net-mvc-app
*
* *** Setup instructions are at the bottom of this file ***
*
*/
using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using clojure.lang;
using MvcPlay;
namespace MvcPlay
{
public class ClojureHttpHandler : IHttpHandler
{
private static readonly Symbol CLOJURE_MAIN = Symbol.intern("clojure.main");
private static readonly Var REQUIRE = RT.var("clojure.core", "require");
private static readonly Var MAIN = RT.var("clojure.main", "main");
public void ProcessRequest(HttpContext context)
{
var routeValues = RouteData.Values;
// exit if we weren't told what script to run
if (routeValues["script"] == null) return;
// Redirect clojure output to a writer so we can do what we like with it
TextWriter clojureOutput = new StringWriter();
RT.OUT.BindRoot(clojureOutput);
REQUIRE.invoke(CLOJURE_MAIN);
// Load a script, then execute a particular function inside the script.
// We can pass parameters in as well.
// This is just to demo execution of clojureCLR.
// A real clojureCLR real web app would dispatch to clojure using
// a more sophisticated mechanism.
// The approach Enclojure uses could be done here too.
var scriptToLoad = context.Server.MapPath(@"~\" + routeValues["script"]);
var functionToExecute = routeValues["function"].ToString();
var valueOfParam1 = routeValues["param1"].ToString();
RT.load(scriptToLoad);
RT.var("zdam", functionToExecute).invoke(valueOfParam1);
// Ideally you would use clojure itself to generate the html.
// Port the html builders in enclojure or use a templating system like enlive
HttpResponse response = context.Response;
response.Write("<html>");
response.Write("<body>");
response.Write("<h1>The result of your funky clojure script:</h1>");
response.Write("<p>");
response.Write(clojureOutput.ToString());
response.Write("</body>");
response.Write("</html>");
}
public bool IsReusable
{
get { return false; }
}
// Gives us access to the RouteData which we dont have in .Net 3.5
public RouteData RouteData { get; set; }
}
// Route handler to route requests to our ClojureHttpHandler,
// we also pass the RouteData along.
public class ClojureRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new ClojureHttpHandler { RouteData = requestContext.RouteData };
}
}
public class MvcApplication : System.Web.HttpApplication
{
// We wire in the ClojureRouteHandler
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
// Some simple routes with some defaults
routes.Add(new Route("{script}/{function}/{param1}",
new RouteValueDictionary
{ { "script", "first" }, { "function", "default" }, { "param1", 1 } },
new ClojureRouteHandler()));
routes.Add(new Route("{*url}", new ClojureRouteHandler()));
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
}
}
/*
* Setup steps:
*
* 1. Ensure you have the ClojureCLR project up and running successfully.
* http://github.com/richhickey/clojure-clr#readme
*
* 2. From inside the ClojureCLR solution in VS,
* - add a new ASP.NET MVC 2 Empty Web Application, called MvcPlay
*
* 3. Ensure your project is set up to use IIS, not Cassini,
* - ensure your site has Anonymous access allowed.
*
* 4. Add project references to:
* Clojure
* Microsoft.Scripting
* Microsoft.Scripting.Core
*
* 5. Replace the contents of Global.asax.cs with this file that you are reading.
* (If you did not call your project MvcPlay,
* you will need to adjust the namespace to match the project name you chose.)
*
* 6. In the file yourPathTo\Clojure\Clojure\Lib\RT.cs change line 1974 from this:
*
* yield return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
*
* to this:
*
* var foundAssembly = Assembly.GetEntryAssembly();
* if (foundAssembly != null)
* {
* yield return Path.GetDirectoryName(foundAssembly.Location);
* }
*
* 7. Create a new file in the root of your project,
* - called first.clj, copy the following into it:
* (ns zdam)
* (defn some-math [multiplier]
* (pr (* multiplier (+ 1 2 3 4))))
*
* (defn default [&args]
* (pr "Welcome to clojure-clr on MVC"))
*
* 8. Add a system variable called clojure.load.path,
* - point it to yourPathTo\Clojure\Clojure.Main\bin\Debug;
*
* 9. Do an IISRESET ! (to ensure the environment variable gets picked up)
*
* 10. Run the web project
*
* 11. On your browser url, append
* first/some-math
* first/some-math/8
* (eg mine looked like: http://localhost:5651/first/some-math )
*
* to invoke the clojure script we created above, with and without parameters.
*
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment