“Badgifying” an ASP.NET page

IMG_3500 I apologize for the neologism. What I’m going to demonstrate in this post is a technique I prototyped a few months ago to make it very easy to embed an ASP.NET page’s content in another page, even if it’s using another server technology. This of course works cross-domain.

The reason why you would do that is to enable people to embed badges with your contents on their own sites. Examples of such badges can be found in the margin of this blog: there’s the ad badge, a Twitter badge, a Facebook badge, an Xbox Live badge, a Zune badge, and there used to be a Flickr badge. There are even full commenting systems that you can include on your blog this way. All those are Flash or JavaScript, and in both cases there’s a short JavaScript stub that includes it.

What’s really nice about this approach is that people can include your contents from the client-side, no matter what server technology they use, with a single script tag. Here’s what it looks like:

<script type="text/javascript" src="AspNetBootstrap.js"
  xmlns:foo="Remote.aspx"
foo:bar="42" foo:baz="glop & co"></script>

The script tag has two parts. The first is a regular script tag that includes a bootstrapping script. The second part are some additional attributes that specify the page to include and optionally parameters. Those parameters will be transmitted to the page as querystring parameters. For example, the script tag above includes the following ASP.NET page:

<%@ Page Language="C#" %>
bar = <%= Request.QueryString["bar"] %><br />
baz = <%= Request.QueryString["baz"] %>

The system relies on two things. First, we have the bootstrap script. It’s a very small piece of code (664 bytes minified, 453 minified and gzipped) that parses the attributes of its own script tag and creates a new script tag pointed at a special handler, the second part of the system.

The handler extracts the page name from the querystring and processes the request. The result of that processing is then embedded into simple JavaScript that writes the rendered page into the document:

public void ProcessRequest(HttpContext context) {
  context.Response.ContentType = "text/javascript";
  var request = context.Request;
  var pagePath = request.QueryString["__page"];
  var sb = new StringBuilder();
  using (var writer = new StringWriter(sb)) {
    var worker = new SimpleWorkerRequest(
pagePath,
context.Request.QueryString.ToString(),
writer); HttpRuntime.ProcessRequest(worker); } context.Response.Write("document.write('" + sb.ToString().Replace(@"'", @"\'")
.Replace("\n", @"\n")
.Replace("\r", @"\r") + "');"); }

Of course, this is only a simple proof of concept and it could be improved in a number of ways:

  • Relative URLs (of images and scripts) are not re-rooted into the host page. This means you’ll need to use absolute URLs.
  • There is no support for any interactions back with the remote server, including with forms or Ajax. It’s not impossible but you’re on your own to implement it.

Still, to include simple contents, this constitutes an extremely simple approach to making your ASP.NET contents accessible to remote pages, no matter what server technology they use (if any).

I’d love to know what you think and if you think this is worth pursuing.

Download the code from here:
http://weblogs.asp.net/blogs/bleroy/Samples/EmbeddedASPNET.zip

14 Comments

  • It's OK for very simple stuff Bertrand - but obviously will not allow you to do anything interactive with a forms based ASP.NET page - where you are better creating the content within an iframe.

    Dave

  • Ah, but iFrames are fixed size and a lot less flexible. For interaction, you could use JSONP calls.

  • "It’s now impossible but you’re on your own to implement it." - I hope you mean "not impossible", otherwise there hardly seems much point! :)

  • Question about the xml namespace inclusion- I've tried this a couple times, but the document won't validate with the W3C validator. I'm using xhtml transitional, so I would think this would be ok, but I don't understand why.

    I saw in the futures package, that the client-side templating engine uses similar syntax with the sys:stuff, so I'm sure this was a consideration for the team. Can you offer any insight as to the implications of adding the custom namespace and attributes?

  • the only problem is possible interferencing between script and css of the two pages.
    If only MS had developed the idea of viewlink element behaviors :(

  • @Town: thanks for the heads up. I fixed the post.

    @mhildreth: yes, the validity of namespaced attributes has been in a fuzzy state for a while but it's now clearer (from HTML 5 for example) that it's not valid and that the W3C folks are firmly opposed to it. They are pushing their HTML 5 data-* attributes as a replacement, which I think is wrong as they don't offer the kind of application-level re-basing of attributes that XML prefixes allow. It's a shame if you ask me, but that's the way it is. I still like it because I find it very clean.
    This being said, it's a very valid concern and it would be easy to change the syntax so that it uses the new HTML 5 data-* attributes, or even a JSON blob inside of the script tag. I can prototype that if you're interested but it should be easy enough to do.

    @OmariO: yes, that's true, and it can actually be an advantage in some cases. If you do need isolation, yes, you may want to consider an iframe instead. And if you need the isolation without the bounds of the iframe, you can try CSS isolation (http://weblogs.asp.net/bleroy/archive/2009/04/14/css-isolation-there-has-got-to-be-a-better-way.aspx) or a script sandbox (http://websandbox.livelabs.com).

  • Badgers, what badgers?

  • I agree that using the namespace prefixing is a cleaner solution. This is the third or fourth thing I've heard about HTML5 that sounds like a step backwards, but I'm interested to know more. Do you have any recommendations for information sources?

    Also, can you provide more information on the JSON blob approach? I'm not sure what you mean by that.

  • @mhildreth: I wouldn't say a step backwards because it was never valid in the first place, but failure to move forward certainly in this case. Information sources include the W3C mailing lists.

    Using a JSON blob, you'd do something like this instead:

    &lt; script type=&quot;text/javascript&quot; src=&quot;AspNetBootstrap.js&quot;&gt;

    &quot;Remote.aspx&quot;: {

    &nbsp;bar: 42,

    &nbsp;baz: &quot;glop &amp; co&quot;

    }

    &lt;/ script&gt;

  • Nice article. There are more advantages of using this over IFrames .

    Thanks,
    Thani

  • It's like the Load method in JQuery API.

  • @Leon: jquery.load won't work cross-domain, which is kind of the whole point.

  • Sorry, this may seems to be a post that was published long ago. However, currently I am working on a new project prototype that exactly require me to post my aspx file hosted on my server as a form of "Badges" to be embedded onto any website regardless of platform.

    However, I would need remote server interaction such as a form will be included into this badges and then embed onto other website. Therefore, when user interact with the badges, they are able to send information back to the remote server, in this case will be the server that host the aspx file.

    Any updated solution?

    It really hard to find a similar solution that is purely done in .NET. :(

  • @miltongoh: JSONP to a service on your server, and then client javascript to take the results of that and display them. The results can be JSON data or just bits of HTML to replace stuff in the badge.

Comments have been disabled for this content.