terça-feira, 26 de setembro de 2017

CRM-GT - Consumo de Web Api usando C#

Este artigo tem como objetivo documentar o uso de um importante recurso do meu sistema de gerenciamento com o cliente, o CRM-GT. Este recurso se chama Web Api, e serve como um [conector] entre o sistema CRMGT e qualquer sistema legado.

Esta é a URL principal de consumo REST: /api/CRMGT/QueryXML

Com este conector, você pode efetuar todo CRUD de operações. Portanto, segue abaixo o uso prático deste recurso, usando C#.

Busca do Token de acesso (OAuth)
var url = "https://crm-gt.com:82/api/CRMGT/GetToken";
url += "?orgName=CRMGT1";
url += "&clientId=+n8c++NABWZrkldVUaf0XYH2T2lG5xvUhZEVxFz46/4=__5@_";
url += "&clientSecret=7RclDz1Ilbp3jyOuXJNnyfaK3bW+MIt5fU0BL1f46to=__0@_";
var jToken = GetString(url);
var token = JsonConvert.DeserializeObject<JObject>(jToken).SelectToken("token").ToString();

Considerações importantes sobre o token.
- Ele expira a cada 3 horas.
- O [clientId] e o [clientSecret] são criados por Organização. O administrador da organização cria estas chaves e as disponibiliza para obtenção do Token.

Para Renovar o Token de acesso (OAuth)
var url = "https://crm-gt.com:82/api/CRMGT/RenewToken";
url += "?orgName=CRMGT1";
url += "&clientId=+n8c++NABWZrkldVUaf0XYH2T2lG5xvUhZEVxFz46/4=__5@_";
url += "&clientSecret=7RclDz1Ilbp3jyOuXJNnyfaK3bW+MIt5fU0BL1f46to=__0@_";
var jToken = GetString(url);
var token = JsonConvert.DeserializeObject<JObject>(jToken).SelectToken("token").ToString();

Como saber se o token de acesso expirou? Ao executar o endpoint /GetToken, o sistema retorna um atributo informando que o tempo expirou ("expires_in" : "0").


Para os métodos de CREATE e UPDATE, no momento da configuração da tag [fields/field] atributo [TYPE], informe os tipos correspondentes aos do [SQL SERVER].
Segue os principais:
bit
char
nchar
varchar
nvarchar
datetime
decimal
text
uniqueidentifier
Desta forma, se precisar adicionar um campo do tipo [string], informe [varchar].
Se precisar adicionar um campo do tipo [valor ou moeda], informe [decimal], e assim por diante.


Para efetuar um SELECT

1 - Monte o "SELECT" através de uma instrução XML:
string xmlSELECT = @"
 <select>
  <organization name='{0}' />
  <table name='User' alias='tb1' />
  <fields>
   <field name='tb1.UserId' label='ID' />
   <field name='tb1.Name' />
   <field name='tb1.Email' />
   <field name='tb2.Name' />
   <field name='tb3.Name' />
  </fields>
  <join name='Status' alias='tb2' fieldFrom='statuscode' fieldTo='statuscode'>
   <filter type='and'>
    <condition field='tb2.name' operator='=' value='Ativo' />
   </filter>                     
  </join>
  <join name='salesorder' alias='tb3' fieldFrom='userid' fieldTo='ownerid'>
   <filter type='and'>
    <condition field='tb3.name' operator='like' value='%ped%' />
   </filter>                     
  </join>
  <filter type='and'>
   <condition field='tb1.name' operator='like' value='%usr%' />
  </filter>
 </select>";

O XML acima é a representação do SELECT-SQL abaixo:
SELECT tb1.UserId, tb1.Name, tb1.Email, tb2.Name, tb3.Name
FROM [User] tb1 
JOIN [Status] tb2 ON tb1.statuscode = tb2.statuscode AND tb2.name = 'Ativo'
JOIN [salesorder] tb3 ON TB1.UserId = tb3.ownerid AND tb3.name like '%ped%'
WHERE tb1.Name like '%usr%'

2 - Passe como parâmetro a informação de [Organização], conforme a sequência abaixo.
var xmlF = string.Format(xmlSELECT, "CRMGT1");

3 - Execute a instrução, chamando a Web Api:
var header = new Dictionary<string, object>();
header.Add("Authorization", "Bearer " + token);
var result = GetStringByXMLPost("https://crm-gt.com:82/api/CRMGT/QueryXML", "GET", xmlF, "application/x-www-form-urlencoded", header);

Segue abaixo métodos [GetString] e [GetStringByXMLPost] que efetuam chamadas HTTP:
public static String GetString(String url)
{
   var urlContents = "";
   try
   {
      using (HttpClient client = new HttpClient())
      {
         urlContents = client.GetStringAsync(new Uri(url)).Result;
      }
   }
   catch (Exception ex)
   {
   }

   return urlContents;
}

public static string GetStringByXMLPost(string url, 
                                        string type, 
                                        string xml, 
                                        string mediaType = "application/json", 
                                        Dictionary<string, object> headerList = null)
{
	string urlContents = "";
	HttpResponseMessage result = null;

	try
	{
		Task.Run(async () =>
		{
			using (HttpClient client = new HttpClient()) {
				if (headerList != null) {
					foreach (var item in headerList) {
						client.DefaultRequestHeaders.Add(item.Key, item.Value.ToString());
					}
				}

				if (mediaType == "application/json") {
					var doc = new XMLDocumentModel() {
						Type = type,
						xmlContent = xml
					};

					var content = JsonConvert.SerializeObject(doc);
					var httpContent = new StringContent(content, Encoding.UTF8, mediaType);
					result = await client.PostAsync(new Uri(url), httpContent);
				}
				else {
					var keyValues = new List<KeyValuePair<string, string>>();
					keyValues.Add(new KeyValuePair<string, string>("Type", type));
					keyValues.Add(new KeyValuePair<string, string>("xmlContent", xml));
					var formContent = new FormUrlEncodedContent(keyValues);

					var request = new HttpRequestMessage(HttpMethod.Post, url);
					request.Content = formContent;
					result = await client.SendAsync(request);
				}

				urlContents = await result.Content.ReadAsStringAsync();
			}
		}).Wait();
	}
	catch (Exception ex)
	{
	}

	return urlContents;
}

P.S.: XMLDocumentModel é uma classe simples de apoio:
public class XMLDocumentModel
{
    public string Type { get; set; }
    public string xmlContent { get; set; }
    public bool DecriptPwd { get; set; }
}


Para efetuar um CREATE

1 - Monte o "CREATE" através de uma instrução XML:
string xmlINSERT = @"
    <insert>
        <organization name='{0}' />
        <table name='{1}' isNN='false' setInternalFields='true' setWorkflowTrigger='false' />
        <records>
            <record>
                <fields>
                    <field name='statuscode' type='int' value='998' />
                    <field name='name' type='varchar' value='test1...' />
                    <field name='ownerid' type='uniqueidentifier' lookuptable='user' lookupsearchfield='name' value='system' />
                </fields>
            </record>
            <record>
                <fields>
                    <field name='statuscode' type='int' value='999' />
                    <field name='name' type='varchar' value='test2...' />
                    <field name='ownerid' type='uniqueidentifier' value='9EC0ABA8-2947-4857-9698-1C43BBBFAB5B' />
                </fields>
            </record>
        </records>
    </insert>";

2 - Passe como parâmetro as informações de [Organização] e [tabela], conforme a sequência abaixo.
var xmlF = string.Format(xmlINSERT, "CRMGT1", "lead");

3 - Execute a instrução, chamando a Web Api:
var header = new Dictionary<string, object>();
header.Add("Authorization", "Bearer " + token);
var result = GetStringByXMLPost("https://crm-gt.com:82/api/CRMGT/QueryXML", "SET", xmlF, "application/x-www-form-urlencoded", header);

Para inserir dados em uma tabela N-N, adicione o atributo [isNN='true'] na tag xml [table], conforme exemplificado abaixo:
string xmlINSERT = @"
    <insert>
        <organization name='{0}' />
        <table name='{1}' isNN='true' />
        <records>
            <record>
                <fields>
                    <field name='pricelist_productid' type='uniqueidentifier' value='NEWID' />
                    <field name='pricelistid' type='uniqueidentifier' value='3BEF33F8-A159-4F77-964D-B820B8414E59' />
                    <field name='productid' type='uniqueidentifier' value='B091A317-4FF7-42BE-AD86-D77C22059E49' />
                </fields>
            </record>
            <record>
                <fields>
                    <field name='pricelist_productid' type='uniqueidentifier' value='NEWID' />
                    <field name='pricelistid' type='uniqueidentifier' value='3BEF33F8-A159-4F77-964D-B820B8414E59' />
                    <field name='productid' type='uniqueidentifier' value='6922B778-B4FF-4564-A992-E40A020C599F' />
                </fields>
            </record>
        </records>
    </insert>";

Se precisar definir uma regra antes da criação dos registros, você pode adicionar a seguinte tag [rules] depois da tag [table]:
<rules>
	<rule action="insert_ignoreifexists" actionoperator="AND">
		<fields>
			<field name="protocol" type="VarChar" />
			<field name="incidentNumber" type="Int" />
		</fields>
	</rule>
</rules>

Desta forma, através da regra [insert_ignoreifexists] você não permite a inclusão do registro se os campos especificados na tag [fields] existirem na tabela.


Para efetuar um UPDATE

1 - Monte o "UPDATE" através de uma instrução XML:
string xmlUPDATE = @"
    <update>
        <organization name='{0}' />
        <table name='{1}' setWorkflowTrigger='false' />
        <set>
            <field name='name' type='varchar' value='TEST UPD...' setWorkflowFieldTrigger='false' />
            <field name='modifiedOn' type='datetime' value='GETDATE' />
        </set>
        <filter type='and'>
            <condition field='name' operator='=' value='TEST' />
        </filter>
    </update>";

2 - Passe como parâmetro as informações de [Organização] e [tabela], conforme a sequência abaixo.
var xmlF = string.Format(xmlUPDATE, "CRMGT1", "Status");

3 - Execute a instrução, chamando a Web Api:
var header = new Dictionary<string, object>();
header.Add("Authorization", "Bearer " + token);
var result = GetStringByXMLPost("https://crm-gt.com:82/api/CRMGT/QueryXML", "SET", xmlF, "application/x-www-form-urlencoded", header);


Para efetuar um DELETE

1 - Monte o "DELETE" através de uma instrução XML:
string xmlDELETE = @"
    <delete>
        <organization name='{0}' />
        <table name='{1}' setWorkflowTrigger='false' />
        <filter type='and'>
            <condition field='name' operator='=' value='TEST...' />
        </filter>
    </delete>";

2 - Passe como parâmetro as informações de [Organização] e [tabela], conforme a sequência abaixo.
var xmlF = string.Format(xmlDELETE, "CRMGT1", "Status");

3 - Execute a instrução, chamado a Web Api:
var header = new Dictionary<string, object>();
header.Add("Authorization", "Bearer " + token);
var result = GetStringByXMLPost("https://crm-gt.com:82/api/CRMGT/QueryXML", "SET", xmlF, "application/x-www-form-urlencoded", header);


Para executar uma [QUERY EXEC]

1 - Monte a "QUERY EXEC" através de uma instrução XML:
string xmlQE = @"
	<queryexec>
	<organization name='{0}' />
	<queryexecid value='{1}' />
	<paramset>
		<param name = '@_id_' value='62a9a715-8574-4813-a69f-e732c76313e0' />
	</paramset>
	<filter type='and'>
		<condition field='inc.StatusCode' operator='=' value='1' />
	</filter>
	</queryexec>";

2 - Passe como parâmetro as informações de [Organização] e [ID da query exec], conforme a sequência abaixo.
var xmlF = string.Format(xmlQE, "CRMGT1", "buscarocorrencias");

3 - Execute a instrução, chamado a Web Api:
var header = new Dictionary<string, object>();
header.Add("Authorization", "Bearer " + token);
var result = GetStringByXMLPost("https://crm-gt.com:82/api/CRMGT/QueryXML", "QueryExec", xmlF, "application/x-www-form-urlencoded", header);

Obs: As tags <paramset> e <filter> são [opcionais]. Elas são úteis quando precisar passar mais parâmetros de filtro para a Query Exec criada no sistema ou para substituir o valor das macros do sistema (@_id_ por exemplo).

Nenhum comentário:

Postar um comentário

<< Ao enviar um comentário, favor clicar na opção [Enviar por e-mail comentários de acompanhamento para gtezini@gmail.com] >>