public EsiModel Get(WebHeaderCollection headers, string address, int cacheSeconds = 0)
        {
            System.Net.WebClient client = new System.Net.WebClient
            {
                Headers = { ["UserAgent"] = _userAgent }
            };

            if (headers != null)
            {
                client.Headers = headers;
                client.Headers["UserAgent"] = _userAgent;
            }

            CacheModel cachedItem = _cache.Get <CacheModel>(address);
            EsiModel   esiModel   = new EsiModel();

            try
            {
                if (cacheSeconds == 0)
                {
                    esiModel.Model = client.DownloadString(address);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    return(esiModel);
                }

                if (cachedItem != null)
                {
                    if (DateTime.Compare(cachedItem.Expires, DateTime.UtcNow) >= 0)
                    {
                        esiModel.Model    = cachedItem.Item;
                        esiModel.Etag     = cachedItem.Etag;
                        esiModel.MaxPages = cachedItem.Page;

                        return(esiModel);
                    }

                    if (!string.IsNullOrEmpty(cachedItem.Etag))
                    {
                        client.Headers["If-None-Match"] = cachedItem.Etag;
                    }

                    string esiResponse = client.DownloadString(address);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    cachedItem = new CacheModel(esiResponse, esiModel.Etag, cacheSeconds, esiModel.MaxPages);

                    _cache.Remove(address);
                    _cache.Add(address, cachedItem);
                }
                else
                {
                    string esiResponse = client.DownloadString(address);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    cachedItem = new CacheModel(esiResponse, esiModel.Etag, cacheSeconds, esiModel.MaxPages);

                    _cache.Add(address, cachedItem);
                }

                esiModel.Model = cachedItem.Item;

                return(esiModel);
            }
            catch (WebException e)
            {
                EsiModel returned = BuildException(e, cachedItem, esiModel, address, string.Empty);

                if (returned != null)
                {
                    return(returned);
                }

                throw;
            }
        }
        private EsiModel BuildException(WebException e, CacheModel cachedItem, EsiModel esiModel, string address, string data)
        {
            HttpWebResponse webResponse = e.Response as HttpWebResponse;

            switch (webResponse?.StatusCode)
            {
            case HttpStatusCode.NotModified:
                if (cachedItem == null)
                {
                    return(null);
                }

                esiModel.Model    = cachedItem.Item;
                esiModel.Etag     = cachedItem.Etag;
                esiModel.MaxPages = cachedItem.Page;

                return(esiModel);

            case HttpStatusCode.BadRequest:
            case HttpStatusCode.Forbidden:
            case HttpStatusCode.NotFound:
            case HttpStatusCode.InternalServerError:
            case HttpStatusCode.BadGateway:
            case HttpStatusCode.ServiceUnavailable:
            case HttpStatusCode.GatewayTimeout:
                Stream responseStream = webResponse.GetResponseStream();

                if (responseStream == null)
                {
                    throw new EsiException($"{e.Message} Url: {address}");
                }

                string resp         = new StreamReader(responseStream).ReadToEnd();
                string errorMessage = string.Empty;

                string returnHeadersString = string.Empty;

                WebHeaderCollection returnHeaders = webResponse.Headers;

                try
                {
                    EsiError error = JsonConvert.DeserializeObject <EsiError>(resp);

                    errorMessage = error.Error;

                    if (returnHeaders != null)
                    {
                        for (int i = 0; i < returnHeaders.Count; i++)
                        {
                            returnHeadersString += $"{returnHeaders.GetKey(i)}: {returnHeaders.Get(i)} | ";
                        }
                    }
                }
                catch (Exception)
                {
                    // ignored
                }

                throw new EsiException($"{e.Message} Url: {address} Message From Server: {errorMessage} : Return Headers = {returnHeadersString} . Data: {data}", e);
            }

            return(null);
        }
        public async Task <EsiModel> PostAsync(WebHeaderCollection headers, string address, string data, int cacheSeconds = 0)
        {
            System.Net.WebClient client = new System.Net.WebClient
            {
                Headers     = headers,
                CachePolicy = new HttpRequestCachePolicy()
            };

            client.Headers["UserAgent"] = _userAgent;

            CacheModel cachedItem = _cache.Get <CacheModel>(address);
            EsiModel   esiModel   = new EsiModel();

            try
            {
                if (cacheSeconds == 0)
                {
                    esiModel.Model = await client.UploadStringTaskAsync(address, data);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    return(esiModel);
                }

                if (cachedItem != null)
                {
                    if (DateTime.Compare(cachedItem.Expires, DateTime.UtcNow) <= 0)
                    {
                        esiModel.Model    = cachedItem.Item;
                        esiModel.Etag     = cachedItem.Etag;
                        esiModel.MaxPages = cachedItem.Page;

                        return(esiModel);
                    }

                    if (!string.IsNullOrEmpty(cachedItem.Etag))
                    {
                        client.Headers["If-None-Match"] = cachedItem.Etag;
                    }

                    string esiResponse = await client.UploadStringTaskAsync(address, data);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    cachedItem = new CacheModel(esiResponse, esiModel.Etag, cacheSeconds, esiModel.MaxPages);

                    _cache.Remove(address);
                    _cache.Add(address, cachedItem);
                }
                else
                {
                    string esiResponse = await client.UploadStringTaskAsync(address, data);

                    esiModel = BuildHeaders(client.ResponseHeaders, esiModel);

                    cachedItem = new CacheModel(esiResponse, esiModel.Etag, cacheSeconds, esiModel.MaxPages);

                    _cache.Add(address, cachedItem);
                }

                esiModel.Model = cachedItem.Item;

                return(esiModel);
            }
            catch (WebException e)
            {
                EsiModel returned = BuildException(e, cachedItem, esiModel, address, data);

                if (returned != null)
                {
                    return(returned);
                }

                throw;
            }
        }