views:

508

answers:

4

I have an issue with my browser failing to recognise the content types I am sending in my responses and trying to download the file instead of displaying it.

I have a generic handler (named SPARQL.ashx) written in ASP.Net which does some work and produces an object which is of two possible types. Either it gets a SPARQLResultSet or a Graph and it then sets the appropriate content type before using the appropriate Save method to send the content to the user. Code fragment is below:

  //Execute the Query
  Object result = store.ExecuteQuery(sparqlquery);

  if (result is SPARQLResultSet) 
  {
        //Return as SPARQL Results XML Format
        context.Response.ContentType = MIMETypesHelper.SPARQL[0];
        SPARQLResultSet resultset = (SPARQLResultSet)result;
        resultset.Save(new StreamWriter(context.Response.OutputStream));
  } 
  else if (result is Graph) 
  {
        //Return as Turtle
        context.Response.ContentType = MIMETypesHelper.Turtle[0];
        Graph g = (Graph)result;
        TurtleWriter ttlwriter = new TurtleWriter();
        ttlwriter.PrettyPrintMode = true;
        ttlwriter.Save(g, new StreamWriter(context.Response.OutputStream));
  }

My issue is that my browser will often prompt to download the results rather than displaying them despite the fact that one format is XML based and the other plain text based and so should both be displayable in any modern browser.

Behaviour varies from browser to browser and some will prompt for download regardless of result format and some will for one but not the other.

Am I likely to need to configure IIS somehow to ensure the correct MIME types are sent. For the record I have the official file extensions and MIME types registered in IIS. Or is this an issue with the fact that I'm using a Generic Handler? Or does anyone have any other ideas why this might be happening?

Edit

Added code from MIMETypesHelper class for clarity

/// <summary>
/// Helper Class containing arrays of MIME Types for the various RDF Concrete Syntaxes
/// </summary>
/// <remarks>The first type in each array is the canonical type that should be used</remarks>
public class MIMETypesHelper
{
  /// <summary>
  /// MIME Types for Turtle
  /// </summary>
  public static string[] Turtle = { "text/turtle", "application/x-turtle", "application/turtle" };

  /// <summary>
  /// MIME Types for RDF/XML
  /// </summary>
  public static string[] RDFXML = { "application/rdf+xml" };

  /// <summary>
  /// MIME Types for Notation 3
  /// </summary>
  public static string[] Notation3 = { "text/n3", "text/rdf+n3" };

  /// <summary>
  /// MIME Types for NTriples
  /// </summary>
  public static string[] NTriples = { "text/plain" };

  /// <summary>
  /// MIME Types for SPARQL Result Sets
  /// </summary>
  public static string[] SPARQL = { "application/sparql-results+xml" };

  ///etc.
}
+1  A: 

What's the Content-Dispostion header set to? It should be set to "inline". You might want to try setting it manually to see if the behavior changes.

tvanfosson
+2  A: 

From your code it looks like you are relying on the mimetypes in the rdf library (you don't say which one). When a browser such as firefox / IE (you don't say which you are using) sees a mime type application/SOMETHING it typically offers to save it rather than view it.

The mime type for RDF/XML is application/rdf+xml (I know, since I wrote the spec) and that will cause the save-as approach. The mime type for Turtle (which I created in Turtle note) is not registered but was suggested to be text/turtle which should display fine.

dajobe
The library is called dotNetRDF which is my own RDF implementation (still pre-alpha release) so I'm intimately familar with all the RDF specs yours included. The MIME Types Helper class has a set of arrays which contain recognised MIME Types for different RDF syntaxes, the first item in both the arrays (referenced in the code) is the most standard type for that syntax.Behaviour varies by browser and PC, FF on my dev machine displays SPARQL results but downloads Turtle while a home machine displays both. IE/Chrome/Safari all exhibit similar inconsistency in behaviour.
RobV
I'm not sure if there is a good answer to all of this but @tvanfosson has another useful suggestion - Content-Disposition http://www.ietf.org/rfc/rfc2183.txt which I seem to recall IE may use.
dajobe
A: 

In our family of RDF storage engines we attack this problem by doing content negotiation.

That is, we check the Accept line in the HTTP request headers, and adjust our behaviour accordingly. If the Accept line mentions any RDF flavours, or the SPARQL results MIME type explicitly, then we send back the appropriate Content-type and associated response. This serves dedicated SPARQL clients, hand-rolled code and various RDF "browser" tools very well in our experience.

But for a typical web browser the Accept line just lists HTML and a few image formats, and our HTTP daemon sets the Content-type to text/plain (or for a blank SPARQL query, text/html, with the response body being a web page with a form for writing manual queries from a web browser for testing)

Finally if the Accept header is missing altogether we know it's a very naive piece of software, most likely someone's Perl script or something, and we have a special case for that to make people's lives easier when developing against the storage engine.

tialaramex
some of my other stuff does this but this was simply a quite SPARQL endpoint I knocked up to test the SPARQL implementation so I haven't included any proper 303/conneg stuff in this code
RobV
A: 

Finally found the source of the issue, seems you have to call Clear() on the response and use Buffering or the Content Type header doesn't get sent as expected:

eg.

//Return as Turtle
context.Response.ContentType = MIMETypesHelper.Turtle[0];

//Clear any other output from this Response
//Then use buffering
context.Response.Clear();
context.Response.BufferOutput = true;

//Write the Output
Graph g = (Graph)result;
TurtleWriter ttlwriter = new TurtleWriter();
ttlwriter.PrettyPrintMode = true;
ttlwriter.Save(g, new StreamWriter(context.Response.OutputStream));
RobV