Files
itca_api_sap_wms/Net.Connection.ServiceLayer/ConnectionServiceLayer.cs
T
GeorgeandClaude Sonnet 5.5 ac725aed9b ConnectionServiceLayer: unificar LoginPost en Login (eran identicos)
Las 4 llamadas a LoginPost() ahora llaman a Login(). Sin cambios de comportamiento.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 19:49:20 -05:00

839 lines
42 KiB
C#

using Microsoft.Extensions.Configuration;
using Net.Business.Entities.ServicesLayer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace Net.Connection.ServiceLayer
{
public class ConnectionServiceLayer
{
public static bool ServicioActivo = false;
public static string SLSession;
// Se invoca solo cuando SAP rechaza un envio: (ruta del recurso, JSON enviado, respuesta de SAP).
// Lo asigna Startup (esta capa no conoce HANA).
public static Action<string, object, string> ErrorLogger;
private static void LogErrorEnvio(string query, object jsonEnviado, string respuesta)
{
try { ErrorLogger?.Invoke(query, jsonEnviado, respuesta); }
catch { /* el log nunca debe romper el flujo principal */ }
}
private readonly string _url;
private readonly string _company;
private readonly string _user;
private readonly string _password;
private readonly string _language;
private readonly IHttpClientFactory _httpClient;
private ResponseLoginServiceLayer _responseLoginServiceLayer;
public ConnectionServiceLayer(IConfiguration configuration, IHttpClientFactory clientFactory)
{
_url = configuration["SapServiceLayer:url"];
_company = configuration["SapServiceLayer:company"];
_user = configuration["SapServiceLayer:user"];
_password = configuration["SapServiceLayer:password"];
_language = configuration["SapServiceLayer:language"];
_httpClient = clientFactory;
_responseLoginServiceLayer = new ResponseLoginServiceLayer();
}
// Inicia sesion en el Service Layer (cookie B1SESSION). Usa SapServiceLayer:company/user/password de appsettings.json
public async Task<ResponseLoginServiceLayer> Login()
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/Login");
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL Content CON EL OBJETO A ENVIAR SERIALIZADO.
request_.Content = new StringContent("{\"CompanyDB\":\"" + _company + "\",\"Password\":\"" + _password + "\",\"UserName\":\"" + _user + "\"}");
// DEFINIMOS EL ContentType, EN ESTE CASO ES "application/json"
request_.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
request_.Headers.Add("cache-control", "no-cache");
// DEFINIMOS EL MÉTODO HTTP
request_.Method = new HttpMethod("POST");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK) // 200
{
// DESERIALIZAMOS Content DEL RESPONSE
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = true;
_responseLoginServiceLayer.MensajeLogin = "Autenticación Correcta";
return _responseLoginServiceLayer;
}
else
// SI NO SE ESTÁ AUTORIZADO ...
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
{
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
_responseLoginServiceLayer.MensajeLogin = "401 Unauthorized. Las credenciales de acceso del usuario son incorrectas.";
return _responseLoginServiceLayer;
}
else
// CUALQUIER OTRA RESPUESTA ...
if (response_.StatusCode != System.Net.HttpStatusCode.OK && // 200
response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
{
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
_responseLoginServiceLayer.MensajeLogin = "401 Unauthorized. Las credenciales de acceso del usuario son incorrectas.";
return _responseLoginServiceLayer;
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return _responseLoginServiceLayer;
}
}
catch (Exception ex)
{
_responseLoginServiceLayer.ServicioActivo = false;
_responseLoginServiceLayer.MensajeLogin = ex.Message.ToString();
return _responseLoginServiceLayer;
}
}
// GET al Service Layer. dinamico = true: la respuesta es una sola entidad (ej. Invoices(123)); false: coleccion { value: [...] }
public async Task<List<T>> GetAsync<T>(string Query, int maxpagesize,bool dinamico = false)
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/" + Query);
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
//AUTENTICAMOS PARA REALIZAR LAS CONSULTAS
await Login();
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL MÉTODO HTTP
request_.Method = new HttpMethod("GET");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
request_.Headers.Add("cache-control", "no-cache");
request_.Headers.Add("Prefer", "odata.maxpagesize=" + maxpagesize.ToString());
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
if (_responseLoginServiceLayer.ServicioActivo)
//request_.Headers = new AuthenticationHeaderValue("B1SESSION", _responseLoginServiceLayer.SessionId);
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK) // 200
{
// DESERIALIZAMOS Content DEL RESPONSE
if (!dinamico)
{
var responseBody_ = JsonConvert.DeserializeObject<ResponseGetServiceLayer<T>>(responseText_);
return responseBody_.value;
}
if (dinamico)
{
List<T> lista = new List<T>();
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
//responseBody.Exito = true;
//var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString();
//responseBody.Mensaje = "Datos Correctos del SAP";
lista.Add(responseBody);
return lista;
}
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return default(List<T>);
}
}
finally
{
// NO UTILIZAMOS CATCH,
// PASAMOS LA EXCEPCIÓN A LA APP.
}
}
// POST con cuerpo JSON. Reintenta una vez si la sesion expiro (401). Si SAP rechaza, devuelve Exito = false y guarda
// el JSON enviado con ErrorLogger (tabla ITCA_LOG_INTEGRACION)
public async Task<T> PostAsync<T>(string Query, object obj)
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/" + Query);
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
int NumError = 0;
band:
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL MÉTODO HTTP GET
request_.Method = new HttpMethod("POST");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("odata=minimalmetadata"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("charset=utf-8"));
var a = JsonConvert.SerializeObject(obj);
request_.Content = new StringContent(JsonConvert.SerializeObject(obj), System.Text.Encoding.UTF8, "application/json");
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created) // 200 or Created
{
// DESERIALIZAMOS Content DEL RESPONSE
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = true;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "SE ENVIO CORRECTAMENTE A SAP BO ";
return responseBody;
}
else
// SI NO SE ESTÁ AUTORIZADO ...
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
else
// CUALQUIER OTRA RESPUESTA ...
if (response_.StatusCode != System.Net.HttpStatusCode.OK && // 200
response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return default(T);
}
}
finally
{
// NO UTILIZAMOS CATCH,
// PASAMOS LA EXCEPCIÓN A LA APP.
}
}
// POST sin cuerpo para reabrir un documento (ej. Invoices(n)/Reopen). SAP responde 204 sin contenido y se toma como exito
public async Task<T> PostReOpen<T>(string Query)
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/" + Query);
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
int NumError = 0;
band:
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL MÉTODO HTTP GET
request_.Method = new HttpMethod("POST");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("odata=minimalmetadata"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("charset=utf-8"));
//var a = JsonConvert.SerializeObject(obj);
//request_.Content = new StringContent(JsonConvert.SerializeObject(obj), System.Text.Encoding.UTF8, "application/json");
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created || response_.StatusCode == HttpStatusCode.NoContent) // 200 or Created
{
// DESERIALIZAMOS Content DEL RESPONSE
// Reopen responde 204 sin cuerpo: DeserializeObject devuelve null, asi que
// se crea una instancia vacia para poder marcar el exito.
dynamic responseBody = string.IsNullOrWhiteSpace(responseText_)
? Activator.CreateInstance<T>()
: JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = true;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "SE ENVIO CORRECTAMENTE A SAP BO ";
return responseBody;
}
else
// SI NO SE ESTÁ AUTORIZADO ...
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
else
// CUALQUIER OTRA RESPUESTA ...
if (response_.StatusCode != System.Net.HttpStatusCode.OK && // 200
response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return default(T);
}
}
finally
{
// NO UTILIZAMOS CATCH,
// PASAMOS LA EXCEPCIÓN A LA APP.
}
}
// POST sin cuerpo para cerrar un documento (.../Close)
public async Task<T> PostClose<T>(string Query)
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/" + Query);
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
int NumError = 0;
band:
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL MÉTODO HTTP GET
request_.Method = new HttpMethod("POST");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("odata=minimalmetadata"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("charset=utf-8"));
//var a = JsonConvert.SerializeObject(obj);
//request_.Content = new StringContent(JsonConvert.SerializeObject(obj), System.Text.Encoding.UTF8, "application/json");
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created || response_.StatusCode == HttpStatusCode.NoContent) // 200 or Created
{
// DESERIALIZAMOS Content DEL RESPONSE
dynamic responseBody = new BE_BaseResponseSap(); //JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = true;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "SE ENVIO CORRECTAMENTE A SAP BO ";
return responseBody;
}
else
// SI NO SE ESTÁ AUTORIZADO ...
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
else
// CUALQUIER OTRA RESPUESTA ...
if (response_.StatusCode != System.Net.HttpStatusCode.OK && // 200
response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
responseBody.Exito = false;
var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
}
goto band;
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return default(T);
}
}
finally
{
// NO UTILIZAMOS CATCH,
// PASAMOS LA EXCEPCIÓN A LA APP.
}
}
// PATCH con cuerpo JSON. OJO: con un 204 real devuelve null sin marcar exito (bug conocido); para PATCH sin respuesta usar PatchNoContentAsync
public async Task<T> PatchAsyncSBA<T>(string Query, object obj)
{
try
{
// CONSTRUIMOS LA URL DE LA ACCIÓN
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
.Append("/" + Query);
var url_ = urlBuilder_.ToString();
// RECUPERAMOS EL HttpClient
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
int NumError = 0;
band:
using (var request_ = new HttpRequestMessage())
{
///////////////////////////////////////
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
///////////////////////////////////////
// DEFINIMOS EL MÉTODO HTTP GET
request_.Method = new HttpMethod("PATCH");
// DEFINIMOS LA URI
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("odata=minimalmetadata"));
//request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("charset=utf-8"));
request_.Content = new StringContent(JsonConvert.SerializeObject(obj), System.Text.Encoding.UTF8, "application/json");
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
/////////////////////////////////////////
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
/////////////////////////////////////////
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
// OBTENEMOS EL Content DEL RESPONSE como un String
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
// SI ES LA RESPUESTA ESPERADA !! ...
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created) // 200 or Created
{
// DESERIALIZAMOS Content DEL RESPONSE
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "SE ENVIO CORRECTAMENTE A SAP BO ";
return responseBody;
}
else
// SI NO SE ESTÁ AUTORIZADO ...
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
{
NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
if (NumError == 2)
{
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody;
}
if (_responseLoginServiceLayer.error.code.ToString() == "301")
{
await Login();
goto band;
}
}
else
// CUALQUIER OTRA RESPUESTA ...
if (response_.StatusCode != System.Net.HttpStatusCode.OK && response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
{
//NumError += 1;
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
_responseLoginServiceLayer.ServicioActivo = false;
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody;
}
if (response_.StatusCode == System.Net.HttpStatusCode.NoContent)
{
//dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
////responseBody.Mensaje = "OK";
//return responseBody;
}
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
return default(T);
}
}
catch (Exception ex)
{
return default(T);
}
}
// === NUEVO (SolicitudTransferencia / Picking HojaRuta Cerrar) ===
//
// PatchAsyncSBA<T>/PostAsync<T> estan pensados para respuestas con body
// (200/201) que se deserializan a T y se les "inyecta" Exito/Mensaje/CodigoHttp
// via dynamic - no sirven para una respuesta sin body como el 204 real que
// devuelve SAP en un PATCH exitoso o en una accion /Close, y PatchAsyncSBA
// tiene ademas un bug conocido ahi (ver docs/PORTE_FUNCIONALIDAD_NUEVA.md,
// hallazgo #2): con un 204 real cae a "return default(T)" sin marcar exito.
// Por eso estos dos metodos nuevos son deliberadamente simples: no devuelven
// un T deserializado, solo exito (sin excepcion) o fallo (excepcion con el
// mensaje real de SAP).
public async Task PatchNoContentAsync(string Query, object obj, Dictionary<string, string> extraHeaders = null)
{
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "").Append("/" + Query);
var url_ = urlBuilder_.ToString();
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
await Login();
using (var request_ = new HttpRequestMessage())
{
request_.Method = new HttpMethod("PATCH");
request_.RequestUri = new Uri(url_, UriKind.RelativeOrAbsolute);
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
request_.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
if (extraHeaders != null)
{
foreach (var kv in extraHeaders)
request_.Headers.Add(kv.Key, kv.Value);
}
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response_.StatusCode == HttpStatusCode.OK || response_.StatusCode == HttpStatusCode.NoContent)
{
return; // exito real - sin body que parsear
}
var mensajeError = ExtraerMensajeErrorSap(responseText_);
LogErrorEnvio(Query, obj, mensajeError);
throw new Exception(mensajeError);
}
}
public async Task PostActionAsync(string Query)
{
var urlBuilder_ = new StringBuilder();
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "").Append("/" + Query);
var url_ = urlBuilder_.ToString();
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
await Login();
using (var request_ = new HttpRequestMessage())
{
request_.Method = new HttpMethod("POST");
request_.RequestUri = new Uri(url_, UriKind.RelativeOrAbsolute);
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
request_.Content = new StringContent("{}", Encoding.UTF8, "application/json");
if (_responseLoginServiceLayer.ServicioActivo)
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response_.StatusCode == HttpStatusCode.OK || response_.StatusCode == HttpStatusCode.Created || response_.StatusCode == HttpStatusCode.NoContent)
{
return; // exito real - sin body que parsear
}
throw new Exception(ExtraerMensajeErrorSap(responseText_));
}
}
private static string ExtraerMensajeErrorSap(string responseText)
{
try
{
var parsed = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText);
var mensaje = parsed?.error?.message;
if (mensaje == null) return responseText;
// "message" esta tipado como object en ErrorServiceLayer (ver
// ResponseLoginServiceLayer.cs) - Json.NET lo deja como JObject.
if (mensaje is JObject jMensaje) return jMensaje.Value<string>("value") ?? responseText;
return mensaje.ToString();
}
catch
{
return responseText;
}
}
}
}