How can I attach file to message with Microsoft Bot Framework? - asp.net-web-api

I have Web API service:
[ActionName("download")]
[HttpGet]
public HttpResponseMessage Download()
{
var stream = new FileStream(HostingEnvironment.MapPath("~/tmp/") + "doc.pdf", FileMode.Open);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(stream)
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = document.Name + "." + document.AssociatedApplication.Extension
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
Bot's code:
if (message.Text.StartsWith("/d"))
{
var contentType = "application/pdf";
var attachment = new Attachment(contentType, "https://localhost/api/documents.download");
var response = await client.GetAsync("https://localhost/api/documents.download");
var data = await response.Content.ReadAsByteArrayAsync();
System.IO.File.WriteAllBytes(HostingEnvironment.MapPath("~/tmp/") + document.Name + "." + document.Extension, data);
var stream = System.IO.File.ReadAllBytes(HostingEnvironment.MapPath("~/tmp/") + document.Name + "." + document.Extension);
attachment.Content = stream;
var msg = message.CreateReplyMessage("This is your document: ");
msg.Attachments = new[] { attachment };
await context.PostAsync(msg);
}
If I change content type on the server and client to "image/png" and send PNG image from server to client then this sample works perfect - in the Bot Framework Emulator I got text "This is your document: " and received image.
But if I try to send PDF document with content type "application/pdf" or "application/octet-stream" and get it on the client with content type "application/pdf" then on the Bot Framework Emulator I got message like that:
This is your document: (https://localhost/api/documents.download)
Is this possible to get in the conversation "real" document instead of link for download (how it works with images)?
PS: This question works only for "image/png" or similar content types.

2 things:
1. it doesn't look like you are setting the content type for the attachment (the code above is using "")
2. Content is not for pushing media files. Our messages are limited to 256k serialized json. If you want to send a document or image you send an attachment with url pointing to the file and contenttype for the file
3. Not all channels have semantics for files other than images and they represent them as links. We use the contenttype to determine if we can do something channel specific for a given attachment.

Related

MinIO Uploading a file with name containing especial characters issues an HTTP 403 Forbidden

Uploading an object from a .net webclient to MinIO where the object contains special characters in the name issues an HTTP 403.
This object fails: old_me_bold+19(1).jpg
This object is ok: old_me_bold19.jpg
The message is:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
What is breaking in MinIO?
Encoding the Url did not work either. I also tried PresignedPutObjectAsync to create a tmp Url already signed then I did a PUT using an HttpClient with the same result. To test that this way would work, I removed the special characters from the name of the file and the client was able to send the file to MinIO.
This code fails:
public async System.Threading.Tasks.Task PutAttachementAsync(
Attachment attachment,
string bukectName,
string objectName,
string attachmentType = "application/octet-stream")
{
using (HttpClient client = new HttpClient())
{
var minioClient = GetMinioClient();
client.BaseAddress = new Uri(Config.Instance.GetConfig("MinIOURL"));
var tempFileName = CreateAttachmentTempFile(attachment, out bool virusScanResult);
if (!virusScanResult)
return;
using (FileStream str = new FileStream(tempFileName.FileAttachmentPath, FileMode.Open))
{
try
{
String signedTMPUrl = await minioClient.PresignedPutObjectAsync(bukectName, objectName, 60 * 60 * 24);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(attachmentType));
HttpResponseMessage response = await client.PutAsync(signedTMPUrl, new StreamContent(str));
if (response.IsSuccessStatusCode)
{
Log.InfoFormat("Request Message Information:- \n\n" + response.RequestMessage + "\n");
Log.InfoFormat("Response Message Header \n\n" + response.Content.Headers + "\n");
}
else
{
Log.InfoFormat("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
catch (MinioException e)
{
Log.Error("Error occurred: " + e.Message);
}
}
}
}
That code is running from an ASP.Net application hosted in IIS. I wonder if IIS is injecting something into the header before the message goes to MinIO.
Any other file that I send to MinIO, if the name does not contain characters such as (), then the upload works always.

Bad Request when sending Inline Picture as a MS Team Bot

I am receiving bad request when I including an attachment as an inline picture for the MS Teams Bot using the following code (the code works without attachments):
var message = Activity.CreateMessageActivity();
message.Text = "message here";
message.Attachments = new List<Attachment>();
var webClient = new WebClient();
byte[] imageBytes = webClient.DownloadData("https://img.icons8.com/windows/452/showing-small-size.png");
string url = "data:image/png;base64," + Convert.ToBase64String(imageBytes);
message.Attachments.Add(new Attachment
{
ContentType = "image/png",
ContentUrl = url
});
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(outputChannelId),
},
Activity = (Activity)message
};
var response = await connectorClient.Conversations.CreateConversationAsync(conversationParameters);
I received the following error:
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an invalid status code 'BadRequest'
at Microsoft.Bot.Connector.Conversations.CreateConversationWithHttpMessagesAsync
Thanks in advance!
Rather than including the image as an attachment, consider instead sending an Adaptive Card and you can display the image directly to the user. See more on Adaptive Cards here.
As an alternative if you don't want to show the image but it's hosted somewhere, just include a link to it in the text message, using the markdown format that regular text message support in Teams (see more here).

Microsoft.Rest.ValidationException While trying to create a reply

I'm using the Microsoft Bot Framework with C# and I'm trying to create a reply message with an image like so:
IMessageActivity m = Activity.CreateMessageActivity();
var images = doc.DocumentNode.SelectNodes("//img[#src]").ToList();
var src = images[10].GetAttributeValue("src", null);
Attachment att = new Attachment();
att.ContentType = "image";
att.ContentUrl = src;
m.Attachments.Add(att);
await context.PostAsync(m);
context.Wait(MessageReceived);
I know that the image source is being extracted correctly but I still get the error:
Microsoft.Rest.ValidationException
What is the cause of this and how do I fix it?
I expect to have a message with the image attached but instead I just get the default bot code error message.
Edit: this is the exception message - 'ReplyToId' cannot be null.
If you are creating a message using the Activity.CreateMessageActivity() then you need to specify the details of user account(ToId,ToName), bot account(FromId, FromName) and conversation(conservationId, channelId).
eg:
var userAccount = new ChannelAccount(toId,toName);
var botAccount = new ChannelAccount(fromId, fromName);
var connector = new ConnectorClient(new Uri(serviceUrl));
IMessageActivity message = Activity.CreateMessageActivity();
if (!string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(channelId))
{
message.ChannelId = channelId;
}
else
{
conversationId = (await connector.Conversations.CreateDirectConversationAsync( botAccount, userAccount)).Id;
}
message.From = botAccount;
message.Recipient = userAccount;
message.Conversation = new ConversationAccount(id: conversationId);
message.Text = "The text you want to send";
//You can add your attachment here
message.Locale = "en-Us";
await connector.Conversations.SendToConversationAsync((Activity)message);
Looking at your code it looks like you can access the context of the Dialog since you are posting the message using context.PostAsync, so the easier way would be to send a message using the context since the context will already contain the details of user, bot and conversation.
You can do this by using context.MakeMessage()
eg:
IMessageActivity reply = context.MakeMessage();
var images = doc.DocumentNode.SelectNodes("//img[#src]").ToList();
var src = images[10].GetAttributeValue("src", null);
Attachment att = new Attachment();
att.ContentType = "image/png";
att.ContentUrl = src;
reply.Attachments.Add(att);
await context.PostAsync(reply);
context.Wait(MessageReceived);

Upload a file to specific folderid using REST Api

I've searched all documents in google drive api and I can't able to find how to upload a file to folderid using REST APi. Can anyone please help me on this?
public void UploadFiletoDrive()
{
var gmodel = GetAccessToken();
WebRequest request = WebRequest.Create("https://www.googleapis.com/upload/drive/v3/files/?uploadType=media");
request.Method = "POST";
request.Headers["Authorization"] = "Bearer " + gmodel.access_token;
request.ContentType = "image/jpeg";
Stream dataStream = request.GetRequestStream();
FileStream filestream = new FileStream(#"C:\Users\Developer\Downloads\unnamed (2).jpg", FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = filestream.Read(buffer, 0, buffer.Length)) != 0)
{
dataStream.Write(buffer, 0, bytesRead);
}
filestream.Close();
dataStream.Close();
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
}
It seems you've missed the Work with Folders docs.
Inserting a file in a folder using Java:
String folderId = "0BwwA4oUTeiV1TGRPeTVjaWRDY1E";
File fileMetadata = new File();
fileMetadata.setName("photo.jpg");
fileMetadata.setParents(Collections.singletonList(folderId));
java.io.File filePath = new java.io.File("files/photo.jpg");
FileContent mediaContent = new FileContent("image/jpeg", filePath);
File file = driveService.files().create(fileMetadata, mediaContent)
.setFields("id, parents")
.execute();
System.out.println("File ID: " + file.getId());
Implementation for other languages are also included like PHP, Python, NodeJS.
Also, check this SO thread for additional reference.
body.setParents(Arrays.asList(new ParentReference().setId(folderId)));
Your sample code is doing a media upload, ie. no metadata, You should be using a multipart upload so you can specify both metadata such as parent folder id and content.
Uploading a file to google drive using REST API has following steps.
Get parent folderID using list API
Create file with parent="folder ID" using create api and get "fileId" in response
upload file to "fileId
Following is javascript code to upload file using REST API
const url = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=media';
if(self.fetch){
// console.log("Fetch found, Using fetch");
var setHeaders = new Headers();
setHeaders.append('Authorization', 'Bearer ' + authToken.access_token);
setHeaders.append('Content-Type', mime);
var setOptions = {
method: 'PATCH',
headers: setHeaders,
body: blob
};
fetch(url,setOptions)
.then(response => { if(response.ok){
// console.log("save to google using fetch");
}
else{
// console.log("Response wast not ok");
}
})
.catch(error => {
// console.log("There is an error " + error.message);
});
}

Allow images in AtomPub ASPNET Web Api Server

I'm trying to create an Atompub service with ASP.NET WEB API, all it's ok but when I try to post any image from Windows Live Writer I get an error "The blog doesn't allow the image load" I'm reading the ietf doc.
My services controller code:
public class ServicesController : ApiController
{
public HttpResponseMessage Get()
{
var serviceDocument = new ServiceDocument();
var workSpace = new Workspace
{
Title = new TextSyndicationContent("Nicoloco Site"),
BaseUri = new Uri(Request.RequestUri.GetLeftPart(UriPartial.Authority))
};
var posts = new ResourceCollectionInfo("Nicoloco Blog",
new Uri(Url.Link("DefaultApi", new { controller = "blogapi" })));
posts.Accepts.Add("application/atom+xml;type=entry");
var images = new ResourceCollectionInfo("Images Blog",
new Uri(Url.Link("DefaultApi", new { controller = "images" })));
images.Accepts.Add("image/png");
images.Accepts.Add("image/jpeg");
images.Accepts.Add("image/jpg");
images.Accepts.Add("image/gif");
var categoriesUri = new Uri(Url.Link("DefaultApi", new { controller = "tags", format = "atomcat" }));
var categories = new ReferencedCategoriesDocument(categoriesUri);
posts.Categories.Add(categories);
workSpace.Collections.Add(posts);
workSpace.Collections.Add(images);
serviceDocument.Workspaces.Add(workSpace);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var formatter = new AtomPub10ServiceDocumentFormatter(serviceDocument);
var stream = new MemoryStream();
using (var writer = XmlWriter.Create(stream))
{
formatter.WriteTo(writer);
}
stream.Position = 0;
var content = new StreamContent(stream);
response.Content = content;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/atomsvc+xml");
return response;
}
}
The http GET Request generate the follow XML:
<?xml version="1.0" encoding="utf-8"?>
<app:service
xmlns:a10="http://www.w3.org/2005/Atom"
xmlns:app="http://www.w3.org/2007/app">
<app:workspace xml:base="http://localhost:53644/">
<a10:title type="text">Nicoloco Site</a10:title>
<app:collection href="http://localhost:53644/api/blogapi">
<a10:title type="text">Nicoloco Blog</a10:title>
<app:accept>application/atom+xml;type=entry</app:accept>
<app:categories href="http://localhost:53644/api/tags?format=atomcat" />
</app:collection>
<app:collection href="http://localhost:53644/api/images">
<a10:title type="text">Images Blog</a10:title>
<app:accept>image/png</app:accept>
<app:accept>image/jpeg</app:accept>
<app:accept>image/jpg</app:accept>
<app:accept>image/gif</app:accept>
</app:collection>
</app:workspace>
</app:service>
But I can't publish images using this service.
Best regards.
I found my error on "categories line", WLW log file shows a malformed XML error in this line, I removed it and all works fine for me... in this blog post explains how WLW Works with image files
If somebody have any comment... I'll be grateful

Resources