Posted on August 27, 2008 17:34 by baugustine
 

Interesting issue Shawn and I ran into today with the <script> tag in ASP .Net. A page was defined with <script> tag that was closed with a /> instead of </script> as shown below.

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript" />

 

And any time a control on the page did a post back it started throwing java script errors such as "Object Expected". Other variants could be "__doPostback not defined" but I did not see that error. Anyway the culprit was the /> closing tag. So to fix the error I had to end the <script> tag with </script> tag instead of />. So changing the above statement to

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript"><script>

 

fixed the error.

 

Incidentally this worked also.

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript" />

<script></script>

 

Go figure.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on March 23, 2008 10:53 by mcollins

Yesterday, in my flurry of posting activity all day long, we covered the Blogger API, the MetaWeblog API, and in a screencast I demonstrated how Microsoft Office Word 2007 would use the MetaWeblog API to communicate with the website and publish text and images to the website using operations from each of those APIs.

Today, we turn our attention to using Windows Live Writer and geting Windows Live Writer to work with our website.  While we could connect Windows Live Writer up to our website directly, just like we did with Word, there are some features supported by Windows Live Writer that make the content publishing experience much easier when the website supports it.

The first feature that we're going to implement to add support for Windows Live Writer is a protocol called Really Simple Discovery (RSD).  RSD is basically an XML document that is placed on your website (or in our case, will be generated by our website using an HTTP handler in ASP.NET).  The XML elements in the RSD document tell a client program such as Windows Live Writer where to locate the MetaWeblog publishing service.  The link to the RSD document is contained in the header of the home page for the blog or website that we're publishing to from Windows Live Writer.

At runtime, what will happen is that we'll start up Windows Live Writer and register a new blog or website with it.  Windows Live Writer will ask us for the URL to the home page for the blog or website, which we'll type in.  Windows Live Writer will download the contents of the home page and will look in the <head> section for an HTML element that will look similar to this:

   1: <html>
   2:     <head>
   3:         ...
   4:         <link rel="EditURI" type="application/rsd+xml"
   5:             title="RSD" href="http://localhost:9500/rsd.ashx"/>
   6:         ...
   7:     </head>
   8:     <body>
   9:         ...
  10:     </body>
  11: </html>

 

The <link> element in the HTML uses the rel attribute to identify the link for RSD.  Once a program such as Windows Live Writer finds this line, Windows Live Writer will be able to use the URL in the href attribute to locate the RSD document (or in our case, our HTTP handler).

While I could have created an XML file for RSD, I chose to go with creating an HTTP handler that will build the RSD document at runtime.  The reason why I chose to do this is that the URLs specified in the RSD document need to be absolute URLs for Windows Live Writer to locate the APIs correctly.  In my HTTP handler, I use the current request information to build the URL for the MetaWeblog API implementation.  Here's the code for the RSD HTTP handler:

   1: public class ReallySimpleDiscoveryHandler : IHttpHandler {
   2:     /// <summary>
   3:     /// Returns true to indicate that the HTTP handler can be reused for
   4:     /// multiple requests.
   5:     /// </summary>
   6:     public bool IsReusable {
   7:         get { return true; }
   8:     }
   9:  
  10:     /// <summary>
  11:     /// Handles the request and serves the RSD document to the client.
  12:     /// </summary>
  13:     /// <param name="context">
  14:     /// The <see cref="HttpContext"/> used to handle the current
  15:     /// request.
  16:     /// </param>
  17:     public void ProcessRequest(HttpContext context) {
  18:         string rootUrl = String.Format("{0}://{1}:{2}/",
  19:             context.Request.Url.Scheme, context.Request.Url.Host,
  20:             context.Request.Url.Port);
  21:  
  22:         XNamespace ns = "http://archipelago.phrasewise.com/rsd";
  23:         XDocument rsdDocument = new XDocument(new XElement(ns + "rsd",
  24:             new XAttribute("version", "1.0"),
  25:             new XElement(ns + "service", "Content Publishing 101"),
  26:             new XElement(ns + "engineLine", 
  27:                 "http://www.sogeti-phoenix.com"),
  28:             new XElement(ns + "homePageLink", rootUrl),
  29:             new XElement(ns + "apis",
  30:                 new XElement(ns + "api",
  31:                     new XAttribute("name", "MetaWeblog"),
  32:                     new XAttribute("preferred", "true"),
  33:                     new XAttribute("apiLink", rootUrl +
  34:                         "ContentPublishingService.ashx"),
  35:                     new XAttribute("blogID", "michael")),
  36:                 new XElement(ns + "api",
  37:                     new XAttribute("name", "Blogger"),
  38:                     new XAttribute("preferred", "false"),
  39:                     new XAttribute("apiLink", rootUrl +
  40:                         "ContentPublishingService.ashx"),
  41:                     new XAttribute("blogID", "michael")))));
  42:  
  43:         context.Response.Write(rsdDocument.ToString());
  44:     }
  45: }

 

I'm using the new LINQ XML support introduced in .NET 3.5 to build the RSD XML document.  The RSD that I am generating tells an RSD client that we support both the MetaWeblog API and the Blogger API, but the MetaWeblog API is preferred over the Blogger API.  The XML that this handler outputs looks like this:

   1: <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
   2:   <service>Content Publishing 101</service>
   3:   <engineLine>http://www.sogeti-phoenix.com</engineLine>
   4:   <homePageLink>http://localhost:9500/</homePageLink>
   5:   <apis>
   6:     <api name="MetaWeblog" preferred="true" 
   7:         apiLink="http://localhost:9500/ContentPublishingService.ashx" 
   8:         blogID="michael" />
   9:     <api name="Blogger" preferred="false" 
  10:         apiLink="http://localhost:9500/ContentPublishingService.ashx" 
  11:         blogID="michael" />
  12:   </apis>
  13: </rsd>

 

One thing to note is that I thought that I read someplace that the blogID attribute in the RSD output isn't used, however when I tried this out I discovered that Windows Live Writer does use it to get the blogid value that it will use with the Blogger and MetaWeblog APIs.  This has important ramifications for using Windows Live Writer for your blog or website.

The main issue that will affect your website is if you were to build some sort of multi-blogger experience, or build a website with several subsites, each with their own sets of categories.  The way that Windows Live Writer requires and uses the blogID attribute means that you can't have one global RSD file that works for the entire site.  Each blog or subsite on your website will need to have its own RSD file.

Now that we have told Windows Live Writer how to find our content publishing service using RSD, it's not time that we help Windows Live Writer out by telling it what features that we support.  Windows Live Writer is actually a fully developed editing environment with a lot of features for creating new content to be published up to a website.  However, Windows Live Writer also knows that it can't be everything to everyone.  There are some features that Windows Live Writer does support that some blog engines and content management systems don't support.  So we have to help out Windows Live Writer from our website to tell WLW what features we do support.  We also want to go a step beyond that and help customize Windows Live Writer to give our content authors a few customizations to help them do their jobs of publishing content.  We can do all of this by providing Windows Live Writer with an XML manifest file that tells Windows Live Writer about our blog or website.

During the blog/website registration process with Windows Live Writer, Windows Live Writer will download our RSD file to find the location of the MetaWeblog API.  Windows Live Writer, like Microsoft Office Word 2007, will then make some calls to our website to make sure that the blog exists and to get the list of categories for the website.  Somewhere during the registration process, Windows Live Writer will look at our home page to also find a link to the manifest file for Windows Live Writer.  We will add this link right next to the RSD link in the header section of our home page:

   1: <html xmlns="http://www.w3.org/1999/xhtml">
   2: <head runat="server">
   3:     <title>Untitled Page</title>
   4:     <link rel="EditURI" type="application/rsd+xml" title="RSD"
   5:         href="http://localhost:9500/rsd.ashx" />
   6:     <link rel="wlwmanifest" type="application/wlwmanifest+xml"
   7:         href="http://localhost:9500/wlwmanifest.ashx" />
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <div>
  12:     
  13:     </div>
  14:     </form>
  15: </body>
  16: </html>

 

On line 6 is the link to our manifest file for Windows Live Writer.  I've chosen once again to implement this as an HTTP handler because at some point in the future I may choose to allow the website administrator to selectively configure which options the website should support.  For example, the website administrator may not want posts that have embedded JavaScript code in them, or <embed> elements.

Before I show you the source code for the HTTP handler and the resulting XML generated by it, you might want to pause and take a look at the manifest file specification for Windows Live Writer.  Here's the source code for my manifest file generator:

   1: public void ProcessRequest(HttpContext context) {
   2:     XNamespace ns = "http://schemas.microsoft.com/wlw/manifest/weblog";
   3:     XDocument xmlDocument = new XDocument(new XElement(ns + "manifest",
   4:         new XElement(ns + "options",
   5:             new XElement(ns + "clientType", "Metaweblog"),
   6:             new XElement(ns + "supportsScripts", "Yes"),
   7:             new XElement(ns + "supportsEmbeds", "Yes")),
   8:         new XElement(ns + "weblog",
   9:             new XElement(ns + "serviceName", "Michael's Blog"),
  10:             new XElement(ns + "homepageLinkText",
  11:                 "View Michael's Blog"),
  12:             new XElement(ns + "adminLinkText",
  13:                 "Manage Michael's Blog"),
  14:             new XElement(ns + "adminUrl",
  15:                 new XCData("http://localhost:9500/Admin")),
  16:             new XElement(ns + "postEditingUrl", new XCData(
  17:                 "http://localhost:9500/EditPost.aspx?postId={post-id}"))),
  18:         new XElement(ns + "views",
  19:             new XElement(ns + "default", "WebLayout"),
  20:             new XElement(ns + "view",
  21:                 new XAttribute("type", "WebLayout"),
  22:                 new XAttribute("src",
  23:                     "http://localhost:9500/WebLayout.aspx")),
  24:             new XElement(ns + "view",
  25:                 new XAttribute("type", "WebPreview"),
  26:                 new XAttribute("src",
  27:                     "http://localhost:9500/WebPreview.aspx")))));
  28:  
  29:     context.Response.Write(xmlDocument.ToString());
  30: }

 

Again, I used the new LINQ XML support to generate the XML for the Windows Live Writer manifest.  Here's what the generated XML looks like:

   1: <manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
   2:   <options>
   3:     <clientType>Metaweblog</clientType>
   4:     <supportsScripts>Yes</supportsScripts>
   5:     <supportsEmbeds>Yes</supportsEmbeds>
   6:   </options>
   7:   <weblog>
   8:     <serviceName>Michael's Blog</serviceName>
   9:     <homepageLinkText>View Michael's Blog</homepageLinkText>
  10:     <adminLinkText>Manage Michael's Blog</adminLinkText>
  11:     <adminUrl><![CDATA[http://localhost:9500/Admin]]></adminUrl>
  12:     <postEditingUrl><![CDATA[
  13:         http://localhost:9500/EditPost.aspx?postId={post-id}
  14:     ]]></postEditingUrl>
  15:   </weblog>
  16:   <views>
  17:     <default>WebLayout</default>
  18:     <view type="WebLayout" 
  19:         src="http://localhost:9500/WebLayout.aspx" />
  20:     <view type="WebPreview" 
  21:         src="http://localhost:9500/WebPreview.aspx" />
  22:   </views>
  23: </manifest>

 

There are several important things to note from this manifest file, mostly on lines 3, 4, and 5.  First, on line 3, I am saying that my blog or website supports the MetaWeblog API, which I implemented in the earlier posts.  You might want to look again at the manifest specification to see what specific features that I am saying that I am supporting for Windows Live Writer.  On lines 4 and 5, I am extending this feature set to say that I'm going to allow new posts to have embedded JavaScript and embedded objects such as Silverlight or YouTube videos, or SlideShare presentations.

Lines 18 and 20 of the listing above also show that I have defined two preview views for Windows Live Writer to use.  Windows Live Writer provides a true WYSIWYG experience for blog publishing in that WLW tries to allow you to write your blog post in the same format that your blog is rendered in.  For example, I am at the moment writing my blog post in Windows Live Writer, and Windows Live Writer has rendered the editor with the same column limitations, fonts, etc., that the Sogeti-Phoenix.com blog has.  So while I am editing my blog post, I get to actually see what it's going to look like when published to and rendered on my blog.  We'll cover these templates more in a later post, but I just thought that I'd mention them.

At this point, we have everything that we need for Windows Live Writer to connect to our website, autodetect the publishing service, and determine what features to provide to authors who will be writing content for the website.

I hope that the next post on this subject will be another screencast where we'll take a look at our new website publishing interfaces from the perspective of Windows Live Writer instead of Microsoft Office Word 2007.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on March 23, 2008 00:40 by mcollins

I created a screencast showing Microsoft Office Word 2007 talking to my implementation of the MetaWeblog API.  The video is 23 minutes in length, but because Silverlight Streaming Services has a 10 minute video limit, I had to break the video up into three parts.

Word to MetaWeblog API Part 1_Thumb

Check them out:



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted on March 22, 2008 13:01 by mcollins

I'm a product developer, even though I'm a consultant.  I try to approach all of my projects from that perspective, even though I may not be with them for years, I try to think about how they'll be maintained, enhanced, and deployed when I'm no longer with a project.  One of the hardest things to consider when developing software that will later be deployed is how to plan for the security settings in the deployment environment.

Each deployment environment is different and provides its own challenges.  I've been in environments where users all have administrative rights for their machines.  I've been at a client site before where users were not allowed to write to their Windows registry, even their user settings, and all Internet access went through a proxy server that was locked down.  These are the things that you have to consider when planning for deploying software into production environments.

When I start building a new software application from scratch, I usually begin by working with the security settings.  Typically, my approach is that I plan for the minimal security settings that I need, so I will start off by creating my own security sandbox.  If I'm developing a desktop application, I'll go into the .NET security policy settings and create a code access security policy that gives me no security rights, except for executing.  Then, as I build more and more features, I'll selectively turn on those security settings that I need for the new feature to work.  I'll also make the decision at that time as to what's necessary functionality and what's optional functionality, so I can implement degrading functionality as necessary to still get my application to run in stricter application environments.

One application type that I honestly haven't been using a sandboxed approach for are ASP.NET websites and web applications.  I've been lucky so far, in that all of the environments that I've developed web applications for have let me run in full trust, but I understand that may not be desirable or necessary in all cases.  I know of quite a few hosters out there that require websites run in medium trust.  My hoster doesn't, but I understand why some do.  I also see this as a problem that pops up sometimes when people try to use pre-packed web applications such as Community Server and BlogEngine.NET in a medium trust environment.  Reflecting on this, I realize that if I build a website in full trust mode, I have no idea how it's going to perform in a medium trust environment, or if I'm doing all that I need to do to make sure that my assemblies will run in a restricte