Is there a way to have a distance between 2 addresses calculated by Google Maps?
How?
If you just have two addreses first try to get lat lan by GEOCODING and then there are many methods to get distance in between.
OR
if you dont need geocoding and want a CS SOLUTION try this :
public int getDistance(string origin, string destination)
{
System.Threading.Thread.Sleep(1000);
int distance = 0;
//string from = origin.Text;
//string to = destination.Text;
string url = "http://maps.googleapis.com/maps/api/directions/json?origin=" + origin + "&destination=" + destination + "&sensor=false";
string requesturl = url;
//string requesturl = #"http://maps.googleapis.com/maps/api/directions/json?origin=" + from + "&alternatives=false&units=imperial&destination=" + to + "&sensor=false";
string content = fileGetContents(requesturl);
JObject o = JObject.Parse(content);
try
{
distance = (int)o.SelectToken("routes[0].legs[0].distance.value");
return distance;
}
catch
{
return distance;
}
return distance;
//ResultingDistance.Text = distance;
}
protected string fileGetContents(string fileName)
{
string sContents = string.Empty;
string me = string.Empty;
try
{
if (fileName.ToLower().IndexOf("http:") > -1)
{
System.Net.WebClient wc = new System.Net.WebClient();
byte[] response = wc.DownloadData(fileName);
sContents = System.Text.Encoding.ASCII.GetString(response);
}
else
{
System.IO.StreamReader sr = new System.IO.StreamReader(fileName);
sContents = sr.ReadToEnd();
sr.Close();
}
}
catch { sContents = "unable to connect to server "; }
return sContents;
}
OR
if you dont want to mess with google and need only AIR DISTANCE,Try this :
public decimal calcDistance(decimal latA, decimal longA, decimal latB, decimal longB)
{
double theDistance = (Math.Sin(DegreesToRadians(latA)) *
Math.Sin(DegreesToRadians(latB)) +
Math.Cos(DegreesToRadians(latA)) *
Math.Cos(DegreesToRadians(latB)) *
Math.Cos(DegreesToRadians(longA - longB)));
return Convert.ToDecimal((RadiansToDegrees(Math.Acos(theDistance)))) * 69.09M * 1.6093M;
}
NB: As of June 11th 2018 this approach will no longer work as Google has disabled keyless access to the Maps API. If you wish to use this approach you will have to sign up for their cloud platform and enable billing.
You can do this using the Google Directions API, you pass the start/end locations to the API as address strings or coordinates and Google will do all the leg work for you.
Routes are made up of various legs based on how many way points you specify. In your scenario (0 way points) you should only have 1 leg which should have an estimated distance property.
I have fixed the code from the answer above for it to work with google key.
Get you API key for google maps
Install Nuget package: Newtonsoft.Json
3.
public int getDistance(string origin, string destination)
{
System.Threading.Thread.Sleep(1000);
int distance = 0;
string key = "YOUR KEY";
string url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + origin + "&destination=" + destination + "&key=" + key;
url = url.Replace(" ", "+");
string content = fileGetContents(url);
JObject o = JObject.Parse(content);
try
{
distance = (int)o.SelectToken("routes[0].legs[0].distance.value");
return distance;
}
catch
{
return distance;
}
}
protected string fileGetContents(string fileName)
{
string sContents = string.Empty;
string me = string.Empty;
try
{
if (fileName.ToLower().IndexOf("https:") > -1)
{
System.Net.WebClient wc = new System.Net.WebClient();
byte[] response = wc.DownloadData(fileName);
sContents = System.Text.Encoding.ASCII.GetString(response);
}
else
{
System.IO.StreamReader sr = new System.IO.StreamReader(fileName);
sContents = sr.ReadToEnd();
sr.Close();
}
}
catch { sContents = "unable to connect to server "; }
return sContents;
}
Send a request to the Distance Matrix service or to the Directions-Service (when you need the distance of a route)
And I did this: but it return an empty string.
url = "http://maps.googleapis.com/maps/api/directions/json?origin=3320, rue de verdun, verdun&destination=379, 19e avenue, La Guadeloupe, G0M 1G0&sensor=false"
public string fileGetContents(string url)
{
string text = "";
var webRequest = HttpWebRequest.Create(url);
IAsyncResult asyncResult = null;
asyncResult = webRequest.BeginGetResponse(
state =>
{
var response = webRequest.EndGetResponse(asyncResult);
using (var sr = new StreamReader(response.GetResponseStream()))
{
text = sr.ReadToEnd();
}
}, null
);
return text;
}
Related
i have try with postman in my local server to route the API
this is my code
[HttpPost]
[Route("photo")]
public IHttpActionResult Upload()
{
// LOCAL VARIABLE
int ErrCode = 1;
dynamic ExpObj = new ExpandoObject();
string FilePath = HttpContext.Current.Server.MapPath("/Img");
// GET SID & DECRYPTING OBJEK TO JSON OBJ
var HttpRequest = HttpContext.Current.Request;
string SID = GetSID(this.Request.Headers);
dynamic objek = GetobjekuMultipart(SID, HttpRequest.Form["objek"]);
// EXTRACT OBJEK
string UserID = objek.userID;
if (HttpRequest.Files.Count > 0)
{
// GET UPLOADED IMAGE
var PostedFile = HttpRequest.Files["image"];
// SET FILE NAME ( USERID + Right(FileName,10) )
string FileName = GetFileName(UserID, PostedFile.FileName, 10);
// SAVE IMAGE
string ImagePath = Path.Combine(FilePath, FileName);
PostedFile.SaveAs(ImagePath);
ExpObj.imageURL = ServerUrl + ServerPath + FileName;
}
else
{
ErrCode = -900;
}
// RETURN IF GOT ERROR
if (ErrCode < 0)
{
return StatusCode((HttpStatusCode)(ErrCode * (-1)));
}
// SERIALIZING & ENCRYPTING
string SerializedObj = JsonConvert.SerializeObject(ExpObj, JsonSetting);
string EncryptedReturn = Encrypt(SerializedObj, SID);
// RETURN
return Ok(EncryptedReturn);
}
and this is my public method (General Method)
public string Decrypt(string cipherText, string sid)
{
RNCryptor.Decryptor D = new Decryptor();
string DecryptedString = "";
if (Prod == true)
{
try
{
DecryptedString = D.Decrypt(cipherText, sid + SigningKey);
}
catch (Exception ex)
{
int ErrCode = -902; // Error in Decrypt
throw new HttpResponseException((HttpStatusCode)(ErrCode * (-1)));
}
}
else
{
DecryptedString = cipherText;
}
return DecryptedString.Trim();
}
public dynamic GetObjekMultipart(string sid, string Objek)
{
string StrObjek = Decrypt(Objek, sid);
return JsonConvert.DeserializeObject<dynamic>(StrObjek);
}
public string GetFileName(string UserID, string fileName, int length)
{
string FileName;
string FileFormat;
// GET FILE FORMAT
string[] Words = fileName.Split('.');
FileFormat = "." + Words[Words.Length - 1];
// GET FILE NAME WITHOUT THE FILE FORMAT
FileName = fileName.Substring(0, fileName.Length - FileFormat.Length);
// SET THE FILE NAME
FileName = UserID + "-" + GetRight(FileName, length) + FileFormat;
return FileName;
}
and POSTMAN Result is "Object reference not set to an instance of an object"
the result said that the httprequest.form is NULL
please help :(
I've been wrestling with this for a while now and can't seem to find a solution. The closest I've come is PHP code for Oauth-1 by Joe Chung (https://github.com/joechung/oauth_yahoo), but I can't get my head wrapped around it.
I'm using Asp.Net, and this code is in the ContactController. I have no trouble Getting contacts from Yahoo. The problem is Adding a contact to a user's Yahoo address book. The program proceeds through the Yahoo login process, and there are no errors. But the contact is not saved. I hope someone can take a look at this and tell me what I'm missing.
Thanks.
private string AddYahooContact(string responseFromServer, string contactIdForYahoo)
{
// Some of this from http://www.yogihosting.com/implementing-yahoo-contact-reader-in-asp-net-and-csharp/
responseFromServer = responseFromServer.Substring(1, responseFromServer.Length - 2);
string accessToken = "", xoauthYahooGuid = "", refreshToken = "";
string[] splitByComma = responseFromServer.Split(',');
foreach (string value in splitByComma)
{
if (value.Contains("access_token"))
{
string[] accessTokenSplitByColon = value.Split(':');
accessToken = accessTokenSplitByColon[1].Replace('"'.ToString(), "");
}
else if (value.Contains("xoauth_yahoo_guid"))
{
string[] xoauthYahooGuidSplitByColon = value.Split(':');
xoauthYahooGuid = xoauthYahooGuidSplitByColon[1].Replace('"'.ToString(), "");
}
else if (value.Contains("refresh_token"))
{
string[] refreshTokenSplitByColon = value.Split(':');
refreshToken = refreshTokenSplitByColon[1].Replace('"'.ToString(), "");
}
}
// How to build contactUrl from https://developer.yahoo.com/social/rest_api_guide/contacts-resource.html#contacts-xml_request_put
// This is Yahoo's address to add a contact
string contactUrl = "https://social.yahooapis.com/v1/user/" + xoauthYahooGuid + "/contacts";
// Much of this from https://developer.yahoo.com/dotnet/howto-rest_cs.html
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(contactUrl);
webRequest.Method = "POST";
webRequest.Headers["Authorization"] = "Bearer " + accessToken;
webRequest.ContentType = "application/x-www-form-urlencoded"; // Tried "application/x-www-form-urlencoded & application/xml" & "text/xml".
// Create the data we want to send
string yahooContact = BuildYahooContact(contactIdForYahoo);
byte[] byteData = UTF8Encoding.UTF8.GetBytes(yahooContact);
webRequest.ContentLength = byteData.Length;
using (Stream postStream = webRequest.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
responseFromServer = "";
try
{
using (HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
responseFromServer = reader.ReadToEnd();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return yahooContact;
}
private string BuildYahooContact(string contactIdForYahoo)
{
Guid contactId = Guid.Parse(contactIdForYahoo);
Models.Contact contact = GetContactForId(contactId); // And find the contact
string firstName = "";
string lastName = "";
if (contact.FullName != null)
{
int index = contact.FullName.IndexOf(" ");
if (index > 0)
{
firstName = contact.FullName.Substring(0, index);
lastName = (contact.FullName.Substring(index + 1));
}
else
{
lastName = contact.FullName;
}
}
StringBuilder data = new StringBuilder();
data.Append("<contact>");
data.Append("<fields><type>name</type><value>");
data.Append("<givenName>" + firstName + "</givenName><middleName/>");
data.Append("<familyName>" + lastName + "</familyName>");
data.Append("<prefix/><suffix/><givenNameSound/><familyNameSound/>");
data.Append("</value></fields>");
data.Append("<fields><type>address</type>");
data.Append("<value><street>" + contact.Address + "</street>");
data.Append("<city>" + contact.City + "</city>");
data.Append("<stateOrProvince>" + contact.State + "</stateOrProvince>");
data.Append("<postalCode>" + contact.Zip + "</postalCode>");
data.Append("<country>United States</country>");
data.Append("<countryCode>US</countryCode>");
data.Append("</value></fields>");
data.Append("<fields><type>notes</type><value>" + contact.Note + "</value></fields>");
data.Append("<fields><type>link</type><value>" + contact.Website + "</value></fields>");
data.Append("<fields><type>email</type><value>" + contact.Email + "</value></fields>");
data.Append("<fields><type>phone</type><value>" + contact.BusinessPhone + "</value><flags>WORK</flags></fields>");
data.Append("<fields><type>phone</type><value>" + contact.BestPhone + "</value><flags>MOBILE</flags></fields>");
data.Append("<fields><type>phone</type><value>" + contact.SecondPhone + "</value><flags>PERSONAL</flags></fields>");
data.Append("<categories><category><name>GoGoContract</name></category></categories>");
data.Append("</contact>");
return data.ToString();
}
I'm using google map API. I have 4 destinations and I want to get their locations ordered by nearest location first followed by second nearest. I have to show on Google Map which location is 1st being the nearest and then the next nearest and so on. So far I have only successfully calculated the distance between 2 locations by using below code:
private void button1_Click(object sender, EventArgs e)
{
getDistance("DECATUR FARM ROAD CHICHESTER PO20 8JT", "UNIT 01 CLIFF REACH GREENHITHE DA9 9SW");
}
public int getDistance(string origin, string destination)
{
System.Threading.Thread.Sleep(1000);
int distance = 0;
//string from = origin.Text;
//string to = destination.Text;
string url = "http://maps.googleapis.com/maps/api/directions/json?origin=" + origin + "&destination=" + destination + "&sensor=false";
string requesturl = url;
//string requesturl = #"http://maps.googleapis.com/maps/api/directions/json?origin=" + from + "&alternatives=false&units=imperial&destination=" + to + "&sensor=false";
string content = fileGetContents(requesturl);
JObject o = JObject.Parse(content);
try
{
distance = (int)o.SelectToken("routes[0].legs[0].distance.value");
return distance;
}
catch
{
return distance;
}
return distance;
//ResultingDistance.Text = distance;
}
protected string fileGetContents(string fileName)
{
string sContents = string.Empty;
string me = string.Empty;
try
{
if (fileName.ToLower().IndexOf("http:") > -1)
{
System.Net.WebClient wc = new System.Net.WebClient();
byte[] response = wc.DownloadData(fileName);
sContents = System.Text.Encoding.ASCII.GetString(response);
}
else
{
System.IO.StreamReader sr = new System.IO.StreamReader(fileName);
sContents = sr.ReadToEnd();
sr.Close();
}
}
catch { sContents = "unable to connect to server "; }
return sContents;
}
How do I show the destinations according to their distance on google map. Any tip or pointers will be appreciated.
Please see the image, this is what I am trying to accomplish
Happy :) Enjoy Coding..
ArrayList arraylist;
List<string> adddistance = new List<string>();
List<string> getfinallist = new List<string>();
private void button1_Click(object sender, EventArgs e)
{
string s = "UNIT 01 CLIFF REACH GREENHITHE DA9 9SW,PINETOP BIRKLANDS LANE ST ALBANS AL1 1EE,HOLYWELL HILL ST ALBANS AL1 1BT,OLD RECTORY HOLYWELL HILL ST ALBANS AL1 1BY";
button("DECATUR FARM ROAD CHICHESTER PO20 8JT", s);
}
public void button(string orign , string destination)
{
string[] words = destination.Split(',');
foreach (string word in words)
{
getDistance(orign, word);
}
sorting();
}
public int getDistance(string origin, string destination)
{
System.Threading.Thread.Sleep(1000);
int distance = 0;
string url = "http://maps.googleapis.com/maps/api/directions/json?origin=" + origin + "&destination=" + destination + "&sensor=false";
string requesturl = url;
string content = fileGetContents(requesturl);
JObject o = JObject.Parse(content);
string strdistance = (string)o.SelectToken("routes[0].legs[0].distance.value") + " , " + destination + " , ";
adddistance.Add(strdistance);
return distance;
}
public void sorting()
{
adddistance.Sort();
string getfirststring = adddistance.FirstOrDefault().ToString() ;
var vals = getfirststring.Split(',')[1];
getfinallist.Add(getfirststring.Split(',')[1]);
StringBuilder builder = new StringBuilder();
adddistance.RemoveAt(0);
foreach (string cat in adddistance) // Loop through all strings
{
builder.Append(cat); // Append string to StringBuilder
}
adddistance.Where((wors, index) => index % 2 == 0);
string result = builder.ToString();
string[] words = result.Split(',');
string[] even = words.Where((str, ix) => ix % 2 == 1).ToArray();
adddistance.Clear();
foreach (string word in even)
{ //string get = Regex.Match(word, #"^[" + numSet + #"]+$").ToString();
if (word != " ")
{
getDistance(vals, word);
}
}
sorting();
}
protected string fileGetContents(string fileName)
{
string sContents = string.Empty;
string me = string.Empty;
try
{
if (fileName.ToLower().IndexOf("http:") > -1)
{
System.Net.WebClient wc = new System.Net.WebClient();
byte[] response = wc.DownloadData(fileName);
sContents = System.Text.Encoding.ASCII.GetString(response);
}
else
{
System.IO.StreamReader sr = new System.IO.StreamReader(fileName);
sContents = sr.ReadToEnd();
sr.Close();
}
}
catch { sContents = "unable to connect to server "; }
return sContents;
}
I am having a problem receiving files from the client. Someone suggested that I should use binary serialization to send and receive messages in stream. Can you give me ideas on how I should serialize this? I just learned about serialization not long ago so I am quite confused on how I should associate it with my program.
This is the client that 'should' be serialize
public void sendthedata()
{
if (!_timer.Enabled) // If timer is not running send data and start refresh interval
{
SendData();
_timer.Enabled = true;
}
else // Stop timer to prevent further refreshing
{
_timer.Enabled = false;
}
}
private List<int> listedProcesses = new List<int>();
private void SendData()
{
String processID = "";
String processName = "";
String processPath = "";
String processFileName = "";
String processMachinename = "";
listBox1.BeginUpdate();
try
{
piis = GetAllProcessInfos();
for (int i = 0; i < piis.Count; i++)
{
try
{
if (!listedProcesses.Contains(piis[i].Id)) //placed this on a list to avoid redundancy
{
listedProcesses.Add(piis[i].Id);
processID = piis[i].Id.ToString();
processName = piis[i].Name.ToString();
processPath = piis[i].Path.ToString();
processFileName = piis[i].FileName.ToString();
processMachinename = piis[i].Machinename.ToString();
output.Text += "\n\nSENT DATA : \n\t" + processFileName + "\n\t" + processMachinename + "\n\t" + processID + "\n\t" + processName + "\n\t" + processPath + "\n";
}
}
catch (Exception ex)
{
wait.Abort();
output.Text += "Error..... " + ex.StackTrace;
}
NetworkStream ns = tcpclnt.GetStream();
String data = "";
data = "--++" + processFileName + " " + processMachinename + " " + processID + " " + processPath;
if (ns.CanWrite)
{
byte[] bf = new ASCIIEncoding().GetBytes(data);
ns.Write(bf, 0, bf.Length);
ns.Flush();
}
}
}
finally
{
listBox1.EndUpdate();
}
}
And deserializing in the server
private void recieveData()
{
NetworkStream nStream = tcpClient.GetStream();
ASCIIEncoding ascii = null;
while (!stopRecieving)
{
if (nStream.CanRead)
{
byte[] buffer = new byte[1024];
nStream.Read(buffer, 0, buffer.Length);
ascii = new ASCIIEncoding();
recvDt = ascii.GetString(buffer);
/*Received message checks if it has +##+ then the ip is disconnected*/
bool f = false;
f = recvDt.Contains("+##+");
if (f)
{
string d = "+##+";
recvDt = recvDt.TrimStart(d.ToCharArray());
clientDis();
stopRecieving = true;
}
//else if (recvDt.Contains("^^"))
//{
// new Transmit_File().transfer_file(file, ipselected);
//}
/* ++-- shutsdown/restrt/logoff/abort*/
else if (recvDt.Contains("++--"))
{
string d = "++--";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
clientDis();
}
/*--++ Normal msg*/
else if (recvDt.Contains("--++"))
{
string d = "--++";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
}
}
Thread.Sleep(1000);
}
}
public void addToOutput()
{
if (recvDt != null && recvDt != "")
{
output.Text += "\n Received Data : " + recvDt;
recvDt = null;
}
}
Thank you.
There are a couple of rules to follow when serialising a piece of data.
It's easy to convert data to bytes, but consider how to reconstruct the data on the other side. Assume that the server can't have any knowledge on what you sended.
In your serialiser you just convert a couple of strings into a byte[] and send it over. Example:
string x = "abcdef";
string y = "ghijk";
var bytes = Encoding.Ascii.GetBytes(x + y);
the server receives: "abcdefghijk";
Is it possible for the server to determine and reconstruct strings x and y?
Since the server has no knowledge of the length of either x and y: no.
There are ways to solve this:
Use fixed length fields. In my example x should always be 6 chars and y should always be 5 chars in length. decoding on the server then becomes as trivial as
string x = data.Substring(0, 6)
string y = data.Substring(6, 5)
Use delimiters between the fields. If you are familiar with cvs, the ',' splits the fields. This however has it drawbacks, how to handle a ',' somewhere in a string? The data send over would be like "abcdef,ghijk"
Send the size of each field before the content of the field.
A naive approach just to clarify: string x would be send as '6abcdef' and y as '5ghijk'
Doing all this things by hand can get really hairy and is something that I would consider only if really needed.
I would resort to existing frameworks that do an excellent job on this subject:
Json.net
protobuf ported by Jon skeet
In this case I would first create a class to define the data send to the server instead of a bunch of strings:
class ProcessInfo{
public string ProcessID {get;set;}
public string ProcessName {get;set;}
public string ProcessPath {get;set;}
public string ProcessFileName {get;set;}
public string ProcessMachinename {get;set;}
};
the using Json to serialise this:
var procinfo = new ProcessInfo{
ProcessId = "1",
...
};
var serialised = JsonConvert.SerializeObject(procinfo);
var bytes = Encoding.Utf8.GetBytes(serialised);
ns.Write(bytes, 0, bytes.Length);
And restore it on the server just by:
var procInfo = JsonConvert.DeserializeObject<ProcessInfo>(json);
I have some code that uses the WEBDAV 'SEARCH' method to retrieve emails from an an Exchange Mailboxs 'Inbox' folder - my code takes the the innerXML of the HTTPWebRquests WEBresponse.
Using 'selectingSingleNode' on these namsspaces:
'urn:schemas:httpmail' & urn:schemas:mailheader
Alows me to extract the elements:
f:textdescription
d:fromd:subject
f:datareceived...and so on
I then create a collection of these details in a list and using the 'Subject' along with the URI use the 'PUT' method to recreate these messages in the 'draft's folder before using the 'MOVE' to send the mails (puts them in the sent items using '/##DavMailSubmissionURI##/"' statement.
The problem i have is the nature of the emails i am dealing with tend to come in with the same subject line so it gets confused with which emails have been sent/or not.
Does anyone know of a way around this, I dont know why the 'PUT' relies on the Subject line for the URI to the mail resource rather than say the HREF tag which is unique. Any ideas:
Code is below:
public class EmailReaderWebDav
{
public enum enmHTTPType
{
HTTP,
HTTPS,
}
private String strServer { get; set; } //"mail1" ------ Exchange server name
public String strPassword { get; set; } //"password" ------ Account Domain Password
public String strDomain { get; set; } //"mydocmian" ------ Domain
public String strMailBox { get; set; } //"mymailbox" ------ UserName
public String mailFolder { get; set; } //"inbox" ------ Mail Folder
private String httpProtocol { get; set; } //http:// ? or https://
private String mailboxURI { get; set; } //httpprotocol// + strserver + "/exhange/" + strmailbox
public List<MailStruct > ListOfEmailDetails { get; private set; }
private String strQuerySearch { get; set; }
public EmailReaderWebDav(String serverName, String domain, String mailBox, String password, String mailmailFolder,enmHTTPType HTTPType)
{
strServer = serverName;
strDomain = domain;
strMailBox = mailBox;
strPassword = password;
mailFolder = mailmailFolder;
httpProtocol = (HTTPType == enmHTTPType.HTTPS) ? "https://" : "http://";
mailboxURI = httpProtocol + strServer + "/exchange/" + strMailBox + "/inbox/";
}
public void forwardEmails(List<MailStruct> emailsToSend)
{
emailsToSend.ForEach(x => SendEmail(x,enmHTTPType.HTTP ));
}
public void MakeListofEmailsToForward()
{
String tmpQuery =
"<?xml version=\"1.0\"?>"
+ "<D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>"
+ " SELECT "
+ "\"urn:schemas:mailheader:to\","
+ "\"urn:schemas:mailheader:from\","
+ "\"urn:schemas:mailheader:subject\","
+ "\"urn:schemas:httpmail:datereceived\","
+ "\"urn:schemas:httpmail:textdescription\""
+ " FROM \"" + mailboxURI + "\""
+ " WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"
+ "</D:sql>"
+ "</D:searchrequest>";
// Search Request to get emails from target folder.
HttpWebRequest SearchRequest = MakeWebRequest("SEARCH", "text/xml", mailboxURI);
Byte[] bytes = Encoding.UTF8.GetBytes((String)tmpQuery);
SearchRequest.ContentLength = bytes.Length;
Stream SearchRequestStream = SearchRequest.GetRequestStream();
SearchRequestStream.Write(bytes, 0, bytes.Length);
SearchRequestStream.Close();
// get the webresponse from the searchrequest.
WebResponse SearchResponse = MakeWebResponse(SearchRequest);
String EmailsInXML = extractXMLFromWebResponse(SearchResponse);
ListOfEmailDetails = extractMailPropertiesFromXMLString(EmailsInXML);
}
public void SendEmail(MailStruct mailToForward, enmHTTPType HTTPType)
{
String submissionUri = httpProtocol + strServer + "/" + "exchange" + "/" + strMailBox + "/##DavMailSubmissionURI##/";
String draftsUri = httpProtocol + strServer + "/" +"exchange" + "/" + strMailBox + "/Drafts/" + mailToForward.Subject + ".eml";
String message = "To: " + mailToForward.To + "\n"
+ "Subject: " + mailToForward.Subject + "\n"
+ "Date: " + mailToForward.Received
+ "X-Mailer: mailer" + "\n"
+ "MIME-Version: 1.0" + "\n"
+ "Content-Type: text/plain;" + "\n"
+ "Charset = \"iso-8859-1\"" + "\n"
+ "Content-Transfer-Encoding: 7bit" + "\n"
+ "\n" + mailToForward.MailBody;
// Request to put an email the drafts folder.
HttpWebRequest putRequest = MakeWebRequest("PUT", "message/rfc822",draftsUri );
Byte[] bytes = Encoding.UTF8.GetBytes((String)message);
putRequest.Headers.Add("Translate", "f");
putRequest.Timeout = 300000;
putRequest.ContentLength = bytes.Length;
Stream putRequestStream = putRequest.GetRequestStream();
putRequestStream.Write(bytes, 0, bytes.Length);
putRequestStream.Close();
// Put the message in the Drafts folder of the sender's mailbox.
HttpWebResponse putResponse = MakeWebResponse(putRequest);
putResponse.Close();
// Request to move the email from the drafts to the mail submission Uri.
HttpWebRequest moveRequest = MakeWebRequest("MOVE", "text/xml", draftsUri);
moveRequest.Headers.Add("Destination", submissionUri);
// Put the message in the mail submission folder.
HttpWebResponse moveResponse = MakeWebResponse(moveRequest);
moveResponse.Close();
}
private CredentialCache getCredentials(String URI)
{
CredentialCache tmpCreds = new CredentialCache();
tmpCreds.Add(new Uri(URI), "NTLM", new NetworkCredential(strMailBox, strPassword,strDomain ));
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
return tmpCreds;
}
private HttpWebRequest MakeWebRequest(String method,String contentType,String URI)
{
HttpWebRequest tmpWebRequest;
tmpWebRequest = (HttpWebRequest)HttpWebRequest.Create(URI);
tmpWebRequest.Credentials = getCredentials (URI);
tmpWebRequest.Method = method;
tmpWebRequest.ContentType = contentType ;
return tmpWebRequest ;
}
private HttpWebResponse MakeWebResponse(HttpWebRequest webRequest)
{
HttpWebResponse tmpWebresponse = (HttpWebResponse)webRequest.GetResponse();
return tmpWebresponse;
}
WebResponse getMailsFromWebRequest(String strRootURI, String strQuerySearch)
{
HttpWebRequest SEARCHRequest;
WebResponse SEARCHResponse;
CredentialCache MyCredentialCache;
Byte[] bytes = null;
Stream SEARCHRequestStream = null;
try
{
MyCredentialCache = new CredentialCache();
MyCredentialCache.Add(new Uri(strRootURI ), "NTLM", new NetworkCredential(strMailBox.ToLower(), strPassword, strDomain));
SEARCHRequest = (HttpWebRequest)HttpWebRequest.Create(strRootURI );
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
SEARCHRequest.Credentials = MyCredentialCache;
SEARCHRequest.Method = "SEARCH";
SEARCHRequest.ContentType = "text/xml";
bytes = Encoding.UTF8.GetBytes((string)strQuerySearch);
SEARCHRequest.ContentLength = bytes.Length;
SEARCHRequestStream = SEARCHRequest.GetRequestStream();
SEARCHRequestStream.Write(bytes, 0, bytes.Length);
SEARCHResponse =(HttpWebResponse ) SEARCHRequest.GetResponse();
SEARCHRequestStream.Close();
SEARCHRequest.Timeout = 300000;
System.Text.Encoding enc = System.Text.Encoding.Default;
if (SEARCHResponse == null)
{
Console.WriteLine("Response returned NULL!");
}
else
{
Console.WriteLine(SEARCHResponse.ContentLength);
}
return SEARCHResponse;
}
catch (Exception ex)
{
Console.WriteLine("Problem: {0}", ex.Message);
return null;
}
}
private String extractXMLFromWebResponse(WebResponse SearchResponse)
{
String tmpStream;
using(StreamReader strmReader = new StreamReader(SearchResponse.GetResponseStream(), System.Text.Encoding.ASCII))
{
tmpStream = strmReader.ReadToEnd();
strmReader.Close();
}
return tmpStream;
}
private List<MailStruct > extractMailPropertiesFromXMLString(String strXmlStream)
{
List<MailStruct> tmpListOfMailProperties = new List<MailStruct>();
XmlDocument doc = new XmlDocument();
doc.InnerXml = strXmlStream ;
XmlNamespaceManager xmlNameSpaces = new XmlNamespaceManager(doc.NameTable);
xmlNameSpaces.AddNamespace("a", "DAV:");
xmlNameSpaces.AddNamespace("f", "urn:schemas:httpmail:");
xmlNameSpaces.AddNamespace("d", "urn:schemas:mailheader:");
XmlNodeList mailNodes = doc.SelectNodes("//a:propstat[a:status='HTTP/1.1 200 OK']/a:prop", xmlNameSpaces);
foreach (XmlElement node in mailNodes)
{
tmpListOfMailProperties.Add(new MailStruct()
{
MailBody = node.SelectSingleNode("//f:textdescription",xmlNameSpaces ).InnerText ,
from = node.SelectSingleNode ("//d:from",xmlNameSpaces ).InnerText ,
To = "dfoster#liquidcapital.com",
Subject = node.SelectSingleNode("//d:subject",xmlNameSpaces ).InnerText.ToString () ,
Received = node.SelectSingleNode ("//f:datereceived",xmlNameSpaces ).InnerText.ToString ()
}
);
}
return tmpListOfMailProperties;
}
public struct MailStruct
{
public String To { get; set; }
public String from { get; set; }
public String Subject { get; set; }
public String Received { get; set; }
public String MailBody { get; set; }
}
}
}
Using just the subject to identify email is, indeed, not a good way. If I remember it's correct, there are no automatic / obvious email id for exchange / webdav?
If you parse the subject to pick message, I would also pick more information of the email envelope - Like it size, length to create my own id. The best step should be that you create some sort of hash (check Cryptography) out of the whole message body OR i.e. first character of first xx word in the email body (heavier processing though). That will end up in same hash value everytime you call it on same email envelope. Of until the email content is leaved unchanged.
Looks like you're working with Exchange 2003. Be aware that WebDAV is no longer supported in Exchange Version 2010... and with 2007 and newer you can use a WSDL to do everything you need. All you need is an Exchange 2007 CAS to do this.
What I mentioned is a better longer term approach and has less headaches than parsing unsupported WEBDAV XML
To answer your question, there is a property that is unique per message. Use MFCMapi (on codeplex) to look for it. The property will be named "MessageURL" or something like that. Use that property in the URL for your webdav calls.