Discord.net better Help command - c#

So I've got a basic help command which takes the summery and remarks and it works great now. But it looks chunky when every command is together and every other line the text is darker, is there a way to fix both these issues. Here's the code:
public class HelpHandler : ModuleBase<SocketCommandContext>
{
private readonly CommandService _service;
public HelpHandler(CommandService service)
{
Global.ConsoleLog("Started HelpHandler", ConsoleColor.Blue);
_service = service;
}
[Command("help")]
public async Task HelpAsync()
{
var builder = new EmbedBuilder()
{
Color = new Color(114, 137, 218),
Description = "These are the commands you can use"
};
foreach (var module in _service.Modules)
{
string description = null;
foreach (var cmd in module.Commands)
{
var result = await cmd.CheckPreconditionsAsync(Context);
if (result.IsSuccess)
description += $"{Global.Preflix}{cmd.Aliases.First()}\n";
}
if (!string.IsNullOrWhiteSpace(description))
{
builder.AddField(x =>
{
x.Name = module.Name;
x.Value = description;
x.IsInline = false;
});
}
}
await ReplyAsync("", false, builder.Build());
}
}
So to be more specific, is there a way to make it so that I can have different cards full of x amount of commands each and they you can scroll threw them with emoji reactions such as backwards and forwards? And is there a way to remove the horrible way it goes darker every other line of text for no apparent reason?
Thanks!

Related

Mongo Tailable cursor not working when trying to run in separate thread

I am trying to use Mongo Tailable cursor in my application I am using below code to create capped collection and tailable cursor
using MongoDB.Bson;
using MongoDB.Driver;
public static class TailableCursor
{
private const string DbUrl = ""//TODO use actual connectionstring
private const string DbName = "Test_App";
private const string CollectionName = "ExchangeMessage";
public static bool CreateCollection()
{
var name = "ExchangeMessage";
var count = 100;
var client = new MongoClient(new MongoUrl(DbUrl));
#pragma warning disable CS0618 // Type or member is obsolete
var server = client.GetServer();
#pragma warning restore CS0618 // Type or member is obsolete
var db = server.GetDatabase(DbName);
if (db == null)
{
return false;
}
if (!db.CollectionExists(name))
{
var options = new CollectionOptionsDocument(new Dictionary<string, object> {
{ "capped", true },
{ "size", count * 1024 },
{ "max", count }
});
db.CreateCollection(name, options);
var collection = db.GetCollection(name);
collection.Insert(new ExchangeMessage());
}
else
{
var collection = db.GetCollection(name);
if (collection.Count() == 0)
{
collection.Insert(new ExchangeMessage());
}
}
server.Disconnect();
return true;
}
public static void SubscribeTailAbleCursor()
{
var client = new MongoClient(new MongoUrl(DbUrl));
var database = client.GetDatabase(DbName);
var collection = database.GetCollection<BsonDocument>(CollectionName);
// Set lastInsertDate to the smallest value possible
BsonValue lastInsertDate = BsonMinKey.Value;
var options = new FindOptions<BsonDocument>
{
// Our cursor is a tailable cursor and informs the server to await
CursorType = CursorType.TailableAwait,
NoCursorTimeout = true
};
// Initially, we don't have a filter. An empty BsonDocument matches everything.
BsonDocument filter = new BsonDocument();
// NOTE: This loops forever. It would be prudent to provide some form of
// an escape condition based on your needs; e.g. the user presses a key.
int i = 0;
while (true)
{
//// Start the cursor and wait for the initial response
//using (var cursor = collection.FindSync(filter, options))
var cursor = collection.FindSync(filter, options);
{
foreach (var document in cursor.ToEnumerable())
{
i++;
// Set the last value we saw
lastInsertDate = document["InsertDate"];
Console.WriteLine(i.ToString());
// Write the document to the console.
Console.WriteLine(document.ToString());
}
}
// The tailable cursor died so loop through and restart it
// Now, we want documents that are strictly greater than the last value we saw
filter = new BsonDocument("$gt", new BsonDocument("InsertDate", lastInsertDate));
}
}
}
//The above code work when called as below from startup or main method but it blocks main //thread
TailableCursor.CreateCollection();
TailableCursor.SubscribeTailAbleCursor();
//When I try to run code in separate thread tailable cursor does not work.
Task.Run(async () =>{
TailableCursor.CreateCollection();
TailableCursor.SubscribeTailAbleCursor();
});

Roslyn scripting entry point?

I am building a REPL interface with Blazor webassembly.
I have build a textarea where you can write code. The code compiles successfully. The problem is that the textarea is empty. Normally, as a C# developer, you would see an entry point (the Main method) by which the program starts.
How do I fix that?
Try dotnet is an good example of what I want to achieve. In my case the textarea is empty, but I can program in there. Not sure what the entry point is in my case.
I am really stuck here since I cannot find much about Roslyn scripting with Blazor.
Please help me out.
My code to compile input:
private ScriptState _scriptState = null;
private StringWriter _sw;
private string _output;
public ChallengeCompiler()
{
_sw = new StringWriter();
Console.SetOut(_sw);
Console.SetError(_sw);
}
public string CompileCode(string input)
{
string[] references =
{
"System",
"System.Collections",
"System.Collections.Generic",
"System.Collections.Concurrent",
"System.Console",
"System.Diagnostics.Debug",
"System.Diagnostics.Process",
"System.Diagnostics.StackTrace",
"System.Globalization",
"System.IO",
"System.Reflection",
"System.Runtime",
"System.Runtime.InteropServices",
"System.Text",
"System.Text.Encoding",
"System.Text.RegularExpressions",
"System.Threading",
"System.Threading.Tasks",
"System.Threading.Tasks.Parallel",
"System.Threading.Thread",
"System.ValueTuple",
};
try
{
if (_scriptState == null)
{
_scriptState = CSharpScript.RunAsync(input, ScriptOptions.Default.WithImports(references)).Result;
}
else
{
_scriptState = _scriptState.ContinueWithAsync(input).Result;
}
if (_scriptState.ReturnValue != null && !string.IsNullOrEmpty(_scriptState.ReturnValue.ToString()))
{
_output = _scriptState.ReturnValue.ToString();
}
else
{
_output = _sw.ToString();
}
}
catch (CompilationErrorException e)
{
_output = "-----------------------------------\n";
_output += string.Join(Environment.NewLine, e.Diagnostics);
}
return _output;
}

Given a connected and ready DiscordSocketClient and a Discord Channel Id, How does one send a message to that channel?

I am trying to set up automated messages.
When I am setting up my client I use:
client.Ready += OnClientReady;
From there I start my Scheduler class:
private Task OnClientReady()
{
var scheduler = new Scheduler(client);
scheduler.Start();
return Task.CompletedTask;
}
Which looks like this:
public class Scheduler
{
private readonly DiscordSocketClient _client;
private static Timer _timer;
public void Start(object state = null)
{
Sender.Send(_client);
_timer = new Timer(Start, null, (int)Duration.FromMinutes(1).TotalMilliseconds, 0);
}
public Scheduler(DiscordSocketClient client)
{
_client = client;
}
}
When the timer ticks, it calls out and passes the client to the Sender class below:
public static class Sender
{
public static void Send(DiscordSocketClient client)
{
var currentLocalDateTime = SystemClock.Instance.InTzdbSystemDefaultZone().GetCurrentLocalDateTime();
var elapsedRotations = new List<Rotations>();
using (var db = new GOPContext())
{
elapsedRotations = db.Rotations
.Include(r => r.RotationUsers)
.Where(r => r.LastNotification == null ||
Period.Between(r.LastNotification.Value.ToLocalDateTime(),
currentLocalDateTime).Hours >= 23)
.ToList();
}
foreach (var rotation in elapsedRotations)
{
var zone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(rotation.Timezone);
var zonedDateTime = SystemClock.Instance.InZone(zone).GetCurrentZonedDateTime();
if (zonedDateTime.Hour != 17)
continue;
//I need to send a message to the channel here.
//I have access to the connected / ready client,
//and the channel Id which is "rotation.ChannelId"
}
}
}
I have tried getting the channel like this:
var channel = client.GetChannel((ulong) rotation.ChannelId);
which gives me a SocketChannel and also like this:
var channel = client.Guilds
.SelectMany(g => g.Channels)
.SingleOrDefault(c => c.Id == rotation.ChannelId);
which gives me a SocketGuildChannel. Neither of these give me an option to send a message directly to the channel. I have tried researching how to do this, but have not found anything... The documentation does not seem to have any examples of this...
It seems like a simple thing to do, but I'm at my wits end on it. Anybody know how to do this?
This is because both SocketGuildChannel and SocketChannel could be either a voice or a text channel.
Instead you want the ISocketMessageChannel, IMessageChannel or SocketTextChannel
To get this you could simply cast the SocketChannel you are getting
var channel = client.GetChannel((ulong) rotation.ChannelId);
var textChannel = channel as IMessageChannel;
if(textChannel == null)
// this was not a text channel, but a voice channel
else
textChannel.SendMessageAsync("This is a text channel");

SSIS Custom Data-Flow Component being Automatically Removed when Running under SQL Server 2016 (As Opposed to Visual Studio 2015)

I am working on an ETL process that is part of a larger system.
This larger system includes a logging system using a REST API.
The ETL section is running under SSIS, developed in Visual Studio 2015 and deployed on SQL Server 2016.
The ETL is covered with integration tests including tests of logs being generated.
The REST API cannot be guaranteed to be running during these integration tests, and even if it is, the asynchronous nature makes testing log generation... awkward.
We could use a script component to handle the logging, but we have 30+ packages requiring logging (each a distinct operation, based on a data-point to be calculated from one database into the next, so that a team can work concurrently without having TFS merge butcher XML definitions as much as possible), so maintenance becomes a headache.
In order to get around this, I have written a custom component that will bundle up all the errors across a package execution (separated into Fatal, Error, Warning, Info, and Detail levels), add a source, and fire JSON off to the REST API. In the event that the REST API is not specified, the system will log locally instead (which for the integration tests, means that we have a synchronous and local log source to check).
The ComponentType is ComponentType.DestinationAdapter.
The component has two custom properties, one for the variable name of the logging url (defaults to $Project::LoggingURL), one for the source of the log (defaults to System::PackageName).
The component validates the custom properties to not be blank.
The component has a single connection, defaulting to a master database, used as a fallback.
The component validates that the connection is set.
The component has multiple (five) inputs and no outputs.
Each input is marked as having side-effects.
Each attached input is validated as having a single input column of type DT_WSTR.
Unattached inputs are fine (a package that cannot log any fatal errors will leave that input unattached).
If any Fatal or Error messages are detected, the component fails the package in the Post-Execute step (in order to detect as many issues as possible in a run, rather than only the first).
The build targets 32-bit, and .NET Framework 4.
On Post-Build, the dll is copied to the DTS/PipelineComponents folder, and the assembly is deregistered then reregistered in the GAC.
When executing a package through Visual Studio (right-click on the package, 'Execute Package'), the component behaves exactly as expected.
When the package is deployed to the local SQL Server 2016 instance on my machine and the integration tests are run, the validation claims that the outputs leading into my component are not used and should be removed, and the component does nothing (as if it was never there). There are no messages about the component whatsoever.
I would very much like to have the component run in SQL Server, otherwise it is completely useless.
This is the code (there is an associated UI, but the Design-Time behaviour is as expected):
[DtsPipelineComponent(
DisplayName = "Custom Logging Component",
ComponentType = ComponentType.DestinationAdapter,
IconResource = "DestinationIcon",
CurrentVersion = 1,
UITypeName = "ETLCustomDataFlowComponents.CustomLoggingComponentUI,ETLCustomDataFlowComponents,Version=1.0.0.0,Culture=neutral,PublicKeyToken=051a7fa35dda5a9f"
)]
public class HermesCustomLoggingComponent : PipelineComponent
{
public const string _SOURCE_PROPERTY = "Source Name";
public const string _LOG_PROPERTY = "Log URL";
public const string _MASTER_CONN_PROPERTY = "Master Connection";
public override void ProvideComponentProperties()
{
base.ProvideComponentProperties();
base.RemoveAllInputsOutputsAndCustomProperties();
var loggingPath = ComponentMetaData.CustomPropertyCollection.New();
loggingPath.Description = "The url to send json log messages to";
loggingPath.Name = _LOG_PROPERTY;
loggingPath.Value = string.Empty;
loggingPath.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;
var source = ComponentMetaData.CustomPropertyCollection.New();
source.Description = "The source to which the log is to be attributed";
source.Name = _SOURCE_PROPERTY;
source.Value = string.Empty;
var masterConn = ComponentMetaData.RuntimeConnectionCollection.New();
masterConn.Name = _MASTER_CONN_PROPERTY;
masterConn.Description = "The connection to log.Log as a backup when centralised logging fails";
foreach (var level in new[] { "Fatal", "Error", "Warning", "Info", "Debug" })
{
var input = ComponentMetaData.InputCollection.New();
input.Name = level;
input.HasSideEffects = true;
}
}
public override DTSValidationStatus Validate()
{
bool broken = false;
bool cancel;
foreach (IDTSInput100 input in ComponentMetaData.InputCollection)
{
if (input.IsAttached)
{
if (input.InputColumnCollection.Count != 1)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{input.Name} should have only a message input", "", 0, out cancel);
broken = true;
}
else
{
if (input.InputColumnCollection[0].DataType != DataType.DT_WSTR)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"Input to {input.Name} is not of type DT_WSTR", "", 0, out cancel);
broken = true;
}
}
}
else
{
input.InputColumnCollection.RemoveAll();
}
}
if (ComponentMetaData.CustomPropertyCollection[_SOURCE_PROPERTY].Value == string.Empty)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_SOURCE_PROPERTY} parameter has not been set", "", 0, out cancel);
broken = true;
}
if (ComponentMetaData.CustomPropertyCollection[_LOG_PROPERTY].Value == string.Empty)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_LOG_PROPERTY} parameter has not been set", "", 0, out cancel);
broken = true;
}
if (ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager == null)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_MASTER_CONN_PROPERTY} has not been set", "", 0, out cancel);
broken = true;
}
if (broken)
{
return DTSValidationStatus.VS_ISBROKEN;
}
return base.Validate();
}
private readonly List<Dictionary<string, string>> _logMessages = new List<Dictionary<string, string>>();
private readonly Dictionary<int, IDTSInput100> _inputs = new Dictionary<int, IDTSInput100>();
private readonly Dictionary<string, int> _messageCounts = new Dictionary<string, int>();
private string _source = string.Empty;
private string _loggingPath = string.Empty;
private SqlConnection sqlConnection;
public override void AcquireConnections(object transaction)
{
if (ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager != null)
{
ConnectionManager cm = DtsConvert.GetWrapper(ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager);
ConnectionManagerAdoNet cmAdoNet = cm.InnerObject as ConnectionManagerAdoNet;
if (cmAdoNet == null) throw new Exception($"Connection Manager {cm.Name} is not ADO.NET");
sqlConnection = cmAdoNet.AcquireConnection(transaction) as SqlConnection;
if ((sqlConnection != null) && (sqlConnection.State != ConnectionState.Open)) sqlConnection.Open();
}
}
public override void ReleaseConnections()
{
if ((sqlConnection != null) && (sqlConnection.State != ConnectionState.Closed)) sqlConnection.Close();
}
public override void PreExecute()
{
var sourceVar = ComponentMetaData.CustomPropertyCollection[_SOURCE_PROPERTY].Value;
if (sourceVar != string.Empty)
{
IDTSVariables100 variables;
VariableDispenser.LockForRead(sourceVar);
VariableDispenser.GetVariables(out variables);
_source = variables[sourceVar].Value.ToString();
}
var loggingVar = ComponentMetaData.CustomPropertyCollection[_LOG_PROPERTY].Value;
if (loggingVar != string.Empty)
{
IDTSVariables100 variables;
VariableDispenser.LockForRead(loggingVar);
VariableDispenser.GetVariables(out variables);
_loggingPath = variables[loggingVar].Value.ToString();
}
foreach (IDTSInput100 input in ComponentMetaData.InputCollection)
{
_inputs[input.ID] = input;
_messageCounts[input.Name] = 0;
}
}
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
while (buffer.NextRow())
{
string message = buffer[0].ToString();
_messageCounts[_inputs[inputID].Name] += 1;
_logMessages.Add(new Dictionary<string, string>
{
{"Level", _inputs[inputID].Name},
{"InstanceId", Environment.MachineName},
{"Source", _source},
{"Message", message}
});
}
}
public override void PostExecute()
{
if (string.IsNullOrWhiteSpace(_loggingPath))
{
List<string> logMessagesList = new List<string>();
foreach (var logMessage in _logMessages)
{
logMessagesList.Add(
$"('{logMessage["Level"].Substring(0, 1)}', '{logMessage["Source"]}', '{logMessage["Message"]}')");
}
if ((sqlConnection != null) && (sqlConnection.State == ConnectionState.Open))
{
var command = sqlConnection.CreateCommand();
command.CommandText =
$"INSERT INTO log.Log ([Level], [Source], [Message]) VALUES {string.Join(", ", logMessagesList)}";
command.ExecuteNonQuery();
}
}
else
{
List<string> logMessagesList = new List<string>();
foreach (var logMessage in _logMessages)
{
List<string> logJsonList = new List<string>();
foreach (var logElement in logMessage)
{
logJsonList.Add($"\"{logElement.Key}\":\"{logElement.Value}\"");
}
var logString = string.Join(", ", logJsonList);
if (!logMessagesList.Contains(logString))
{
logMessagesList.Add(logString);
}
}
string logJson = "[{" + string.Join("}, {", logMessagesList) + "}]";
var request = (HttpWebRequest)WebRequest.Create(_loggingPath + "api/log");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = logJson.Length;
using (var requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII))
{
requestWriter.Write(logJson);
}
}
foreach (var level in new[] { "Fatal", "Error" })
{
if (_messageCounts[level] > 0)
{
bool cancel;
ComponentMetaData.FireError(0, _source, "Package has logged an exception, and cannot continue", "",
0,
out cancel);
}
}
}
public override void PerformUpgrade(int pipelineVersion)
{
ComponentMetaData.Version = 1;
}
}

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