Created
February 28, 2010 00:00
-
-
Save zdam/317069 to your computer and use it in GitHub Desktop.
Use clojureCLR inside an asp.net MVC app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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