Sending Form data alongwith File Data for Content Type "application/vnd.ms-project" for MPP files - postdata

I need to send some post data along with a file stream. I'm using the following code.
This code is taken from
http://technet.rapaport.com/Info/LotUpload/SampleCode/Full_Example.aspx.
private Stream GetPostStream(string filePath, Dictionary<string, string> paramMap, string boundary) {
Stream postDataStream = new System.IO.MemoryStream();
//adding form data
string formDataHeaderTemplate = Environment.NewLine + "--" + boundary + Environment.NewLine +
"Content-Disposition: form-data; name=\"{0}\";" + Environment.NewLine + Environment.NewLine + "{1}";
foreach (KeyValuePair<string, string> pair in paramMap)
{
byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(formDataHeaderTemplate, pair.Key, pair.Value));
postDataStream.Write(formItemBytes, 0, formItemBytes.Length);
}
//adding file data
FileInfo fileInfo = new FileInfo(filePath);
string fileHeaderTemplate = Environment.NewLine + "--" + boundary + Environment.NewLine +
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
Environment.NewLine + "Content-Type: application/vnd.ms-project" + Environment.NewLine + Environment.NewLine;
byte[] fileHeaderBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(fileHeaderTemplate, "UploadMPPFile", fileInfo.FullName));
postDataStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
FileStream fileStream = fileInfo.OpenRead();
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
postDataStream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] endBoundaryBytes = System.Text.Encoding.UTF8.GetBytes("--" + boundary + "--");
postDataStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
return postDataStream;
}
On the server side which is on JAVA, I'm using MPXJ 3rd party library to read the the file data. However, there I'm encountering the following exception. It reports some mismatch error in Header signature.
Nested exception is: net.sf.mpxj.MPXJException: Error reading file]
with root cause java.io.IOException: Invalid header signature; read
0x2D2D2D2D2D2D0A0D, expected 0xE11AB1A1E011CFD0 at
org.apache.poi.poifs.storage.HeaderBlockReader.(HeaderBlockReader.java:125)
at
org.apache.poi.poifs.filesystem.POIFSFileSystem.(POIFSFileSystem.java:153)
at net.sf.mpxj.mpp.MPPReader.read(MPPReader.java:84)
Could anyone please help me out with this situation and suggest some solutions!
Thanks a lot.

Looks suspiciously like the receiving end is not separating the header data you are writing to the stream from the payload data. Might be worth trying the following:
Validate that you are reading the MPP file correctly by replacing the call to postDataStream.Write with a write to a local file stream. Validate that the content of the file you create is identical to the file you are reading.
Replace the receiving code on the server side with something which simply echos the received data to a file so you can validate what is being received.
Update the existing receiving code to write the extracted header data and the payload data to separate files to validate that both are being received correctly and that the payload filematches what is being sent from the client.

Related

Use Exchange Web Service Managed API to retrieve max send mail size limit

I've been looking around for some way to use the EWS managed API to retrieve the maximum mail size limit for sending, but have not found any working solution...
So far, I've came across this link: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-get-service-configuration-information-by-using-ews-in-exchange#code-example-get-service-configuration-information-for-mail-tips-by-using-ews
Which basically retrieves the The maximum message size in the Mail Tips. But the thing is, when I tried out the code, I got an 500 internal server error. And there doesn't seem to be a way to do this directly using the Managed API itself.
Greatly appreciate any help.
Thanks!
There is a bug in the Microsoft Sample they have modified the SOAP namespaces from http to https. Probably some editor thought they where doing the correct thing without understanding how XML schema's work. But a working sample is
private static void GetServiceConfiguration()
{
// XML for the GetServiceConfiguration request SOAP envelope for mail tips configuration information.
const string getServiceConfigurationRequest =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\"\n" +
" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" \n" +
" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" +
" <soap:Header>\n" +
" <t:RequestServerVersion Version=\"Exchange2013\" />\n" +
" </soap:Header>\n" +
" <soap:Body>\n" +
" <m:GetServiceConfiguration>\n" +
" <m:ActingAs>\n" +
" <t:EmailAddress>user#domain.com</t:EmailAddress>\n" +
" <t:RoutingType>SMTP</t:RoutingType>\n" +
" </m:ActingAs>\n" +
" <m:RequestedConfiguration>\n" +
" <m:ConfigurationName>MailTips</m:ConfigurationName>\n" +
" </m:RequestedConfiguration>\n" +
" </m:GetServiceConfiguration>\n" +
" </soap:Body>\n" +
"</soap:Envelope>";
// Encoded GetServiceConfiguration operation request.
byte[] payload = System.Text.Encoding.UTF8.GetBytes(getServiceConfigurationRequest);
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://outlook.office365.com/ews/exchange.asmx");
request.AllowAutoRedirect = false;
request.Credentials = new NetworkCredential("user#domain.com", "blah");
request.Method = "POST";
request.ContentType = "text/xml";
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
Stream requestStream = request.GetRequestStream();
requestStream.Write(payload, 0, payload.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine("You will need to parse this response to get the configuration information:\n\n" + responseFromServer);
reader.Close();
responseStream.Close();
}
else
throw new WebException(response.StatusDescription);
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
I've also added in a useragent as this can sometimes also cause the code to fail if useragent restriction have been set. But you should also switch to using OAuth if you are using this against Office365.

How can I attach file to message with Microsoft Bot Framework?

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.

Uploading big files with POST freezes the system

i have an application which upload files (video files) to a server using the standard post request, something like:
QNetworkRequest request(QUrl("myUrl"));
QString bound="margin";
QByteArray data(QString("--"+bound+"\r\n").toLatin1());
data += "Content-Disposition: form-data; name=\"media_id\"\r\n\r\n";
data += id + "\r\n";
data += QString("--" + bound + "\r\n").toLatin1();
QString str = "Content-Disposition: form-data; name=\"file\"; filename=\"" + name + "\r\n";
data += str;
data += "Content-Type: video/mp4\r\n\r\n";
QFile f(path);
if(! f.open(QIODevice::ReadOnly))
{
qDebug() << "uploadMediaRequest error opening " << path;
return false;
}
QByteArray bytes;
bytes = f.readAll();
data.append(bytes);
data += "\r\n";
data += QString("--" + bound + "\r\n.").toLatin1();
data += "\r\n";
f.close();
request.setRawHeader(QString("Accept").toLatin1(),QString("application/json, text/javascript, */*; q=0.01").toLatin1());
request.setRawHeader(QString("Origin").toLatin1(),QString("http://dev.teamhood.io").toLatin1());
request.setRawHeader(QString("API-Client").toLatin1(),QString("desktop").toLatin1());
request.setRawHeader(QString("withCredentials").toLatin1(), QString("true").toLatin1());
request.setRawHeader(QString("Content-Type").toLatin1(),QString("multipart/form-data; boundary=" + bound).toLatin1());
request.setRawHeader(QString("Content-Length").toLatin1(), QString::number(data.length()).toLatin1());
And then POST that request.
For files of 1GB or less it works just fine but if i try to upload a file of 1,5GB i get
myProgramName[948:32028] Communications error: <OS_xpc_error: <error: 0x7fff7c37bb60> { count = 1, contents =
"XPCErrorDescription" => <string: 0x7fff7c37bfa8> { length = 22, contents = "Connection interrupted" }}>
Got xpc error message: Connection interrupted
and the app and the SO freeze to death.
I suppose i can split the big files and upload them in parts and make the server assemble them but i was wondering if any of you could give me an explanation for this strange errors.
I work with OSX & Qt 5.4, thx in advance!
Solved by user Pavel Strakhov:
QNetworkRequest request(QUrl("myUrl"));
QFile *f = new QFile(path);
if(! f->open(QIODevice::ReadOnly))
{
qDebug() << "uploadMediaRequest error opening " << path;
return false;
}
QHttpMultiPart * multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart idPart, mediaPart;
idPart.setHeader(QNetworkRequest::ContentDispositionHeader,QVariant("form-data; name=\"media_id\""));
idPart.setBody(id.toLatin1());
mediaPart.setHeader(QNetworkRequest::ContentTypeHeader, type);
mediaPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\""+ name + "\""));
mediaPart.setBodyDevice(f);
f->setParent(multiPart);
multiPart->append(idPart);
multiPart->append(mediaPart);
request.setRawHeader(QString("Accept").toLatin1(),QString("application/json, text/javascript, */*; q=0.01").toLatin1());
request.setRawHeader(QString("Origin").toLatin1(),QString("http://dev.teamhood.io").toLatin1());
request.setRawHeader(QString("API-Client").toLatin1(),QString("desktop").toLatin1());
request.setRawHeader(QString("withCredentials").toLatin1(), QString("true").toLatin1());
networkManager->post(request, multiPart));
Now it runs great.

square Connect API Batch

I am using .NET to list the payments from my square account.
I am able to get a list of the payments, but to get the description field I have to go one level deeper and make http end point calls for each payment. This is time consuming.
Question: Can anyone provide me with a sample in Visual C# or Java to make batch calls for retrieving payments (using multiple payment id's)?
Your help is greatly appreciated.
Thanks,
Prashant
#Andrew - Here's what I am using, I am just not sure how to add the headers for batch payments retrieval.
string res = string.Empty;
string qs = string.Empty;
foreach (string s in parameters.Keys)
{
if (qs == string.Empty)
qs = "?";
else
qs += "&";
qs += s + "=" + parameters[s];
}
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(_connectUrl + "/" + command + qs); ///
request.Proxy = null;
request.Headers.Add("Authorization", "Bearer " + _accessToken);// ");
request.ContentType = "application/json";
request.Method = method; // "GET";
try { HttpWebResponse responseGet = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(responseGet.GetResponseStream());
StringBuilder output = new StringBuilder();
output.Append(reader.ReadToEnd());
responseGet.Close();
request = null;
return output.ToString();
}
catch (Exception exp)
Looks like I've been able to answer my own query.
We need to be able to send the following POST to the HTTP Endpoint
{"requests":[{"method":"GET","relative_path":"/v1/me/payments/<payment_id>","access_token":"XXXX","request_id":"1"},{"method":"GET","relative_path":"/v1/me/payments/<payment_id>","access_token":"XXXX","request_id":"2"}]}
the following code in .NET achieves the above
//Convert the body of request into a byte array
byte[] byteArray = Encoding.UTF8.GetBytes(body);
//Set the length
request.ContentLength = byteArray.Length;
//Write the body to the request by using a datastream
//This line never returns....
Stream datastream = request.GetRequestStream();
datastream.Write(byteArray, 0, byteArray.Length);
datastream.Close();
And that's all there is to it.
Hope this helps anyone is is set out to use the batch mode.
Thanks

How can I get the Exchange Server programmatically from my App(C#)

Currently I can send email successfully through WebDAV with C#, but there is a shortage in my App that I have hard-code the Exchange Server of my outlook, so it might only works for me, if it were moved to another PC and use another outlook account, it might not work because the Exchange Server for this outlook account might not the same as mine(that's beacuse our company for different email account might assign different Exchange server), so my question is that how can I get the Exchange Server for the current Email accout dynamically. In fact I can get this Exchange Server from the outlook client when I clicked the menu item to add a new Outlook Account, but dose there exist any API for me to get this Exchange Server programmatically such as with C#?
In fact I use the following code to send Email:
using System;
using System.Net;
using System.IO;
namespace WebDavNET
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
static void Main(string[] args)
{
try
{
// TODO: Replace with the name of the computer that is running Exchange 2000.
string strServer = "ExchServe";
// TODO: Replace with the sender's alias.
string strSenderAlias = "sender";
// TODO: Replace with the sender's e-mail address.
string strFrom = "sender#example.com";
// TODO: Replace with the recipient's e-mail address.
string strTo = "recipient#example.com";
string strSubject = "Send Using HttpWebRequest";
string strBody = "Hello World";
string sUri;
sUri = "http://" + strServer + "/Exchange/" + strSenderAlias;
sUri = sUri + "/%23%23DavMailSubmissionURI%23%23/";
System.Uri myUri = new System.Uri(sUri);
HttpWebRequest HttpWRequest = (HttpWebRequest)WebRequest.Create(myUri);
string sQuery;
DateTime mySentTime = new DateTime();
sQuery = "From: " + strFrom + "\n" +
"To: " + strTo + "\n" +
"Subject: " + strSubject + "\n" +
"Date: " + DateTime.Now.ToString() + "\n" +
"X-Mailer: My DAV mailer" + "\n" +
"MIME-Version: 1.0" + "\n" +
"Content-Type: text/plain;" + "\n" +
"Charset = \"iso-8859-1\"" + "\n" +
"Content-Transfer-Encoding: 7bit" + "\n" + "\n" +
strBody;
// Set the credentials.
// TODO: Replace with the appropriate user credential.
NetworkCredential myCred = new NetworkCredential(#"DomainName\User", "Password");
CredentialCache myCredentialCache = new CredentialCache();
myCredentialCache.Add(myUri, "Basic", myCred);
HttpWRequest.Credentials = myCredentialCache;
// Set the headers.
HttpWRequest.Headers.Set("Translate", "f");
HttpWRequest.ContentType = "message/rfc822";
HttpWRequest.ContentLength = sQuery.Length;
//Set the request timeout to 5 minutes.
HttpWRequest.Timeout = 300000;
// Set the request method.
HttpWRequest.Method = "PUT";
// Store the data in a byte array.
byte[] ByteQuery = System.Text.Encoding.ASCII.GetBytes(sQuery);
HttpWRequest.ContentLength = ByteQuery.Length;
Stream QueryStream = HttpWRequest.GetRequestStream();
// write the data to be posted to the Request Stream
QueryStream.Write(ByteQuery,0,ByteQuery.Length);
QueryStream.Close();
// Send the request and get the response.
HttpWebResponse HttpWResponse = (HttpWebResponse)HttpWRequest.GetResponse();
// Get the Status code.
int iStatCode = (int)HttpWResponse.StatusCode;
string sStatus = iStatCode.ToString();
Console.WriteLine("Status Code: {0}", sStatus);
// Get the request headers.
string sReqHeaders = HttpWRequest.Headers.ToString();
Console.WriteLine(sReqHeaders);
// Read the response stream.
Stream strm = HttpWResponse.GetResponseStream();
StreamReader sr = new StreamReader(strm);
string sText = sr.ReadToEnd();
Console.WriteLine("Response: {0}", sText);
// Close the stream.
strm.Close();
// Clean up.
myCred = null;
myCredentialCache = null;
HttpWRequest = null;
HttpWResponse = null;
QueryStream = null;
strm = null;
sr = null;
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
}
}
As you can see in the code there is a variable named "strServer", In my App I just hard-code my Exchange Server for this variable, so my question is that dose there exist any API for me to get the Exchange Server dynamically for the specific outlook account?
Thanks!
You can use EWS(exchange Web Services) too. here is the link
You can use XML creator for creating items or requests required for operations in the link. Just go through the operations given on the link.

Resources