Smart homepage switching on HTTP accept-language headers

by Damiaan Peeters 1. December 2013 10:18

Http Headers

Every time time a browser requests a webpage from a web server, there are headers added to the the request.  Information like: Give me page X, I accept HTTP, you can Gzip or deflate data, proxy information, …

On of these http headers are the “Accept-Language” http headers.  So what does these headers mean?

Each language-range MAY be given an associated quality value which represents an estimate of the user's preference for the languages specified by that range.

If you open your browser hit F12, you can find for every request the headers back.  The accept language headers can look like this:

image

This means: I prefer Dutch, but will accept US English or any English dialect if available.  Every user can change the browser settings to reflect their language preference.

Sometimes – from a user design perspective, using the http headers to show understandable content to the user might be a good idea.  A lot of UX experts argue pro and/or contra.  We won’t go into the discussion because this is mainly a technical blog.  Let’s just try to implement it, because we can!  Glimlach

The solution

I’ll be using the IContentFinder for the solution. Never heard of the ContentFinderResolver?  Then read my previous blogpost or some official umbraco documentation.

I think that this is one of the cases where you can use IContentFinder to control what Umbraco serves to the rendering process.  We need to start with adding a new entry to the ContentFinderResolver.  This time we want it to be launched before the default umbraco implementation.  We can do this by using the following code:

ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNiceUrl, MyCustomHttpAcceptLanguageContentFinder>();

The rest of the idea is simple, for all root content nodes, search back the “Domain” object, and check whether the language matches.

try {
  string acceptLanguage = HttpContext.Current.Request.UserLanguages[0].Split('-')[0];
  string domainName = System.Web.HttpContext.Current.Request.Url.Host.ToLower();
  var rootDocs = UmbracoContext.Current.Application.Services.ContentService.GetRootContent();
  foreach (var rootDoc in rootDocs)
  {
    var domains = Domain.GetDomainsById(rootDoc.Id);

    var domainmatch = domains.FirstOrDefault(domain => domain.Language.CultureAlias.StartsWith(acceptLanguage));
    if (domainmatch != null)
    {
        contentRequest.PublishedContent = rootDoc;
        continue;
     }
  }
} catch {
  // search engines don't send language-accept headers
}

Attention, this is a very basic implementation and not ready for production at all! 

The SEO Warning

Like mentioned in the code: take care when implementing a solution using accept-language.  Googlebot is NOT sending any accept language headers along.  So be sure that you don’t get trapped in sending empty pages or (500) errors to the Search Engines.

With that I would like to ask, do you consider this as a valid use of IContentFinder?  What other Content Finders do you have in mind?  Have you already used the ContentFinderResolver?

Http POST to webserver using C#

by Damiaan Peeters 6. March 2008 11:38

I 've written some time ago a HTML scraper to search the VIES VAT number Validation web site of the European Union.  The service offered no web service at that time, so I needed to use the HTTP POST method.

The code is not too difficult.

[more]

    private readonly string Url = "http://ec.europa.eu/taxation_customs/vies/cgi-bin/viesquer";
private readonly string Referer = "http://ec.europa.eu/taxation_customs/vies/en/vieshome.htm";
List<Exception> Exceptions = null;
     ASCIIEncoding encoding = new ASCIIEncoding();
string postData = "Lang=EN";
postData += ("&VAT=" + VatNumber);
postData += ("&MS=" + CountryCode);
postData += ("&ISO=" + CountryCode);
byte[] data = encoding.GetBytes(postData);
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(this.Url);
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.Referer = Referer;
myRequest.ContentLength = data.Length;
myRequest.ProtocolVersion = HttpVersion.Version10;
myRequest.Method = "POST";
Stream newStream = myRequest.GetRequestStream();
// Send the data.
     newStream.Write(data, 0, data.Length);
newStream.Close();
HttpWebResponse resp = null;
try
     {
resp = (HttpWebResponse)myRequest.GetResponse();
}
catch (Exception ex)
{
Exceptions.Add(ex);
}
     StreamWriter myWriter = null;
try
     {
myWriter = new StreamWriter(resp.GetResponseStream());
myWriter.Write(data);
}
catch (Exception e)
{
Exceptions.Add(e);
return VatCheckOk.NotChecked;
}
finally
     {
myWriter.Close();
}
HttpWebResponse objResponse = (HttpWebResponse)myRequest.GetResponse();
using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
{
string result = sr.ReadToEnd();
// Close and clean up the StreamReader
         sr.Close();
}
If i remember well, i used the result string to check for the string: "Yes, Valid number".

Who.I.am

Certified Umbraco, .net and Azure developer, seo lover. Magician in my spare time.

Month List