-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathservices.cs
139 lines (126 loc) · 6.21 KB
/
services.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Ayva.InreachIPC
{
public class Services
{
private readonly Config _config = new Config();
public Services(string username, string password, Config.RegionalEndpoints region = Config.RegionalEndpoints.US)
{
_config.Username = username;
_config.Password = password;
}
public async Task<APIModel> Process(APIModel model)
{
model.Response = new HttpResponseMessage();
model.ModelStatus = APIModel.ModelStatuses.SENDING;
using (var httpClient = new HttpClient(new HttpClientHandler() { Credentials = new NetworkCredential(_config.Username, _config.Password) }))
{
var modelAttribute = (APIModel.ServicePath)model.GetType().GetCustomAttributes(typeof(APIModel.ServicePath), true).Single();
switch (modelAttribute.method)
{
case APIModel.ServicePath.HttpMethods.POST:
var payload = JsonConvert.SerializeObject(model,
new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
});
var postContent = new StringContent(payload, Encoding.UTF8, "application/json");
model.Response = await httpClient.PostAsync($"{_config.GetEndpointUri}/{model.BuildUri()}", postContent);
break;
case APIModel.ServicePath.HttpMethods.GET:
model.Response = await httpClient.GetAsync($"{_config.GetEndpointUri}/{model.BuildUri()}");
break;
}
}
if (model.Response.StatusCode != HttpStatusCode.OK)
{
model.ModelStatus = APIModel.ModelStatuses.ERROR;
throw new InreachIPCException($"API request failed", model, this);
}
JsonConvert.PopulateObject(await model.Response.Content.ReadAsStringAsync(), model);
model.ModelStatus = APIModel.ModelStatuses.PROCESSED;
return model;
}
public class InreachIPCException : Exception
{
public InreachIPCException(string message, APIModel model, Services services)
: base($"{{Message=\"{message}\"," +
$"{(model.Response != null ? $"Code={Enum.GetName(typeof(HttpStatusCode), model.Response.StatusCode)}, Response={model.Response.Content.ReadAsStringAsync().Result}, " : string.Empty)}" +
$"Model={model}, " +
$"ServicesEndpoint={Enum.GetName(typeof(Config.RegionalEndpoints), services._config.APIEndpoint)}}}")
{
}
}
[JsonObject(MemberSerialization.OptIn)]
public abstract class APIComponent
{ }
public abstract class APIModel : APIComponent
{
protected string pathParameters = string.Empty;
public HttpResponseMessage Response;
public ModelStatuses ModelStatus = ModelStatuses.NEW;
public Guid MessageID = Guid.NewGuid();
public enum ModelStatuses
{
NEW,
SENDING,
PROCESSED,
ERROR
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
internal class ServicePath : Attribute
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Path is required on types that implement APIMessage")]
public string path;
[Required(ErrorMessage = "Method is required on types that implement APIMessage")]
public HttpMethods method;
public enum HttpMethods
{
POST,
GET
}
}
internal virtual Uri BuildUri()
{
var modelAttribute = (ServicePath)GetType().GetCustomAttributes(typeof(ServicePath), true).SingleOrDefault();
if (modelAttribute == null || String.IsNullOrEmpty(modelAttribute.path))
throw new ArgumentException("Model is missing required attribute data [ServicePath path=value method=value]");
if (!String.IsNullOrEmpty(pathParameters) && modelAttribute.method != ServicePath.HttpMethods.GET)
throw new ArgumentException("Model has path parameters with an incompatible method type");
return new Uri($"{modelAttribute.path}{pathParameters}", UriKind.Relative);
}
public async Task<string> GetJsonResult()
{
if (ModelStatus != ModelStatuses.PROCESSED)
throw new MethodAccessException("Result JSON is only available after the Model has been successfully processed");
return JToken.Parse(await Response.Content.ReadAsStringAsync()).ToString(Formatting.Indented);
}
public async Task<string> GetRawResult()
{
if (Response == null)
throw new MethodAccessException("Result text is only available after the Model has been processed");
return await Response.Content.ReadAsStringAsync();
}
public override string ToString()
{
var modelContent = JsonConvert.SerializeObject(this,
new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
Formatting = Formatting.None
});
return $"{{Type={GetType().Name}, Path={BuildUri()}, Status={Enum.GetName(typeof(ModelStatuses), ModelStatus)}, ID={MessageID}, JSON={modelContent}}}";}
}
}
}