Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DI Refactor #36

Merged
merged 7 commits into from
May 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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