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 }