Google Cloud Print using C# - c#

I try to use Google Cloud Print using C#. Internet has just one example, who wrote Josh Goebel.
I will not publish the complete example, here is the only method that sends a file to print:
public CloudPrintJob PrintDocument(string printerId, string title, byte[] document)
{
try
{
string authCode;
if (!Authorize(out authCode))
return new CloudPrintJob() { success = false };
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com/cloudprint/submit?output=json");
request.Method = "POST";
string queryString =
"printerid=" + HttpUtility.UrlEncode(printerId) +
"&capabilities=" + HttpUtility.UrlEncode("") +
"&contentType=" + HttpUtility.UrlEncode("application/pdf") +
"&title=" + HttpUtility.UrlEncode(title) +
"&content=" + HttpUtility.UrlEncode(Convert.ToBase64String(document));
byte[] data = new ASCIIEncoding().GetBytes(queryString);
request.Headers.Add("X-CloudPrint-Proxy", Source);
request.Headers.Add("Authorization", "GoogleLogin auth=" + authCode);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
Stream stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
// Get response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CloudPrintJob));
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(responseContent));
CloudPrintJob printJob = serializer.ReadObject(ms) as CloudPrintJob;
return printJob;
}
catch (Exception ex)
{
return new CloudPrintJob() { success = false, message = ex.Message };
}
}
I run this code, then there is an interface of my printer, but print is not happening. The interface of my printer says that the pages to print 0, and the file size
does not coincide with the one I sent to the printer.
Google Cloud Print says that the task(job) is successfully added, but at the interface of Google Cloud Print next to the name of the document display "Error".
I thought that might have a problem with HttpUtility.UrlEncode or Convert.ToBase64String, but I tried the reverse transformation - everything works.
Does anyone have any ideas?

I appreciate this question is a little old now, but I've recently had to look at this for something I'm doing at work, and whilst the sample code posted started me off in the right direction it did take me quite a while to get it working completely.
The "list printers" function worked OK as described, but I couldn't get the Submit working properly, it just went straight to Error as the OP describes.
After profiling an actual submit request in Chrome using Fiddler, and looking at the PHP sample code on google's website, I discovered that the submit needed to be a multipart MIME message or it wouldn't work properly.
This is an example of the HTTP POST message which finally got the Submit operation working. Note that the gcp Printer Id needs to be passed in the request URL, and the data (whether it be a PDF, JPG or PNG) needs to be Base64 encoded and the correct mime type set (application/pdf, image/jpeg ...) for the "content" block (the last one in the list below):
POST http://www.google.com/cloudprint/submit?printerid=<printerid>&output=json HTTP/1.1
Host: www.google.com
Content-Length: 44544
X-CloudPrint-Proxy: Google-JS
Content-Type: multipart/form-data; boundary=----CloudPrintFormBoundaryqeq6g6ncj5v7
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="capabilities"
{"capabilities":[{}]}
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="contentType"
dataUrl
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="title"
zodiac-pig-pic.jpg
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="content"
data:image/jpeg;base64,JVBERi0xLjQKJeHp69MKMiAwIG...2NgolJUVPRg==
------CloudPrintFormBoundaryqeq6g6ncj5v7--
Things which tripped me up were that the Boundary value specified in the header has 2 less hyphens (--) than the actual usage of them (not obvious when you're staring at something wondering why it's not working!), the very last boundary instance has two additional hyphens at the end, and that I needed to get rid of the C# Expect100Continue header (by using request.ServicePoint.Expect100Continue = false).
UPDATE: Here is the complete code I wrote at the time, in case it helps anyone out.
using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using GoogleCloudPrintServices.DTO;
namespace GoogleCloudPrintServices.Support
{
public class GoogleCloudPrint
{
public string UserName { get; set; }
public string Password { get; set; }
public string Source { get; set; }
private const int ServiceTimeout = 10000;
public GoogleCloudPrint (String source)
{
Source = source;
}
public CloudPrintJob PrintDocument (string printerId, string title, byte[] document, String mimeType)
{
try
{
string authCode;
if (!Authorize (out authCode))
return new CloudPrintJob { success = false };
var b64 = Convert.ToBase64String (document);
var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/submit?output=json&printerid=" + printerId);
request.Method = "POST";
// Setup the web request
SetupWebRequest (request);
// Add the headers
request.Headers.Add ("X-CloudPrint-Proxy", Source);
request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
var p = new PostData ();
p.Params.Add (new PostDataParam { Name = "printerid", Value = printerId, Type = PostDataParamType.Field });
p.Params.Add (new PostDataParam { Name = "capabilities", Value = "{\"capabilities\":[{}]}", Type = PostDataParamType.Field });
p.Params.Add (new PostDataParam { Name = "contentType", Value = "dataUrl", Type = PostDataParamType.Field });
p.Params.Add (new PostDataParam { Name = "title", Value = title, Type = PostDataParamType.Field });
p.Params.Add (new PostDataParam
{
Name = "content",
Type = PostDataParamType.Field,
Value = "data:" + mimeType + ";base64," + b64
});
var postData = p.GetPostData ();
Trace.WriteLine (postData);
byte[] data = Encoding.UTF8.GetBytes (postData);
request.ContentType = "multipart/form-data; boundary=" + p.Boundary;
Stream stream = request.GetRequestStream ();
stream.Write (data, 0, data.Length);
stream.Close ();
// Get response
var response = (HttpWebResponse)request.GetResponse ();
var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
var serializer = new DataContractJsonSerializer (typeof (CloudPrintJob));
var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
var printJob = serializer.ReadObject (ms) as CloudPrintJob;
return printJob;
}
catch (Exception ex)
{
return new CloudPrintJob { success = false, message = ex.Message };
}
}
public CloudPrinters Printers
{
get
{
var printers = new CloudPrinters ();
string authCode;
if (!Authorize (out authCode))
return new CloudPrinters { success = false };
try
{
var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/search?output=json");
request.Method = "POST";
// Setup the web request
SetupWebRequest (request);
// Add the headers
request.Headers.Add ("X-CloudPrint-Proxy", Source);
request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = 0;
var response = (HttpWebResponse)request.GetResponse ();
var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
var serializer = new DataContractJsonSerializer (typeof (CloudPrinters));
var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
printers = serializer.ReadObject (ms) as CloudPrinters;
return printers;
}
catch (Exception)
{
return printers;
}
}
}
private bool Authorize (out string authCode)
{
var result = false;
authCode = "";
var queryString = String.Format ("https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email={0}&Passwd={1}&service=cloudprint&source={2}",
UserName, Password, Source);
var request = (HttpWebRequest)WebRequest.Create (queryString);
// Setup the web request
SetupWebRequest (request);
var response = (HttpWebResponse)request.GetResponse ();
var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
var split = responseContent.Split ('\n');
foreach (var s in split)
{
var nvsplit = s.Split ('=');
if (nvsplit.Length == 2)
{
if (nvsplit[0] == "Auth")
{
authCode = nvsplit[1];
result = true;
}
}
}
return result;
}
private static void SetupWebRequest (HttpWebRequest webRequest)
{
// Get the details
var appSettings = ConfigurationManager.AppSettings;
// Create some credentials
if (!String.IsNullOrWhiteSpace (appSettings["ProxyUsername"]))
{
var cred = new NetworkCredential (appSettings["ProxyUsername"], appSettings["ProxyPassword"],
appSettings["ProxyDomain"]);
// Set the credentials
webRequest.Credentials = cred;
webRequest.Proxy = WebRequest.DefaultWebProxy;
webRequest.Proxy.Credentials = cred;
}
// Set the timeout
webRequest.Timeout = ServiceTimeout;
webRequest.ServicePoint.ConnectionLeaseTimeout = ServiceTimeout;
webRequest.ServicePoint.MaxIdleTime = ServiceTimeout;
// Turn off the 100's
webRequest.ServicePoint.Expect100Continue = false;
}
}
}
using System.Runtime.Serialization;
namespace GoogleCloudPrintServices.DTO
{
[DataContract]
public class CloudPrinter
{
[DataMember (Order = 0)]
public string id { get; set; }
[DataMember (Order = 1)]
public string name { get; set; }
[DataMember (Order = 2)]
public string description { get; set; }
[DataMember (Order = 3)]
public string proxy { get; set; }
[DataMember (Order = 4)]
public string status { get; set; }
[DataMember (Order = 5)]
public string capsHash { get; set; }
[DataMember (Order = 6)]
public string createTime { get; set; }
[DataMember (Order = 7)]
public string updateTime { get; set; }
[DataMember (Order = 8)]
public string accessTime { get; set; }
[DataMember (Order = 9)]
public bool confirmed { get; set; }
[DataMember (Order = 10)]
public int numberOfDocuments { get; set; }
[DataMember (Order = 11)]
public int numberOfPages { get; set; }
}
}
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace GoogleCloudPrintServices.DTO
{
[DataContract]
public class CloudPrinters
{
[DataMember (Order = 0)]
public bool success { get; set; }
[DataMember (Order = 1)]
public List<CloudPrinter> printers { get; set; }
}
}
using System.Runtime.Serialization;
namespace GoogleCloudPrintServices.DTO
{
[DataContract]
public class CloudPrintJob
{
[DataMember (Order = 0)]
public bool success { get; set; }
[DataMember (Order = 1)]
public string message { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace GoogleCloudPrintServices.Support
{
internal class PostData
{
private const String CRLF = "\r\n";
public string Boundary { get; set; }
private List<PostDataParam> _mParams;
public List<PostDataParam> Params
{
get { return _mParams; }
set { _mParams = value; }
}
public PostData ()
{
// Get boundary, default is --AaB03x
Boundary = "----CloudPrintFormBoundary" + DateTime.UtcNow;
// The set of parameters
_mParams = new List<PostDataParam> ();
}
public string GetPostData ()
{
var sb = new StringBuilder ();
foreach (var p in _mParams)
{
sb.Append ("--" + Boundary).Append (CRLF);
if (p.Type == PostDataParamType.File)
{
sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)).Append (CRLF);
sb.Append ("Content-Type: ").Append (p.FileMimeType).Append (CRLF);
sb.Append ("Content-Transfer-Encoding: base64").Append (CRLF);
sb.Append ("").Append (CRLF);
sb.Append (p.Value).Append (CRLF);
}
else
{
sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"", p.Name)).Append (CRLF);
sb.Append ("").Append (CRLF);
sb.Append (p.Value).Append (CRLF);
}
}
sb.Append ("--" + Boundary + "--").Append (CRLF);
return sb.ToString ();
}
}
public enum PostDataParamType
{
Field,
File
}
public class PostDataParam
{
public string Name { get; set; }
public string FileName { get; set; }
public string FileMimeType { get; set; }
public string Value { get; set; }
public PostDataParamType Type { get; set; }
public PostDataParam ()
{
FileMimeType = "text/plain";
}
}
}

For anyone struggling with this, I have created a github repository with code and instructions on how to use Google cloud print with a service account, updated for their new OAuth2 authentication method:
https://github.com/io7/GoogleCloudPrint

Looks like the reason of the problem is encoding of the data you sent to the server.
The most reliable solutions in this case would be to use data URI scheme when you send the document.
To do that you need to set contentType to "dataUrl" and pass data in the following format:
"data:application/pdf;base64," + Convert.ToBase64String(document)

It should be noted that sending capabilities is mandatory. Not sending it will result in the job turning to Error immediately after submission. A default value should always be sent:
{"capabilities":[{}]}

Related

Sending a post request with body and a header in it with UnityWebRequest

I am trying to send a post request to an Api called Paycell Api.
I dont need to authenticate for testing the request.
When I send the request with PostMan, it returns 200 OK.
Here is the exact request.
{
"msisdn": "5380521479",
"requestHeader": {
"applicationName": "PAYCELLTEST",
"applicationPwd": "PaycellTestPassword",
"clientIPAddress": "10.252.187.81",
"transactionDateTime": "20160309084056197",
"transactionId": "12345678901234567893"
}
}
When ı try to implement it to C# it returns 406 Not Acceptable.
Here is how it looks
using Newtonsoft.Json;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
public class GetCardsRequest : MonoBehaviour
{
private string url = "https://tpay-test.turkcell.com.tr:443/tpay/provision/services/restful/getCardToken/getCards/";
public void GetCards()
{
StartCoroutine(MakeCardRequest());
}
IEnumerator MakeCardRequest()
{
var bodyRequest = new GetCardRequest() {
requestHeader = new RequestHeader()
{
applicationName = "PORTALTEST",
applicationPwd = "ZDyXmMLWE2z7OzJU",
clientIPAddress = "10.252.187.81",
transactionDateTime = "20160309084056197",
transactionId = "12345678901234567893"
},
msisdn = "5380521479"
};
bodyRequest.requestHeader = new RequestHeader();
var body = JsonConvert.SerializeObject(bodyRequest);
UnityWebRequest request = UnityWebRequest.Post(url, body);
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Accept", "text/csv");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
Debug.Log(request.error);
}
else
{
//var cardName = JsonConvert.DeserializeObject<GetCardResponse>(request.downloadHandler.text);
}
}
}
İf I delete the part
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Accept", "text/csv");
It returns 415 Unsupported Media Type Error.
How can I send this request, please help me.
Here's the documentation of the API, it shows an example request.
Paycell API
And here is how I implemented GetCardRequest
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class RequestHeader
{
public string applicationName { get; set; }
public string applicationPwd { get; set; }
public string clientIPAddress { get; set; }
public string transactionDateTime { get; set; }
public string transactionId { get; set; }
}
public class GetCardRequest
{
public string msisdn { get; set; }
public RequestHeader requestHeader { get; set; }
}
Now with your code the first main issue is mot probably that your JSON is always empty fields.
you are doing
bodyRequest.requestHeader = new RequestHeader();
which erases all the previously filled in values
and then as mentioned before another thing to try might be rather using
IEnumerator MakeCardRequest()
{
var bodyRequest = new GetCardRequest()
{
requestHeader = new RequestHeader()
{
applicationName = "PORTALTEST",
applicationPwd = "ZDyXmMLWE2z7OzJU",
clientIPAddress = "10.252.187.81",
transactionDateTime = "20160309084056197",
transactionId = "12345678901234567893"
},
msisdn = "5380521479"
};
var body = JsonConvert.SerializeObject(bodyRequest);
var bytes = Encoding.UTF8.GetBytes(body);
using(var request = new UnityWebRequest(url, "POST"))
{
request.uploadHandler = (UploadHandler) new UploadHandlerRaw(data);
request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log(request.error);
}
else
{
var cardName = JsonConvert.DeserializeObject<GetCardResponse>(request.downloadHandler.text);
Debug.Log(cardName);
}
}
}

Streaming Api consumption

I have an api http://oversea-download.hikvision.com/uploadfile/Leaflet/ISAPI/HIKVISION%20ISAPI_2.0-IPMD%20Service.pdf I want to receive which uses a HTTP get and wants connection keep-alive.
Once connected it sends XML responses which I want to deserialise. I've created a class to represent the data structure, but I'm not sure how to continually update a list or similar as and when the data is sent back, for example the response (from wireshark) looks like:
I'm not concerned with the parsing of data and updating the list, more how I can keep listening on a socket and see that its XML data and needs to be serialised.. without processing the stream into a buffer and looking for delimiters?
So far the code I had been unsuccessfully playing with looks like:
public static async Task NewTask()
{
var client = new RestClient("http://192.168.0.152:80/");
client.Authenticator = new HttpBasicAuthenticator("admin", "ThePassword");
client.Encoding = Encoding.UTF8;
var request = new RestRequest("ISAPI/Event/notification/alertStream", Method.GET);
request.AddHeader("Connection", "keep-alive");
request.AddHeader("Content-Type", "application/xml");
IRestResponse<EventNotificationAlert> response2 = client.Execute<EventNotificationAlert>(request);
var name = response2.Data.eventType;
Console.WriteLine(name);
//var asyncHandle = client.ExecuteAsync<EventNotificationAlert>(request, response => {
// Console.WriteLine(response.Data.eventDescription);
//});
}
and the class:
public class EventNotificationAlert
{
public string version { get; set; }
public string ipAddress { get; set; }
public string portNo { get; set; }
public string protocol { get; set; }
public string macAddress { get; set; }
public string channelID { get; set; }
public string dateTime { get; set; }
public string activePostCount { get; set; }
public string eventType { get; set; }
public string eventState { get; set; }
public string eventDescription { get; set; }
}
disregard my comment, can't format it.. this kind of works.. but given I get boundary and content-type text I've got crude processing in...
var messageBuffer = string.Empty;
var request = WebRequest.Create("http://192.168.0.152:80/ISAPI/Event/notification/alertStream");
request.Credentials = new NetworkCredential("admin", "ThePassword");
request.BeginGetResponse(ar =>
{
var req = (WebRequest)ar.AsyncState;
// TODO: Add exception handling: EndGetResponse could throw
using (var response = req.EndGetResponse(ar))
using (var reader = new StreamReader(response.GetResponseStream()))
{
// This loop goes as long as the api is streaming
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line == xmlEndStr)
{
messageBuffer += line;
GotMessage(messageBuffer);
messageBuffer = string.Empty;
}
else if (line.StartsWith("<"))
{
messageBuffer += line;
}
}
}
}, request);
static void GotMessage(string msg)
{
var mySerializer = new XmlSerializer(typeof(EventNotificationAlert));
var stringReader = new StringReader(msg);
var eventAlert = (EventNotificationAlert)mySerializer.Deserialize(stringReader);
Console.WriteLine($"DateTime: {eventAlert.dateTime} Channel: {eventAlert.channelID} Type: {eventAlert.eventType} Description: {eventAlert.eventDescription}");
}
Happy to hear of better ways (as you can tell I'm not great with c#!)

Sample code for calling Marketo Rest Api in .net/c# [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Does anyone have an example of calling a Marketo Rest API from .net/C#.
I am particularly interested in the oauth authentication piece.
http://developers.marketo.com/documentation/rest/authentication/
I plan to call this endpoint
http://developers.marketo.com/documentation/rest/get-multiple-leads-by-list-id/
I cannot find any example out there on the interweb.
I was able to code up a solution for calling a Marketo Rest API and do the OAuth. Below is a how-to
The below code shows the basics, but needs clean up, logging and error handling to be production worthy.
You need to get the Rest api URL's for your Marketo instance. To do this, log into marketo, and navigate to Admin\Integration\Web Services, and use the URLs in the Rest API Section.
You need to get your user id and secret from marketo - navigate to Admin\Integration\Launch Pont. View the details of your Rest Service to get id and secret. If you don't have a Service, then follow these instructions http://developers.marketo.com/documentation/rest/custom-service/.
Finally, you need your list id for the list of leads you want to get. You can get this by navigating to your list and copying the numeric portion of the id out of the url. Example: https://XXXXX.marketo.com/#ST1194B2 —> List ID = 1194
private void GetListLeads()
{
string token = GetToken().Result;
string listID = "XXXX"; // Get from Marketo UI
LeadListResponse leadListResponse = GetListItems(token, listID).Result;
//TODO: do something with your list of leads
}
private async Task<string> GetToken()
{
string clientID = "XXXXXX"; // Get from Marketo UI
string clientSecret = "XXXXXX"; // Get from Marketo UI
string url = String.Format("https://XXXXXX.mktorest.com/identity/oauth/token?grant_type=client_credentials&client_id={0}&client_secret={1}",clientID, clientSecret ); // Get from Marketo UI
var fullUri = new Uri(url, UriKind.Absolute);
TokenResponse tokenResponse = new TokenResponse();
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(fullUri);
if (response.IsSuccessStatusCode)
{
tokenResponse = await response.Content.ReadAsAsync<TokenResponse>();
}
else
{
if (response.StatusCode == HttpStatusCode.Forbidden)
throw new AuthenticationException("Invalid username/password combination.");
else
throw new ApplicationException("Not able to get token");
}
}
return tokenResponse.access_token;
}
private async Task<LeadListResponse> GetListItems(string token, string listID)
{
string url = String.Format("https://XXXXXX.mktorest.com/rest/v1/list/{0}/leads.json?access_token={1}", listID, token);// Get from Marketo UI
var fullUri = new Uri(url, UriKind.Absolute);
LeadListResponse leadListResponse = new LeadListResponse();
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(fullUri);
if (response.IsSuccessStatusCode)
{
leadListResponse = await response.Content.ReadAsAsync<LeadListResponse>();
}
else
{
if (response.StatusCode == HttpStatusCode.Forbidden)
throw new AuthenticationException("Invalid username/password combination.");
else
throw new ApplicationException("Not able to get token");
}
}
return leadListResponse;
}
private class TokenResponse
{
public string access_token { get; set; }
public int expires_in { get; set; }
}
private class LeadListResponse
{
public string requestId { get; set; }
public bool success { get; set; }
public string nextPageToken { get; set; }
public Lead[] result { get; set; }
}
private class Lead
{
public int id { get; set; }
public DateTime updatedAt { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public DateTime datecreatedAt { get; set; }
public string firstName { get; set; }
}
Old question, just hoping to help the next guy who ends up here from a google search :-)
This page was probably not there at the time of this post, but there is now a good page with examples in several languages. The page is at
http://developers.marketo.com/documentation/rest/get-multiple-leads-by-list-id
Just in case the link goes dead, here is the code example that they provide for C#
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Samples
{
class LeadsByList
{
private String host = "CHANGE ME"; //host of your marketo instance, https://AAA-BBB-CCC.mktorest.com
private String clientId = "CHANGE ME"; //clientId from admin > Launchpoint
private String clientSecret = "CHANGE ME"; //clientSecret from admin > Launchpoint
public int listId;
public int batchSize;//max 300, default 300
public String[] fields;//array of field names to retrieve
public String nextPageToken;//paging token
/*
public static void Main(String[] args)
{
MultipleLeads leads = new MultipleLeads();
leads.listId = 1001
String result = leads.getData();
Console.WriteLine(result);
while (true)
{
}
}
*/
public String getData()
{
StringBuilder url = new StringBuilder(host + "/rest/v1/list/" + listId + "/leads.json?access_token=" + getToken());
if (fields != null)
{
url.Append("&fields=" + csvString(fields));
}
if (batchSize > 0 && batchSize < 300)
{
url.Append("&batchSize=" + batchSize);
}
if (nextPageToken != null)
{
url.Append("&nextPageToken=" + nextPageToken);
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.ToString());
request.ContentType = "application/json";
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
return reader.ReadToEnd();
}
private String getToken()
{
String url = host + "/identity/oauth/token?grant_type=client_credentials&client_id=" + clientId + "&client_secret=" + clientSecret;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
String json = reader.ReadToEnd();
//Dictionary<String, Object> dict = JavaScriptSerializer.DeserializeObject(reader.ReadToEnd);
Dictionary<String, String> dict = JsonConvert.DeserializeObject<Dictionary<String, String>>(json);
return dict["access_token"];
}
private String csvString(String[] args)
{
StringBuilder sb = new StringBuilder();
int i = 1;
foreach (String s in args)
{
if (i < args.Length)
{
sb.Append(s + ",");
}
else
{
sb.Append(s);
}
i++;
}
return sb.ToString();
}
}
}
At the time of this response - this page has all of the api calls documented
http://developers.marketo.com/documentation/rest/

Google Drive API File Upload Error: "Missing end boundary in multipart body."

I'm attempting to do a multipart upload to Google via web request, and I've followed Google's instructions on how to construct a valid multipart file upload request so I can send up metadata and the actual file data at the same time, but I keep getting a "Missing end boundary in multipart body." error when I try and upload a file and am out of ideas as to why. What am I doing wrong?
Also, I'm not using the Drive SDK as it did not suit my needs.
Here's my code:
public bool WriteFileData(Stream data, DSFile file, DSUser user)
{
var parent = new Parent();
var folders = GetUserFolders(user, false);
DSFolder parentFolder = folders.Where(f => f.FullPath == file.VirtualPath).FirstOrDefault();
parent.Id = parentFolder.DepositoryFolderId;
var addFileRequest = new AddFileRequest();
addFileRequest.Parents.Add(parent);
addFileRequest.Title = (file.FileName.ToLower().Contains(".ext") == false) ? file.FileName + ".ext" : file.FileName;
addFileRequest.ModifiedDate = ServiceUtil.ToISO8601(DateTime.Now);
addFileRequest.MimeType = "application/octet-stream";
addFileRequest.WritersCanShare = false;
addFileRequest.Description = file.Description;
addFileRequest.Labels = new FileLabels();
byte[] binData = new byte[data.Length];
data.Read(binData, 0, (int)data.Length);
string metadata = Microsoft.Http.HttpContentExtensions.CreateJsonDataContract<AddFileRequest>(addFileRequest).ReadAsString();
string binData64 = Convert.ToBase64String(binData);
string contentString = "--123ABC Content-Type: application/json; charset=UTF-8 " + metadata;
contentString += "--123ABC Content-Type: application/octet-stream " + binData64;
contentString += " --123ABC--";
HttpResponseMessage response;
try
{
HttpClient client = new HttpClient();
AddAuthHeader(client, credential.AccessToken);
client.DefaultHeaders.ContentType = "multipart/related; boundary=\"123ABC\"";
client.DefaultHeaders.ContentLength = HttpContent.Create(contentString).ReadAsByteArray().Length;
response = client.Post("https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart", HttpContent.Create(contentString));
string responseText = response.Content.ReadAsString();
return false;
}
catch (Exception ex)
{
return false;
}
}
EDIT: Here's my definition for AddFileRequest:
[DataContract]
public class AddFileRequest
{
[DataMember(Name="title")]
public string Title { get; set; }
[DataMember(Name = "labels")]
public FileLabels Labels { get; set; }
[DataMember(Name = "mimeType")]
public string MimeType { get; set; }
[DataMember(Name = "modifiedDate")]
public string ModifiedDate { get; set; }
[DataMember(Name = "parents")]
public List<Parent> Parents { get; set; }
[DataMember(Name = "description")]
public string Description { get; set; }
[DataMember(Name="writersCanShare")]
public bool WritersCanShare { get; set; }
}
Found a solution. I decided to poke around the object browser and noticed that the System.Net.Http namespace has a "MultipartFormDataContent" class that did the trick. I didn't see it before because, for some reason, there are two different sets of nearly identical (but incompatible) HTTP namespaces: Microsoft.Http and System.Net.Http. Here's the updated code that works:
public bool WriteFileData(Stream data, DSFile file, DSUser user)
{
var parent = new Parent();
var folders = GetUserFolders(user, false);
DSFolder parentFolder = folders.Where(f => f.FullPath == file.VirtualPath).FirstOrDefault();
parent.Id = parentFolder.DepositoryFolderId;
var addFileRequest = new AddFileRequest();
addFileRequest.Parents.Add(parent);
addFileRequest.Title = (file.FileName.ToLower().Contains(".ext") == false) ? file.FileName + ".ext" : file.FileName;
addFileRequest.ModifiedDate = ServiceUtil.ToISO8601(DateTime.Now);
addFileRequest.MimeType = "application/octet-stream";
addFileRequest.WritersCanShare = false;
addFileRequest.Description = file.Description;
addFileRequest.Labels = new FileLabels();
string metadata = Microsoft.Http.HttpContentExtensions.CreateJsonDataContract<AddFileRequest>(addFileRequest).ReadAsString();
var content = new System.Net.Http.MultipartFormDataContent("ABC123");
content.Add(new System.Net.Http.StringContent(metadata, System.Text.Encoding.UTF8, "application/json"));
content.Add(new System.Net.Http.StreamContent(data));
try
{
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", credential.AccessToken);
var response = client.PostAsync("https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart", content).Result;
string responseText = response.Content.ReadAsStringAsync().Result;
return false;
}
catch (Exception ex)
{
return false;
}
}

iphone push notification urbanairship

i"m want to send notification from my server side (c#) via urbanairship api
is there any example in c# how to do it?
thanks
Basically...
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Examples.System.Net
{
public class WebRequestPostExample
{
public static void Main ()
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create ("https://go.urbanairship.com/api/push/");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
broken out to multiple lines so you can read it
string postData = "{
"device_tokens": [
"some device token",
"another device token"
],
"aliases": [
"user1",
"user2"
],
"tags": [
"tag1",
"tag2"
],
"schedule_for": [
"2010-07-27 22:48:00",
"2010-07-28 22:48:00"
],
"exclude_tokens": [
"device token you want to skip",
"another device token you want to skip"
],
"aps": {
"badge": 10,
"alert": "Hello from Urban Airship!",
"sound": "cat.caf"
}
}";
and then
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/json";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
//Do a http basic authentication somehow
string username = "<application key from urban airship>";
string password = "<master secret from urban airship>";
string usernamePassword = username + ":" + password;
CredentialCache mycache = new CredentialCache();
mycache.Add( new Uri( "https://go.urbanairship.com/api/push/" ), "Basic", new NetworkCredential( username, password ) );
request.Credentials = mycache;
request.Headers.Add( "Authorization", "Basic " + Convert.ToBase64String( new ASCIIEncoding().GetBytes( usernamePassword ) ) );
// Get the request stream.
Stream dataStream = request.GetRequestStream ();
// Write the data to the request stream.
dataStream.Write (byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close ();
// Get the response.
WebResponse response = request.GetResponse ();
// Display the status.
Console.WriteLine (((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream ();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader (dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd ();
// Display the content.
Console.WriteLine (responseFromServer);
// Clean up the streams.
reader.Close ();
dataStream.Close ();
response.Close ();
}
}
}
See api docs, msdn and here for more on https
The accepted answer doesn't work, you need to change the following line:
request.ContentType = "application/x-www-form-urlencoded";
to
request.ContentType = "application/json";
Complete working code shown below:
using System;
using System.IO;
using System.Net;
using System.Text;
namespace UrbanAirship_Tes_1
{
class Program
{
public static void Main()
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("https://go.urbanairship.com/api/push/");
request.Credentials = new NetworkCredential("pvYMExk3QIO7p2YUs6BBkg", "rO3DsucETRadbbfxHkd6qw");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
//WRITE JSON DATA TO VARIABLE D
string postData = "{\"aps\": {\"badge\": 1, \"alert\": \"Hello from Urban Airship!\"}, \"device_tokens\": [\"6334c016fc643baa340eca25bc661d15055a07b475e9a6108f3f644b15dd05ac\"]}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/json";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
// Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
}
}
public class PushNotificationHelper
{
private readonly ILog log4netEngine;
private string UrbanAirshipApplicationKey { get; set; }
private string UrbanAirshipApplicationSecret { get; set; }
private string UrbanAirshipApplicationMasterSecret { get; set; }
public PushNotificationHelper(string UrbanAirshipApplicationKey, string UrbanAirshipApplicationSecret, string UrbanAirshipApplicationMasterSecret)
{
log4netEngine = LogManager.GetLogger(typeof(PushNotificationHelper).Name);
this.UrbanAirshipApplicationKey = UrbanAirshipApplicationKey;
this.UrbanAirshipApplicationSecret = UrbanAirshipApplicationSecret;
this.UrbanAirshipApplicationMasterSecret = UrbanAirshipApplicationMasterSecret;
}
public void PushNotification2iPhones(string alertText, string[] apids, string extra)
{
if (!string.IsNullOrEmpty(alertText) && apids.Length > 0)
{
iPhonePushNotification pushNotification = new iPhonePushNotification
{
MessageBody = new iPhonePushNotificationMessageBody
{
Alert = alertText
},
Extra = extra,
APIDs = apids
};
string jsonMessageRequest = pushNotification.ToJsonString();
try
{
SendMessageToUrbanAirship(jsonMessageRequest);
log4netEngine.InfoFormat("Push Notification Success , iPhoneDevice:{0}, message:{1},extra:{2}", string.Join(",", apids), alertText, extra);
}
catch (Exception ex)
{
log4netEngine.InfoFormat("Push Notification Error:{0}, iPhoneDevice:{1}, message:{2},extra:{3}", ex.Message, string.Join(",", apids), alertText, extra);
}
}
}
public void PushNotification2Androids(string alertText, string[] apids, string extra)
{
if (!string.IsNullOrEmpty(alertText) && apids.Length > 0)
{
AndroidPushNotification pushNotification = new AndroidPushNotification
{
MessageBody = new AndroidPushNotificationMessageBody
{
Alert = alertText,
Extra = extra
},
APIDs = apids
};
string jsonMessageRequest = pushNotification.ToJsonString();
try
{
SendMessageToUrbanAirship(jsonMessageRequest);
log4netEngine.InfoFormat("Push Notification Success , androidDevice:{0}, message:{1},extra:{2}", string.Join(",", apids), alertText, extra);
}
catch (Exception ex)
{
log4netEngine.InfoFormat("Push Notification Error:{0}, androidDevice:{1}, message:{2},extra:{3}", ex.Message, string.Join(",", apids), alertText, extra);
}
}
}
private void SendMessageToUrbanAirship(string jsonMessageRequest)
{
var uri = new Uri("https://go.urbanairship.com/api/push/");
var encoding = new UTF8Encoding();
var request = WebRequest.Create(uri);
request.Method = "POST";
request.Credentials = new NetworkCredential(this.UrbanAirshipApplicationKey, this.UrbanAirshipApplicationMasterSecret);
request.ContentType = "application/json";
request.ContentLength = encoding.GetByteCount(jsonMessageRequest);
using (var stream = request.GetRequestStream())
{
stream.Write(encoding.GetBytes(jsonMessageRequest), 0, encoding.GetByteCount(jsonMessageRequest));
stream.Close();
var response = request.GetResponse();
response.Close();
}
}
}
public class NotificationToPush
{
public int ReceiverUserID { get; set; }
public string Message { get; set; }
public Dictionary<string, string> Extra { get; set; }
}
[DataContract(Name = "PushNotificationBody")]
internal class PushNotification
{
public string ToJsonString()
{
var result = JsonConvert.SerializeObject(this);
return result;
}
}
[DataContract(Name = "iPhonePushNotification")]
internal class iPhonePushNotification : PushNotification
{
[DataMember(Name = "aps")]
public iPhonePushNotificationMessageBody MessageBody { get; set; }
[DataMember(Name = "extra")]
public string Extra { get; set; }
[DataMember(Name = "device_tokens")]
public string[] APIDs { get; set; }
}
[DataContract(Name = "iPhonePushNotificationMessageBody")]
internal class iPhonePushNotificationMessageBody
{
[DataMember(Name = "alert")]
public string Alert { get; set; }
}
[DataContract(Name = "AndroidPushNotification")]
internal class AndroidPushNotification : PushNotification
{
[DataMember(Name = "android")]
public AndroidPushNotificationMessageBody MessageBody { get; set; }
[DataMember(Name = "apids")]
public string[] APIDs { get; set; }
}
[DataContract(Name = "AndroidPushNotificationMessageBody")]
internal class AndroidPushNotificationMessageBody
{
[DataMember(Name = "alert")]
public string Alert { get; set; }
[DataMember(Name = "extra")]
public string Extra { get; set; }
}
Here is how to do it using the System.Net.Http.HttpClient async methods.
var handler = new HttpClientHandler { Credentials = new NetworkCredential(urbanairshipapiKey, urbanairshipApiAppMasterSecret) };
var client = new HttpClient(handler);
var added = client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/vnd.urbanairship+json; version=3;");
var response = await client.PostAsync(apiUrl + "/push/", new StringContent(json, Encoding.UTF8, "application/json"));
I wrote a c# library to simplify the use of the UrbanAirship API
https://github.com/JeffGos/urbanairsharp
Hope it helps!

Categories

Resources