Wednesday, March 25, 2015

Integrating Meteor client only application with ASP.NET MVC 5

I recently had a project where I wanted to use Meteor but we were unable to utilize the meteor server for our phase 1 deliverable.  Instead we had to integrate with an existing ASP.NET MVC 5 application.  Here is how I did it:

1) Use HTTP instead of DDP for all communication to the server.  Meteor makes client/server communication really easy through publications, DDP and meteor methods.  While there are some DDP libraries that may allow your non meteor server to integrate via DDP, this was not the route we took.  Instead we decided to do all RESTful calls to our server as it had existing REST APIs that we wanted to us.

2) Tell the meteor client code to disconnect from the meteor server.  The meteor client code assumes there is a meteor server and immediately tries to establish a DDP connection to communicate with it.  Not only for normal client/server calls, but also to receive notifications of hot code pushes.  Since we don't have a meteor server in our case, we need to explicitly disconnect like so in my client/main.js:

Meteor.disconnect();

3) Build meteor for deployment.  Building meteor for deployment will generate a single JS and CSS file from all JS/CSS used by the client side in your project.  This means it will concatenate, uglify and minify everything for you.  Create a build output directory "build" as a peer to your meteor project and generate the build outout:

meteor build --directory ../build

4) Copy the generated js and css files into your ASP.NET MVC project.  The generated files should be in the build/bundle/programs/web.browser directory.  You should find a scripts folder in your ASP.NET MVC project, I created a sub directory to hold my meteor code.  Note that the meteor build creates a unique filename for the js and css file (presumably based on a file hash as it does not rename the file if the file contents dont change).  I simply renamed the js and css files from the generated name to a consistent name (e.g. main.js and main.css) so I didn't have to add/remove files to TFS all the time.  I put the files in a bundle to ensure that new versions invalidated older cached versions of the files.

5) Load the meteor js and css files from your ASP.NET CSHTML file and add the meteor runtime config.  The meteor client code depends on a global variable named __meteor_runtime_config__ which the meteor server uses to pass several properties to the client.  Since we don't have a meteor server, you need to set this up and pass it to the client from your ASP.NET MVC app.  Here is our CSHTML that we are using:

@model MeteorViewModel
@{
    ViewBag.Title = "";
    Layout = "";
    ViewBag.RootUrl = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
}

<link rel="stylesheet" type="text/css" class="__meteor-css__" href="@Url.Content("~/Scripts/Meteor/main.css?meteor_css_resource=true")">

<script type="text/javascript">
__meteor_runtime_config__ = {
    "meteorRelease": "METEOR@1.0.3.1",
    "ROOT_URL": "@ViewBag.RootUrl" + "Scripts/Meteor/Public/",
    "ROOT_URL_PATH_PREFIX": "",
    "autoupdateVersion": "af58dd0d8e3b4c9b85ee2fa53553d2502663b530",
    "autoupdateVersionRefreshable": "a6de052a32154229bfac08baf16f2141a6b943e2",
    "autoupdateVersionCordova": "none",
    "Data": "@Model.Data"
};
</script>


@Scripts.Render("~/bundles/Meteor")


A few notes about this:
1) We need to set the ROOL_URL correctly for where we are serving the public folder from
2) I added the "Data" property to pass some data from our ASP.NET MVC app to the meteor app
3) We use ASP.NET MVC's bundle feature with the meteor code to avoid caching issues on the browser

You should be able to follow the above steps to integrate Meteor client only applications with other server side stacks.

8 comments:

  1. Chris! Thanks. This is great stuff. Perhaps you could post an example of how you mocked the __meteor_runtime_config__ example in the .net mvc app -- that snippet really helped make the idea real. Also, it would be good to list the things you can't do with this approach: presumably meteor method calls, or pub/subs. Another idea would be to modify the Meteor.call invocation on the client side so it could in fact make calls to asp.net MVC controllers, but I'm not sure where you want to stop 'stubbing' in the functionality and instead try to integrate the fullstack inside 'brownfield' apps such as this. To achieve this, I know first you have the compliance/security issues...it would be pretty cool to build providers that can simulate pub/sub and meteor.call methods (without reactivity) onto legacy systems. Thanks again for sharing!

    ReplyDelete
  2. I updated the blog entry with a sample CSHTML file. If your server stack has a DPP library, it might be possible to use meteor methods and publications - I haven't tried that. We are using bare HTTP calls to communicate with the server side.

    ReplyDelete
  3. Just to let anyone know that may find it useful, i'm implemented a .Net DDP Server library. It's still in beta which is available from my github account https://github.com/jamie-tigereye/DDP.Server.Net. As far as I know this is the first publically available instancce of a .Net DDP Server. There is a client available. Any forks, improvements or suggestions would be appreciated.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete