2011-10-21 18 views
5

Provo a utilizzare Google Cloud Print utilizzando C#. Internet ha solo uno example, che ha scritto Josh Goebel. Non pubblicherò l'esempio completo, qui è l'unico metodo che invia un file da stampare:Google Cloud Print con C#

 

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 }; 
     } 
    } 
 

corro questo codice, poi c'è un'interfaccia di mia stampante, ma la stampa non sta accadendo. L'interfaccia della mia stampante dice che le pagine devono essere stampate 0, e la dimensione del file non coincide con quella che ho inviato alla stampante.

Google Cloud Print indica che l'attività (lavoro) è stata aggiunta correttamente, ma all'interfaccia di Google Cloud Print accanto al nome del documento "Errore".

ho pensato che potrebbe avere un problema con HttpUtility.UrlEncode o Convert.ToBase64String, ma ho provato la trasformazione inversa - tutto funziona.

Qualcuno ha qualche idea?

+0

ho scritto a Josh Goebel via Twitter - ha detto quello che non ha scritto questo esempio. Ehi, ragazzi che conoscono questo programmatore, chi l'ha scritto? :) – t0rch

+1

È passato molto tempo, quindi ho dimenticato la risposta :) Ma guardo il mio codice e quello che vedo (basta confrontare con il codice in alto): "& contentType =" + HttpUtility.UrlEncode ("url") + " & content = "+ HttpUtility.UrlEncode (contenuto); Inoltre cancello tutto il codice dopo la stringa responseContent = new StreamReader (response.GetResponseStream()). ReadToEnd(); – t0rch

risposta

2

Sembra che la causa del problema sia la codifica dei dati inviati al server. Le soluzioni più affidabili in questo caso sarebbero utilizzare lo schema URI di dati quando si invia il documento. Per fare questo è necessario impostare contentType a "DataURL" e passare i dati nel seguente formato: "Dati: application/pdf; Base64," + Convert.ToBase64String (documento)

+0

Ho trascorso un'intera serata a cercare di far funzionare la stampa cloud su Java, e questa è l'unica cosa che mi è sfuggita! Grazie gentile signore! – Sver

6

Apprezzo questa domanda è un po ' vecchio ora, ma di recente ho dovuto guardare a questo per qualcosa che sto facendo al lavoro, e mentre il codice di esempio pubblicato mi ha avviato nella giusta direzione mi ci è voluto un po 'di tempo per farlo funzionare completamente.

La funzione "lista stampanti" ha funzionato correttamente come descritto, ma non è stato possibile far funzionare correttamente Invia, è andato direttamente a Errore come l'OP descrive.

Dopo aver profilato una richiesta di invio effettiva in Chrome utilizzando Fiddler, e guardando il codice di esempio PHP sul sito web di Google, ho scoperto che l'invio doveva essere un messaggio MIME multipart o non funzionava correttamente.

Questo è un esempio del messaggio HTTP POST che ha finalmente funzionato l'operazione di invio. Si noti che l'Id della stampante gcp deve essere passato nell'URL della richiesta e che i dati (che si tratti di PDF, JPG o PNG) devono essere codificati Base64 e il tipo di mime corretto impostato (application/pdf, image/jpeg .. .) per il blocco "contenuto" (l'ultimo nella lista qui sotto):

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-- 

cose che mi erano sgambetto che il valore limite indicato nell'intestazione ha 2 meno trattini (-) rispetto a quella reale utilizzo (non ovvio quando stai fissando qualcosa che si domanda perché non funziona!), l'ultima istanza al limite ha due trattini aggiuntivi alla fine e che ho bisogno di eliminare l'intestazione C# Expect100Continue (usando la richiesta .ServicePoint.Expect100Continue = false).

AGGIORNAMENTO: ecco il codice completo che ho scritto in quel momento, nel caso in cui aiuti qualcuno fuori.

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"; 
     } 
    } 
} 
+0

Ho lavorato a questo negli ultimi due giorni ... La tua risposta alla fine mi ha aiutato a farlo bene. Lasciare a Google di documentare in modo errato i loro servizi ... – Justin

+1

Se sei riuscito a far funzionare Cloud Print con C# e potresti incollare un esempio funzionante, sarebbe fantastico. – Craig

+0

Deevodavis, ho pubblicato il tuo codice porting su Monodroid all'indirizzo: https://github.com/slackshot/GoogleCloudPrintMonodroid Xamarin produrrà alcuni esempi. L'ho rilasciato sotto la licenza MIT. Se potessi inviarti messaggi qui, vorrei chiedere il permesso, ma dal momento che l'hai pubblicato qui, presumo che tu volessi che le persone ne beneficiassero. –

0

Va notato che l'invio di capabilities è obbligatoria. Se non lo invii, il lavoro si trasformerà in Errore immediatamente dopo l'invio.Un valore di default dovrebbe essere sempre inviato:

{"capabilities":[{}]} 
5

Per tutti coloro che lottano con questo, ho creato un repository github con il codice e le istruzioni su come utilizzare Google Cloud Print con un account di servizio, aggiornato per il loro nuovo metodo di autenticazione OAuth2 :

https://github.com/io7/GoogleCloudPrint