Tengo una aplicación Java y estoy intentando actualizar una oportunidad a través de la API web de crm. Cuando trato de usar un método HTTP no estándar como PATCH (que es necesario para la actualización) y lo anulo con el "X-HTTP-Method-Override" como lo encontré en varios códigos de ejemplo, no funciona.

Código para la actualización de la oportunidad:

public int updateOpportunity(OpportunityDaoModel model) throws IOException, URISyntaxException {
JSONObject opportunity = new JSONObject();
opportunity.put("name", model.getTopic());

HttpURLConnection connection = null;
URL url = new URL(RESOURCE + "/api/data/"+API_VERSION+"/opportunities(" + model.getCrmguid() + ")");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("X-HTTP-Method-Override", "PATCH");
connection.setRequestProperty("OData-MaxVersion", "4.0");
connection.setRequestProperty("OData-Version", "4.0");
connection.setRequestProperty("Accept", "application/json");
connection.addRequestProperty("Authorization", "Bearer " + token);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.connect();

OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write(opportunity.toString());
out.flush();
out.close();
int responseCode = connection.getResponseCode();
return responseCode;
}

Después de ejecutar este método, aparece el siguiente error:

{
 "error":{
   "code":"","message":"Unmapped Request found, PathTemplate:~/entityset/key, HttpVerb:POST","innererror":{
     "message":"Unmapped Request found, PathTemplate:~/entityset/key, HttpVerb:POST","type":"Microsoft.Crm.CrmHttpException","stacktrace":"   at Microsoft.Crm.Extensibility.OData.EntityController.HandleUnmappedRequest(ODataPath path)\r\n   at lambda_method(Closure , Object , Object[] )\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
   }
 }
}

Después de que no encontré ninguna información en la web para este error, probé una entrada diferente y quería usar la actualización de un solo atributo a través de PUT. Esto tiene éxito para los atributos normales (como el atributo de nombre en muchas entidades) pero cuando intento actualizar un campo de búsqueda, obtengo un error diferente. Pero primero mi método:

Código para la actualización de un solo atributo:

public int updateAttribute(String entity, String id, String attribute, String value) throws IOException, URISyntaxException {
JSONObject opportunity = new JSONObject();
HttpURLConnection connection = null;
String urlString = "";
if(attribute.contains("@odata.bind")) { // lookup value
    urlString = RESOURCE + "/api/data/"+API_VERSION+"/"+entity+"(" + id + ")";
        opportunity.put(attribute, value);
} else { // text value
        urlString = RESOURCE + "/api/data/"+API_VERSION+"/"+entity+"(" + id + ")/" + attribute;
        opportunity.put("value", value);
}
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setRequestProperty("OData-MaxVersion", "4.0");
connection.setRequestProperty("OData-Version", "4.0");
connection.setRequestProperty("Accept", "application/json");
connection.addRequestProperty("Authorization", "Bearer " + token);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.connect();

OutputStreamWriter out = new     OutputStreamWriter(connection.getOutputStream());
out.write(opportunity.toString());
out.flush();
out.close();
int responseCode = connection.getResponseCode();
return responseCode;
}

Llamo a este método a través de

 updateAttribute("opportunities", model.getCrmguid(), "lookupentityid@odata.bind", "/entityendpointwiths("+model.getProgress()+")");

El mensaje de error:

{
 "error":{
    "code":"","message":"Operation not supported on opportunity","innererror":{
    "message":"Operation not supported on opportunity","type":"Microsoft.Crm.CrmHttpException","stacktrace":"   at Microsoft.Crm.Extensibility.OData.EntityController.PutEntity(String entityName, String key, EdmEntityObject entity)\r\n   at lambda_method(Closure , Object , Object[] )\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
    }
  }
 }

Gracias por cualquier ayuda.

Saludos cordiales, Dennis

1
Dennis Reese 12 ene. 2017 a las 14:47
Encontré un artículo interesante. Desafortunadamente, no ayuda: msdn.microsoft.com/en-us /library/mt607875.aspx#Anchor_3
 – 
Dennis Reese
18 ene. 2017 a las 13:39

1 respuesta

La mejor respuesta

Si alguien más debería estar en esta posición, me complace presentarles mi respuesta. En lugar de usar el encabezado x-http-override, debe usar HTTPPatch-Class de java.

Método:

public String updateAttribute(String entity, String id, List<Map<String, Object>> parameters) throws IOException, URISyntaxException {
JSONObject object = new JSONObject();
    for (Map<String, Object> map : parameters) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            object.put(key, value);
        }
    }

    String urlString = "";
    urlString = RESOURCE + "/api/data/"+API_VERSION+"/"+entity+"(" + id + ")/";
    StringEntity stringEntity = new StringEntity(object.toString());

    URL url = new URL(urlString);
    HttpPatch httpPatch = new HttpPatch(urlString);
    httpPatch.addHeader("OData-MaxVersion", "4.0");
    httpPatch.addHeader("OData-Version", "4.0");
    httpPatch.addHeader("Accept", "application/json");
    httpPatch.addHeader("Authorization", "Bearer " + token);
    httpPatch.addHeader("Content-Type", "application/json");
    httpPatch.setEntity(stringEntity);

    CloseableHttpClient httpClient = HttpClients.createDefault();
    HttpResponse httpResponse = httpClient.execute(httpPatch);

int responseCode =  httpResponse.getStatusLine().getStatusCode();

if (responseCode > 299) {
    InputStream inputStream = httpResponse.getEntity().getContent();
    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }

    throw new IOException(result.toString("UTF-8"));
}

return responseCode;
}

Llamar al método a través de:

List<Map<String,Object>> opportunityParameterList = new ArrayList<>();
Map<String, Object> opportunityParameters = new HashMap<>();      
opportunityParameters.put("name", opportunityDaoModel.getTopic());
opportunityParameters.put("lookupfield@odata.bind", "/lookupentityendpoint("+opportunityDaoModel.getProgress()+")");
opportunityParameterList.add(opportunityParameters);
this.crmHelper.updateAttribute("opportunities", opportunityDaoModel.getCrmguid(), opportunityParameterList);
0
Dennis Reese 18 ene. 2017 a las 18:14