So I know I can get data from asana and display it in my application using the API. I was wondering if it’s possible to do it the other way around? I will try to attach a screen shot to further illustrate, but this is what we want to do. We’ve added a custom field called PA (project administrator) on our tasks. It will be set to one of our employees. Then in our database, we’re able to set and change this field in one of our tables. We’d like any update in our table to be read and updated back in the asana task. Is it possible?
Do you want to change the PA available in the field and/or change the value for some tasks?
I’m not sure exactly what you’re asking so I’ll just say a bit more to clarify the question. The grid on the right in my screen shot is coming from our database. So the first row is a project going on in our company, “New System - Pre-Sale etc”. The PA assigned is 71. We have an asana task created shown on the left. I circled the custom PA field that has been created. When we set or change PA = 71, can the custom field automatically update?
Yes, if your system calls the Asana API to update the custom field value of that particular task. Either the custom fields already have all PA and you are good to go, if not you’ll have to update the values available for the field and then select the value (assuming we are talking about a drop-down field).
Does it make sense?
Yes, it makes sense. Thank you! This will probably be continued as I start to work on it. For now I just wanted a “proof of concept” answer. I will probably get to it later this week; next week at the latest.
@Bastien_Siebman, do you have any links handy of what the API calls are? I have not worked with the API extensively yet. I know how to get authorization and exchange tokens, and from there what I’ve done is access a story and display it in our application as “notes”. Then our users can make a new note in our application which I give it to asana to store.
I will start to dig; maybe I can find it on my own. Thanks so far!
You have everything in the official API documentation Build an app with Asana
Also I suggest you use one of their official library (they have PHP, Node…)
I have found what I need to do, but I need help with the syntax. The application I am working with is C#/Windows.
This is the documentation I have found:
Custom fields are set with PUT requests similarly to setting other fields on tasks; the format of the request is to set the id to the new value. That is, custom_fields:{custom_field_id:custom_field_value}
Custom fields of type text
are set by passing in custom_field_id:string
Custom fields of type number
are set by passing in custom_field_id:number
Custom fields of type enum
are set by passing in custom_field_id:enum_value_id
So what I am currently doing in my application to write data, is a call into this code:
private string GetResponse(string uri, string data = "", string method = "GET")
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Create Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.PreAuthenticate = true;
request.Method = method;
request.ContentType = "application/x-www-form-urlencoded";
string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(tokenCode + ":"));
request.Headers["Authorization"] = "Basic " + authInfo;
// send data if supplied
if (data != "")
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
request.ContentLength = dataBytes.Length;
using (Stream requestBody = request.GetRequestStream())
{
requestBody.Write(dataBytes, 0, dataBytes.Length);
}
}
// receive response
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
}
catch (Exception ex)
{
//MessageBox.Show(String.Format("Exceptioned {0}", ex.Message));
return "-1";
}
}
I am using this currently to add to a task’s stories. I do not know what to supply for the uri and data parameter to update my custom field. I know uri is something like “https://app.asana.com/api/1.0/tasks/<task+id>/custom_fields” but “something like” isn’t helpful when you’re writing code. I have the task id and the id of my custom field and the new value I want to write to asana for that custom field, but how do I put it all together?
What I do to save an Asana object in C# is create a Dictionary<string, object>
containing the field names as the keys and the values in the object
.
Then I do this:
string data = JsonConvert.SerializeObject(args);
data = "{\"data\":" + data + "}";
where args
is that Dictionary. The resulting variable is the data
variable in your code snippet.
In terms of how to construct custom field info in that dictionary, what you want to do is build a second Dictionary<string, object>
where the keys are the custom field IDs and the objects are the values (text string for Text type fields, numeric value for Number type fields, Enum ID for Enum type fields). Then put that second dictionary into one entry in the first dictionary, where the key is custom_fields
and the value is the second dictionary.
Let me know if any of that isn’t clear or you have further questions. (I looked at pasting some more of my code to illustrate the above but it’s pretty intertwined into my overall app, sorry!)
Your instructions are clear; what is not clear is why it isn’t working
Dictionary<string, object> dictPA = new Dictionary<string, object>();
// build a Dictionary<string, object> where the keys are the custom field IDs and the objects are the values (text string for Text type fields)
string idOfPA = "1111111111111111";
dictPA.Add(idOfPA, "Marlene");
Dictionary<string, object> dictCustomFields = new Dictionary<string, object>();
// put that second dictionary into one entry in the first dictionary, where the key is custom_fields and the value is the second dictionary
dictCustomFields.Add("custom_fields", dictPA);
string data;
//data = JsonConvert.SerializeObject(args);
data = Newtonsoft.Json.JsonConvert.SerializeObject(dictCustomFields);
response = GetResponseAndRetry(String.Format("https://app.asana.com/api/1.0/tasks/{0}/", task), data, "POST");
I am getting Bad Request, even though it looks good to me. It must be a syntax issue, and my last one took me hours to get right. Any ideas to help speed this along?
I realized I was missing the extra step to set data, but that didn’t work either.
string data;
//data = JsonConvert.SerializeObject(args);
data = Newtonsoft.Json.JsonConvert.SerializeObject(dictCustomFields);
data = "{\"data\":" + data + "}";
response = GetResponseAndRetry(String.Format("https://app.asana.com/api/1.0/tasks/{0}/", task), data, "POST");
You need to change your ContentType
to JSON. Specifically, here’s what I set on the request:
request.AllowWriteStreamBuffering = false;
request.ContentType = "application/json";
request.Accept = "Accept=application/json";
request.SendChunked = false;
Thank you for your reply but that code change is giving me a (404) Not Found error. Previously, it was a (400) Bad Request. I am not sure but isn’t that a step backwards?
I currently have the infrastructure in place which is allowing me to call the asana API to get the stories in a task so I can display them in our application and to add a story. So my code is already making GET and POST calls successfully.
I wanted help with the syntax of the request to GET and POST a custom field, to translate the high-level documentation which says:
Custom fields are set with PUT requests similarly to setting other fields on tasks;
the format of the request is to set the id to the new value.
That is,
custom_fields:{custom_field_id:custom_field_value}
into C# code for a Windows application. All their examples are for other technologies.
Am I wrong in my approach? Even issuing the command “natively” through a web browser isn’t working. I thought if I could get that working, I would have the syntax I need.
I know everyone is busy with their own work but because of a lack of documentation, asking questions here is the only way I’ve been able to find what I need. Does everyone understand what I am asking? I honestly think it’s just a syntax problem I’m having but I thought I had tried all possible combinations if how I can compose the command, and nothing is working. I can connect and communicate with he API fine; it’s just this one particular command. Thanks.
I’m baffled; it makes no sense that those 4 lines I posted would cause a Bad Request to become a Not Found. 404 indicates that the endpoint you’re calling does not correspond to a valid Asana API endpoint. Can you re-check the endpoint you’re calling? Are you saying that if you just remove those 4 lines, it goes back from a 404 back to a 400 error?
OK, thanks for the reply. I’ve already spent way more time on this than my boss had wanted me to so when I get back to it I will answer your question and post more complete code. Thanks.
In the meantime, do you happen to have the native URL that I could post, like https://app.asana.com/api/1.0/tasks/1234567890123456?opt_fields=custom_fields:{1126645169471189:“Marlene”} ? Sometimes it’s helpful for me to work backwards from that.
Sounds good!
No, I’m afraid not; in fact, none of us have been able to successfully update custom fields via CURL, as you can see here:
But I can promise you that it’s possible via C#/.NET as I’m doing it in production in Flowsana probably many times a day.
Yes, I will take you at your word. I believe it is possible too! I will get there.
Hi Phil. It’s been a while but I returned to this issue yesterday and I have it working now. You had given me four lines of code and I left them in my code with a comment:
//// 06/17/19 - What Phil said to do
//request.AllowWriteStreamBuffering = false;
//request.ContentType = “application/json”;
//request.Accept = “Accept=application/json”;
//request.SendChunked = false;
But when I added them they broke other things that had been working. What i had to do was put in a conditional test to see if updating the custom field was what I came in to do, so the whole routine looks like this:
private string GetResponse(string uri, string data = "", string method = "GET")
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Create Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.PreAuthenticate = true;
request.Method = method;
request.ContentType = "application/x-www-form-urlencoded";
// 09/05/19 - I thought it didn't work but it does but only if I use it for this specific request!
// 06/17/19 - What Phil said to do
if (method == "PUT" && data.IndexOf("custom_fields") >= 0)
{
request.AllowWriteStreamBuffering = false;
request.ContentType = "application/json";
request.Accept = "Accept=application/json";
request.SendChunked = false;
}
string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(tokenCode + ":"));
request.Headers["Authorization"] = "Basic " + authInfo;
// send data if supplied
if (data != "")
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
request.ContentLength = dataBytes.Length;
using (Stream requestBody = request.GetRequestStream())
{
requestBody.Write(dataBytes, 0, dataBytes.Length);
}
}
// receive response
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
}
catch (Exception ex)
{
//MessageBox.Show(String.Format("Exceptioned {0}", ex.Message));
return "-1";
}
}
}
Also, it has to be a POST request not a PUT request. What is the difference?
Anyway, thank you again!