diff --git a/.gitignore b/.gitignore index 7dfead3..467807b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ CSharpHTTPClient/packages/ CSharpHTTPClient/CSharpHTTPClient.sln.VisualState.xml *.PublicKey *.pfx +project.lock.json \ No newline at end of file diff --git a/NetCore/CSharpHTTPClient.sln b/NetCore/CSharpHTTPClient.sln new file mode 100644 index 0000000..a4b73a7 --- /dev/null +++ b/NetCore/CSharpHTTPClient.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{005FE017-F738-4C16-9548-89C39600F1EA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FCEEA0BD-11CB-4DB8-94D0-E705B99B071D}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SendGrid.CSharp.HTTP.Client", "src\SendGrid.CSharp.HTTP.Client\SendGrid.CSharp.HTTP.Client.xproj", "{DE550D30-B53D-4256-AEBD-31FE5F4A43BA}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Example", "src\Example\Example.xproj", "{0D6C6178-0950-41CA-AEB4-546F3FCFE9EE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6A21EE25-6B85-4D59-924A-4891D7576EB7}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UnitTest", "test\UnitTest\UnitTest.xproj", "{661B8EEA-0919-4B66-ABB6-449432053CBA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DE550D30-B53D-4256-AEBD-31FE5F4A43BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE550D30-B53D-4256-AEBD-31FE5F4A43BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE550D30-B53D-4256-AEBD-31FE5F4A43BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE550D30-B53D-4256-AEBD-31FE5F4A43BA}.Release|Any CPU.Build.0 = Release|Any CPU + {0D6C6178-0950-41CA-AEB4-546F3FCFE9EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D6C6178-0950-41CA-AEB4-546F3FCFE9EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D6C6178-0950-41CA-AEB4-546F3FCFE9EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D6C6178-0950-41CA-AEB4-546F3FCFE9EE}.Release|Any CPU.Build.0 = Release|Any CPU + {661B8EEA-0919-4B66-ABB6-449432053CBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {661B8EEA-0919-4B66-ABB6-449432053CBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {661B8EEA-0919-4B66-ABB6-449432053CBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {661B8EEA-0919-4B66-ABB6-449432053CBA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DE550D30-B53D-4256-AEBD-31FE5F4A43BA} = {005FE017-F738-4C16-9548-89C39600F1EA} + {0D6C6178-0950-41CA-AEB4-546F3FCFE9EE} = {005FE017-F738-4C16-9548-89C39600F1EA} + {661B8EEA-0919-4B66-ABB6-449432053CBA} = {6A21EE25-6B85-4D59-924A-4891D7576EB7} + EndGlobalSection +EndGlobal diff --git a/NetCore/global.json b/NetCore/global.json new file mode 100644 index 0000000..c0a4d84 --- /dev/null +++ b/NetCore/global.json @@ -0,0 +1,6 @@ +{ + "projects": [ "src", "test" ], + "sdk": { + + } +} diff --git a/NetCore/src/Example/Example.cs b/NetCore/src/Example/Example.cs new file mode 100644 index 0000000..309dc4d --- /dev/null +++ b/NetCore/src/Example/Example.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using SendGrid.CSharp.HTTP.Client; +using System.Web.Script.Serialization; + +// This is a working example, using the SendGrid API +// You will need a SendGrid account and an active API Key +// They key should be stored in an environment variable called SENDGRID_APIKEY +namespace Example +{ + class Example + { + static void Main(string[] args) + { + String host = "https://e9sk3d3bfaikbpdq7.stoplight-proxy.io"; + Dictionary globalRequestHeaders = new Dictionary(); + string apiKey = Environment.GetEnvironmentVariable("SENDGRID_APIKEY", EnvironmentVariableTarget.User); + globalRequestHeaders.Add("Authorization", "Bearer " + apiKey); + globalRequestHeaders.Add("Content-Type", "application/json"); + + String version = "v3"; + dynamic client = new Client(host: host, requestHeaders: globalRequestHeaders, version: version); + + // GET Collection + string queryParams = @"{ + 'limit': 100 + }"; + Dictionary requestHeaders = new Dictionary(); + requestHeaders.Add("X-Test", "test"); + dynamic response = client.version("v3").api_keys.get(queryParams: queryParams, requestHeaders: requestHeaders); + // Console.WriteLine(response.StatusCode); + // Console.WriteLine(response.ResponseBody.ReadAsStringAsync().Result); + // Console.WriteLine(response.ResponseHeaders.ToString()); + + var dssResponseBody = response.DeserializeResponseBody(response.ResponseBody); + foreach ( var value in dssResponseBody["result"]) + { + Console.WriteLine("name: {0}, api_key_id: {1}",value["name"], value["api_key_id"]); + } + + var dssResponseHeaders = response.DeserializeResponseHeaders(response.ResponseHeaders); + foreach (var pair in dssResponseHeaders) + { + Console.WriteLine("{0}: {1}", pair.Key, pair.Value); + } + + Console.WriteLine("\n\nPress any key to continue to POST."); + Console.ReadLine(); + + // POST + string requestBody = @"{ + 'name': 'My API Key 5', + 'scopes': [ + 'mail.send', + 'alerts.create', + 'alerts.read' + ] + }"; + requestHeaders.Clear(); + requestHeaders.Add("X-Test", "test2"); + response = client.api_keys.post(requestBody: requestBody, requestHeaders: requestHeaders); + Console.WriteLine(response.StatusCode); + Console.WriteLine(response.ResponseBody.ReadAsStringAsync().Result); + Console.WriteLine(response.ResponseHeaders.ToString()); + JavaScriptSerializer jss = new JavaScriptSerializer(); + var ds_response = jss.Deserialize>(response.ResponseBody.ReadAsStringAsync().Result); + string api_key_id = ds_response["api_key_id"]; + + Console.WriteLine("\n\nPress any key to continue to GET single."); + Console.ReadLine(); + + // GET Single + response = client.api_keys._(api_key_id).get(); + Console.WriteLine(response.StatusCode); + Console.WriteLine(response.ResponseBody.ReadAsStringAsync().Result); + Console.WriteLine(response.ResponseHeaders.ToString()); + + Console.WriteLine("\n\nPress any key to continue to PATCH."); + Console.ReadLine(); + + // PATCH + requestBody = @"{ + 'name': 'A New Hope' + }"; + response = client.api_keys._(api_key_id).patch(requestBody: requestBody); + Console.WriteLine(response.StatusCode); + Console.WriteLine(response.ResponseBody.ReadAsStringAsync().Result); + Console.WriteLine(response.ResponseHeaders.ToString()); + + Console.WriteLine("\n\nPress any key to continue to PUT."); + Console.ReadLine(); + + // PUT + requestBody = @"{ + 'name': 'A New Hope', + 'scopes': [ + 'user.profile.read', + 'user.profile.update' + ] + }"; + response = client.api_keys._(api_key_id).put(requestBody: requestBody); + Console.WriteLine(response.StatusCode); + Console.WriteLine(response.ResponseBody.ReadAsStringAsync().Result); + Console.WriteLine(response.ResponseHeaders.ToString()); + + Console.WriteLine("\n\nPress any key to continue to DELETE."); + Console.ReadLine(); + + // DELETE + response = client.api_keys._(api_key_id).delete(); + Console.WriteLine(response.StatusCode); + Console.WriteLine(response.ResponseHeaders.ToString()); + + Console.WriteLine("\n\nPress any key to exit."); + Console.ReadLine(); + } + } +} diff --git a/NetCore/src/Example/Example.xproj b/NetCore/src/Example/Example.xproj new file mode 100644 index 0000000..b7a7989 --- /dev/null +++ b/NetCore/src/Example/Example.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 0d6c6178-0950-41ca-aeb4-546f3fcfe9ee + Example + ..\..\artifacts\obj\$(MSBuildProjectName) + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/NetCore/src/Example/Properties/AssemblyInfo.cs b/NetCore/src/Example/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d644cc5 --- /dev/null +++ b/NetCore/src/Example/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Example")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Example")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0d6c6178-0950-41ca-aeb4-546f3fcfe9ee")] diff --git a/NetCore/src/Example/project.json b/NetCore/src/Example/project.json new file mode 100644 index 0000000..1cbadd0 --- /dev/null +++ b/NetCore/src/Example/project.json @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + "description": "Example Console Application", + "authors": [ "ecelletti" ], + + "buildOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "SendGrid.CSharp.HTTP.Client": "1.0.0-*" + }, + + "commands": { + "Example": "Example" + }, + + "frameworks": { + "net451": {} + } +} diff --git a/NetCore/src/SendGrid.CSharp.HTTP.Client/Client.cs b/NetCore/src/SendGrid.CSharp.HTTP.Client/Client.cs new file mode 100644 index 0000000..9b1ae7f --- /dev/null +++ b/NetCore/src/SendGrid.CSharp.HTTP.Client/Client.cs @@ -0,0 +1,351 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +#if NET451 +using System.Web.Script.Serialization; +using System.Web; +#else +using Newtonsoft.Json; +using System.Collections.Specialized; +#endif + +namespace SendGrid.CSharp.HTTP.Client +{ + public class Response + { + public HttpStatusCode StatusCode; + public HttpContent ResponseBody; + public HttpResponseHeaders ResponseHeaders; + + /// + /// Holds the response from an API call. + /// + /// https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx + /// https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx + /// https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx + public Response(HttpStatusCode statusCode, HttpContent responseBody, HttpResponseHeaders responseHeaders) + { + StatusCode = statusCode; + ResponseBody = responseBody; + ResponseHeaders = responseHeaders; + } + + /// + /// Converts string formatted response body to a Dictionary. + /// + /// https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx + /// Dictionary object representation of HttpContent + public virtual Dictionary DeserializeResponseBody(HttpContent content) + { +#if NET451 + JavaScriptSerializer jss = new JavaScriptSerializer(); + var dsContent = jss.Deserialize>(content.ReadAsStringAsync().Result); +#else + var dsContent = JsonConvert.DeserializeObject>(content.ReadAsStringAsync().Result); +#endif + return dsContent; + } + + /// + /// Converts string formatted response headers to a Dictionary. + /// + /// https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx + /// Dictionary object representation of HttpRepsonseHeaders + public virtual Dictionary DeserializeResponseHeaders(HttpResponseHeaders content) + { + var dsContent = new Dictionary(); + foreach (var pair in content) + { + dsContent.Add(pair.Key, pair.Value.First()); + } + return dsContent; + } + + } + + + public class Client : DynamicObject + { + public string Host; + public Dictionary RequestHeaders; + public string Version; + public string UrlPath; + public string MediaType; + public enum Methods + { + DELETE, GET, PATCH, POST, PUT + } + + /// + /// REST API client. + /// + /// Base url (e.g. https://api.sendgrid.com) + /// A dictionary of request headers + /// API version, override AddVersion to customize + /// Path to endpoint (e.g. /path/to/endpoint) + /// Fluent interface to a REST API + public Client(string host, Dictionary requestHeaders = null, string version = null, string urlPath = null) + { + Host = host; + if(requestHeaders != null) + { + AddRequestHeader(requestHeaders); + } + Version = (version != null) ? version : null; + UrlPath = (urlPath != null) ? urlPath : null; + } + + /// + /// Add requestHeaders to the API call + /// + /// A dictionary of request headers + public void AddRequestHeader(Dictionary requestHeaders) + { + RequestHeaders = (RequestHeaders != null) + ? RequestHeaders.Union(requestHeaders).ToDictionary(pair => pair.Key, pair => pair.Value) : requestHeaders; + } + + /// + /// Build the final URL + /// + /// A string of JSON formatted query parameters (e.g {'param': 'param_value'}) + /// Final URL + private string BuildUrl(string queryParams = null) + { + string endpoint = null; + + if( Version != null) + { + endpoint = Host + "/" + Version + UrlPath; + } + else + { + endpoint = Host + UrlPath; + } + + if (queryParams != null) + { +#if NET451 + JavaScriptSerializer jss = new JavaScriptSerializer(); + var ds_query_params = jss.Deserialize>(queryParams); + var query = HttpUtility.ParseQueryString(string.Empty); +#else + + var ds_query_params = JsonConvert.DeserializeObject>(queryParams); + var query = new NameValueCollection(); +#endif + foreach (var pair in ds_query_params) + { + query[pair.Key] = pair.Value.ToString(); + } + string queryString = query.ToString(); + endpoint = endpoint + "?" + queryString; + } + + return endpoint; + } + + /// + /// Create a new Client object for method chaining + /// + /// Name of url segment to add to the URL + /// A new client object with "name" added to the URL + private Client BuildClient(string name = null) + { + string endpoint; + + if (name != null) + { + endpoint = UrlPath + "/" + name; + } + else + { + endpoint = UrlPath; + } + + UrlPath = null; // Reset the current object's state before we return a new one + return new Client(Host, RequestHeaders, Version, endpoint); + + } + + /// + /// Add the authorization header, override to customize + /// + /// Authoriztion header + /// Authorization value to add to the header + public virtual AuthenticationHeaderValue AddAuthorization(KeyValuePair header) + { + string[] split = header.Value.Split(new char[0]); + return new AuthenticationHeaderValue(split[0], split[1]); + } + + /// + /// Add the version of the API, override to customize + /// + /// Version string to add to the URL + public virtual void AddVersion(string version) + { + Version = version; + } + + /// + /// Deal with special cases and URL parameters + /// + /// Name of URL segment + /// A new client object with "name" added to the URL + public Client _(string name) + { + return BuildClient(name); + } + + /// + /// Reflection. We capture undefined variable access here + /// + /// The calling object properties + /// The callback + /// The callback returns a new client object with "name" added to the URL + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = BuildClient(binder.Name); + return true; + } + + /// + /// Reflection. We capture the final method call here + /// + /// The calling object properties + /// The calling object's arguements + /// If "version", returns new client with version attached + /// If "method", returns a Response object + /// The callback is described in "result" + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + if (binder.Name == "version") + { + AddVersion(args[0].ToString()); + result = BuildClient(); + return true; + } + + if( Enum.IsDefined(typeof(Methods), binder.Name.ToUpper())) + { + string queryParams = null; + string requestBody = null; + int i = 0; + + foreach (object obj in args) + { + string name = binder.CallInfo.ArgumentNames.Count > i ? + binder.CallInfo.ArgumentNames[i] : null; + if (name == "queryParams") + { + queryParams = obj.ToString(); + } + else if (name == "requestBody") + { + requestBody = obj.ToString(); + } + else if (name == "requestHeaders") + { + AddRequestHeader((Dictionary)obj); + } + i++; + } + result = RequestAsync(binder.Name.ToUpper(), requestBody: requestBody, queryParams: queryParams).Result; + return true; + } + else + { + result = null; + return false; + } + + } + + /// + /// Make the call to the API server, override for testing or customization + /// + /// Client object ready for communication with API + /// The parameters for the API call + /// Response object + public async virtual Task MakeRequest(HttpClient client, HttpRequestMessage request) + { + HttpResponseMessage response = await client.SendAsync(request); + return new Response(response.StatusCode, response.Content, response.Headers); + } + + /// + /// Prepare for async call to the API server + /// + /// HTTP verb + /// JSON formatted string + /// JSON formatted queary paramaters + /// Response object + private async Task RequestAsync(string method, String requestBody = null, String queryParams = null) + { + using (var client = new HttpClient()) + { + try + { + // Build the URL + client.BaseAddress = new Uri(Host); + string endpoint = BuildUrl(queryParams); + + // Build the request headers + client.DefaultRequestHeaders.Accept.Clear(); + if(RequestHeaders != null) + { + foreach (KeyValuePair header in RequestHeaders) + { + if (header.Key == "Authorization") + { + client.DefaultRequestHeaders.Authorization = AddAuthorization(header); + } + else if (header.Key == "Content-Type") + { + MediaType = header.Value; + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaType)); + } + else + { + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + } + + // Build the request body + StringContent content = null; + if (requestBody != null) + { + content = new StringContent(requestBody.ToString().Replace("'", "\""), Encoding.UTF8, MediaType); + } + + // Build the final request + HttpRequestMessage request = new HttpRequestMessage + { + Method = new HttpMethod(method), + RequestUri = new Uri(endpoint), + Content = content + }; + return await MakeRequest(client, request); + + } + catch (Exception ex) + { + HttpResponseMessage response = new HttpResponseMessage(); + string message; + message = (ex is HttpRequestException) ? ".NET HttpRequestException" : ".NET Exception"; + message = message + ", raw message: \n\n"; + response.Content = new StringContent(message + ex.Message); + return new Response(response.StatusCode, response.Content, response.Headers); + } + } + } + } +} diff --git a/NetCore/src/SendGrid.CSharp.HTTP.Client/Properties/AssemblyInfo.cs b/NetCore/src/SendGrid.CSharp.HTTP.Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..95ec95e --- /dev/null +++ b/NetCore/src/SendGrid.CSharp.HTTP.Client/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SendGrid.CSharp.HTTP.Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SendGrid.CSharp.HTTP.Client")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("de550d30-b53d-4256-aebd-31fe5f4a43ba")] diff --git a/NetCore/src/SendGrid.CSharp.HTTP.Client/SendGrid.CSharp.HTTP.Client.xproj b/NetCore/src/SendGrid.CSharp.HTTP.Client/SendGrid.CSharp.HTTP.Client.xproj new file mode 100644 index 0000000..6ed6157 --- /dev/null +++ b/NetCore/src/SendGrid.CSharp.HTTP.Client/SendGrid.CSharp.HTTP.Client.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + de550d30-b53d-4256-aebd-31fe5f4a43ba + SendGrid.CSharp.HTTP.Client + ..\..\artifacts\obj\$(MSBuildProjectName) + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/NetCore/src/SendGrid.CSharp.HTTP.Client/project.json b/NetCore/src/SendGrid.CSharp.HTTP.Client/project.json new file mode 100644 index 0000000..088faf5 --- /dev/null +++ b/NetCore/src/SendGrid.CSharp.HTTP.Client/project.json @@ -0,0 +1,29 @@ +{ + "version": "1.0.0-*", + "description": "SendGrid.CSharp.HTTP.Client Class Library", + "authors": [ "ecelletti" ], + "dependencies": { + }, + "frameworks": { + "net451": { + "frameworkAssemblies": { + "System.Web.Extensions": "4.0.0.0", + "System.Web": "4.0.0.0", + "System.Net.Http": "4.0.0" + } + }, + "netstandard1.3": { + "dependencies": { + "System.Runtime.InteropServices": "4.1.0", + "System.Net.Http": "4.1.0", + "Microsoft.CSharp": "4.0.1", + "System.Collections": "4.0.11", + "System.Collections.Specialized": "4.0.1", + "System.Linq": "4.1.0", + "System.Runtime": "4.1.0", + "System.Threading": "4.0.11", + "Newtonsoft.Json": "9.0.1" + } + } + } +} diff --git a/NetCore/test/UnitTest/Properties/AssemblyInfo.cs b/NetCore/test/UnitTest/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7bd8f55 --- /dev/null +++ b/NetCore/test/UnitTest/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnitTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UnitTest")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("661b8eea-0919-4b66-abb6-449432053cba")] diff --git a/NetCore/test/UnitTest/UnitTest.cs b/NetCore/test/UnitTest/UnitTest.cs new file mode 100644 index 0000000..845f2cf --- /dev/null +++ b/NetCore/test/UnitTest/UnitTest.cs @@ -0,0 +1,77 @@ +using System; +using SendGrid.CSharp.HTTP.Client; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text; +using System.Net; +using Xunit; + +namespace UnitTest +{ + + // Mock the Client so that we intercept network calls + public class MockClient : Client + { + public MockClient(string host, Dictionary requestHeaders = null, string version = null, string urlPath = null) : base (host, requestHeaders, version, urlPath) + { + } + + public async override Task MakeRequest(HttpClient client, HttpRequestMessage request) + { + HttpResponseMessage response = new HttpResponseMessage(); + response.Content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json"); + response.StatusCode = HttpStatusCode.OK; + return new Response(response.StatusCode, response.Content, response.Headers); + } + } + + public class TestClient + { + [Fact] + public void TestInitialization() + { + var host = "http://api.test.com"; + Dictionary requestHeaders = new Dictionary(); + var version = "v3"; + var urlPath = "/test/url/path"; + var test_client = new MockClient(host: host, requestHeaders: requestHeaders, version: version, urlPath: urlPath); + requestHeaders.Add("Authorization", "Bearer SG.XXXX"); + requestHeaders.Add("Content-Type", "application/json"); + requestHeaders.Add("X-TEST", "test"); + Assert.NotNull(test_client); + Assert.Equal(host, test_client.Host); + Assert.Equal(requestHeaders, test_client.RequestHeaders); + Assert.Equal(version, test_client.Version); + Assert.Equal(urlPath, test_client.UrlPath); + } + + [Fact] + public void TestReflection() + { + var host = "http://api.test.com"; + dynamic test_client = new MockClient(host: host); + dynamic url1 = test_client.my.test.path; + Assert.Equal(url1.UrlPath, "/my/test/path"); + url1 = test_client.my._("test").path; + Assert.Equal(url1.UrlPath, "/my/test/path"); + url1 = test_client.version("v4").my.test.path; + Assert.Equal(url1.Version, "v4"); + Assert.Equal(url1.UrlPath, "/my/test/path"); + url1 = url1.final.result; + Assert.Equal(url1.UrlPath, "/my/test/path/final/result"); + } + + [Fact] + public void TestMethodCall() + { + var host = "http://api.test.com"; + dynamic test_client = new MockClient(host: host); + Response response = test_client.get(); + Assert.NotNull(response); + Assert.Equal(response.StatusCode, HttpStatusCode.OK); + var content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json"); + Assert.Equal(response.ResponseBody.ReadAsStringAsync().Result, content.ReadAsStringAsync().Result); + } + } +} diff --git a/NetCore/test/UnitTest/UnitTest.xproj b/NetCore/test/UnitTest/UnitTest.xproj new file mode 100644 index 0000000..c468b65 --- /dev/null +++ b/NetCore/test/UnitTest/UnitTest.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 661b8eea-0919-4b66-abb6-449432053cba + UnitTest + ..\..\artifacts\obj\$(MSBuildProjectName) + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/NetCore/test/UnitTest/project.json b/NetCore/test/UnitTest/project.json new file mode 100644 index 0000000..87a18b0 --- /dev/null +++ b/NetCore/test/UnitTest/project.json @@ -0,0 +1,28 @@ +{ + "version": "1.0.0-*", + "description": "UnitTest Class Library", + "authors": [ "" ], + + "testRunner": "xunit", + + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + } + }, + "imports": [ + "dotnet5.6", + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "dependencies": { + "SendGrid.CSharp.HTTP.Client": "1.0.0-*", + "xunit": "2.2.0-beta2-build3300", + "dotnet-test-xunit": "2.2.0-preview2-build1029" + } +}