Skip to content
Open
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ The application calling the service can be a console app. You have total freedom
• Write the outputs of the service call to a console window.

Create a pull request once you have it working. I will clone your repository, verify that it works, and evaluate it. Please ensure you include any instructions for running that may be required.


Instructions: If you have visual studio, there is a debug/run configuration that will start the service and launch the client program. It is
called "Client and Service". Once you have it set, you can go to "Run" -> "Start Without Debugging", and the web service will start and the
client program will launch.
163 changes: 163 additions & 0 deletions ServiceCall/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Text.RegularExpressions;

namespace ServiceCall
{
class Program
{
async static Task Main(string[] args)
{
int option = 0;
do
{
Console.WriteLine();
Console.WriteLine("Choose an option");
Console.WriteLine("1) search by order id");
Console.WriteLine("2) search by msa and status");
}
while ((!int.TryParse(Console.ReadLine(), out option)) || (option < 1 || option > 2));
Dictionary<string, object> dict = new Dictionary<string, object>();
Console.WriteLine();
if (option == 1)
{
dict.Add("OrderID", validateData(() =>
{
Console.Write("Enter the order number: ");
return Console.ReadLine();
}, "[0-9]").AsNumber());
//dict.Add("OrderID", Console.ReadLine().asNumber());
}
else
{
dict.Add("MSA", validateData(() =>
{
Console.Write("Enter the MSA (value is a number): ");
return Console.ReadLine();
}, "[0-9]").AsNumber());
Console.WriteLine();
dict.Add("Status", validateData(() =>
{
Console.Write("Enter the status (value is a number): ");
return Console.ReadLine();
}, "[0-9]").AsNumber());
}
Console.WriteLine();
string date = validateDate(() => validateData(() => {
Console.WriteLine("For the completion date, first give the year (in \"yyyy-mm-dd\" format): ");
return Console.ReadLine();
}, @"[0-9]{4}\-[0-9]{2}\-[0-9]{2}"));
string time = validateTime(() => validateData(() => {
Console.WriteLine("then the time (in \"hh:mm:ss\" format): ");
return Console.ReadLine();
}, @"[0-9]{2}\:[0-9]{2}\:[0-9]{2}"));
//dict.Add("CompletionDte", "2018-01-12T05:10:00");
dict.Add("CompletionDte", $"{date}T{time}");
Console.WriteLine();
string pagenumber = validateData(() =>
{
Console.Write("What is the page number to start at (leave blank to start at the beginning, page numbers start at 0)? ");
return Console.ReadLine();
}, "[0-9]", true);
if(!String.IsNullOrEmpty(pagenumber))
{
dict.Add("page", pagenumber.AsNumber());
}
Console.WriteLine();
string pagesize = validateData(() =>
{
Console.Write("What is the page size to start at (leave blank for all results or a default size of 25 will be used if a page number was specified and page size was left blank)? ");
return Console.ReadLine();
}, "[0-9]", true);
if (!String.IsNullOrEmpty(pagesize))
{
dict.Add("size", pagesize.AsNumber());
}
Console.WriteLine();
using (HttpClient client = new HttpClient())
{
string json = JsonConvert.SerializeObject(dict);
using (HttpContent content = new StringContent(json))
{
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
var result = await client.PostAsync("https://localhost:5001/api/order", content);
Console.WriteLine(await result.Content.ReadAsStringAsync());
}

}
System.Threading.Thread.Sleep(10000);
}

private static string validateData(Func<string> func, string regex, bool allowBlanks = false)
{
string validate;
do
{
validate = func();
}
while (allowBlanks ? ((!String.IsNullOrEmpty(validate)) && (!Regex.IsMatch(validate, regex))) : (!Regex.IsMatch(validate, regex)));
return validate;
}

private static string validateDate(Func<string> func)
{
string validate;
//now we check hour, minute, and second values to see if they are kosher
//here, we will only care about 24 hour time
bool verified = false;
do
{
validate = func();
string[] timesplits = validate.Split('-');
//we don't care about year because those keep going on and on, but month and day are important
int month = int.Parse(timesplits[1]);
int day = int.Parse(timesplits[2]);
bool leap = (int.Parse(timesplits[0]) % 4) == 0;
//leap years are tricky
if(month == 2 && day > 0 && ((leap && day < 30) || day < 29))
{
verified = true;
}
else if((month == 4 || month == 6 || month == 9 || month == 11) && day > 0 && day < 31)
{
verified = true;
}
else if((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day > 0 && day < 32)
{
verified = true;
}
}
while (!verified);
return validate;
}

private static string validateTime(Func<string> func)
{
string validate;
//now we check hour, minute, and second values to see if they are kosher
//here, we will only care about 24 hour time
bool verified = false;
do
{
validate = func();
string[] timesplits = validate.Split(':');
if(int.Parse(timesplits[0]) < 24 && int.Parse(timesplits[1]) < 60 && int.Parse(timesplits[2]) < 60) {
verified = true;
}
}
while (!verified);
return validate;
}
}

public static class StringExpansions
{
public static int AsNumber(this string s)
{
return int.Parse(s);
}
}
}
16 changes: 16 additions & 0 deletions ServiceCall/ServiceCall.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<None Include="..\README.md">
<Link>README.md</Link>
</None>
</ItemGroup>
</Project>
56 changes: 56 additions & 0 deletions simpleOrderSearch/Controllers/OrderController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace simpleOrderSearch.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
// POST api/values
[HttpPost]
public OrderResult Post([FromBody]IDictionary<string, System.Text.Json.JsonElement> request)
{
if(!request.ContainsKey("CompletionDte"))
{
throw new Exception("missing date");
}
//now for finding an item, we can look at either order number or a combination of MSA and Status
//since OrderID is our "primary key", we look for that first before looking for MSA and Status combination
if(request.ContainsKey("OrderID"))
{
var id = request["OrderID"].GetInt64();
DateTime date = request["CompletionDte"].GetDateTime();
var page = (request.ContainsKey("page")) ? Math.Max(request["page"].GetInt32(), 0) : 0;
var take = (request.ContainsKey("size")) ? Math.Max(request["size"].GetInt32(), 0) : 0;
return new OrderResult()
{
Results = OrderStore.instance.fetch(id, date, page, take),
PageNumber = page,
PageSize = (take == 0 && page > 0) ? 25 : take
};
}
else if(request.ContainsKey("MSA") && request.ContainsKey("Status"))
{
long status = request["Status"].GetInt64();
long msa = request["MSA"].GetInt64();
DateTime date = request["CompletionDte"].GetDateTime();
var page = (request.ContainsKey("page")) ? Math.Max(request["page"].GetInt32(), 0) : 0;
var take = (request.ContainsKey("size")) ? Math.Max(request["size"].GetInt32(), 0) : 0;
return new OrderResult()
{
Results = OrderStore.instance.fetch(msa, status, date, page, take),
PageNumber = page,
PageSize = (take == 0 && page > 0) ? 25 : take
};
}
else
{
throw new Exception("To search, you must provide either an order id or a combination of MSA and status.");
}
}
}
}
37 changes: 37 additions & 0 deletions simpleOrderSearch/Order.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Globalization;
using Newtonsoft.Json;

namespace simpleOrderSearch
{
public class Order
{
[JsonProperty("OrderID")]
public long OrderId { get; set; }

[JsonProperty("ShipperID")]
public long ShipperId { get; set; }

[JsonProperty("DriverID")]
public long DriverId { get; set; }

[JsonProperty("CompletionDte")]
public DateTime CompletionDte { get; set; }

[JsonProperty("Status")]
public long Status { get; set; }

[JsonProperty("Code")]
public string Code { get; set; }

[JsonProperty("MSA")]
public long Msa { get; set; }

[JsonProperty("Duration")]
public string Duration { get; set; }

[JsonProperty("OfferType")]
public long OfferType { get; set; }
}

}
32 changes: 32 additions & 0 deletions simpleOrderSearch/OrderResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Linq;
using System.Collections.Generic;

namespace simpleOrderSearch
{
public class OrderResult
{
public IEnumerable<Order> Results
{
get;
set;
}

public int Count
{
get { return Results.Count(); }
}

public int PageNumber
{
get;
set;
}

public int PageSize
{
get;
set;
}
}
}
51 changes: 51 additions & 0 deletions simpleOrderSearch/OrderStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace simpleOrderSearch
{
public class OrderStore
{
public static OrderStore instance = new OrderStore();
private Order[] store;

private OrderStore()
{
string json = System.IO.File.ReadAllText(@"../data/orderInfo.json");
store = JsonConvert.DeserializeObject<Order[]>(json);
}

internal IEnumerable<Order> fetch(long id, DateTime date, int page, int size)
{
//size and page of 0 means that the user wants all instances that meet the criteria
if (page == 0 && size == 0)
{
return store.Where(q => q.OrderId == id && q.CompletionDte == date);
}
else
{
//since the user has opted for pagination, we change the number of items taken to the default page size of 25 if page size is not initially given
size = (size == 0) ? 25 : size;
var skipped = page * size;
return store.Where(q => q.OrderId == id && q.CompletionDte == date).Skip(skipped).Take(size);
}
}

internal IEnumerable<Order> fetch(long msa, long status, DateTime date, int page, int size)
{
//size of 0 means that the user wants all instances that meet the criteria
if (page == 0 && size == 0)
{
return store.Where(q => q.Msa == msa && q.Status == status && q.CompletionDte == date);
}
else
{
//since the user has opted for pagination, we change the number of items taken to the default page size of 25 if page size is not initially given
size = (size == 0) ? 25 : size;
var skipped = page * size;
return store.Where(q => q.Msa == msa && q.Status == status && q.CompletionDte == date).Skip(skipped).Take(size);
}
}
}
}