Skip to content

Commit

Permalink
Merge pull request #36 from jpsingleton/refactor
Browse files Browse the repository at this point in the history
DI Refactor
  • Loading branch information
jpsingleton committed May 18, 2015
2 parents bf79931 + cc64c7e commit 9686f68
Show file tree
Hide file tree
Showing 41 changed files with 488 additions and 167 deletions.
50 changes: 50 additions & 0 deletions src/Huxley/App_Start/NinjectWebCommon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Huxley.ldbServiceReference;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Huxley.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Huxley.App_Start.NinjectWebCommon), "Stop")]

namespace Huxley.App_Start {
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;

public static class NinjectWebCommon {
private static readonly Bootstrapper Bootstrapper = new Bootstrapper();

/// <summary>
/// Starts the application
/// </summary>
public static void Start() {
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Bootstrapper.Initialize(CreateKernel);
}

/// <summary>
/// Stops the application.
/// </summary>
public static void Stop() {
Bootstrapper.ShutDown();
}

/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel() {
var kernel = new StandardKernel();
try {
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<ILdbClient>().To<LdbClient>().InRequestScope();
kernel.Bind<LDBServiceSoapClient>().To<LDBServiceSoapClient>().InRequestScope();
return kernel;
} catch {
kernel.Dispose();
throw;
}
}
}
}
3 changes: 3 additions & 0 deletions src/Huxley/Controllers/CrsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public IEnumerable<CrsRecord> Get() {

// GET /crs/{query}
public IEnumerable<CrsRecord> Get(string query) {
if (query.Equals("London Terminals", StringComparison.InvariantCultureIgnoreCase)) {
return HuxleyApi.LondonTerminals;
}
// Could use a RegEx here but putting user input into a RegEx can be dangerous
var results = HuxleyApi.CrsCodes.Where(c => c.StationName.IndexOf(query, StringComparison.InvariantCultureIgnoreCase) >= 0);
return results;
Expand Down
176 changes: 70 additions & 106 deletions src/Huxley/Controllers/DelaysController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ You should have received a copy of the GNU Affero General Public License
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Web.Http;
using Huxley.Models;
using Huxley.ldbServiceReference;

namespace Huxley.Controllers {
public class DelaysController : BaseController {
public class DelaysController : LdbController {

public DelaysController(ILdbClient client)
: base(client) {
}

// GET /delays/{crs}/{filtertype}/{filtercrs}/{numrows}/{stds}?accessToken=[your token]
public async Task<DelaysResponse> Get([FromUri] StationBoardRequest request) {

Expand Down Expand Up @@ -61,121 +65,81 @@ public async Task<DelaysResponse> Get([FromUri] StationBoardRequest request) {
}
}

// https://en.wikipedia.org/wiki/London_station_group
// Farringdon [ZFD] is not a London Terminal but it probably should be (maybe when Crossrail opens it will be)
var londonTerminals = new List<string> {
"BFR", // Blackfriars
"CST", // Cannon Street
"CHX", // Charing Cross
"CTX", // City Thameslink
"EUS", // Euston
"FST", // Fenchurch Street
"KGX", // King's Cross
"LST", // Liverpool Street
"LBG", // London Bridge
"MYB", // Marylebone
"MOG", // Moorgate
"OLD", // Old Street
"PAD", // Paddington
"STP", // St. Pancras
"VXH", // Vauxhall
"VIC", // Victoria
"WAT", // Waterloo
"WAE", // Waterloo East
};

var client = new LDBServiceSoapClient();
var totalDelayMinutes = 0;
var delayedTrains = new List<ServiceItem>();

// Avoiding Problems with the Using Statement in WCF clients
// https://msdn.microsoft.com/en-us/library/aa355056.aspx
try {
var totalDelayMinutes = 0;
var delayedTrains = new List<ServiceItem>();
var token = MakeAccessToken(request.AccessToken);

var token = MakeAccessToken(request.AccessToken);
var filterCrs = request.FilterCrs;
if (request.FilterCrs.Equals("LON", StringComparison.InvariantCultureIgnoreCase) ||
request.FilterCrs.Equals("London", StringComparison.InvariantCultureIgnoreCase)) {
filterCrs = null;
}

var filterCrs = request.FilterCrs;
if (request.FilterCrs.Equals("LON", StringComparison.InvariantCultureIgnoreCase) ||
request.FilterCrs.Equals("London", StringComparison.InvariantCultureIgnoreCase)) {
filterCrs = null;
}

var board = await client.GetDepartureBoardAsync(token, request.NumRows, request.Crs, filterCrs, request.FilterType, 0, 0);

var response = board.GetStationBoardResult;
var filterLocationName = response.filterLocationName;

var trainServices = response.trainServices ?? new ServiceItem[0];
var railReplacement = null != response.busServices && !trainServices.Any() && response.busServices.Any();
var messagesPresent = null != response.nrccMessages && response.nrccMessages.Any();

if (null == filterCrs) {
// This only finds trains terminating at London terminals. BFR/STP etc. won't be picked up if called at en-route.
// Could query for every terminal or get service for every train and check calling points. Very chatty either way.
switch (request.FilterType) {
case FilterType.to:
trainServices = trainServices.Where(ts => ts.destination.Any(d => londonTerminals.Contains(d.crs.ToUpperInvariant()))).ToArray();
break;
case FilterType.from:
trainServices = trainServices.Where(ts => ts.origin.Any(d => londonTerminals.Contains(d.crs.ToUpperInvariant()))).ToArray();
break;
default:
throw new ArgumentOutOfRangeException();
}
filterCrs = "LON";
filterLocationName = "London";
var board = await Client.GetDepartureBoardAsync(token, request.NumRows, request.Crs, filterCrs, request.FilterType, 0, 0);

var response = board.GetStationBoardResult;
var filterLocationName = response.filterLocationName;

var trainServices = response.trainServices ?? new ServiceItem[0];
var railReplacement = null != response.busServices && !trainServices.Any() && response.busServices.Any();
var messagesPresent = null != response.nrccMessages && response.nrccMessages.Any();

if (null == filterCrs) {
// This only finds trains terminating at London terminals. BFR/STP etc. won't be picked up if called at en-route.
// Could query for every terminal or get service for every train and check calling points. Very chatty either way.
switch (request.FilterType) {
case FilterType.to:
trainServices = trainServices.Where(ts => ts.destination.Any(d => HuxleyApi.LondonTerminals.Any(lt => lt.CrsCode == d.crs.ToUpperInvariant()))).ToArray();
break;
case FilterType.from:
trainServices = trainServices.Where(ts => ts.origin.Any(o => HuxleyApi.LondonTerminals.Any(lt => lt.CrsCode == o.crs.ToUpperInvariant()))).ToArray();
break;
default:
throw new ArgumentOutOfRangeException();
}
filterCrs = "LON";
filterLocationName = "London";
}

// If STDs are provided then select only the train(s) matching them
if (stds.Count > 0) {
trainServices = trainServices.Where(ts => stds.Contains(ts.std.Replace(":", ""))).ToArray();
}
// If STDs are provided then select only the train(s) matching them
if (stds.Count > 0) {
trainServices = trainServices.Where(ts => stds.Contains(ts.std.Replace(":", ""))).ToArray();
}

// Parse the response from the web service.
foreach (var si in trainServices.Where(si => !si.etd.Equals("On time", StringComparison.InvariantCultureIgnoreCase))) {
if (si.etd.Equals("Delayed", StringComparison.InvariantCultureIgnoreCase) ||
si.etd.Equals("Cancelled", StringComparison.InvariantCultureIgnoreCase)) {
delayedTrains.Add(si);
} else {
DateTime etd;
// Could be "Starts Here", "No Report" or contain a * (report overdue)
if (DateTime.TryParse(si.etd.Replace("*", ""), out etd)) {
DateTime std;
if (DateTime.TryParse(si.std, out std)) {
var late = etd.Subtract(std);
totalDelayMinutes += (int)late.TotalMinutes;
if (late.TotalMinutes > HuxleyApi.Settings.DelayMinutesThreshold) {
delayedTrains.Add(si);
}
// Parse the response from the web service.
foreach (var si in trainServices.Where(si => !si.etd.Equals("On time", StringComparison.InvariantCultureIgnoreCase))) {
if (si.etd.Equals("Delayed", StringComparison.InvariantCultureIgnoreCase) ||
si.etd.Equals("Cancelled", StringComparison.InvariantCultureIgnoreCase)) {
delayedTrains.Add(si);
} else {
DateTime etd;
// Could be "Starts Here", "No Report" or contain a * (report overdue)
if (DateTime.TryParse(si.etd.Replace("*", ""), out etd)) {
DateTime std;
if (DateTime.TryParse(si.std, out std)) {
var late = etd.Subtract(std);
totalDelayMinutes += (int)late.TotalMinutes;
if (late.TotalMinutes > HuxleyApi.Settings.DelayMinutesThreshold) {
delayedTrains.Add(si);
}
}
}
}

return new DelaysResponse {
GeneratedAt = response.generatedAt,
Crs = response.crs,
LocationName = response.locationName,
Filtercrs = filterCrs,
FilterLocationName = filterLocationName,
Delays = delayedTrains.Count > 0 || railReplacement || messagesPresent,
TotalTrainsDelayed = delayedTrains.Count,
TotalDelayMinutes = totalDelayMinutes,
TotalTrains = trainServices.Length,
DelayedTrains = delayedTrains,
};

} catch (CommunicationException) {
client.Abort();
} catch (TimeoutException) {
client.Abort();
} catch (Exception) {
client.Abort();
throw;
} finally {
client.Close();
}
return new DelaysResponse();

return new DelaysResponse {
GeneratedAt = response.generatedAt,
Crs = response.crs,
LocationName = response.locationName,
Filtercrs = filterCrs,
FilterLocationName = filterLocationName,
Delays = delayedTrains.Count > 0 || railReplacement || messagesPresent,
TotalTrainsDelayed = delayedTrains.Count,
TotalDelayMinutes = totalDelayMinutes,
TotalTrains = trainServices.Length,
DelayedTrains = delayedTrains,
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ You should have received a copy of the GNU Affero General Public License
using Huxley.ldbServiceReference;

namespace Huxley.Controllers {
public class BaseController : ApiController {
public class LdbController : ApiController {

protected readonly ILdbClient Client;

public LdbController(ILdbClient client) {
Client = client;
}

protected static AccessToken MakeAccessToken(Guid accessToken) {
// If ClientAccessToken is an empty GUID then no token is required in the Huxley URL.
// If ClientAccessToken matches the token in the URL then the DarwinAccessToken will be used instead in the SOAP call.
Expand Down
33 changes: 9 additions & 24 deletions src/Huxley/Controllers/ServiceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,42 +19,27 @@ You should have received a copy of the GNU Affero General Public License
*/

using System;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Web.Http;
using Huxley.Models;
using Huxley.ldbServiceReference;

namespace Huxley.Controllers {
public class ServiceController : BaseController {
public class ServiceController : LdbController {

public ServiceController(ILdbClient client)
: base(client) {
}

// GET /service/ID?accessToken=[your token]
public async Task<ServiceDetails> Get([FromUri] ServiceRequest request) {

Guid sid;
if (Guid.TryParse(request.ServiceId, out sid)) {
request.ServiceId = Convert.ToBase64String(sid.ToByteArray());
}

var client = new LDBServiceSoapClient();

// Avoiding Problems with the Using Statement in WCF clients
// https://msdn.microsoft.com/en-us/library/aa355056.aspx
try {
var token = MakeAccessToken(request.AccessToken);

var service = await client.GetServiceDetailsAsync(token, request.ServiceId);
return service.GetServiceDetailsResult;
} catch (CommunicationException) {
client.Abort();
} catch (TimeoutException) {
client.Abort();
} catch (Exception) {
client.Abort();
throw;
} finally {
client.Close();
}
return new ServiceDetails();
var token = MakeAccessToken(request.AccessToken);
var service = await Client.GetServiceDetailsAsync(token, request.ServiceId);
return service.GetServiceDetailsResult;
}
}
}
Loading

0 comments on commit 9686f68

Please sign in to comment.