Data not predictably received in skype using bots - bots

I am working on Bots Project using Microsoft BotFramework, in that I am using to display some video files. Here I am facing the issue is when I am running my project in local Bot Frame work Emulator its getting the data properly at every time and I am configuring my Bot to Skype Channel its working first time properly and when I am using the second time it’s not getting the data some times and sometimes it’s getting data like only one video file that is nothing but first video file.
Is there any proper solution for getting the complete data every time?
For this I am write the below line of code in my method
Activity replyToConversation = message.CreateReply("Welcome to **My Bot**." + "(Hi)");
replyToConversation.Recipient = message.From;
replyToConversation.Type = "message";
replyToConversation.Attachments = new List<Attachment>();
Dictionary<string, string> cardContentList = new Dictionary<string, string>();
cardContentList.Add("Jason Bourne", "");
cardContentList.Add("The Land", "");
cardContentList.Add("Yoga Hosers", "");
foreach (KeyValuePair<string, string> cardContent in cardContentList)
{
if (cardContent.Key == "Jason Bourne")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "https://ht39ea-bn1306.files.1drv.com/y3mz35iB6o_EJVzJvmSQz9_jNz5Cmpk33LgbGJQjpoZvQaBXrABBDvHrOS5gdHvqh_MIlJoFBIujrSkhkCGRnApldRbmT6W61NTEyOulUGUZtge9hRyKKvh9BHT-VYV_opRLSMnHt7g3b3IaiTNKcjZqQ/Jason%20Bourne%20Official%20Trailer%20%231%20(2016",
Name = "Jason Bourne"
});
}
else if (cardContent.Key == "The Land")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "https://ht39ea-bn1306.files.1drv.com/y3mGspCfSmGDdvQjKK_3UcUIdnZRsAC2jRgHesmL61sIV_zc9F9UQQIWkyHE5E4t6r4T56aWKDQSfN-qduP2VJbiH0rYZ4Ce5DLI2U1DKx-4Tv4UB4OL2Egtk_-BWAow0fC4wf7HCC2ypyQ2dIXrs1hsw/The%20Land%20Official%20Trailer%201%20(2016",
ContentType = "video/mp4",
Name = "The Land"
});
}
else if (cardContent.Key == "Yoga Hosers")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "https://ht39ea-bn1306.files.1drv.com/y3mThBzywEPjMFSh2rdNldHPW1oxtzVTXyrhLrJOp_ACh2YPLQcuw5W-MaSB_5DBJluNXJpvwWBcoWKcQO6Ijx7dWcj2MqHA2uFvvbH6h7mPKsiBhDuC8j5I4_qi-ZsdMuM2G6ztoUtAsdRV0pla-aOGQ/Yoga%20Hosers%20TRAILER%20(2016",
ContentType = "video/mp4",
Name = "Yoga Hosers"
});
}
}
replyToConversation.AttachmentLayout = AttachmentLayoutTypes.List;
await context.PostAsync(replyToConversation);

Two issues. First, the"Jason Bourne" item is missing the ContentType field so the post is being rejected. Secondly the links provided don't seem to be valid or publicly available. If I add the ContentType field and swap out the links it works find.
Activity replyToConversation = message.CreateReply("Welcome to **My Bot**." + "(Hi)");
replyToConversation.Recipient = message.From;
replyToConversation.Type = "message";
replyToConversation.Attachments = new List<Attachment>();
Dictionary<string, string> cardContentList = new Dictionary<string, string>();
cardContentList.Add("Jason Bourne", "");
cardContentList.Add("The Land", "");
cardContentList.Add("Yoga Hosers", "");
foreach (KeyValuePair<string, string> cardContent in cardContentList)
{
if (cardContent.Key == "Jason Bourne")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "http://www.sample-videos.com/video/mp4/240/big_buck_bunny_240p_1mb.mp4",
ContentType = "video/mp4", // NEW LINE
Name = "Jason Bourne"
});
}
else if (cardContent.Key == "The Land")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "http://www.sample-videos.com/video/mp4/240/big_buck_bunny_240p_1mb.mp4",
ContentType = "video/mp4",
Name = "The Land"
});
}
else if (cardContent.Key == "Yoga Hosers")
{
replyToConversation.Attachments.Add(new Attachment()
{
ContentUrl = "http://www.sample-videos.com/video/mp4/240/big_buck_bunny_240p_1mb.mp4",
ContentType = "video/mp4",
Name = "Yoga Hosers"
});
}
}
replyToConversation.AttachmentLayout = AttachmentLayoutTypes.List;

Related

Xamarin.iOS Cannot display photo in Push Notification

I have a Notification Service Extension and an AppGroup. I save a photo from camera in the PCL project and copy it to the App Group Container (shared folder).
In the Notification Service Extension I try to download the photo from the App Group container and attach it to the notification but it just does not display in the notification.
I also cannot debug the Service Extension to see what is going. As far as I know that is not possible currently still in Xamarin unless someone can correct me on that please.
Here is the code:
1.in my PCL I save the photo to the AppGroup when a save button is pressed:
private void ButtonSavePhoto_Clicked(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(photoFilePath))
{
Preferences.Set(AppConstants.CUSTOM_PICTURE_FILE_PATH, photoFilePath);
Preferences.Set(AppConstants.CUSTOM_PHOTO_SET_KEY, true);
if (Device.RuntimePlatform == Device.iOS)
{
bool copiedSuccessfully = DependencyService.Get<IPhotoService>().CopiedFileToAppGroupContainer(photoFilePath);
if (copiedSuccessfully)
{
var customPhotoDestPath = DependencyService.Get<IPhotoService>().GetAppContainerCustomPhotoFilePath();
// save the path of the custom photo in the AppGroup container to pass to Notif Extension Service
DependencyService.Get<IGroupUserPrefs>().SetStringValueForKey("imageAbsoluteString", customPhotoDestPath);
// condition whether to use custom photo in push notification
DependencyService.Get<IGroupUserPrefs>().SetBoolValueForKey("isCustomPhotoSet", true);
}
}
buttonSavePhoto.IsEnabled = false;
}
}
2.in my iOS project, Dependency injection calls this method when pressing save button:
public bool CopiedFileToAppGroupContainer(string filePath)
{
bool success = false;
string suiteName = "group.com.company.appName";
var appGroupContainerUrl = NSFileManager.DefaultManager.GetContainerUrl(suiteName);
var appGroupContainerPath = appGroupContainerUrl.Path;
var directoryNameInAppGroupContainer = Path.Combine(appGroupContainerPath, "Pictures");
var filenameDestPath = Path.Combine(directoryNameInAppGroupContainer, AppConstants.CUSTOM_PHOTO_FILENAME);
try
{
Directory.CreateDirectory(directoryNameInAppGroupContainer);
if (File.Exists(filenameDestPath))
{
File.Delete(filenameDestPath);
}
File.Copy(filePath, filenameDestPath);
success = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return success;
}
Now the path for the photo in the App Group container is:
/private/var/mobile/Containers/Shared/AppGroup/12F209B9-05E9-470C-9C9F-AA959D940302/Pictures/customphoto.jpg
3.Finally in the Notification Service Extension I try to attach the photo to the push notification:
public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
{
ContentHandler = contentHandler;
BestAttemptContent = (UNMutableNotificationContent)request.Content.MutableCopy();
string imgPath;
NSUrl imgUrl;
string notificationBody = BestAttemptContent.Body;
string notifBodyInfo = "unknown";
string suiteName = "group.com.company.appname";
NSUserDefaults groupUserDefaults = new NSUserDefaults(suiteName, NSUserDefaultsType.SuiteName);
string pref1_value = groupUserDefaults.StringForKey("user_preference1");
string[] notificationBodySplitAtDelimiterArray = notificationBody.Split(',');
userPrefRegion = notificationBodySplitAtDelimiterArray[0];
bool isCustomAlertSet = groupUserDefaults.BoolForKey("isCustomAlert");
bool isCustomPhotoSet = groupUserDefaults.BoolForKey("isCustomPhotoSet");
string alarmPath = isCustomAlertSet == true ? "customalert.wav" : "default_alert.m4a";
if (isCustomPhotoSet)
{
// this is the App Group url of the custom photo saved in PCL
imgPath = groupUserDefaults.StringForKey("imageAbsoluteString");
}
else
{
imgPath = null;
}
if (imgPath != null )
{
imgUrl = NSUrl.FromString(imgPath);
}
else
{
imgUrl = null;
}
if (!string.IsNullOrEmpty(pref1_value))
{
if (BestAttemptContent.Body.Contains(pref1_value))
{
if (imgUrl != null)
{
// download the image from the AppGroup Container
var task = NSUrlSession.SharedSession.CreateDownloadTask(imgUrl, (tempFile, response, error) =>
{
if (error != null)
{
ContentHandler(BestAttemptContent);
return;
}
if (tempFile == null)
{
ContentHandler(BestAttemptContent);
return;
}
var cache = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User, true);
var cachesFolder = cache[0];
var guid = NSProcessInfo.ProcessInfo.GloballyUniqueString;
var fileName = guid + "customphoto.jpg";
var cacheFile = cachesFolder + fileName;
var attachmentUrl = NSUrl.CreateFileUrl(cacheFile, false, null);
NSError err = null;
NSFileManager.DefaultManager.Copy(tempFile, attachmentUrl, out err);
if (err != null)
{
ContentHandler(BestAttemptContent);
return;
}
UNNotificationAttachmentOptions options = null;
var attachment = UNNotificationAttachment.FromIdentifier("image", attachmentUrl, options, out err);
if (attachment != null)
{
BestAttemptContent.Attachments = new UNNotificationAttachment[] { attachment };
}
});
task.Resume();
}
BestAttemptContent.Title = "My Custom Title";
BestAttemptContent.Subtitle = "My Custom Subtitle";
BestAttemptContent.Body = "Notification Body";
BestAttemptContent.Sound = UNNotificationSound.GetSound(alarmPath);
}
}
else
{
pref1_value = "error getting extracting user pref";
}
// finally display customized notification
ContentHandler(BestAttemptContent);
}
/private/var/mobile/Containers/Shared/AppGroup/12F209B9-05E9-470C-9C9F-AA959D940302/Pictures/customphoto.jpg
From shared code, when image getting from AppGroup .You can check the file path whether work in this project.
imgPath = groupUserDefaults.StringForKey("imageAbsoluteString");
If not getting file from this path. You can get Url from AppGroup directly.Here is a sample as follow:
var FileManager = new NSFileManager();
var appGroupContainer = FileManager.GetContainerUrl("group.com.company.appName");
NSUrl fileURL = appGroupContainer.Append("customphoto.jpg", false);
And if fileURL can not be directly used, also can convert to NSData and save to local file system. This also can be a try.
Here is a sample below that grabs from local file system:
public static void Sendlocalnotification()
{
var localURL = "...";
NSUrl url = NSUrl.FromString(localURL) ;
var attachmentID = "image";
var options = new UNNotificationAttachmentOptions();
NSError error;
var attachment = UNNotificationAttachment.FromIdentifier(attachmentID, url, options,out error);
var content = new UNMutableNotificationContent();
content.Attachments = new UNNotificationAttachment[] { attachment };
content.Title = "Good Morning ~";
content.Subtitle = "Pull this notification ";
content.Body = "reply some message-BY Ann";
content.CategoryIdentifier = "message";
var trigger1 = UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false);
var requestID = "messageRequest";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger1);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
Console.Write("Notification Error");
}
});
}

Resumable Upload using Google Mail APIs throwing exception: "Bad Request"

I am trying to insert mail to Google Mailbox using GMail APIs.
I want to upload mails of size more than 5 mb. So that I am using Resumable upload request.
I have used POST request first to initiate a resumable upload which gives "200 OK" response.
Post Request:
String postUrl = "https://www.googleapis.com/upload/gmail/v1/users/" + "<username>" + "/messages/send?uploadType=resumable";
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(postUrl);
httpRequest.Headers["Authorization"] = "Bearer " + f_token;// AccessToken;
httpRequest.Headers["X-Upload-Content-Type"] = "message/rfc822";
httpRequest.Headers["X-Upload-Content-Length"] = f_bytes.Length.ToString();
httpRequest.Method = "POST";
httpRequest.ContentLength = 0;
var response = (HttpWebResponse)httpRequest.GetResponse(); // 200 OK
From that response I get location URL to upload EML.
Location: https://www.googleapis.com/upload/gmail/v1/users//messages/send?uploadType=resumable&upload_id=AEnB2UqeNYKVyyQdL07RZcbenWOqY8a2NFVIsQrbA-S-vxwUXC_W4ORQtpPx1HG6tc4Indx8AvqDjwXII3F6OW0G3wsdUMUjHw
To upload EML file I used Location URL as PUT URL to create request.
putUrl = https://www.googleapis.com/upload/gmail/v1/users/<username>/messages/send?uploadType=resumable&upload_id=AEnB2UqeNYKVyyQdL07RZcbenWOqY8a2NFVIsQrbA-S-vxwUXC_W4ORQtpPx1HG6tc4Indx8AvqDjwXII3F6OW0G3wsdUMUjHw";
HttpWebRequest httpRequest1 = (HttpWebRequest)WebRequest.Create(postUrl);
httpRequest1.Method = "PUT";
httpRequest1.ContentLength = f_bytes.Length;
int EndOffset = f_bytes.Length;//5120000;5242880
httpRequest1.Headers["Content-Range"] = "bytes " + 0 + "-" + EndOffset + "/" + f_bytes.Length;
httpRequest1.ContentType = "message/rfc822";
MemoryStream stream = new MemoryStream(f_bytes);
System.IO.Stream requestStream = httpRequest1.GetRequestStream();
{
stream.CopyTo(requestStream);
requestStream.Flush();
requestStream.Close();
}
HttpWebResponse f_webResponse = (HttpWebResponse)httpRequest1.GetResponse(); //Exception
Exception :
The remote server returned an error: (400) Bad Request.
Please suggest soluion to upload eml file in a particular folder of mailbox .
I am able to send mail using resumable upload.
if (f_MailService == null)
{
bool isCreated = createMailService(ref f_MailService);
}
FileStream fs = new FileStream(#p_EMLPath, FileMode.Open,FileAccess.Read);
Create HTTPRequest for sending mail :
string postUrl = "https://www.googleapis.com/upload/gmail/v1/users/ab#edu.cloudcodes.com/messages/send?uploadType=resumable";
HttpWebRequest f_httpRequest = (HttpWebRequest)WebRequest.Create(postUrl);
f_httpRequest.Headers["X-Upload-Content-Type"] = "message/rfc822";
f_httpRequest.Headers["X-Upload-Content-Length"] = fs.Length.ToString();
f_httpRequest.Headers["Authorization"] = "Bearer " + f_token;
f_httpRequest.Method = "POST";
//f_httpRequest.ContentLength = 524288;
f_httpRequest.ContentType = "application/json; charset=UTF-8";//"message/rfc822";
f_httpRequest.ContentLength = fs.Length;
f_httpRequest.Timeout = 6000000;
f_httpRequest.SendChunked = true;
Get Response for first POST request :
try
{
using (Stream f_ObjHttpStream = f_httpRequest.GetRequestStream())
{
}
}
catch (Exception EX)
{
}
try
{
using (var response = (HttpWebResponse)f_httpRequest.GetResponse())
{
// data = ReadResponse(response);
UploadUrl = response.Headers["Location"].ToString();
}
}
catch (WebException exception)
{
using (var response = (HttpWebResponse)exception.Response)
{
// data = ReadResponse(response);
}
}
Read EML File & send chunk data to upload
byte[] Arrbyte = new byte[1024];
int ReadByte = 0;
while (fs.Length > ReadByte)
{
bool ac = false;
int ByteRead = 0;
byte[] Data = new byte[4194304];
byte[] LastData;
//Read block of bytes from stream into the byte array
// if (ReadByte == 0)
{
ByteRead = fs.Read(Data, 0, Data.Length);
}
//else
{
if ((ReadByte + Data.Length) > fs.Length)
{
//fs.Length - ReadByte-
LastData = new byte[fs.Length - ReadByte];
ByteRead = fs.Read(LastData, 0, LastData.Length);
CallPUTReq(fs.Length, LastData);
ac = true;
}
}
//f_MsgRawStr = Convert.ToBase64String(f_bytes).TrimEnd(padding).Replace('+', '-').Replace('/', '_');
ReadByte = ReadByte + ByteRead;
if (ac == false)
{
CallPUTReq(fs.Length, Data);
}
//long pos = fs.Seek(0, SeekOrigin.Current );
//fs.Position = ReadByte;
}
private void CallPUTReq(long p_lenth, byte[] Arrbyte)
{
try
{
String postUrl = UploadUrl; //"https://www.googleapis.com/upload/gmail/v1/users/ab#edu.cloudcodes.com/messages/send?uploadType=resumable&upload_id=AEnB2UqZNtZVwWulAOhAVoFp-pZ-vTMcIXOpt_0dH_6jJecpm2Y1MNOGkE6JoDb0kn9Dt4yuHHMZWR--dBncxWQkZctF9h6jiPSL5uJDKeYE9Ut1c7-fImc";
int EndOffset = 0;
HttpWebRequest httpRequest1 = (HttpWebRequest)WebRequest.Create(postUrl);
httpRequest1.Method = "PUT";
httpRequest1.ContentLength = Arrbyte.Length;
if (rangeStartOffset == 0)
{
EndOffset = Arrbyte.Length - 1;
}
else
{
EndOffset = rangeStartOffset + Arrbyte.Length - 1;
if (EndOffset > p_lenth)
{
EndOffset = Convert.ToInt32(p_lenth);
httpRequest1.ContentLength = EndOffset - rangeStartOffset;
}
}//5120000;5242880
httpRequest1.Headers["Content-Range"] = "bytes " + rangeStartOffset + "-" + EndOffset + "/" + p_lenth; //"bytes */" + p_lenth; //
httpRequest1.ContentType = "message/rfc822";
httpRequest1.Timeout = 6000000;
UTF8Encoding encoding = new UTF8Encoding();
Stream stream = httpRequest1.GetRequestStream();
stream.Write(Arrbyte, 0, Arrbyte.Length);
stream.Close();
try
{
using (Stream f_ObjHttpStream = httpRequest1.GetRequestStream())
{
}
}
catch (Exception EX)
{
}
WebResponse response1 = null;
try
{
using (response1 = (HttpWebResponse)httpRequest1.GetResponse())
{
}
}
catch (Exception ex)
{
// UploadUrl = response1.Headers["Location"].ToString();
}
//4194303
rangeStartOffset = EndOffset +1;
}
catch (Exception)
{
}
}

How to get Logic App Metrics?

I'm trying to get Logic Apps metrics like BillableExecutions, Latency etc in my console application.
Currently I'm able to list the logic apps runs, triggers, versions using the .Net Client Microsoft.Azure.Management. But it doesn't seem to have the API to access the monitoring API's.
Code excerpt
private static void Main(string[] args)
{
var token = GetTokenCredentials();
var client = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (client)
{
var logicAppsWorkFlows = client.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
var runs = GetWorkflowRuns(client, logicAppsWorkFlow.Id.Split('/')[4], logicAppsWorkFlow.Name);
Console.WriteLine(runs.Count);
}
Console.WriteLine(logicAppsWorkFlows.Count());
}
}
Can someone tell me how to access Logic Apps Metrics? Is there a client similar to Microsoft.Azure.Management for access metrics data?
Update 2
I have found a client dll which was in pre release mode which is used to get metrics. Below is my current code
var token = GetTokenCredentials();
var insightsClient = new InsightsClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var logicManagementClient = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "name.value eq 'ActionLatency' and startTime ge '2014-07-16'"
};
IEnumerable<Metric> metricsList = null;
try
{
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}
I'm getting an exception saying the filter string is not valid. Im referring the filter string structure provided here
https://learn.microsoft.com/en-us/rest/api/monitor/filter-syntax
Can someone tell what im doing wrong here?
Thanks
It looks like ge is not allowed for Logic Apps StartTime field for some reason. I had to change the code to below to make it work
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "startTime eq " + DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + " and name.value eq 'BillableTriggerExecutions' and endTime eq " + DateTime.Now.ToString("yyyy-MM-dd")
};
var query = metricsDataQuery.GetQueryString();
Console.WriteLine(query);
IEnumerable<Metric> metricsList = null;
try
{
//throws exception if there is no metrics data
//TODO: Check whether the logic app ran atleast one time
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}

How to use the ThumbnailCard in IDialog Context

Hi I am developing one bot using Microsoft botframework project in that I am using IDialog interface. In that I am using the ThumbnailCard for displaying the cards. Here when I am attaching some data to my cards and the data is attaching properly but within the PostAsync method it’s not providing the reply.
public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
ThumbnailCard plCard = null;
IMessageActivity replyToConversation =await argument;
replyToConversation.Type = "message";
replyToConversation.Attachments = new List<Attachment>();
replyToConversation.Text = "welcome to book my show";
Dictionary<string, string> cardContentList = new Dictionary<string, string>();
cardContentList.Add("Jason Bourne", "URL");
cardContentList.Add("The Land", "URL");
cardContentList.Add("Yoga Hosers", "URL");
foreach (KeyValuePair<string, string> cardContent in cardContentList)
{
List<CardImage> cardImages = new List<CardImage>();
cardImages.Add(new CardImage(url: cardContent.Value));
List<CardAction> cardButtons = new List<CardAction>();
if (cardContent.Key == "Jason Bourne")
{
CardAction plButton1 = new CardAction()
{
Value = $"",
Type = "openUrl",
Title = "Book Now"
};
CardAction plButton2 = new CardAction()
{
Value = "tel:1-800-800-5705",
Type = "call",
Title = "Show timings"
};
cardButtons.Add(plButton1);
cardButtons.Add(plButton2);
plCard = new ThumbnailCard()
{
Title = $"Jason Bourne",
Subtitle = " ",
Images = cardImages,
Buttons = cardButtons,
};
Attachment plAttachment = plCard.ToAttachment();
replyToConversation.Attachments.Add(plAttachment);
}
else if (cardContent.Key == "The Land")
{
CardAction plButton1 = new CardAction()
{
Value = $"",
Type = "openUrl",
Title = "Book Now"
};
CardAction plButton2 = new CardAction()
{
Value = "tel:1-800-800-5705",
Type = "call",
Title = "Show Timings"
};
cardButtons.Add(plButton1);
cardButtons.Add(plButton2);
plCard = new ThumbnailCard()
{
Title = $"The Land",
Subtitle = "",
Images = cardImages,
Buttons = cardButtons,
};
Attachment plAttachment = plCard.ToAttachment();
replyToConversation.Attachments.Add(plAttachment);
}
else if (cardContent.Key == "Yoga Hosers")
{
CardAction plButton1 = new CardAction()
{
Value = $"",
Type = "openUrl",
Title = "Book Now"
};
CardAction plButton2 = new CardAction()
{
Value = "tel:1-800-800-5705",
Type = "call",
Title = "Show timings"
};
cardButtons.Add(plButton1);
cardButtons.Add(plButton2);
plCard = new ThumbnailCard()
{
Title = $"Yoga Hosers",
Subtitle = "",
Images = cardImages,
Buttons = cardButtons,
};
Attachment plAttachment = plCard.ToAttachment();
replyToConversation.Attachments.Add(plAttachment);
}
}
replyToConversation.AttachmentLayout = AttachmentLayoutTypes.List;
await context.PostAsync(replyToConversation);
}
When I run the bot its show the following error
Can we use cards in IDialog Context for attachments?
The issue is with the IMessageActivity, you are trying to send IMessageActicity in context.PostAsync. That's the reason it is failing.
Do the following changes to make it work
Change the method signature like below
private async Task messageReceived(IDialogContext context, IAwaitable<object> argument)
and modify the IMessageActivity replyToConversation =await argument; to like below
var message = await argument as Activity;
Activity replyToConversation = message.CreateReply("Welcome." + "(Hi)");
replyToConversation.Recipient = message.From;
Now it should work, if you still have issue please comment here.
-Kishore

Sharepoint: How to upload files with metadata including Taxonomy fields through web services

Being very new to SharePoint coding I have been assigned the task to create a prototype code to upload a file and setting the field values for that file that will show up when opening the sharepoint page with the file.
This has to be done from a remote machine and not the Sharepoint server itself so using the .Net objects for Sharepoint is out the question.
I quickly found out how to upload a file through the Sharepoint Web Service Copy.asmx:
void UploadTestFile() {
var file = #"C:\Temp\TestFile.doc";
string destinationUrl = "http://mysharepointserver/Documents/"
+ Path.GetFileName(file);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = "http://mysharepointserver/_vti_bin/copy.asmx";
CopyResult[] result;
byte[] data = File.ReadAllBytes(file);
FieldInformation mf1 = new FieldInformation {
DisplayName = "title",
InternalName = "title",
Type = FieldType.Text,
Value = "Dummy text"
};
FieldInformation mf2 = new FieldInformation {
DisplayName = "MyTermSet",
InternalName = "MyTermSet",
Type = FieldType.Note,
Value = "Test; Unit;"
};
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[] { mf1, mf2 },
data,
out result);
}
This code easily uploads any file to the target site but only fills the "title" field with info. The field MyTermSet in which I have added 3 terms allready - Test, Unit and Page - will not update with the values "Test;" and "Unit;".
Being very new to Sharepoint and me not grasping all the basics googling has told me that updating "File", "Computed" or "Lookup" fields does not work with the CopyIntoItems method, and MyTermSet being a Taxonomy field is - if I am correct - a Lookup field.
So how do I get MyTermSet updated with the values "Test;" and "Unit;" ?
I would really prefer If someone has a sample code on this. I have followed several hint-links but I am none the wiser. I have found no sample-code on this at all.
Have anyone made one single method that wraps it all? Or another method that takes in the destinationUrl from the file upload and updates the Term Set/Taxonomy field.
Puzzling together what I have found so far, I am now able to do as I wanted. But I would really like to be able to get the Taxonomy field GUIDs dynamically and NOT having to explicitly set them myself:
void UploadTestFile(string FileName, string DocLib, Dictionary<string, string> Fields = null) {
//Upload the file to the target Sharepoint doc lib
string destinationUrl = DocLib + Path.GetFileName(FileName);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = new Uri(new Uri(DocLib), "/_vti_bin/copy.asmx").ToString();
CopyResult[] result;
var data = File.ReadAllBytes(FileName);
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[0],
data,
out result);
if (Fields == null) return; //Done uploading
//Get the ID and metadata information of the fields
var list = new ListsWS.Lists();
list.UseDefaultCredentials = true;
var localpath = new Uri(DocLib).LocalPath.TrimEnd('/');
var site = localpath.Substring(0, localpath.LastIndexOf("/")); //Get the site of the URL
list.Url = new Uri(new Uri(DocLib), site + "/_vti_bin/lists.asmx").ToString(); //Lists on the right site
FieldInformation[] fiOut;
byte[] filedata;
var get = CopyWS.GetItem(destinationUrl, out fiOut, out filedata);
if (data.Length != filedata.Length) throw new Exception("Failed on uploading the document.");
//Dictionary on name and display name
var fieldInfos = fiOut.ToDictionary(x => x.InternalName, x => x);
var fieldInfosByName = new Dictionary<string, FieldInformation>();
foreach (var item in fiOut) {
if (!fieldInfosByName.ContainsKey(item.DisplayName)) {
fieldInfosByName.Add(item.DisplayName, item);
}
}
//Update the document with fielddata - this one can be extended for more than Text and Note fields.
if (!fieldInfos.ContainsKey("ID")) throw new Exception("Could not get the ID of the upload.");
var ID = fieldInfos["ID"].Value; //The ID of the document we just uploaded
XDocument doc = new XDocument(); //Creating XML with updates we need
doc.Add(XElement.Parse("<Batch OnError='Continue' ListVersion='1' ViewName=''/>"));
doc.Element("Batch").Add(XElement.Parse("<Method ID='1' Cmd='Update'/>"));
var methNode = doc.Element("Batch").Element("Method");
//Add ID
var fNode = new XElement("Field");
fNode.SetAttributeValue("Name", "ID");
fNode.Value = ID;
methNode.Add(fNode);
//Loop each field and add each Field
foreach (var field in Fields) {
//Get the field object from name or display name
FieldInformation fi = null;
if (fieldInfos.ContainsKey(field.Key)) {
fi = fieldInfos[field.Key];
}
else if (fieldInfosByName.ContainsKey(field.Key)) {
fi = fieldInfosByName[field.Key];
}
if (fi != null) {
//Fix for taxonomy fields - find the correct field to update
if (fi.Type == FieldType.Invalid && fieldInfos.ContainsKey(field.Key + "TaxHTField0")) {
fi = fieldInfos[field.Key + "TaxHTField0"];
}
else if (fi.Type == FieldType.Invalid && fieldInfosByName.ContainsKey(field.Key + "_0")) {
fi = fieldInfosByName[field.Key + "_0"];
}
fNode = new XElement("Field");
fNode.SetAttributeValue("Name", fi.InternalName);
switch (fi.Type) {
case FieldType.Lookup:
fNode.Value = "-1;#" + field.Value;
break;
case FieldType.Choice:
case FieldType.Text:
fNode.Value = field.Value;
break;
case FieldType.Note: //TermSet's
var termsetval = "";
var terms = field.Value.Split(';');
foreach (var term in terms) {
termsetval += "-1;#" + term + ";";
}
fNode.Value = termsetval.TrimEnd(';');
break;
default:
//..Unhandled type. Implement if needed.
break;
}
methNode.Add(fNode); //Adds the field to the XML
}
else {
//Field does not exist. No use in uploading.
}
}
//Gets the listname (not sure if it is the full path or just the folder name)
var listname = new Uri(DocLib).LocalPath;
var listcol = list.GetListCollection(); //Get the lists of the site
listname = (from XmlNode x
in listcol.ChildNodes
where x.Attributes["DefaultViewUrl"].InnerText.StartsWith(listname, StringComparison.InvariantCultureIgnoreCase)
select x.Attributes["ID"].InnerText).DefaultIfEmpty(listname).First();
//Convert the XML to XmlNode and upload the data
var xmldoc = new XmlDocument();
xmldoc.LoadXml(doc.ToString());
list.UpdateListItems(listname, xmldoc.DocumentElement);
}
Then I call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page|a4ba29c1-3ed5-47e9-b43f-36bc59c0ea5c;Unit|4237dfbe-22a2-4d90-bd08-09f4a8dd0ada");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);
I would however prefer to call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page;Unit");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);

Resources