Download cyotek.web.trackback.zip, last updated 22/09/2010 (6.50 KB)

Download
  • md5: 1e2d47df8c24030e01a8c1c979e60e41
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
using HtmlAgilityPack;

namespace Cyotek.Web.Trackback
{
  /// <summary>
  /// A helper class for implementing trackback requests in an ASP.NET application.
  /// </summary>
  public static class TrackbackHandler
  {
    #region  Public Class Methods

    /// <summary>
    /// Gets the trackback XML for the given request.
    /// </summary>
    /// <param name="form">The data used to build the request.</param>
    /// <param name="saveTrackbackDelegate">A delegate for saving trackbacks into an application specific format.</param>
    /// <param name="getTrackbackUrlDelegate">A delegate for returning a fully qualified URI from a given ID.</param>
    /// <returns>A string containing formatted XML describing the result of the trackback.</returns>
    /// <remarks>HttpRequest.Params or a MVC FormCollection can be used for the form parameter.</remarks>
    public static string GetTrackback(NameValueCollection form, SaveTrackbackDelegate saveTrackbackDelegate, GetTrackbackUrlDelegate getTrackbackUrlDelegate)
    {
      string url;

      if (form == null)
        throw new ArgumentNullException("form");

      if (saveTrackbackDelegate == null)
        throw new ArgumentNullException("saveTrackbackDelegate");

      if (getTrackbackUrlDelegate == null)
        throw new ArgumentNullException("getTrackbackUrlDelegate");

      url = form["url"];
      if (!string.IsNullOrEmpty(url) && url.Contains(","))
        url = url.Split(',')[0];

      return TrackbackHandler.GetTrackback(saveTrackbackDelegate, getTrackbackUrlDelegate, form["id"], url, form["title"], form["excerpt"], form["blog_name"]);
    }

    #endregion  Public Class Methods

    #region  Private Class Methods

    /// <summary>
    /// Checks to see if the given source URI can be found in a destination URI.
    /// </summary>
    /// <param name="lookingFor">The URI to be matched.</param>
    /// <param name="lookingIn">The URI to be searched.</param>
    /// <param name="pageTitle">The title of the searched URI.</param>
    /// <returns><c>true</c> if lookinFor was found at the searched URI; otherwise <c>false</c>.</returns>
    private static bool CheckSourceLinkExists(Uri lookingFor, Uri lookingIn, out string pageTitle)
    {
      bool result;

      pageTitle = null;

      try
      {
        string html;

        html = GetPageHtml(lookingIn);

        if (string.IsNullOrEmpty(html.Trim()) | html.IndexOf(lookingFor.ToString(), StringComparison.InvariantCultureIgnoreCase) < 0)
          result = false;
        else
        {
          HtmlDocument document;

          document = new HtmlDocument();
          document.LoadHtml(html);
          pageTitle = document.GetDocumentTitle();

          result = true;
        }
      }
      catch
      {
        result = false;
      }
      return result;
    }

    /// <summary>
    /// Gets the title of a HTML document.
    /// </summary>
    /// <param name="document">The document.</param>
    /// <returns>The title of the document if available, otherwise an empty string.</returns>
    private static string GetDocumentTitle(this HtmlDocument document)
    {
      HtmlNode titleNode;
      string title;

      titleNode = document.DocumentNode.SelectSingleNode("//head/title");
      if (titleNode != null)
        title = titleNode.InnerText;
      else
        title = string.Empty;

      title = title.Replace("\n", "");
      title = title.Replace("\r", "");
      while (title.Contains("  "))
        title = title.Replace("  ", " ");

      return title.Trim();
    }

    /// <summary>
    /// Gets the HTML at the destination URL.
    /// </summary>
    /// <param name="uri">The URI to download.</param>
    /// <returns>The content downloaded from the given URI</returns>
    private static string GetPageHtml(Uri uri)
    {
      WebRequest request;
      HttpWebResponse response;
      string encodingName;
      Encoding encoding;
      string result;

      request = WebRequest.Create(uri);
      response = (HttpWebResponse)request.GetResponse();

      encodingName = response.ContentEncoding.Trim();
      if (string.IsNullOrEmpty(encodingName))
        encodingName = "utf-8";
      encoding = Encoding.GetEncoding(encodingName);

      using (Stream stream = response.GetResponseStream())
      {
        using (StreamReader reader = new StreamReader(stream, encoding))
          result = reader.ReadToEnd();
      }

      return result;
    }

    /// <summary>
    /// Gets the trackback XML for the given request.
    /// </summary>
    /// <param name="saveTrackbackDelegate">A delegate for saving trackbacks into an application specific format.</param>
    /// <param name="getTrackbackUrlDelegate">A delegate for returning a fully qualified URI from a given ID.</param>
    /// <param name="id">The ID of the item being tracked.</param>
    /// <param name="url">The URL of the page making the request.</param>
    /// <param name="title">The title of the page making the request.</param>
    /// <param name="excerpt">An excerpt from the page making the request.</param>
    /// <param name="blogName">Name of the blog or site making the request.</param>
    /// <returns>A string containing formatted XML describing the result of the trackback.</returns>
    private static string GetTrackback(SaveTrackbackDelegate saveTrackbackDelegate, GetTrackbackUrlDelegate getTrackbackUrlDelegate, string id, string url, string title, string excerpt, string blogName)
    {
      string result;
      try
      {
        HttpRequest request;

        request = HttpContext.Current.Request;

        if (string.IsNullOrEmpty(id))
          result = GetTrackbackResponse(TrackbackErrorCode.Error, "The entry ID is missing");
        else if (request.HttpMethod != "POST")
          result = GetTrackbackResponse(TrackbackErrorCode.Error, "An invalid request was made.");
        else if (string.IsNullOrEmpty(url))
          result = TrackbackHandler.GetTrackbackResponse(TrackbackErrorCode.Error, "Trackback URI not specified.");
        else
        {
          TrackbackInfo trackbackInfo;
          string trackbackTitle;
          Uri targetUri;

          trackbackInfo = new TrackbackInfo()
          {
            Id = id,
            Title = title,
            BlogName = blogName,
            Excerpt = excerpt,
            Uri = new Uri(url)
          };

          targetUri = getTrackbackUrlDelegate.Invoke(trackbackInfo);

          if (targetUri == null)
            result = GetTrackbackResponse(TrackbackErrorCode.Error, "The entry ID could not be matched.");
          else if (!TrackbackHandler.CheckSourceLinkExists(targetUri, trackbackInfo.Uri, out trackbackTitle))
            result = GetTrackbackResponse(TrackbackErrorCode.Error, string.Format("Sorry couldn't find a link for \"{0}\" in \"{1}\"", targetUri.ToString(), trackbackInfo.Uri.ToString()));
          else
          {
            if (string.IsNullOrEmpty(blogName))
              trackbackInfo.BlogName = trackbackTitle;

            saveTrackbackDelegate.Invoke(trackbackInfo);

            result = TrackbackHandler.GetTrackbackResponse(TrackbackErrorCode.Success, string.Empty);
          }
        }
      }
      catch (Exception ex)
      {
        //handle the error.
        result = TrackbackHandler.GetTrackbackResponse(TrackbackErrorCode.Error, ex.Message);
      }

      return result;
    }

    /// <summary>
    /// Gets the response XML for a trackback request.
    /// </summary>
    /// <param name="errorCode">The error code.</param>
    /// <param name="errorText">The error text.</param>
    /// <returns>A string containing formatted XML describing the result of the trackback.</returns>
    private static string GetTrackbackResponse(TrackbackErrorCode errorCode, string errorText)
    {
      StringBuilder builder;

      builder = new StringBuilder();

      using (StringWriter writer = new StringWriter(builder))
      {
        XmlWriterSettings settings;
        XmlWriter xmlWriter;

        settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.Encoding = Encoding.UTF8;

        xmlWriter = XmlWriter.Create(writer, settings);

        xmlWriter.WriteStartDocument(true);
        xmlWriter.WriteStartElement("response");
        xmlWriter.WriteElementString("response", ((int)errorCode).ToString());
        if (!string.IsNullOrEmpty(errorText))
          xmlWriter.WriteElementString("message", errorText);
        xmlWriter.WriteEndElement();
        xmlWriter.WriteEndDocument();
        xmlWriter.Close();
      }

      return builder.ToString();
    }

    #endregion  Private Class Methods
  }
}

Donate

Donate