using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Soap;
using System.Web;
using System.Web.Caching;
using System.Web.Services;
using System.Web.Services.Protocols;
///
/// Track Wahoo scores
///
[WebService(Namespace = "http://www.sellsbrothers.com/WahooScoresService/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ScoresService : System.Web.Services.WebService {
// Only keep the big ones
const byte _maxScores = 10;
static ScoresService() {
// Load cached high scores
LoadScores();
}
///
/// Store a new high score
///
[WebMethod]
public void RegisterScore(string name, int score) {
HttpContext context = HttpContext.Current;
Cache cache = context.Cache;
try {
// Synchronize access to the scores
context.Application.Lock();
WahooScore[] scores = GetScores();
// Check to see if score makes the cut
if( scores[_maxScores - 1].Score >= score ) {
//throw new ApplicationException("Sorry, but your score is too low to make the top " + _maxScores);
throw new DiscreteSoapException("Sorry, " + name + ", but your score of " + score + " is too low to make the top " + _maxScores);
}
// Add score by bumping off the bottom guy
scores[_maxScores - 1] = new WahooScore(name, score);
// Sort list
Array.Sort(scores, new WahooScoreComparer());
// Save high scores now in case bad stuff happens later
SaveScores(scores);
// Cache the scores
cache["scores"] = scores;
}
finally {
context.Application.UnLock();
}
}
///
/// Return scores sorted highest to lowest
///
[WebMethod]
public WahooScore[] GetScores() {
Cache cache = HttpContext.Current.Cache;
WahooScore[] scores;
try {
HttpContext.Current.Application.Lock();
scores = (WahooScore[])cache["scores"];
if( scores == null ) {
cache["scores"] = scores = LoadScores();
}
}
finally {
HttpContext.Current.Application.UnLock();
}
return scores;
}
#region Wahoo score storage
// Score storage
// NOTE: This implementation requires a user with permissions to read/write files, e.g.
// machine.config:
// ...
static private string ScoresFileName {
get {
return HttpContext.Current.Request.PhysicalApplicationPath + @"App_Data\WahooScores.txt";
}
}
static private WahooScore[] LoadScores() {
WahooScore[] scores = new WahooScore[_maxScores];
try {
using( FileStream file = new FileStream(ScoresFileName, FileMode.Open) ) {
IFormatter formatter = new SoapFormatter();
scores = (WahooScore[])formatter.Deserialize(file);
}
}
catch {
for( int i = 0; i != _maxScores; ++i ) {
scores[i] = new WahooScore("nobody", 0);
}
}
return scores;
}
private void SaveScores(WahooScore[] scores) {
using( FileStream file = new FileStream(ScoresFileName, FileMode.Create) ) {
IFormatter formatter = new SoapFormatter();
formatter.Serialize(file, scores);
}
}
#endregion
}