2011-10-21 58 views
5

Tôi cố gắng sử dụng Google Cloud Print bằng C#. Internet chỉ có một số example, người đã viết Josh Goebel. tôi sẽ không công bố các ví dụ hoàn chỉnh, đây là phương pháp duy nhất để gửi một tập tin để in:Google Cloud Print bằng 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 }; 
     } 
    } 
 

tôi chạy mã này, sau đó là một giao diện của máy in của tôi, nhưng in không xảy ra. Giao diện máy in của tôi cho biết các trang cần in 0 và kích thước tệp không trùng với trang tôi đã gửi tới máy in.

Google Cloud Print cho biết nhiệm vụ (công việc) đã được thêm thành công, nhưng tại giao diện của Google Cloud Print bên cạnh tên hiển thị tài liệu "Lỗi".

Tôi nghĩ rằng có thể có một vấn đề với HttpUtility.UrlEncode hoặc Convert.ToBase64String, nhưng tôi đã cố gắng chuyển đổi ngược lại - mọi thứ hoạt động.

Có ai có ý tưởng nào không?

+0

Tôi đã viết cho Josh Goebel qua Twitter - anh ấy nói những gì không viết ví dụ này. Hey, những người biết lập trình viên này, ai đã viết bài này? :) – t0rch

+1

Đã lâu rồi, nên tôi quên câu trả lời :) Nhưng tôi nhìn vào mã của tôi và những gì tôi thấy (chỉ cần so sánh với mã trên): "& contentType =" + HttpUtility.UrlEncode ("url") + " & content = "+ HttpUtility.UrlEncode (nội dung); Ngoài ra tôi xóa tất cả các mã sau chuỗi responseContent = new StreamReader (response.GetResponseStream()). ReadToEnd(); – t0rch

Trả lời

2

Có vẻ như lý do của sự cố là mã hóa dữ liệu bạn đã gửi đến máy chủ. Các giải pháp đáng tin cậy nhất trong trường hợp này là sử dụng lược đồ URI dữ liệu khi bạn gửi tài liệu. Để làm điều đó bạn cần phải thiết lập contentType để "dataUrl" và truyền dữ liệu theo định dạng sau: "dữ liệu: application/pdf; base64," + Convert.ToBase64String (tài liệu)

+0

Tôi đã dành toàn bộ buổi tối cố gắng để thực hiện công việc in trên nền tảng đám mây trên Java và đây là điều duy nhất tôi bỏ lỡ! Cảm ơn bạn loại sir! – Sver

6

Tôi đánh giá cao câu hỏi này là một chút bây giờ, nhưng gần đây tôi đã phải xem xét điều này cho một cái gì đó tôi đang làm tại nơi làm việc, và trong khi mã mẫu đã đăng tôi bắt đầu đi đúng hướng, tôi đã mất khá nhiều thời gian để nó hoạt động hoàn toàn.

Chức năng "danh sách máy in" hoạt động OK như được mô tả, nhưng tôi không thể nhận được Gửi hoạt động đúng cách, nó chỉ đi thẳng đến Lỗi như mô tả OP.

Sau khi gửi yêu cầu gửi thực tế trong Chrome bằng Fiddler và xem mã mẫu PHP trên trang web của google, tôi phát hiện rằng bản gửi cần phải là tin nhắn MIME nhiều phần hoặc không hoạt động chính xác.

Đây là ví dụ về thông báo HTTP POST mà cuối cùng đã hoạt động Gửi hoạt động. Lưu ý rằng Id Máy in gcp cần được chuyển vào URL yêu cầu và dữ liệu (cho dù đó là PDF, JPG hoặc PNG) cần phải được mã hóa Base64 và đặt loại mime chính xác (application/pdf, image/jpeg .. .) cho các "nội dung" khối (người cuối cùng trong danh sách dưới đây):

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

những điều mà vấp tôi là rằng giá trị ranh giới quy định trong tiêu đề có 2 dấu gạch nối trừ (-) so với thực tế sử dụng chúng (không rõ ràng khi bạn nhìn chằm chằm vào thứ gì đó tự hỏi tại sao nó không hoạt động!), thể hiện ranh giới cuối cùng có thêm hai dấu gạch ngang ở cuối, và tôi cần loại bỏ tiêu đề C# Expect100Continue (bằng cách sử dụng yêu cầu .ServicePoint.Expect100Continue = false).

CẬP NHẬT: Đây là mã hoàn chỉnh tôi đã viết vào thời điểm đó, trong trường hợp nó giúp mọi người.

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

Tôi đã làm việc này trong vài ngày qua ... Câu trả lời của bạn cuối cùng đã giúp tôi làm đúng. Hãy để Google gửi tài liệu đến dịch vụ của họ không chính xác ... – Justin

+1

Nếu bạn đã quản lý Cloud Print hoạt động với C# và có thể dán ví dụ hoạt động, điều đó thật tuyệt. – Craig

+0

Deevodavis, tôi đã đăng mã của bạn được chuyển đến Monodroid tại: https://github.com/slackshot/GoogleCloudPrintMonodroid Xamarin sẽ thực hiện một số ví dụ. Tôi đã phát hành nó theo Giấy phép MIT. Nếu tôi có thể nhắn tin cho bạn ở đây, tôi sẽ phải xin phép, nhưng vì bạn đã đăng nó ở đây, tôi cho rằng bạn muốn mọi người hưởng lợi từ nó. –

0

Cần lưu ý rằng việc gửi capabilities là bắt buộc. Không gửi nó sẽ dẫn đến việc chuyển sang số Lỗi ngay sau khi gửi.Giá trị mặc định nên luôn luôn được gửi:

{"capabilities":[{}]} 
5

Đối với bất cứ ai đang gặp khó khăn với điều này, tôi đã tạo ra một kho github với mã và hướng dẫn về cách sử dụng Cloud Print của Google với một tài khoản dịch vụ, cập nhật cho phương thức xác thực OAuth2 mới của họ :

https://github.com/io7/GoogleCloudPrint

Các vấn đề liên quan