verificar iOS en el recibo de compra de la aplicación con C #

Estoy verificando mi ios in app purchase recibo de in app purchase en mi server usando C# service web C#

Recibí recibo como cadena haciendo abajo en Xcode:

 - (void) completeTransaction: (SKPaymentTransaction *)transaction { NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier]; NSLog(@"%@",receiptString); NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSData *receipt = [NSData dataWithContentsOfURL:receiptURL]; NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0]; } 

y estoy enviando esa cadena (recibo) a mi service web C# como parámetro. Aquí está mi método de service web:

 [WebMethod(Description = "Purchase Item Verify")] public string PurchaseItem(string receiptData) { string returnmessage = ""; try { var json = "{ 'receipt-data': '" + receiptData + "'}"; ASCIIEncoding ascii = new ASCIIEncoding(); byte[] postBytes = Encoding.UTF8.GetBytes(json); HttpWebRequest request; request = WebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt") as HttpWebRequest; request.Method = "POST"; request.ContentType = "application/json"; request.ContentLength = postBytes.Length; Stream postStream = request.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Close(); var sendresponse = (HttpWebResponse)request.GetResponse(); string sendresponsetext = ""; using (var streamReader = new StreamReader(sendresponse.GetResponseStream())) { sendresponsetext = streamReader.ReadToEnd(); } returnmessage = sendresponsetext; } catch (Exception ex) { ex.Message.ToString(); } return returnmessage; } 

Siempre devuelve {"status":21002} . He estado buscando por dos días, pero todavía no puedo encontrar la solución. ¿Alguien puede ayudarme? ¿Qué estoy mal?

** Estoy probando en sandbox por eso uso la URL de sandbox. Puedo verificar el recibo de la transacción dentro de mi aplicación.

Tengo solucion

El código final que me funciona es:

  public string PurchaseItem(string receiptData) { string returnmessage = ""; try { // var json = "{ 'receipt-data': '" + receiptData + "'}"; var json = new JObject(new JProperty("receipt-data", receiptData)).ToString(); ASCIIEncoding ascii = new ASCIIEncoding(); byte[] postBytes = Encoding.UTF8.GetBytes(json); // HttpWebRequest request; var request = System.Net.HttpWebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt"); request.Method = "POST"; request.ContentType = "application/json"; request.ContentLength = postBytes.Length; //Stream postStream = request.GetRequestStream(); //postStream.Write(postBytes, 0, postBytes.Length); //postStream.Close(); using (var stream = request.GetRequestStream()) { stream.Write(postBytes, 0, postBytes.Length); stream.Flush(); } // var sendresponse = (HttpWebResponse)request.GetResponse(); var sendresponse = request.GetResponse(); string sendresponsetext = ""; using (var streamReader = new StreamReader(sendresponse.GetResponseStream())) { sendresponsetext = streamReader.ReadToEnd().Trim(); } returnmessage = sendresponsetext; } catch (Exception ex) { ex.Message.ToString(); } return returnmessage; 

Pasar dos días y medio solo para cambiar un método. Gracias a Dios.

Aquí hay una implementación asíncrona alternativa utilizando HTTPClient:

 public static async Task<string> CheckReceiptWithAppStore() { string responseStr = null; string uri = "https://sandbox.itunes.apple.com/verifyReceipt"; string receiptData = // Get your receipt from wherever you store it var json = new JObject(new JProperty("receipt-data", receiptData), new JProperty("password", "paste-your-shanetworking-secret-here")).ToString(); using (var httpClient = new HttpClient()) { if (receiptData != null) { HttpContent content = new StringContent(json); try { Task<HttpResponseMessage> getResponse = httpClient.PostAsync(uri, content); HttpResponseMessage response = await getResponse; responseStr = await response.Content.ReadAsStringAsync(); } catch (Exception e) { Console.WriteLine("Error verifying receipt: " + e.Message); } } } return responseStr; } 

El secreto compartido no es obligatorio para las compras basadas en la suscripción.

Para gestionar las suscripciones, la respuesta de @Jerry Naing también requiere la provisión de su secreto compartido (puede recuperarse / generarse desde iTunes Connect). La forma más fácil de include esto es solo para agregar una propiedad adicional en la línea que define el json var.

 var json = new JObject(new JProperty("receipt-data", receiptData), new JProperty("password", "put_your_shanetworking_secret_here")).ToString(); 

Si no se proporciona el secreto compartido, se generará una respuesta de estado 21004.

Este ejemplo de código también me ayudó y puede ayudar a otros: para los desarrolladores de C # existe un proyecto de código abierto útil llamado APNS-Sharp que incluye el código de verificación de recibos que funciona en ASP.NET. En particular, los files Receipt.cs y ReceiptVerification.cs en el directory Jdsoft.Apple.AppStore

Lo encontré de esta página sobre Xamarin: inapp purcasing ios Transactions and Verification