Problem with the AttachFile API

Have a question about Bullhorn's HTTP based APIs? You've found the right place.

API Update [posted on December 13, 2012]:

This version of the Bullhorn APIs should no longer be used.

All new work should be done using Bullhorn's REST or Web Services APIs. For more information please visit: http://developer.bullhorn.com/documentation

Bullhorn REST API provides a simpler and faster way for developers to build applications that interact with the Bullhorn platform and is used by Bullhorn Inc. to develop features of the Bullhorn ATS/CRM application.

Of the BullhornSTAFFING HTTP API interfaces listed below, our analysis shows that the following are most commonly used by developers:

Resume Parsing API
Published Job Data (XML)
The interface to these will continue to work as is because Bullhorn will replace the back end to use REST API. The URLs for these 2 specific APIs may change in the 2nd half of 2013; developers may require to update their applications to use the new URLs.

Moderators: StaffingSupport, s.emmons

Locked
rkarthy
User
Posts: 39
Joined: Mon Feb 11, 2008 12:49 pm
Location: Wakefield, MA, USA

Problem with the AttachFile API

Post by rkarthy » Mon Mar 03, 2008 12:22 pm

Hi,

I'm using the AttachFile API to update the resume for a candidate. I'm passing the following parameters to update the resume.

querystring["privateLabelID"] = Generic.PrivateLabelID;
querystring["encryptedAPIKey"] = Generic.EncryptedAPIKey;
querystring["userID"] = BHID;
querystring["userFile"] = "c:\resume.doc";
querystring["updateResumeOverview"] = "TRUE";

The problem is, when i pass the "updateResumeOverview" parameter as TRUE it should parse the resume in HTML and update it on the candidate profile. But it wouldn't do it. It simply take the "updateResumeOverview" parameter value as "FALSE" and not doing the HTML parsing and updation on candidate profile.

Pls. suggest me.

Thanks in advance,
Regards,
Karthik

cseibert
Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Mar 03, 2008 12:37 pm

There is a known issue when posting from PHP using CURL. Is that the case here?

I assume the file is being attached to the Candidate record properly, but not parsed?

rkarthy
User
Posts: 39
Joined: Mon Feb 11, 2008 12:49 pm
Location: Wakefield, MA, USA

Post by rkarthy » Mon Mar 03, 2008 1:58 pm

Yes. The file is being attached to the Candidate record properly, but not parsed.

I'm using C#. Is there any sample code snippet is there?

Regards,
Karthik

cseibert
Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Mar 03, 2008 2:01 pm

I think I see the issue. Try posting that option field as a FORM variable rather than a query string variable.

See:
http://supportforums.bullhorn.com/viewt ... meoverview

rkarthy
User
Posts: 39
Joined: Mon Feb 11, 2008 12:49 pm
Location: Wakefield, MA, USA

Post by rkarthy » Mon Mar 03, 2008 2:25 pm

Hi,

I'm using only the FORM field variables. I added my code and highlighted the POST method for your reference.

I can able to upload the file using the following code but couldn't parse the document into HTML and update it on the candidate profile.


Code:
-------

resumeContent = "c:\resume.doc";

CookieContainer cookies = new CookieContainer();
NameValueCollection querystring = new NameValueCollection();

querystring["privateLabelID"] = Generic.PrivateLabelID;
querystring["encryptedAPIKey"] = Generic.EncryptedAPIKey;
querystring["userID"] = bhid;
querystring["userFile"] = resumeContent;
querystring["updateResumeOverview"] = "TRUE";

string outdata = Bullhorn.MainClient.UploadFileEx(resumeContent, API.AttachResume, "userFile", "", querystring, cookies);





File Upload Code:
--------------------

public static string UploadFileEx(string uploadfile, string url, string fileFormName, string contenttype, NameValueCollection querystring,CookieContainer cookies)
{
if ((fileFormName == null) ||
(fileFormName.Length == 0))
{
fileFormName = "file";
}

if ((contenttype == null) ||
(contenttype.Length == 0))
{
contenttype = "application/octet-stream";
}


string postdata;
postdata = "?";
if (querystring != null)
{
foreach (string key in querystring.Keys)
{
postdata += key + "=" + querystring.Get(key) + "&";
}
}
Uri uri = new Uri(url + postdata.Substring(0, (postdata.Length - 1)));


string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
webrequest.CookieContainer = cookies;
webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
webrequest.Method = "POST";


// Build up the post message header
StringBuilder sb = new StringBuilder();
sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"");
sb.Append(fileFormName);
sb.Append("\"; filename=\"");
sb.Append(Path.GetFileName(uploadfile));
sb.Append("\"");
sb.Append("\r\n");
sb.Append("Content-Type: ");
sb.Append(contenttype);
sb.Append("\r\n");
sb.Append("\r\n");

string postHeader = sb.ToString();
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

// Build the trailing boundary string as a byte array
// ensuring the boundary appears on a line by itself
byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

FileStream fileStream = new FileStream(uploadfile, FileMode.Open, FileAccess.Read);
long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
webrequest.ContentLength = length;

Stream requestStream = webrequest.GetRequestStream();

// Write out our post header
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

// Write out the file contents
byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);

// Write out the trailing boundary
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
WebResponse responce = webrequest.GetResponse();
Stream s = responce.GetResponseStream();
StreamReader sr = new StreamReader(s);

return sr.ReadToEnd();
}

cseibert
Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Mar 03, 2008 3:13 pm

I know we fixed this as part of Ticket #163183 - API Error in AttachFileAPI.cfm. It was deployed on 1.4.2008.

Are you using www.bullhornstaffing.com versus www.bullhorn.com? The later is not being updated, so it would not have gotten the old code.

cseibert
Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Mar 03, 2008 3:17 pm

I'm not convinced from looking at your code that you're actually posting the parameter in question as a form variable. I see you creating a postData, but then passing it in as the URI to the web request. I don't see where you use postData again. You do format form data for the file info, but not the parameter.

That's the issue. The code on our end only looks in the form scope for that value, unfortunately.

rkarthy
User
Posts: 39
Joined: Mon Feb 11, 2008 12:49 pm
Location: Wakefield, MA, USA

Post by rkarthy » Mon Mar 03, 2008 6:01 pm

Do you have any sample code snippet?

Regards,
Karthik

cseibert
Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Mar 03, 2008 6:35 pm

Looks like you found our FAQ code samples, which are all we have at the moment.

rkarthy
User
Posts: 39
Joined: Mon Feb 11, 2008 12:49 pm
Location: Wakefield, MA, USA

Problem with the AttachFile API - Solved

Post by rkarthy » Tue Apr 01, 2008 2:52 pm

Hi,

Finally i got the result. I'm posting the working code below. So it would be helpful to others. Enjoy!

API Used: https://www.bullhorn.com/BullhornStaffi ... chFile.cfm
Result: Parse the resume and update this data into candidates description field and attach this resume into candidate's profile.

PART#1

attachResume ("1000","c:\\resume.doc","resume.doc")

PART#2

public static string attachResume(string bhid, string resumeContent, string fileName)
{
try
{
CookieContainer cookies = new CookieContainer();
NameValueCollection querystring = new NameValueCollection();

querystring["privateLabelID"] = XXX;
querystring["encryptedAPIKey"] = XXXXXXX;
querystring["userID"] = bhid;
querystring["updateResumeOverview"] = "TRUE";
querystring["userFile"] = resumeContent;

string outdata = Bullhorn.MainClient.FileAttach(resumeContent, "https://www.bullhorn.com/BullhornStaffi ... chFile.cfm", "userFile", "", querystring, cookies);
return outdata;
}
catch (Exception ex)
{
return "";
}
finally
{

}
}


PART#3

public static string FileAttach(string uploadfile, string url, string fileFormName, string contenttype, NameValueCollection querystring, CookieContainer cookies)
{
if ((fileFormName == null) ||
(fileFormName.Length == 0))
{
fileFormName = "file";
}

if ((contenttype == null) ||
(contenttype.Length == 0))
{
contenttype = "application/octet-stream";
}

string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
StringBuilder sb = new StringBuilder();
FileStream fileStream = new FileStream(uploadfile, FileMode.Open, FileAccess.Read);

if (querystring != null)
{
foreach (string key in querystring.Keys)
{
switch (key)
{
case "userFile":
{
sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"");
sb.Append(fileFormName);
sb.Append("\"; filename=\"");
sb.Append(Path.GetFileName(uploadfile));
sb.Append("\"");
sb.Append("\r\n");
sb.Append("Content-Type: ");
sb.Append(contenttype);
sb.Append("\r\n");
sb.Append("\r\n");
break;
}
default:
{
sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"" + key + "\"");
sb.Append("\r\n");
sb.Append("\r\n");
sb.Append(querystring.Get(key));
sb.Append("\r\n");
sb.Append("\r\n");
break;
}
}
}
}
Uri uri = new Uri(url);

HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
webrequest.CookieContainer = cookies;
webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
webrequest.Method = "POST";

string postHeader = sb.ToString();
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

// Build the trailing boundary string as a byte array
// ensuring the boundary appears on a line by itself
byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");


long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
webrequest.ContentLength = length;

Stream requestStream = webrequest.GetRequestStream();

// Write out our post header
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

// Write out the file contents
byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);

// Write out the trailing boundary
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
WebResponse responce = webrequest.GetResponse();
Stream s = responce.GetResponseStream();
StreamReader sr = new StreamReader(s);

return sr.ReadToEnd();
}



Regards,
Karthik

nitinmt
User
Posts: 20
Joined: Wed Nov 26, 2008 2:09 am

Re: Problem with the AttachFile API - Solved

Post by nitinmt » Mon Dec 08, 2008 8:13 am

I am trying to attach a file using Java code calling API. I am not able attach the file. For adding profile, I am able to add the profile without attachment, but facing problem with attachment. If somebody can help.



rkarthy wrote:Hi,

Finally i got the result. I'm posting the working code below. So it would be helpful to others. Enjoy!

API Used: https://www.bullhorn.com/BullhornStaffi ... chFile.cfm
Result: Parse the resume and update this data into candidates description field and attach this resume into candidate's profile.

PART#1

attachResume ("1000","c:\\resume.doc","resume.doc")

PART#2

public static string attachResume(string bhid, string resumeContent, string fileName)
{
try
{
CookieContainer cookies = new CookieContainer();
NameValueCollection querystring = new NameValueCollection();

querystring["privateLabelID"] = XXX;
querystring["encryptedAPIKey"] = XXXXXXX;
querystring["userID"] = bhid;
querystring["updateResumeOverview"] = "TRUE";
querystring["userFile"] = resumeContent;

string outdata = Bullhorn.MainClient.FileAttach(resumeContent, "https://www.bullhorn.com/BullhornStaffi ... chFile.cfm", "userFile", "", querystring, cookies);
return outdata;
}
catch (Exception ex)
{
return "";
}
finally
{

}
}


PART#3

public static string FileAttach(string uploadfile, string url, string fileFormName, string contenttype, NameValueCollection querystring, CookieContainer cookies)
{
if ((fileFormName == null) ||
(fileFormName.Length == 0))
{
fileFormName = "file";
}

if ((contenttype == null) ||
(contenttype.Length == 0))
{
contenttype = "application/octet-stream";
}

string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
StringBuilder sb = new StringBuilder();
FileStream fileStream = new FileStream(uploadfile, FileMode.Open, FileAccess.Read);

if (querystring != null)
{
foreach (string key in querystring.Keys)
{
switch (key)
{
case "userFile":
{
sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"");
sb.Append(fileFormName);
sb.Append("\"; filename=\"");
sb.Append(Path.GetFileName(uploadfile));
sb.Append("\"");
sb.Append("\r\n");
sb.Append("Content-Type: ");
sb.Append(contenttype);
sb.Append("\r\n");
sb.Append("\r\n");
break;
}
default:
{
sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"" + key + "\"");
sb.Append("\r\n");
sb.Append("\r\n");
sb.Append(querystring.Get(key));
sb.Append("\r\n");
sb.Append("\r\n");
break;
}
}
}
}
Uri uri = new Uri(url);

HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
webrequest.CookieContainer = cookies;
webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
webrequest.Method = "POST";

string postHeader = sb.ToString();
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

// Build the trailing boundary string as a byte array
// ensuring the boundary appears on a line by itself
byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");


long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
webrequest.ContentLength = length;

Stream requestStream = webrequest.GetRequestStream();

// Write out our post header
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

// Write out the file contents
byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);

// Write out the trailing boundary
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
WebResponse responce = webrequest.GetResponse();
Stream s = responce.GetResponseStream();
StreamReader sr = new StreamReader(s);

return sr.ReadToEnd();
}



Regards,
Karthik

jp.dowd
User
Posts: 164
Joined: Wed Dec 31, 1969 8:00 pm

Re: Problem with the AttachFile API

Post by jp.dowd » Mon Dec 08, 2008 9:22 am

Hello Nitin,
Have you been able to see the difference between what your code is posting and an html page? I posted instructions on how to see this over on this topic: http://supportforums.bullhorn.com/viewt ... 3320#p3327 for you.

J.P.

jitender
User
Posts: 18
Joined: Tue Mar 01, 2011 3:48 am

Re: Problem with the AttachFile API

Post by jitender » Mon Aug 08, 2011 6:12 am

Hello Karthik,

Thanks a lot for posting the above code. It helped me a lot...:)

Jitender

Locked