The old code I've inherited for Twilio retrieves messages using the absolute PageNumber property of the MessageListRequest but according to the documentation this is obsolete and I should be using GetNextPage and GetPrevPage.
The API metadata shows this as obsolete with the message "Use GetNextPage and GetPreviousPage for paging. Page parameter is scheduled for end of life https://www.twilio.com/engineering/2015/04/16/replacing-absolute-paging-with-relative-paging".
Are there any examples of this usage? I couldn't find any in the documentation except in one of the API test methods and I'm not sure how well I can get to processing multiple pages with this example as a guide.
public class Foo : TwilioBase
{
public string Bar { get; set; }
}
public class FooResult : TwilioListBase
{
public List<Foo> Foos { get; set; }
}
[Test]
public void ShouldGetNextPage()
{
IRestRequest savedRequest = null;
FooResult firstPage = new FooResult();
firstPage.NextPageUri = new Uri("/Foos?PageToken=abc123", UriKind.Relative);
mockClient.Setup(trc => trc.Execute<FooResult>(It.IsAny<IRestRequest>()))
.Callback<IRestRequest>((request) => savedRequest = request)
.Returns(new FooResult());
var client = mockClient.Object;
var response = client.GetNextPage<FooResult>(firstPage);
mockClient.Verify(trc => trc.Execute<FooResult>(It.IsAny<IRestRequest>()), Times.Once);
Assert.IsNotNull(savedRequest);
Assert.AreEqual("/Foos?PageToken=abc123", savedRequest.Resource);
Assert.AreEqual(Method.GET, savedRequest.Method);
Assert.IsNotNull(response);
}
The old usage might look something like so:
var twilio = new TwilioRestClient(config.AccountSid, config.AuthToken);
var result = new List<Message>();
MessageResult tempResult;
int page = 0;
do
{
var request = new MessageListRequest();
request = new MessageListRequest { Count = 1000, DateSent = newestDate, DateSentComparison = ComparisonType.GreaterThanOrEqualTo, PageNumber = page++, To = config.FromNumber };
tempResult = twilio.ListMessages(request);
result.AddRange(tempResult.Messages);
} while (tempResult.NextPageUri != null);
Finally, I built the Twilio API 3.4.1.0 from the twilio-csharp GitHub project instead of NuGet since I need to update it to use the MessagingServiceSid which isn't included in the API yet.
Thanks for any pointers. I'll post a solution if I can figure it out on my own.
Actually, I got it to work now!
MessageResult messages = twilio.ListMessages(request);
do
{
if (messages.Messages != null)
{
foreach (var message in messages.Messages)
{
... process results
}
if (messages.NextPageUri != null)
{
messages = twilio.GetNextPage<MessageResult>(messages);
}
}
} while (messages.NextPageUri != null);
Did you try the example from the API Explorer?
https://www.twilio.com/console/dev-tools/api-explorer/sms/sms-mms-list
var twilio = new TwilioRestClient(AccountSid, AuthToken);
// Build the parameters
var options = new MessageListRequest();
var messages = twilio.ListMessages(options);
foreach (var message in messages.Messages)
{
Console.WriteLine(message.Body);
}
The helper library will automatically fetch from the API as you loop over the list until all records matching your criteria are processed.
You can limit the results with MessageListRequest.
Please give that a try and let me know how it goes.
Related
In my Asp.Net Core 3.1 project I am using AmazonEC2Client for getting info about AWS instances.
I implemented helper method for getting instance list.Method looks like:
public static async Task<List<string>> AwsList(string awsAccessKeyId, string
awsSecretAccessKey)
{
AmazonEC2Client client = new AmazonEC2Client(awsAccessKeyId,awsSecretAccessKey,
RegionEndpoint.EUWest1);
bool done = false;
var instanceIds = new List<string>();
DescribeInstancesRequest request = new DescribeInstancesRequest();
while (!done)
{
DescribeInstancesResponse response = await
client.DescribeInstancesAsync(request);
foreach ( Reservation reservation in response.Reservations)
{
foreach (Instance instance in reservation.Instances)
{
instanceIds.Add(instance.InstanceType);
}
}
request.NextToken= response.NextToken;
if (response.NextToken == null)
{
done = true;
}
}
return instanceIds;
}
Json result is:
[
"t3a.xlarge",
"t2.medium",
"t2.medium",
"t2.micro",
"t3a.xlarge",
"t2.medium",
"t3a.xlarge",
"t3a.xlarge",
"t3a.xlarge"
]
I dont know ram and cpu info inside instance type or not, no experience with aws.
I would like to get cpu and ram info according to instance type.
Later I would like to create method which is accepting string instanceType and according to this get ram and cpu.
For ex: GetRam("t2.micro") -> 2gb
Instead of using DescribeInstanceRequests need to be use DescribeInstanceTypesRequest and appropriate response as well.
foreach ( var instanceType in response.InstanceTypes.Where(x => x.InstanceType == name))
{
instanceIds.Add(instanceType.MemoryInfo.SizeInMiB); // ram
instanceIds.Add(instanceType.VCpuInfo.DefaultVCpus); //cpu
}
I am trying to get the below working from https://github.com/simplefx-ltd/simplefx-api
Request:
{
"H":"quotessubscribehub",
"M":"getLastPrices",
"A":[["BTCUSD","LTCUSD","ETHUSD","TLRY.US","GWPH.US"]],
"I":0
}
hub - quotessubscribehub
method - getLastPrices
arguments:
0 - list of instruments - ["BTCUSD","LTCUSD","ETHUSD","TLRY.US","GWPH.US"]
My first attempt in c# is as follows;
[Command]
public async void LiveTrades()
{
var trades = new List<String>() { "BTCUSD", "LTCBTC" };
var hubConnection = new HubConnection("https://webquotes-v3.simplefx.com/signalr/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("quotessubscribehub");
hubConnection.Headers.Add("H", "quotessubscribehub");
hubConnection.Headers.Add("M", "getLastPrices");
hubConnection.Headers.Add("A", trades.ToString());
hubConnection.Headers.Add("I", "0");
stockTickerHubProxy.On<LiveSymbols>("getLastPrices", stock => TradePrice = stock.R.Data.ToString());
await hubConnection.Start();
}
I'm not 100%, but maybe the arguments list is causing me the main problem.
Any help would be gratefully accepted.
Many thanks
Scott
**Edit:
Looks like I have the list of instruments correct now.
var trades = new List<String>() { "BTCUSD", "LTCBTC" };
string output = new JavaScriptSerializer().Serialize(trades);
returns
["BTCUSD","LTCBTC"]
Connection seems good, but not returning any items to me. Will keep trying
This solved it.
var trades = new List<String>() { "BTCUSD", "LTCBTC" };
await hubConnection.Start();
var returnValue = await stockTickerHubProxy.Invoke<R>("getLastPrices", trades);
I am trying to build a small app in C# to retrieve suggested meeting times from the Microsoft Graph API. After authenticating, I call graphClient.HttpProvider.SendAsync(t); to hopefully get suggested meeting times. However, stepping through with breakpoints everything seems to go fine until that call and then the FindMeetingTimes request content is empty/null.
Calling with: eventsService.RunAsync();
internal async Task RunAsync()
{
try
{
// Create request object
var findMeetingTimeRequest = new FindMeetingTimeRequestModel
{
Attendees = new List<AttendeeBase>
{
new AttendeeBase
{
EmailAddress = new EmailAddress {Address = "myaddress#domain.com" },
Type = AttendeeType.Required
}
},
LocationConstraint = new LocationConstraint
{
IsRequired = true,
SuggestLocation = false,
Locations = new List<LocationItemModel>
{
new LocationItemModel{ DisplayName = "A116", Address = null, Coordinates = null }
}
},
TimeConstraint = new TimeConstraintModel
{
TimeSlots = new List<TimeSlotModel>
{
new TimeSlotModel
{
Start = new DateTimeValueModel
{
Date = "2018-03-23",
Time = "08:00:00",
TimeZone = "Central Standard Time"
},
End = new DateTimeValueModel
{
Date = "2018-03-23",
Time = "09:00:00",
TimeZone = "Central Standard Time"
}
}
}
},
MeetingDuration = new Duration("PT1H"),
MaxCandidates = 99,
IsOrganizerOptional = false,
ReturnSuggestionHints = false
};
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
var t = graphClient.Me.FindMeetingTimes(findMeetingTimeRequest.Attendees, findMeetingTimeRequest.LocationConstraint, findMeetingTimeRequest.TimeConstraint, findMeetingTimeRequest.MeetingDuration, findMeetingTimeRequest.MaxCandidates, findMeetingTimeRequest.IsOrganizerOptional).Request().GetHttpRequestMessage();
await graphClient.AuthenticationProvider.AuthenticateRequestAsync(t);
var response = await graphClient.HttpProvider.SendAsync(t);
var jsonString = await response.Content.ReadAsStringAsync();
Console.WriteLine(jsonString);
return;
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
I'm sort of at a loss as to what to try next. I have looked through examples and there's only a handful out there so far that use GraphServiceClient/SDKHelper to authenticate. Could this be part of the problem?
I get both exceptions during await graphClient.HttpProvider.SendAsync(t);:
Exception thrown: 'Microsoft.Graph.ServiceException' in Microsoft.Graph.Core.dll
Exception thrown: 'System.NullReferenceException' in System.Web.dll
Update: Using both the reference in Michael's comment below and the original code with an empty argument list for FindMeetingTimes(), I'm getting a credentials exception:
"Code: ErrorAccessDenied\r\nMessage: Access is denied. Check credentials and try again.\r\n\r\nInner error\r\n"
Calling with
await eventsService.EventFindMeetingsTimes(graphClient);
public async System.Threading.Tasks.Task EventFindMeetingsTimes(GraphServiceClient graphClient)
{
try
{
User me = await graphClient.Me.Request().GetAsync();
// Get the first three users in the org as attendees unless user is the organizer.
var orgUsers = await graphClient.Users.Request().GetAsync();
List<Attendee> attendees = new List<Attendee>();
Attendee attendee = new Attendee();
attendee.EmailAddress = new EmailAddress();
attendee.EmailAddress.Address = "name#domain.com";
attendees.Add(attendee);
// Create a duration with an ISO8601 duration.
Duration durationFromISO8601 = new Duration("PT1H");
MeetingTimeSuggestionsResult resultsFromISO8601 = await graphClient.Me.FindMeetingTimes(attendees,
null,
null,
durationFromISO8601,
2,
true,
false,
10.0).Request().PostAsync();
List<MeetingTimeSuggestion> suggestionsFromISO8601 = new List<MeetingTimeSuggestion>(resultsFromISO8601.MeetingTimeSuggestions);
}
catch (Exception e)
{
Console.WriteLine("Something happened, check out a trace. Error code: {0}", e.Message);
}
}
The account I'm using to log in works when I test with the GraphExplorer. Is it possible the credentials/token aren't being passed down through the web form and into the graph client?
SOLUTION: Graph Docs example <-- Provided by Michael helped set up the formatting correctly.
Find meeting times problem #559 <-- Tipped off by Marc that the permissions in the end needed updated and eventually solved my updated problem.
You forgot to set the HttpMethod before SendAsync(t). It is using GET instead of POST.
t.Method = System.Net.Http.HttpMethod.Post;
With that said, I agree with Mark. Use the built in functionality of the client library:
https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/tests/Microsoft.Graph.Test/Requests/Functional/EventTests.cs#L88
Without more detail, it is difficult to determine what is going wrong here. That said, you should start with simplifying this code. That will at least reduce the number of moving parts:
var result = await graphClient.Me.FindMeetingTimes()
.Request()
.PostAsync();
if (!string.IsNullOrWhiteSpace(result.EmptySuggestionsReason))
{
Console.WriteLine(result.EmptySuggestionsReason);
}
else
{
foreach (var item in result.MeetingTimeSuggestions)
{
Console.WriteLine($"Suggestion: {item.SuggestionReason}");
}
}
If this fails, be sure to capture the entire exception and update your question.
I am having a scenario in CRM where I need to update multiple accounts values(text fields and option sets) with values from an external sql database table. How can I go about doing this using the execute multiple request. The requirement is to sync all the account data in CRM with our ERP data which comes from a sql table. This process needs to be automated so i opted to use a windows service that runs daily to update accounts that ar flagged for update in the external sql table. I am struggling to find the best approach for this,I tested this idea in a console application on DEV and here is my solution code below. My question is how can I do this better using ExecuteMultipleRequest request.
public static void UpdateAllCRMAccountsWithEmbraceAccountStatus(IOrganizationService service, CRM_Embrace_IntegrationEntities3 db)
{
List<C_Tarsus_Account_Active_Seven__> crmAccountList = new List<C_Tarsus_Account_Active_Seven__>();
//Here I get the list from Staging table
var crmAccounts = db.C_Tarsus_Account_Active_Seven__.Select(x => x).ToList();
foreach (var dbAccount in crmAccounts)
{
CRMDataObjectFour modelObject = new CRMDataObjectFour()
{
ID = dbAccount.ID,
Account_No = dbAccount.Account_No,
Account_Name = dbAccount.Account_Name,
Account_Status = Int32.Parse(dbAccount.Account_Status.ToString()),
Country = dbAccount.Country,
Terms = dbAccount.Terms
};
}
var officialDatabaseList = crmAccounts;
//Here I query CRM to
foreach (var crmAcc in officialDatabaseList)
{
QueryExpression qe = new QueryExpression();
qe.EntityName = "account";
qe.ColumnSet = new ColumnSet("accountnumber", "new_embraceaccountstatus");
qe.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0);
qe.Criteria.AddCondition("accountnumber", ConditionOperator.NotIn, "List of acconts for example"
);
EntityCollection response = service.RetrieveMultiple(qe);
//Here I update the optionset value
foreach (var acc in response.Entities)
{
if (acc.Attributes["accountnumber"].ToString() == crmAcc.Account_No)
{
if (acc.Contains("new_embraceaccountstatus"))
{
continue;
}
else
{
acc.Attributes["new_embraceaccountstatus"] = new OptionSetValue(Int32.Parse(crmAcc.Account_Status.ToString()));
}
service.Update(acc);
}
}
}
}
I know this might not be the right approach, please advise me how to use ExecuteMultipleRequest or perhaps a different solution altogether.
Here is some helper methods I've used before to handle this:
public static ExecuteMultipleRequest MultipleRequest { get; set; }
private const int BatchSize = 250;
public static long LastBatchTime { get; set; }
private static void Batch(IOrganizationService service, OrganizationRequest request)
{
if (MultipleRequest.Requests.Count == BatchSize)
{
ExecuteBatch(service);
}
MultipleRequest.Requests.Add(request);
}
private static void ExecuteBatch(IOrganizationService service)
{
if (!MultipleRequest.Requests.Any())
{
return;
}
Log("Executing Batch size {0}. Last Batch was executed in {1}",MultipleRequest.Requests.Count, LastBatchTime);
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
var response = (ExecuteMultipleResponse)service.Execute(MultipleRequest);
watch.Stop();
LastBatchTime = watch.ElapsedMilliseconds;
Log("Completed Executing Batch in " + watch.ElapsedMilliseconds);
WriteLogsToConsole();
var errors = new List<string>();
// Display the results returned in the responses.
foreach (var responseItem in response.Responses)
{
// A valid response.
if (responseItem.Fault != null)
{
errors.Add(string.Format(
"Error: Execute Multiple Response Fault. Error Code: {0} Message {1} Trace Text: {2} Error Keys: {3} Error Values: {4} ",
responseItem.Fault.ErrorCode,
responseItem.Fault.Message,
responseItem.Fault.TraceText,
responseItem.Fault.ErrorDetails.Keys,
responseItem.Fault.ErrorDetails.Values));
}
}
MultipleRequest.Requests.Clear();
if (errors.Any())
{
throw new Exception(string.Join(Environment.NewLine, errors));
}
}
You can then call this from your normal logic like so:
public static void UpdateAllCRMAccountsWithEmbraceAccountStatus(IOrganizationService service, CRM_Embrace_IntegrationEntities3 db)
{
List<C_Tarsus_Account_Active_Seven__> crmAccountList = new List<C_Tarsus_Account_Active_Seven__>();
//Here I get the list from Staging table
var crmAccounts = db.C_Tarsus_Account_Active_Seven__.Select(x => x).ToList();
foreach (var dbAccount in crmAccounts)
{
CRMDataObjectFour modelObject = new CRMDataObjectFour()
{
ID = dbAccount.ID,
Account_No = dbAccount.Account_No,
Account_Name = dbAccount.Account_Name,
Account_Status = Int32.Parse(dbAccount.Account_Status.ToString()),
Country = dbAccount.Country,
Terms = dbAccount.Terms
};
}
var officialDatabaseList = crmAccounts;
//Here I query CRM to
foreach (var crmAcc in officialDatabaseList)
{
QueryExpression qe = new QueryExpression();
qe.EntityName = "account";
qe.ColumnSet = new ColumnSet("accountnumber", "new_embraceaccountstatus");
qe.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0);
qe.Criteria.AddCondition("accountnumber", ConditionOperator.NotIn, "List of acconts for example");
EntityCollection response = service.RetrieveMultiple(qe);
//Here I update the optionset value
foreach (var acc in response.Entities)
{
if (acc.Attributes["accountnumber"].ToString() == crmAcc.Account_No)
{
if (acc.Contains("new_embraceaccountstatus"))
{
continue;
}
else
{
acc.Attributes["new_embraceaccountstatus"] = new OptionSetValue(Int32.Parse(crmAcc.Account_Status.ToString()));
}
Batch(service, new UpdateRequest { Target = acc });
}
}
}
// Call ExecuteBatch to ensure that any batched requests, get executed.
ExeucteBatch(service)
}
Because it is 2013, and you need to sync records, you'll need to know if some previous records were already in CRM, because depending on that you'll need to send a bunch of Create's or Update's. I would do it in 2 batches of ExecuteMultiple:
1) One batch to execute a query to find which accounts need to be created / updated in CRM, depending on some matching field there.
2) Another batch which will use the previous one to generate all Create / Update operations in one go, depending on the responses you got from 1).
The issue is that they won't run in the same transaction, and that's something which was improved in 2016, as #Daryl said. There is also a new request in 2016 which might improve things even further, because you could merge the 2 batches into one: Upsert, therefore avoiding unnecessary roundtrips to the server.
Maybe this was inspired on Mongo Db's upsert concept which existed long time before? Who knows :)
If you just need to now how to perform an ExecuteMultipleRequest there are samples on the MSDN. Sample: Execute multiple requests.
I'm still a beginner for .NET, C#, RESTful API. Now, I'm learning the POST method in RESTful API. Here is the sample coding of POST method, but I still can't get the meaning of the coding. Can anyone provide me an explanation for each line of the coding in a clearly understand way? Or if you don't mind, can you explain it to me by using comment style? For example:
public string message; //to declare message for what use...`
public class MessageController : ApiController
{
// GET api/values
public class MessageToShow
{
public string message;
public string from;
}
public List<MessageToShow> Get()
{
var x = new cheeAdDCClf3rfFREntities();
var y=x.messages.Take(100);
List<MessageToShow> messageToShow = new List<MessageToShow>();
foreach (var xx in y)
{
MessageToShow m = new MessageToShow();
member me = x.members.FirstOrDefault(j => j.ID == xx.from);
if (me != null)
{
m.from = me.username;
m.message = xx.message1;
messageToShow.Add(m);
}
}
return messageToShow;
}
// POST api/values
public void Post(int memberid, dynamic value)
{
var x = new cheeAdDCClf3rfFREntities();
message m = new message();
m.ID = x.messages.Max(record => record.ID) + 1;
m.from = memberid;
m.message1 = value.value;
x.messages.Add(m);
x.SaveChanges();
}
}
}
I would be very appreciate if anyone would like to share me your knowledge on programming. Thank you so much!!! ^_^
It looks like you posted code for both a GET and POST method.
When I make a GET to your API:
public List<MessageToShow> Get()
{
// Looks like EntityFramework? Represents the items already in database
var x = new cheeAdDCClf3rfFREntities();
// Take to top 100 item already in the database
var y=x.messages.Take(100);
// Create a new list to hold the messages we will return
List<MessageToShow> messageToShow = new List<MessageToShow>();
// For each message in the 100 we just took
foreach (var xx in y)
{
MessageToShow m = new MessageToShow();
// Get the details of the member that send this message
member me = x.members.FirstOrDefault(j => j.ID == xx.from);
// If we found the member, create a message to show
// (populating the message and the username of the member
// who sent it)
if (me != null)
{
m.from = me.username;
m.message = xx.message1;
messageToShow.Add(m);
}
}
// Return the list of messages we just created to the caller of the API
return messageToShow;
}
When I POST to your API this is what happens:
public void Post(int memberid, dynamic value)
{
// Gets the items already in the database
var x = new cheeAdDCClf3rfFREntities();
// Create a new message object
message m = new message();
// Find the highest ID already in the database, then add 1. This is the
// ID for our new item
m.ID = x.messages.Max(record => record.ID) + 1;
// The 'from' property is set to the memberId that the user passed in the POST
m.from = memberid;
// The 'message' property is set to whatever dynamic value is passed in the POST
m.message1 = value.value;
// Add the message to the database
x.messages.Add(m);
x.SaveChanges();
}
To understand more about REST, you can read this:
A beginners Guide To HTTP and REST
The code you posted actually looks more like EntityFramework, which is a way of interacting with a database. It's not specific to APIs.
You can find our more about EF here:
EntityFramework