Chain Email Display Broken by Updating Subject Exchange Online Service in C# - c#

I have read emails from exchnage online and in convesation emails i want to show only last email from its chain messages i have successfully doing that but in desktop outlook application i changed the subject then the Convesation chain mail is not working properly and chain is broken.
First I Have Group by ConvesationId.Then In-reply-to check for mail is convesation email or not.If Convesation email then find it in other way and simple mail then find it another way
It's ConvesationId And ConvesationIndex also changed.
public async Task<IActionResult> TrackEmail()
{
var cca = ConfidentialClientApplicationBuilder
.Create(Clientid)
.WithClientSecret(Clientsecret)
.WithTenantId(Tenantid)
.Build();
var scopes = new string[] { $"{_emailConfiguration.ScopeUrl}" };
var aquireToken = await cca.AcquireTokenForClient(scopes).ExecuteAsync();
aquireToken.ExpiresOn.UtcDateTime.AddMinutes(-5);
ExchangeService ewsClient = new(ExchangeVersion.Exchange2013_SP1);
ewsClient.Url = new Uri($"{_emailConfiguration.ExchangeUrl}");
ewsClient.Credentials = new OAuthCredentials(aquireToken.AccessToken);
ewsClient.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, $"{email}");
ewsClient.TraceEnabled = false;
ewsClient.TraceFlags = TraceFlags.None;
ewsClient.Timeout = 9000000;
if (ewsClient != null)
{
List<ProjectsDataModel>? projectsDataModel = (from p in _db.Projects
where p.Userid== userId
select new ProjectsDataModel
{
Id = p.Id,
ProjectName = p.Projectname,
ProjectDomain = p.Projectdomain,
CreatedDate = p.Createddate
}).ToList();
if (projectsDataModel != null)
{
foreach (var projectData in projectsDataModel)
{
EmailAddress sender = new(projectData.ProjectDomain);
ItemView view = new ItemView(int.MaxValue);
//SearchFilter.IsEqualTo filter = new SearchFilter.IsEqualTo(EmailMessageSchema.Sender, sender);
ExtendedPropertyDefinition PidTagSenderSmtpAddress = new(0x5D01, MapiPropertyType.String);
SearchFilter sf = new SearchFilter.ContainsSubstring(PidTagSenderSmtpAddress, $"{projectData.ProjectDomain}");
var folderItems = ewsClient.FindItems(WellKnownFolderName.Inbox, sf, view);
var conversationItems = from element in folderItems
group element by element.ConversationId
into groups
select groups.OrderByDescending(p => p.DateTimeReceived).FirstOrDefault();
foreach (Item item in conversationItems)
{
EmailMessage messageToCheck = EmailMessage.Bind(ewsClient, item.Id);
if (messageToCheck.InReplyTo != null) //Chain Email or not
{
PropertySet properties = new(BasePropertySet.FirstClassProperties);
// Identify the folders to ignore.
Collection<FolderId> foldersToIgnore = new Collection<FolderId>()
{ WellKnownFolderName.DeletedItems, WellKnownFolderName.Drafts };
// Request the conversation items.
ConversationResponse convesationResponse = ewsClient.GetConversationItems(messageToCheck.ConversationId,
properties,
null,
foldersToIgnore,
ConversationSortOrder.TreeOrderDescending);
//foreach (ConversationNode node in convesationResponse.ConversationNodes)
//{
// // Process each item in the conversation node.
// foreach (Item chainItem in node.Items)
// {
var chainItem = convesationResponse.ConversationNodes.FirstOrDefault()?.Items.FirstOrDefault();
if (chainItem != null)
{
List<EmailInfo> emailInfosList = projectData.EmailInfos.Where(p => p.ConversationId == chainItem.ConversationId).ToList();
if (emailInfosList == null || emailInfosList.Count == 0)
{
EmailMessage chainMessage = EmailMessage.Bind(ewsClient, chainItem.Id);
EmailInfo emailInfo = new();
emailInfo.Subject = chainMessage.Subject;
emailInfo.From = chainMessage.From.ToString();
emailInfo.Body = chainMessage.Body.ToString();
emailInfo.DateTimeCreated = chainMessage.DateTimeCreated;
emailInfo.DateTimeSent = chainMessage.DateTimeSent;
emailInfo.DateTimeReceived = chainMessage.DateTimeReceived;
emailInfo.ConversationId = chainMessage.ConversationId;
projectData.EmailInfos.Add(emailInfo);
}
}
// }
//}
}
else
{
List<EmailInfo> emailInfosList = projectData.EmailInfos.Where(p => p.ConversationId == messageToCheck.ConversationId).ToList();
if (emailInfosList == null || emailInfosList.Count == 0)
{
EmailInfo emailInfo = new();
emailInfo.Subject = messageToCheck.Subject;
emailInfo.From = messageToCheck.From.ToString();
emailInfo.Body = messageToCheck.Body.ToString();
emailInfo.DateTimeCreated = messageToCheck.DateTimeCreated;
emailInfo.DateTimeSent = messageToCheck.DateTimeSent;
emailInfo.DateTimeReceived = messageToCheck.DateTimeReceived;
emailInfo.ConversationId = messageToCheck.ConversationId;
projectData.EmailInfos.Add(emailInfo);
}
}
}
response.Data = projectsDataModel;
}
}
else
{
response.StatusCode = (int)HttpStatusCode.NotFound;
response.Message = ATEmailClientLibrary.Models.ResponseMessage.NoRecordFound;
}
}
else
{
response.StatusCode = (int)HttpStatusCode.NotFound;
response.Message = ATEmailClientLibrary.Models.ResponseMessage.NoRecordFound;
}
}
Why this email chain is broken i want to get only last email from this chain email messages but don't know how to do when subject change then this chain message broken

Related

how can I Distribute Rabbitmq message to specific users and the queue will auto deleted when consumed all message in C#?

I am trying to make a twitter clone using rabbitMQ and .Net core. here when a user post a tweet then it will go through RabbitMQ. And It will create number of followers queue and distribute the post through the queuess and save into user timeline database. after that the queues will be deleted. I tried this code below. but it is not working
ConnectionFactory _factory = new ConnectionFactory() { HostName = "localhost" };
var followers = new List<string>();
if (await _followBlockIndividual.GetAllFollowers(tweet.userName) == null)
{
followers.Add(tweet.userName);
}
else
{
followers = await _followBlockIndividual.GetAllFollowers(tweet.userName);
followers.Add(tweet.userName);
}
tweet.tweetId = Guid.NewGuid().ToString();
using (IConnection connection = _factory.CreateConnection())
using (IModel channel = connection.CreateModel())
{
channel.ExchangeDeclare("Dopamine_Tweet", ExchangeType.Fanout);
byte[] body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(tweet));
channel.BasicPublish(exchange: "Dopamine_Tweet",
routingKey: "",
basicProperties: null,
body: body);
}
and the consumer is
var followers = new List<string>();
if (await _followBlockIndividual.GetAllFollowers(userName) == null)
{
followers.Add(userName);
}
else
{
followers = await _followBlockIndividual.GetAllFollowers(userName);
followers.Add(userName);
}
var consumer = new EventingBasicConsumer(_channel);
Dictionary<String, Object> args = new Dictionary<String, Object>();
args.Add("x-expires", 60000);
foreach (var follower in followers)
{
_channel.QueueDeclare(follower, true, false, false, args);
_channel.QueueBind(follower, "Dopamine_Tweet", follower);
}
consumer.Received += async (m, e) => {
byte[] body = e.Body.ToArray();
var msg = (Tweet) JsonConvert.DeserializeObject<Tweet>(Encoding.UTF8.GetString(body))!;
if (_timelineCollection.Find(x => x.userName == e.RoutingKey).FirstOrDefault() == null)
{
var timeline = new TimelineTweets
{
userName = msg.userName,
tweets = new List<Tweet>()
};
timeline.tweets.Add(msg);
await _timelineCollection.InsertOneAsync(timeline);
}
else
{
var timeline = _timelineCollection.Find(x => x.userName == msg.userName).FirstOrDefault();
timeline.tweets.Add(msg);
await _timelineCollection.ReplaceOneAsync(x => x.userName == msg.userName, timeline);
}
};
foreach (var follower in followers)
{
_channel.BasicConsume(queue: follower,
autoAck: true,
consumer: consumer);
}

Multiple requests (pagination) with RestSharp

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);
};

Check against an Entire list to validate user information

I'm just not getting this.
So I have a list from my API
Of Customers called a
I need to validate weather the fields correlate to any of the 100+ Logins that I'm suppose to receive from the Resposne
How I'm Going about it At the moment
foreach (var c in Users.a)
{
if (Email == c.email && Password == c.password)
{
await App.Current.MainPage.DisplayAlert("Login Success", "", "Ok");
Application.Current.Properties["Email"] = c.email;
Application.Current.Properties["Userid"] = c.id;
Users.Loggedin = true;
await Application.Current.SavePropertiesAsync();
await App.Current.MainPage.Navigation.PushAsync(new Home(c.email));
}
else
{
await App.Current.MainPage.DisplayAlert("Login Fail", "Please enter correct Email and Password", "OK");
}
}
Am I doing this wrong? Is there a better way of doing this.
The Call
RestAPI rest = new RestAPI("http://Site/wp-json/wc/v3/",
"ck_a25f******************dcd0",
"cs_8f247c22************05c");
WCObject wc = new WCObject(rest);
var x = await wc.Customer.GetAll();
Users.a = x;
I Came to the Conclusion that my best way forward with this was to Fetch => Add => Combine Until My list was empty.
RestAPI rest = new RestAPI("http://Yoursite/wp-json/wc/v3/", "Customer Key", "Customer Secret");
WCObject wc = new WCObject(rest);
int pageNum = 1;
var isNull = false;
List<Customer> oldlist;
while (!isNull)
{
var page = pageNum.ToString();
x = await wc.Customer.GetAll(new Dictionary<string, string>() {
{
"page", page
}, {
"per_page", "100"
}
});
oldlist = FetchCustomers.customers ?? new List<Customer>();
if (x.Count == 0) {
break;
}
else
{
pageNum++;
FetchCustomers.customers = oldlist.Union(x).ToList();
}
}
How i'm Validating
var list = FetchCustomers.customers.ToList();
foreach (var user in list)
{
if (user.username == Usernamelabel.Text)
{
Application.Current.Properties["CId"] = user.id;
Application.Current.Properties["CEmail"] = user.email;
Application.Current.Properties["CUsername"] = user.username;
Users.Loggedin = true;
Application.Current.SavePropertiesAsync();
App.Current.MainPage.DisplayAlert("Empty Values", "Phase 2 Done your logged in ", "OK");
}
}
User is Validated From username I'm busy with another Process to Validate the user by The Wordpress API and getting a JWT token then Sending it to this Method to validate and Fetch the Customer and then Persisting the User.
Here's that Extra Method I mentioned
var client = new WordPressClient("http://Youtsite/wp-json/");
client.AuthMethod = AuthMethod.JWT;
await client.RequestJWToken(USername, Password);
var x = client;
var isValidToken = await client.IsValidJWToken();
WpApiCredentials.token = client.GetToken();
if (isValidToken)
{
Login_Phase2();
}
else
{
await App.Current.MainPage.DisplayAlert("Empty Values", "Token not Found", "OK");
}
#endregion

Your Campaign is not ready to send in mailchimp api v3 using C#

I created code to send campaign immediately by consuming mailchimp api v3.0 using C# console. When i tried in free account everything goes well, but when i upgrade my account in premium i got this problem (only add 2 members).
My scenario:
create audience => success
add member subscriber into audience that i created => success
create campaign with specific template => success
send cehcklist in campaign already created => return is_ready false
send campaign => return Your Campaign is not ready to send
When I try to run my console program using console c# consume mailchimp api I got this error:
Type: http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/
Title: Bad Request
Status: 400
Detail: Your Campaign is not ready to send.
instance: 214b85f4-a288-44e7-b890-35925d8601ac
When I checked campaign into mailchimp website portal, I saw a message like this:
To send, you need at least 1 subscriber in your list.
This means that there is no recipients in my campaign, here is detail screenshot:
Please has anyone ever faced this, too? I really appreciate any suggestions.
Is there any way to resolve that issue before sending campaign? Because when I checked mailchimp portal (based on screenshot shown above), I back into campaign list then open my campaign above the problem automatically resolve, this is my confusing one.
Because mailchimp api v3.0 has limitation only 500 members subscriber on one call, finally I created class to partition my list:
//partition list of members more than 500
public static class Extensions
{
public static List<List<T>> SplitPartition<T>(this IEnumerable<T> collection, int size)
{
var chunks = new List<List<T>>();
var count = 0;
var temp = new List<T>();
foreach (var element in collection)
{
if (count++ == size)
{
chunks.Add(temp);
temp = new List<T>();
count = 1;
}
temp.Add(element);
}
chunks.Add(temp);
return chunks;
}
}
this my main code using several scenario to handle single method can call in many way:
public class MailChimpProcessor
{
static MailChimpProcessor()
{
//initialize
ApiHelper.InitializeClient(baseUrl, apiKey);
}
public class MailChimpResponse
{
public string result { get; set; }
public GlobalErrorResponseModel error { get; set; }
}
public static MailChimpResponse MailChimpSendCampaign(SendEmailCampaignModel model)
{
MailChimpResponse mailchimpResult = new MailChimpResponse();
#region PROPERTY OBJECT AUDIENCE
Contact contact = new Contact()
{
company = model.audience_company,
address1 = model.audience_address1,
address2 = model.address2Config,
city = model.audience_city,
state = model.audience_state,
zip = model.audience_zip,
country = model.audience_country,
phone = model.phoneConfig
};
CampaignDefaults campaign = new CampaignDefaults()
{
from_name = model.campaign_from_name,
from_email = model.campaign_reply_to,
subject = model.campaign_subject,
language = "en"
};
AudienceRequestModel audienceModel = new AudienceRequestModel();
audienceModel.name = model.audience_name;
audienceModel.contact = contact;
audienceModel.permission_reminder = permissionReminderConfig;
audienceModel.use_archive_bar = true;
audienceModel.campaign_defaults = campaign;
audienceModel.notify_on_subscribe = "";
audienceModel.notify_on_unsubscribe = "";
audienceModel.email_type_option = true;
#endregion
#region PROPERTY OBJECT MEMBER
List<Member> members = new List<Member>();
//prevent duplicate email_address
var queryMemberList = model.members.GroupBy(x => x.email_address).Select(x => x.First());
foreach (var item in queryMemberList)
{
members.Add(new Member
{
email_address = item.email_address.ToLower(),
status = "subscribed",
status_if_new = "subscribed",
merge_fields = new MergeFields()
{
FNAME = item.merge_fields.FNAME,
LNAME = item.merge_fields.LNAME
}
});
}
bool isUploadContact = false;
int offset = 0;
const int numberPerBatch = 500; // maximum member per execution.
double LoopMax = Math.Ceiling(members.Count / (double)numberPerBatch);
//partition array
var PartitionMembers = members.SplitPartition(numberPerBatch);
#endregion
//create audience using post method
var audienceResult = AudienceProcessor.PostAudienceAsync(audienceModel).Result;
#region PROPERTY OBJECT CAMPAIGN
Recipients recipient = new Recipients()
{
list_id = audienceResult.ResponseModel != null ? audienceResult.ResponseModel.id : "0"
};
Settings setting = new Settings()
{
subject_line = model.campaign_subject,
title = model.campaign_title,
reply_to = model.campaign_reply_to,
from_name = model.campaign_from_name,
template_id = model.campaign_template_id
};
CampaignRequestModel campaignModel = new CampaignRequestModel();
campaignModel.recipients = recipient;
campaignModel.type = "regular";
campaignModel.settings = setting;
#endregion
if (audienceResult.ResponseModel != null)
{
MemberProcessor.MemberResponse memberResult = new MemberProcessor.MemberResponse();
while (offset < LoopMax)
{
MemberRequestModel memberModel = new MemberRequestModel();
memberModel.members = PartitionMembers[offset];//list based on index of array
memberModel.update_existing = true;
//post contact member
memberResult = MemberProcessor.PostContatcAsync(memberModel, audienceResult.ResponseModel.id).Result;
if (memberResult.ResponseModel != null)
{
isUploadContact = true;
}
else
{
isUploadContact = false;
}
offset++; // increment
}
//create campaign
if (isUploadContact)//belum tereksekusi
{
//sleep thread 20 seconds after upload subcriber members
System.Threading.Thread.Sleep(20000);
//create campaign using post method
var campaignResult = CampaignProcessor.PostCampaignAsync(campaignModel).Result;
if (campaignResult.ResponseModel.id != null)
{
#region USING ITERATION TO CHECK CAMPAIGN
CampaignProcessor.CampaignResponseCheckList campaignChecklist = new CampaignProcessor.CampaignResponseCheckList();
bool isReadySend = false;
int check = 0;
while (check <= 10) //maksimum 10 iteration
{
//check campaign using get method
campaignChecklist = CampaignProcessor.GetCheckListCampaign(campaignResult.ResponseModel.id).Result;
if (campaignChecklist.ResponseModel.is_ready == true) //when error model is not null
{
isReadySend = true;
break;
}
else
{
isReadySend = false;
}
System.Threading.Thread.Sleep(1000); // will puase every 1 second
check++;
}
if (isReadySend)
{
//sleep action before send campaign
System.Threading.Thread.Sleep(2000);
//send campaign
var sendCampaignResult = CampaignProcessor.SendCampaignAsync(campaignResult.ResponseModel.id).Result;
if (sendCampaignResult.ErrorModel == null)
mailchimpResult.result = sendCampaignResult.ResponseModel;
else
mailchimpResult.error = sendCampaignResult.ErrorModel; //i got this return indicate that my campaign is not ready
}
else
{
mailchimpResult.error = campaignChecklist.ErrorModel;
mailchimpResult.result = $"failed Check List Campaign / Your Campaign is not ready to send.";
}
#endregion
}
else
{
mailchimpResult.error = campaignResult.ErrorModel;
mailchimpResult.result = "failed create Campaign";
}
}
else
{
mailchimpResult.result = $"failed create contact: {offset}";
mailchimpResult.error = memberResult.ErrorModel;
}
}
else
{
mailchimpResult.error = audienceResult.ErrorModel;
mailchimpResult.result = "failed create Audience";
}
return mailchimpResult;
}
}
Try this code below
System.Threading.Thread.Sleep(40000); //try change this one
//create campaign using post method
var campaignResult = CampaignProcessor.PostCampaignAsync(campaignModel).Result;
if (campaignResult.ResponseModel.id != null)
{
#region USING ITERATION TO CHECK CAMPAIGN
CampaignProcessor.CampaignResponseCheckList campaignChecklist = new CampaignProcessor.CampaignResponseCheckList();
bool isReadySend = false;
int check = 0;
while (true) //just change this condition
{
//check campaign using get method
campaignChecklist = CampaignProcessor.GetCheckListCampaign(campaignResult.ResponseModel.id).Result;
if (campaignChecklist.ResponseModel.is_ready == true) //when error model is not null
{
isReadySend = true;
break;
}
else
{
isReadySend = false;
}
check++;
}
if (isReadySend)
{
//send campaign
var sendCampaignResult = CampaignProcessor.SendCampaignAsync(campaignResult.ResponseModel.id).Result;
if (sendCampaignResult.ErrorModel == null)
mailchimpResult.result = sendCampaignResult.ResponseModel;
else
mailchimpResult.error = sendCampaignResult.ErrorModel; //i got this return indicate that my campaign is not ready
}
else
{
mailchimpResult.error = campaignChecklist.ErrorModel;
mailchimpResult.result = $"failed Check List Campaign / Your Campaign is not ready to send.";
}
#endregion

Dynamic change Microsoft BOT Framework Form's Field Step: hiding and showing the confirmation

I'm new to MS BOT Framework.
I changed MS github MultiDialogsBot.sln , I added a HotelsQuery property to init Form's Field value at HotelsDialog.cs,
public class HotelsDialog : IDialog<object>
{
public HotelsQuery _HotelsQuery { get; set; }
public HotelsDialog()
{
_HotelsQuery = new HotelsQuery{
Destination = "Taiwan",
CheckIn = new DateTime(2017,10,29),
Nights = 3
};
}
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Welcome to the Hotels finder!");
var hotelsFormDialog = FormDialog.FromForm(this.BuildHotelsForm, FormOptions.PromptInStart);
context.Call(hotelsFormDialog, this.ResumeAfterHotelsFormDialog);
}
public IForm<HotelsQuery> BuildHotelsForm()
{
OnCompletionAsyncDelegate<HotelsQuery> processHotelsSearch = async (context, state) =>
{
await context.PostAsync($"Ok. Searching for Hotels in {state.Destination} from {state.CheckIn.ToString("MM/dd")} to {state.CheckIn.AddDays(state.Nights).ToString("MM/dd")}...");
};
var destField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Destination))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = string.IsNullOrWhiteSpace(_HotelsQuery.Destination);
if (!isActive) state.Destination = _HotelsQuery.Destination;
return isActive;
});
var checkInField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.CheckIn))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.CheckIn == DateTime.MinValue;
if (!isActive) state.CheckIn = _HotelsQuery.CheckIn;
return isActive;
});
var nightsField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Nights))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.Nights == 0;
if (!isActive) state.Nights = _HotelsQuery.Nights;
return isActive;
});
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
//clean all fields for showing fields in confirmation
_HotelsQuery.Destination = string.Empty;
_HotelsQuery.CheckIn = DateTime.MinValue;
_HotelsQuery.Nights = 0;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();
return form;
}
public async Task ResumeAfterHotelsFormDialog(IDialogContext context, IAwaitable<HotelsQuery> result)
{
try
{
var searchQuery = await result;
var hotels = await this.GetHotelsAsync(searchQuery);
await context.PostAsync($"I found in total {hotels.Count()} hotels for your dates:");
var resultMessage = context.MakeMessage();
resultMessage.AttachmentLayout = AttachmentLayoutTypes.Carousel;
resultMessage.Attachments = new List<Attachment>();
foreach (var hotel in hotels)
{
HeroCard heroCard = new HeroCard()
{
Title = hotel.Name,
Subtitle = $"{hotel.Rating} starts. {hotel.NumberOfReviews} reviews. From ${hotel.PriceStarting} per night.",
Images = new List<CardImage>()
{
new CardImage() { Url = hotel.Image }
},
Buttons = new List<CardAction>()
{
new CardAction()
{
Title = "More details",
Type = ActionTypes.OpenUrl,
Value = $"https://www.bing.com/search?q=hotels+in+" + HttpUtility.UrlEncode(hotel.Location)
}
}
};
resultMessage.Attachments.Add(heroCard.ToAttachment());
}
await context.PostAsync(resultMessage);
}
catch (FormCanceledException ex)
{
string reply;
if (ex.InnerException == null)
{
reply = "You have canceled the operation. Quitting from the HotelsDialog";
}
else
{
reply = $"Oops! Something went wrong :( Technical Details: {ex.InnerException.Message}";
}
await context.PostAsync(reply);
}
finally
{
context.Done<object>(null);
}
}
private async Task<IEnumerable<Hotel>> GetHotelsAsync(HotelsQuery searchQuery)
{
var hotels = new List<Hotel>();
// Filling the hotels results manually just for demo purposes
for (int i = 1; i <= 5; i++)
{
var random = new Random(i);
Hotel hotel = new Hotel()
{
Name = $"{searchQuery.Destination} Hotel {i}",
Location = searchQuery.Destination,
Rating = random.Next(1, 5),
NumberOfReviews = random.Next(0, 5000),
PriceStarting = random.Next(80, 450),
Image = $"https://placeholdit.imgix.net/~text?txtsize=35&txt=Hotel+{i}&w=500&h=260"
};
hotels.Add(hotel);
}
hotels.Sort((h1, h2) => h1.PriceStarting.CompareTo(h2.PriceStarting));
return hotels;
}
}
I have trouble after the confirmation shows. When a user answers yes, BOT will ask CheckIn's prompt.
Why does it not go to the OnCompletion event?
Thanks for your help.
You are clearing out the values in the .Confirm
Try something like this:
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
if (_HotelsQuery.Destination == string.Empty ||
_HotelsQuery.CheckIn == DateTime.MinValue ||
_HotelsQuery.Nights == 0)
return false;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();

Categories