Multiple requests (pagination) with RestSharp - c#

I'm new to C# and I need help! I need to send paged data through a client rest. As the data mass is very large, I would like to trigger several requests at the same time, however, only a small part of the data is arriving at the destination. Can you help me with what's wrong?
public void SendResultsByFireForget(string env, string transactionId, int days)
{
var client = new RestClient();
var proxyDefinition = new WebProxy("xxx.xxx.xxx.xxx");
proxyDefinition.UseDefaultCredentials = true;
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
client.Proxy = proxyDefinition;
if (String.IsNullOrEmpty(transactionId))
{
throw new ArgumentException("Parameter transactionId is null or empty!");
}
if (String.IsNullOrEmpty(env))
{
throw new ArgumentException("Parameter uri is null or empty!");
}
List<Result> listOfResults = Repository.GetResultsByIntervalPerDay(-31);
if (listOfResults.Count() == 0 || listOfResults == null)
{
throw new Exception("The list of results is empty or null");
}
var tasks = new List<Task>();
foreach (List<Result> page in GetPages(listOfResults, 500))
{
var currentPageCopy = page;
var task = Task.Run(() =>
{
var currentPage = JSonExtensions.ToJSon(currentPageCopy);
var request = new RestRequest(
$"{env.Trim()}/results1/?transaction_id={transactionId.Trim()}",
Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(currentPage);
client.ExecuteAsync(request);
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}

if u can get total result count on first result you can do like this .
// RestClient is extented restsharp client you can do your own .
List<User> UserList = new();
// inline method
UserList getUser(int startCount,int limit)
{
var Data = RestClient.GetData(Url);
return Data;
}
// another inline for getting total count
int GetOrderCounts()
{
// get total counts
var FData = getUser(0,0);
return FData.TotalRecordCount;
}
var GetTotalCount = GetOrderCounts();
for (int ONumber = 0; ONumber <= GetOrderCount; ONumber += 100)
{
var Return = GetOrders(OrderNumber, 100);
if (Return != null)
UserList.AddRange(Return.Data);
};

Related

Return success/error response after making some graph calls

I have the following code to add users to AAD group:
public async Task AddUsersToGroup(IEnumerable<BatchRequestContent> batches)
{
try
{
foreach (var batchRequestContent in batches)
{
var response = await _graphServiceClient
.Batch
.Request()
.WithMaxRetry(10)
.PostAsync(batchRequestContent);
var responses = await response.GetResponsesAsync();
foreach (string key in responses.Keys)
{
var httpResponse = await response.GetResponseByIdAsync(key);
httpResponse.EnsureSuccessStatusCode();
}
}
}
catch (Exception ex)
{
await _log.LogMessageAsync(new LogMessage
{
Message = ex.GetBaseException().ToString(),
RunId = RunId
});
throw;
}
}
I need to update this method to return 'Ok' if all the requests returned a success response, else return 'Error' if any of the requests returned an error response. How would I do that? Please help!
private IEnumerable<BatchRequestContent> GetBatchRequest(IEnumerable<AzureADUser> users, AzureADGroup targetGroup)
{
var batches = new List<BatchRequestContent>();
int maxNoBatchItems = 20;
var batchRequestContent = new BatchRequestContent();
int requestId = 1;
foreach (var user in users)
{
JObject body = new JObject
{
["members#odata.bind"] = $"https://graph.microsoft.com/v1.0/users/{user.ObjectId}"
};
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Patch, $"https://graph.microsoft.com/v1.0/groups/{targetGroup.ObjectId}");
httpRequestMessage.Content = new StringContent(body.ToString(), Encoding.UTF8, "application/json");
batchRequestContent.AddBatchRequestStep(new BatchRequestStep(requestId.ToString(), httpRequestMessage));
if (batchRequestContent.BatchRequestSteps.Count() % maxNoBatchItems == 0)
{
batches.Add(batchRequestContent);
batchRequestContent = new BatchRequestContent();
}
requestId++;
}
if (batchRequestContent.BatchRequestSteps.Count < maxNoBatchItems)
{
batches.Add(batchRequestContent);
}
return batches;
}

How to update AccountNumber value by ContactId in XERO API using C#

I'm trying to achieve update contact with Xero api: I'm trying to update AccountNumber value is null.
This is the code for update method. I'm passing value with ContactId and AccountNumber.
var xContact = new XeroContact
{
AccountNumber = null,
ContactId = CustomerGUID
};
var request = new XeroContactRequest { AuthToken = _authHelper.AccessToken, Search = "", TenantId = _authHelper.TenantId, CustomerGUID = CustomerGUID, Contact = xContact };
var xeroCustomerResult = _xeroContactBusiness.UpdateContact(request);
update function:
public IResult<XeroContact> UpdateContact(XeroContactRequest data)
{
var result = new Result<XeroContact>();
try
{
if (data == null || string.IsNullOrEmpty(data.AuthToken) || string.IsNullOrEmpty(data.TenantId)) throw new ArgumentNullException("data is required");
var client = new RestClient(BaseUrl);
var method = string.Format("/{0}/{1}", _apiMethod, data.CustomerGUID);
var request = new RestRequest(method, Method.POST);
request.AddHeader("Authorization", string.Format("Bearer {0}", data.AuthToken));
request.AddHeader("Accept", "application/json");
request.AddHeader("Xero-tenant-id", data.TenantId);
var postData = JsonConvert.SerializeObject(data.Contact);
request.AddJsonBody(postData);
var response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception(ParseError(response.Content));
}
}
catch (Exception ex)
{
result.HasData = false;
result.Data = null;
result.Error = ex;
}
return result;
}
Can you please help me understand what I'm doing wrong? How can i update AccountNumber by ContactId. Thanks !
I have resolved this issue below way, Just need to send ContactId and those parameter that's need to be updated. Here "AccountNumber" field need to be updated. Thanks !
var body = new
{
ContactId = data.CustomerGUID,
AccountNumber=""
};
var postData = JsonConvert.SerializeObject(body);
request.AddJsonBody(postData);

API is mixing up data from different devices

I have an API that has devices firing data to it at the same time or within a few milliseconds. What I am finding is that the data is getting mixed up. The data is sent every five minutes (on the clock 05, 10, 15 etc.) I have an execution filter that traps the URL data coming in so I always have a real source, then it goes to the endpoint and then onto processing. For example, there will a be random five minute period missing. When I debug step by step with the missing URL from the execution filter it works fine. By that I mean I take the URL and debug, then it inserts.
In summary, I have device id 1 and device id 2.I will get missing intervals even though, I can see the data has hit the execution filter.
I am assuming that the API is not handling these as separate transactions, but somehow mixing them up together, hence the data missing and the serial numbers appearing in the wrong place, such that data from id 1 is appearing in id 2 vice versa etc.
API End Point:
public class SomeController : ApiController
{
[HttpGet]
[ExecutionFilter]
public async Task<HttpResponseMessage> Get([FromUri] FixedDataModel fdm)
{
var reply = new HttpResponseMessage();
string url = HttpUtility.UrlDecode(HttpContext.Current.Request.QueryString.ToString());
if (url.Contains("timestamp"))
{
reply = TimeSyncValidation.TimeSync;
return reply;
}
else if (!url.Contains("timestamp"))
{
reply = await Task.Run(() => DeviceClass.DeviceApiAsync(fdm, url));
}
return reply;
}
}
Processing class:
namespace API.Services
{
public class DeviceClass
{
private static string serialNumber;
private static byte chk;
private static string channelName, channelReadingNumber, channelValue, queryString, readingDate;
private static int colonPosition, chanCountFrom, equalsPosition;
private static bool checkSumCorrect;
public static HttpResponseMessage DeviceApiAsync(FixedDataModel fdm, string urlQqueryString)
{
Guid guid = Guid.NewGuid();
//ExecutionTrackerHandler.Guid = guid;
//Remove question mark
var q = urlQqueryString;
queryString = q.Substring(0);
var items = HttpUtility.ParseQueryString(queryString);
serialNumber = items["se"];
//Store raw uri for fault finding
var rawUri = new List<RawUriModel>
{
new RawUriModel
{
UniqueId = guid,
RawUri = q,
TimeStamp = DateTime.Now
}
};
//Checksum validation
chk = Convert.ToByte(fdm.chk);
checkSumCorrect = CheckSumValidator.XorCheckSum(queryString, chk);
if (!checkSumCorrect)
{
return ValidationResponseMessage.ResponseHeaders("Checksum");
}
//Create list of items that exist in URL
var urldata = new UrlDataList
{
UrlData = queryString.Split('&').ToList(),
};
var data = new List<UriDataModel>();
//Split the URL string into its parts
foreach (var item in urldata.UrlData)
{
colonPosition = item.IndexOf(":");
chanCountFrom = colonPosition + 1;
equalsPosition = item.LastIndexOf("=");
if (colonPosition == -1)
{
channelName = item.Substring(0, equalsPosition);
channelReadingNumber = "";
channelValue = item.Substring(item.LastIndexOf("=") + 1);
}
else
{
channelName = item.Substring(0, colonPosition);
channelReadingNumber = item.Substring(chanCountFrom, equalsPosition - chanCountFrom);
channelValue = item.Substring(item.LastIndexOf("=") + 1);
if (channelName == "atime" || channelName == "adate")
{
readingDate = DateValidator.CreateDate(channelValue);
}
};
bool nullFlag = false;
if (channelValue == null)
nullFlag = true;
bool missingFlag = false;
if (channelValue == "x") {
missingFlag = true;
channelValue = "0";
}
//Add data to model ready for DB insert.
data.Add(new UriDataModel
{
uid = guid,
SerialNumber = serialNumber,
ChannelName = channelName,
ChannelReadingNumber = channelReadingNumber,
ChannelValue = channelValue.Replace(",", "."),
ReadingDate = readingDate,
TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
Processed = false,
NullFlag = nullFlag,
MissingFlag = missingFlag
});
};
//Validate dates
var allDates = (from x in data where x.ChannelName.Contains("atime") || x.ChannelName.Contains("adate") select x.ChannelValue).ToList();
bool dateValidation = DateValidator.IsValid(allDates);
if (!dateValidation)
{
return ValidationResponseMessage.ResponseHeaders("Date");
};
//Validate values
var channels = Enum.GetNames(typeof(Channels)).ToList();
List<string> allChannelValues = data.Where(d => channels.Contains(d.ChannelName)).Select(d => d.ChannelValue).ToList();
bool valueValidation = ValueValidator.IsValid(allChannelValues);
if (!valueValidation)
{
return ValidationResponseMessage.ResponseHeaders("Values");
};
//Insert live data
var insertData = DataInsert<UriDataModel>.InsertData(data, "Staging.UriData");
if (!insertData)
{
return ValidationResponseMessage.ResponseHeaders("Sql");
}
var content = "\r\nSUCCESS\r\n";
var reply = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(content)
};
return reply;
}
}
}
TIA
You are using global variables and static method to process your data.
Change your method to non-static.
Each DeviceClass worker must update only its own isolated data then push that off back to controller.

Combine the multiple API responses in to one JSON object C#

I am calling the Sharepoint REST API from the C# application multiple times becaues of pagination and it cannot return more the 5000 records at a time. I am calling the API through the loop like
for (int i = 0; i < 10000; i = i + 5000)
{
SP_StrainCodes = "GetByTitle('S%20Codes')/items?$skiptoken=Paged=TRUE%26p_ID=" + i + "&$top=1";
core_URL = BaseURL_SP + SP_StrainCodes;
using (var client_sharePoint = new HttpClient(handler))
{
var response = client_sharePoint.GetAsync(core_URL).Result;
var responsedata = await response.Content.ReadAsStringAsync();
returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(responsedata);
if (returnObj.d.Next == null)
continue;
}
}
return returnObj;
}
How do I combine the the returnObj from 1st call and the 2nd Call and return as one Object
Something like this :
List<SharepointDTO.RootObject> results = new List<SharepointDTO.RootObject>();
for (int i = 0; i < 10000; i = i + 5000)
{
SP_StrainCodes = "GetByTitle('S%20Codes')/items?$skiptoken=Paged=TRUE%26p_ID=" + i + "&$top=1";
core_URL = BaseURL_SP + SP_StrainCodes;
using (var client_sharePoint = new HttpClient(handler))
{
var response = client_sharePoint.GetAsync(core_URL).Result;
var responsedata = await response.Content.ReadAsStringAsync();
returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(responsedata);
if (returnObj.d.Next == null)
continue;
}
results.Add(returnObj);
}
return results;

How to get Bitcoin value for corresponding USD value in ASP.NET C#?

I want to get Bitcoin value for corresponding USD value and store it in table or variable. I got this URL from which I can get a Bitcoin value for USK amount. I searched on blockchain and I found this URL.
For example:
500usd = 0.76105818 btc
I tried:
https://blockchain.info/tobtc?currency=USD&value=500
at the end, its USD value which we want to convert in Bitcoin.
I want to get the result in the variable in C# (backend).
How can I accomplish this?
You need to just make call to server and parse the response.
var uri = String.Format("https://blockchain.info/tobtc?currency=USD&value={0}", 500);
WebClient client = new WebClient();
client.UseDefaultCredentials = true;
var data = client.DownloadString(uri);
var result = Convert.ToDouble(data);
Install-Package CoinMarketCapClient
using CoinMarketCap;
public static async Task<double> GetBitcoinInUsd(double usd){
//https://api.coinmarketcap.com/v1/ticker/bitcoin/
CoinMarketCapClient client = CoinMarketCapClient.GetInstance();
var entity = await client.GetTickerAsync("bitcoin");
return entity.PriceUsd * usd;
}
var uri = String.Format(#"https://blockchain.info/tobtc?currency=USD&value={0}",1);
WebClient client = new WebClient();
client.UseDefaultCredentials = true;
var data = client.DownloadString(uri);
var result = 1/Convert.ToDouble(data.Replace('.',',')); //you will receive 1 btc = result;
There are several APIs out there that will allow you to request the prices for a list of crypto currencies, and/or fiat currencies. The problem is that all the APIs do it in a disparate way. The follow on from that is that any one could be down at any given time, so you need to have some failure tolerance built in. I.e. the code should attempt to use one API, and if that fails, move to the next. Of course, this is further complicated by the fact that price is subjective and localised to a given country, exchange and so on. So, getting an accurate value is very difficult.
Here is example Crypto Compare client from CryptoCurrency.Net (https://github.com/MelbourneDeveloper/CryptoCurrency.Net/blob/master/src/CryptoCurrency.Net/APIClients/PriceEstimationClients/CryptoCompareClient.cs):
public class CryptoCompareClient : PriceEstimationClientBase, IPriceEstimationClient
{
public CryptoCompareClient(IRestClientFactory restClientFactory) : base(restClientFactory)
{
RESTClient = restClientFactory.CreateRESTClient(new Uri("https://min-api.cryptocompare.com"));
}
protected override Func<GetPricesArgs, Task<EstimatedPricesModel>> GetPricesFunc { get; } = async a =>
{
var retVal = new EstimatedPricesModel();
if (a.Currencies.ToList().Count == 0)
{
return retVal;
}
retVal.LastUpdate = DateTime.Now;
var symbolsPart = string.Join(",", a.Currencies.Select(c => c.Name));
var priceJson = await a.RESTClient.GetAsync<string>($"data/pricemultifull?fsyms={symbolsPart}&tsyms={a.FiatCurrency}");
var jObject = (JObject)JsonConvert.DeserializeObject(priceJson);
var rawNode = (JObject)jObject.First.First;
foreach (JProperty coinNode in rawNode.Children())
{
var fiatNode = (JProperty)coinNode.First().First;
var allProperties = fiatNode.First.Children().Cast<JProperty>().ToList();
var change24HourProperty = allProperties.FirstOrDefault(p => string.Compare(p.Name, "CHANGEPCT24HOUR", true) == 0);
var priceProperty = allProperties.FirstOrDefault(p => string.Compare(p.Name, "PRICE", true) == 0);
var price = (decimal)priceProperty.Value;
var change24Hour = (decimal)change24HourProperty.Value;
retVal.Result.Add(new CoinEstimate { CurrencySymbol = new CurrencySymbol(coinNode.Name), ChangePercentage24Hour = change24Hour, FiatEstimate = price, LastUpdate = DateTime.Now });
}
//Extreme hack. It's better to show zero than nothing at all and get the coins stuck
foreach (var currency in a.Currencies)
{
if (retVal.Result.FirstOrDefault(ce => ce.CurrencySymbol.Equals(currency)) == null)
{
retVal.Result.Add(new CoinEstimate { ChangePercentage24Hour = 0, CurrencySymbol = currency, FiatEstimate = 0, LastUpdate = DateTime.Now });
}
}
return retVal;
};
}
The PriceEstimationManager will flick through APIs until it finds one that works (https://github.com/MelbourneDeveloper/CryptoCurrency.Net/blob/master/src/CryptoCurrency.Net/APIClients/PriceEstimationClients/PriceEstimationManager.cs):
public class PriceEstimationManager
{
#region Fields
private readonly Collection<IPriceEstimationClient> _Clients = new Collection<IPriceEstimationClient>();
#endregion
#region Constructor
public PriceEstimationManager(IRestClientFactory restClientFactory)
{
foreach (var typeInfo in typeof(PriceEstimationManager).GetTypeInfo().Assembly.DefinedTypes)
{
var type = typeInfo.AsType();
if (typeInfo.ImplementedInterfaces.Contains(typeof(IPriceEstimationClient)))
{
_Clients.Add((IPriceEstimationClient)Activator.CreateInstance(type, restClientFactory));
}
}
}
#endregion
#region Public Methods
/// <summary>
/// TODO: This needs to be averaged. The two current clients give wildly different values. Need to include some Australian exchanges etc.
/// </summary>
public async Task<EstimatedPricesModel> GetPrices(IEnumerable<CurrencySymbol> currencySymbols, string fiatCurrency)
{
//Lets try a client that hasn't been used before if there is one
var client = _Clients.FirstOrDefault(c => c.AverageCallTimespan.TotalMilliseconds == 0);
var currencies = currencySymbols.ToList();
if (client != null)
{
try
{
return await client.GetPrices(currencies, fiatCurrency);
}
catch
{
//Do nothing
}
}
foreach (var client2 in _Clients.OrderBy(c => c.SuccessRate).ThenBy(c => c.AverageCallTimespan).ToList())
{
try
{
return await client2.GetPrices(currencies, fiatCurrency);
}
catch (Exception ex)
{
Logger.Log("Error Getting Prices", ex, nameof(PriceEstimationManager));
}
}
throw new Exception("Can't get prices");
}
#endregion
}
At a higher level, you can use the code like this (https://github.com/MelbourneDeveloper/CryptoCurrency.Net/blob/master/src/CryptoCurrency.Net.UnitTests/PricingTests.cs):
public async Task GetUSDBitcoinPrice()
{
var priceEstimationManager = new PriceEstimationManager(new RESTClientFactory());
var estimatedPrice = await priceEstimationManager.GetPrices(new List<CurrencySymbol> { CurrencySymbol.Bitcoin }, "USD");
Console.WriteLine($"Estimate: {estimatedPrice.Result.First().FiatEstimate}");
}
As more pricing clients are added, it will get more and more reliable.

Categories