Skip to content

Commit

Permalink
Improved error handling for webservice requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
wo80 committed Jan 27, 2015
1 parent be176f7 commit 4e3e8b3
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 67 deletions.
2 changes: 2 additions & 0 deletions AcoustID/AcoustID.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@
<Compile Include="Util\Helper.cs" />
<Compile Include="Web\Artist.cs" />
<Compile Include="Web\IResponseParser.cs" />
<Compile Include="Web\LookupResponse.cs" />
<Compile Include="Web\LookupResult.cs" />
<Compile Include="Web\LookupService.cs" />
<Compile Include="Web\Recording.cs" />
<Compile Include="Web\ReleaseGroup.cs" />
<Compile Include="Web\SubmitResponse.cs" />
<Compile Include="Web\SubmitResult.cs" />
<Compile Include="Web\SubmitService.cs" />
<Compile Include="Web\XmlResponseParser.cs" />
Expand Down
14 changes: 8 additions & 6 deletions AcoustID/Web/IResponseParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ public interface IResponseParser
string Format { get; }

/// <summary>
/// Gets an error message (will be null for successful requests).
/// Indicates if the parser can read the given text format.
/// </summary>
string Error { get; }
/// <param name="text">The webservice response.</param>
/// <returns>Returns true, if the parser can parse the given content.</returns>
bool CanParse(string text);

/// <summary>
/// Parse the content of a lookup response.
/// </summary>
/// <param name="response">The webservice response.</param>
/// <param name="text">The webservice response.</param>
/// <returns>A list of <see cref="LookupResult"/>.</returns>
List<LookupResult> ParseLookupResponse(string response);
LookupResponse ParseLookupResponse(string text);

/// <summary>
/// Parse the content of a submit response.
/// </summary>
/// <param name="response">The webservice response.</param>
/// <param name="text">The webservice response.</param>
/// <returns>A list of <see cref="SubmitResult"/>.</returns>
List<SubmitResult> ParseSubmitResponse(string response);
SubmitResponse ParseSubmitResponse(string text);
}
}
45 changes: 45 additions & 0 deletions AcoustID/Web/LookupResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// -----------------------------------------------------------------------
// <copyright file="LookupResponse.cs" company="">
// Christian Woltering, https://github.com/wo80
// </copyright>
// -----------------------------------------------------------------------

namespace AcoustID.Web
{
using System.Collections.Generic;
using System.Net;

/// <summary>
/// The webservice response containing the status code and a list of lookup results.
/// </summary>
public class LookupResponse
{
public LookupResponse()
: this(HttpStatusCode.OK, null)
{
}

public LookupResponse(HttpStatusCode status, string error)
{
this.StatusCode = status;
this.ErrorMessage = error;

Results = new List<LookupResult>();
}

/// <summary>
/// Gets the status code returned by the webservice.
/// </summary>
public HttpStatusCode StatusCode { get; internal set; }

/// <summary>
/// Gets the error message, in case the status code is not "200 OK".
/// </summary>
public string ErrorMessage { get; internal set; }

/// <summary>
/// Gets a list of <see cref="LookupResult"/>s.
/// </summary>
public List<LookupResult> Results { get; private set; }
}
}
73 changes: 42 additions & 31 deletions AcoustID/Web/LookupService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
namespace AcoustID.Web
{
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
Expand Down Expand Up @@ -41,21 +39,13 @@ public LookupService(IResponseParser parser)
/// </summary>
public bool UseCompression { get; set; }

/// <summary>
/// Gets the last error message (check this if parse methods return empty lists).
/// </summary>
public string Error
{
get { return parser.Error; }
}

/// <summary>
/// Calls the webservice on a worker thread.
/// </summary>
/// <param name="fingerprint">The audio fingerprint.</param>
/// <param name="duration">The total duration of the audio.</param>
/// <returns>A task which, on success, returns a list of lookup results.</returns>
public Task<List<LookupResult>> GetAsync(string fingerprint, int duration)
/// <returns>A task which returns a <see cref="LookupResponse"/>.</returns>
public Task<LookupResponse> GetAsync(string fingerprint, int duration)
{
return GetAsync(fingerprint, duration, null);
}
Expand All @@ -66,19 +56,12 @@ public Task<List<LookupResult>> GetAsync(string fingerprint, int duration)
/// <param name="fingerprint">The audio fingerprint.</param>
/// <param name="duration">The total duration of the audio.</param>
/// <param name="meta">Request meta information.</param>
/// <returns>A task which, on success, returns a list of lookup results.</returns>
public Task<List<LookupResult>> GetAsync(string fingerprint, int duration, string[] meta)
/// <returns>A task which returns a <see cref="LookupResponse"/>.</returns>
public Task<LookupResponse> GetAsync(string fingerprint, int duration, string[] meta)
{
return Task.Factory.StartNew<List<LookupResult>>(() =>
return Task.Factory.StartNew<LookupResponse>(() =>
{
try
{
return Get(fingerprint, duration, meta);
}
catch (Exception)
{
throw;
}
return Get(fingerprint, duration, meta);
});
}

Expand All @@ -87,8 +70,8 @@ public Task<List<LookupResult>> GetAsync(string fingerprint, int duration, strin
/// </summary>
/// <param name="fingerprint">The audio fingerprint.</param>
/// <param name="duration">The total duration of the audio.</param>
/// <returns>List of lookup results.</returns>
public List<LookupResult> Get(string fingerprint, int duration)
/// <returns>A <see cref="LookupResponse"/>.</returns>
public LookupResponse Get(string fingerprint, int duration)
{
return Get(fingerprint, duration, null);
}
Expand All @@ -99,21 +82,48 @@ public List<LookupResult> Get(string fingerprint, int duration)
/// <param name="fingerprint">The audio fingerprint.</param>
/// <param name="duration">The total duration of the audio.</param>
/// <param name="meta">Request meta information.</param>
/// <returns>List of lookup results.</returns>
public List<LookupResult> Get(string fingerprint, int duration, string[] meta)
/// <returns>A <see cref="LookupResponse"/>.</returns>
public LookupResponse Get(string fingerprint, int duration, string[] meta)
{
try
{
string request = BuildRequestString(fingerprint, duration, meta);

// If the request contains invalid parameters, the server will return "400 Bad Request" and
// we'll end up in the first catch block.
string response = RequestService(request);

// TODO: server might return an error message as json.
// Should probably add a json parser anyway ...
return parser.ParseLookupResponse(response);
}
catch (Exception)
catch (WebException e)
{
throw;
// Handle bad requests gracefully.
return CreateErrorResponse(e.Response as HttpWebResponse);
}
catch (Exception e)
{
throw e;
}
}

private LookupResponse CreateErrorResponse(HttpWebResponse response)
{
if (response == null)
{
return new LookupResponse(HttpStatusCode.BadRequest, "Unknown error.");
}

using (var reader = new StreamReader(response.GetResponseStream()))
{
var text = reader.ReadToEnd();

if (parser.CanParse(text))
{
return parser.ParseLookupResponse(text);
}

// TODO: parse error message (JSON).
return new LookupResponse(response.StatusCode, text);
}
}

Expand Down Expand Up @@ -175,6 +185,7 @@ private string RequestService(string request)
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

data = client.UploadData(URL, data);

return encoding.GetString(data);
}
}
Expand Down
12 changes: 12 additions & 0 deletions AcoustID/Web/SubmitResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// -----------------------------------------------------------------------
// <copyright file="SubmitResponse.cs" company="">
// Christian Woltering, https://github.com/wo80
// </copyright>
// -----------------------------------------------------------------------

namespace AcoustID.Web
{
public class SubmitResponse
{
}
}
43 changes: 21 additions & 22 deletions AcoustID/Web/XmlResponseParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
namespace AcoustID.Web
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Xml.Linq;

/// <summary>
Expand All @@ -19,50 +19,49 @@ public class XmlResponseParser : IResponseParser
private static NumberFormatInfo numberFormat = CultureInfo.InvariantCulture.NumberFormat;
private static string format = "xml";

/// <inheritdoc />
public string Format
{
get { return format; }
}

/// <inheritdoc />
public bool CanParse(string text)
{
return !string.IsNullOrEmpty(text) && text.StartsWith("<?xml");
}

/// <summary>
/// Gets the last error message.
/// </summary>
public string Error { get; private set; }

/// <summary>
/// Parse the response of a lookup request.
/// </summary>
/// <param name="response">The response string.</param>
/// <returns>List of lookup results.</returns>
public List<LookupResult> ParseLookupResponse(string response)
/// <inheritdoc />
public LookupResponse ParseLookupResponse(string text)
{
try
{
this.Error = string.Empty;

var root = XDocument.Parse(response).Element("response");
var root = XDocument.Parse(text).Element("response");

var status = root.Element("status");

List<LookupResult> results = new List<LookupResult>();

if (status.Value == "ok")
{
var response = new LookupResponse();

var list = root.Element("results").Descendants("result");

foreach (var item in list)
{
results.Add(ParseLookupResult(item));
response.Results.Add(ParseLookupResult(item));
}

return response;
}
else if (status.Value == "error")

if (status.Value == "error")
{
var error = root.Element("error");

this.Error = error.Element("message").Value;
return new LookupResponse(HttpStatusCode.BadRequest, error.Element("message").Value);
}

return results;
return null;
}
catch (Exception e)
{
Expand All @@ -75,7 +74,7 @@ public List<LookupResult> ParseLookupResponse(string response)
/// </summary>
/// <param name="response">The response string.</param>
/// <returns>List of submit results.</returns>
public List<SubmitResult> ParseSubmitResponse(string response)
public SubmitResponse ParseSubmitResponse(string response)
{
// TODO: implement submit response parsing
throw new NotImplementedException();
Expand Down
17 changes: 9 additions & 8 deletions Fingerprinter/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,20 +203,21 @@ private void Lookup(string fingerprint, int duration)
{
btnOpen.Enabled = true;

var results = t.Result;
var response = t.Result;

if (results.Count == 0)
if (!string.IsNullOrEmpty(response.ErrorMessage))
{
if (String.IsNullOrEmpty(service.Error))
{
MessageBox.Show("No results for given fingerprint.");
}
else MessageBox.Show(service.Error, "Webservice error");
MessageBox.Show(response.ErrorMessage, "Webservice error");
return;
}

if (response.Results.Count == 0)
{
MessageBox.Show("No results for given fingerprint.");
return;
}

foreach (var result in results)
foreach (var result in response.Results)
{
var item = new ListViewItem(new string[]
{
Expand Down

0 comments on commit 4e3e8b3

Please sign in to comment.