In this second part, I’m going to explain the code from the executable class. I’m using attachments because I find them very helpful during testing and even in production. However, you can also work in memory; at the end of this guide, I’ll explain how.
Let’s start with the executable class. We’ll begin by using a couple of directives, declaring a few class scope variables, and writing the main method.
using Microsoft.Dynamics365.LocalizationFramework;
using Microsoft.Dynamics.ElectronicReporting.Instrumentation;
internal final class TST_RunAPI
{
TST_TableAPI tst_tableApi;
str nameExp;
str nameImp;
str expBody;
str answer;
static void main (Args _args)
{
TST_RunAPI tst_RunAPI = new TST_RunAPI();
// Select the record
tst_RunAPI.fillTable(_args);
// Execute ER to file attachment
tst_RunAPI.runEr();
// Gets attachment and saves it on memory
tst_RunAPI.docuRefToMemory();
// Sends the request to the API
tst_RunAPI.sendCom();
// Executes ER with the answer
tst_RunAPI.importAnswer();
// Saves a copy of the answer in memory
tst_RunAPI.saveAnswerToDocRef();
}
}
This method finds the record from where we are calling the class:
protected void fillTable(Args _args)
{
select firstonly * from tst_tableApi
where tst_tableApi.RecId == _args.record().RecId;
}
Runs the ER and saves it as an attachment:
protected void runEr()
{
// Fills the user input parameters
ERModelDefinitionInputParametersAction obj = new ERModelDefinitionInputParametersAction();
obj.addParameter('model/$Id', tst_tableApi.Id);
// The Destination is a file
ERIFileDestination fileDestination = ERObjectsFactory::createFileDestinationAttachmentWithOtherDocuType(
tst_tableApi);
// Runs the ER, saving the filename to a variable, with
// Destinations and Parameters
nameExp = ERObjectsFactory::createFormatMappingRunByFormatMappingId(
AssetParameters::find().TST_ERExport, "", false)
.withFileDestination(fileDestination)
.withParameter(obj)
.run();
}
Finds the generated JSON and saves it in memory:
protected void docuRefToMemory()
{
DocuRef drExpMessage;
System.IO.StreamReader streamReader;
// Finds the created document
select firstonly drExpMessage order by createdDateTime desc
where drExpMessage.RefCompanyId == tst_tableApi.dataAreaId
&& drExpMessage.RefRecId == tst_tableApi.RecId
&& drExpMessage.RefTableId == tst_tableApi.TableId
&& drExpMessage.Name == nameExp;
if (!drExpMessage)
{
throw error("API body not found");
}
// Read the content of the document attachment into memory
streamReader = new System.IO.StreamReader(
DocumentManagement::getAttachmentStream(drExpMessage));
expBody = streamReader.ReadToEnd();
streamReader.Close();
streamReader.Dispose();
}
Sends the request to the API:
protected void sendCom()
{
str headerKey;
str headerValue;
System.Net.WebResponse response;
// Retrieve the API endpoint, user, and password from parameters
str endpoint = AssetParameters::find().TST_ApiUrl;
str password = AssetParameters::find().TST_ApipassNameEdit(false, "");
str user = AssetParameters::find().TST_APIuser;
System.Text.Encoding encoding = System.Text.Encoding::UTF8;
// Encode the user and password for basic authentication
System.Byte[] bytes = encoding.GetBytes(user + ":" + password);
System.String base64 = System.Convert::ToBase64String(bytes);
// Authorization header
headerKey = "Authorization";
headerValue = "Basic " + base64;
// Create the request
System.Net.WebRequest request = System.Net.WebRequest::Create(endpoint);
request.Method = "POST";
request.ContentType = "application/json";
// Add the authorization header
System.Net.WebHeaderCollection headers = request.Headers;
headers.Add(headerKey, headerValue);
// Write the JSON body to the request stream
using (var streamWriter = new System.IO.StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(expBody);
}
try
{
// Get the response from the API
response = request.GetResponse();
// Read the response stream and store the answer
using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))
{
answer = reader.ReadToEnd();
}
}
catch
{
throw error("Error communicating with API");
}
}
Imports the response from the API using ER:
protected void importAnswer()
{
// Fills the user input parameters
ERmodelDefinitionInputParametersAction obj = new ERmodelDefinitionInputParametersAction();
obj.addParameter('$RecId', tst_tableApi.RecId);
// Integration point, this is found in the import mapping if the check
// of the integration point of the destination was selected
str integrationPoint = 'ERTableDestination#TST_TableAPI';
// Create a runner for the import format mapping using the integration point
// and user input parameters
ERIModelMappingDestinationRun runner
= ERObjectsFactory::createMappingDestinationRunByImportFormatMappingId(
AssetParameters::find().TST_ERImport, integrationPoint).withParameter(obj);
runner.init();
// Runs the import without user interaction
if (runner.promptsContractedModelMapping())
{
ERModelDefinitionParameters parameters = runner.getParameters();
ERModelDefinitionParametersTraverser traverser = new ERModelDefinitionParametersTraverser(parameters);
while (traverser.moveNext())
{
ERIImportFormatDataSourceContract current = ERCast::asAny(traverser.current()) as ERIImportFormatDataSourceContract;
if (current)
{
System.IO.MemoryStream stream;
stream = new System.IO.MemoryStream(System.Text.Encoding::UTF8.GetBytes(answer));
stream.Seek(0u, System.IO.SeekOrigin::Begin);
current.parmInputDataStream(stream);
}
}
runner.runUnattended();
}
}
Saves the response to a docuRef:
protected void saveAnswerToDocRef()
{
DocuValue docuValue;
DocuRef drImpMessage;
// A new name based on the export name
nameImp = "Answer_" + nameExp;
// Convert the answer string to a byte array and then to a base64 string
System.Text.Encoding encoding = System.Text.Encoding::UTF8;
System.Byte[] bytes = encoding.GetBytes(answer);
System.String base64String = System.Convert::ToBase64String(bytes);
// Creates the docuValue table, where the attachment is stored and the
// DocuRef table, related to our record
ttsbegin;
docuValue.File = BinData::loadFromBase64(base64String);
docuValue.Name = nameImp;
docuValue.FileName = nameImp;
docuValue.FileType = "JSON";
docuValue.OriginalFileName = nameImp;
docuValue.insert();
drImpMessage.TypeId = DocuType::typeFile();
drImpMessage.Name = nameImp;
drImpMessage.Restriction = DocuRestriction::Internal;
drImpMessage.RefTableId = tst_tableApi.TableId;
drImpMessage.RefRecId = tst_tableApi.RecId;
drImpMessage.RefCompanyId = tst_tableApi.dataAreaId;
drImpMessage.ValueRecId = docuValue.RecId;
drImpMessage.insert();
ttscommit;
}
The entire code:
using Microsoft.Dynamics365.LocalizationFramework;
using Microsoft.Dynamics.ElectronicReporting.Instrumentation;
internal final class TST_RunAPI
{
TST_TableAPI tst_tableApi;
str nameExp;
str nameImp;
str expBody;
str answer;
static void main (Args _args)
{
TST_RunAPI tst_RunAPI = new TST_RunAPI();
// Select the record
tst_RunAPI.fillTable(_args);
// Execute ER to file attachment
tst_RunAPI.runEr();
// Gets attachment and saves it on memory
tst_RunAPI.docuRefToMemory();
// Sends the request to the API
tst_RunAPI.sendCom();
// Executes ER with the answer
tst_RunAPI.importAnswer();
// Saves a copy of the answer in memory
tst_RunAPI.saveAnswerToDocRef();
}
protected void fillTable(Args _args)
{
select firstonly * from tst_tableApi
where tst_tableApi.RecId == _args.record().RecId;
}
protected void runEr()
{
// Fills the user input parameters
ERModelDefinitionInputParametersAction obj = new ERModelDefinitionInputParametersAction();
obj.addParameter('model/$Id', tst_tableApi.Id);
// The Destination is a file
ERIFileDestination fileDestination = ERObjectsFactory::createFileDestinationAttachmentWithOtherDocuType(
tst_tableApi);
// Runs the ER, saving the filename to a global variable, with
// Destinations and Parameters
nameExp = ERObjectsFactory::createFormatMappingRunByFormatMappingId(
AssetParameters::find().TST_ERExport, "", false)
.withFileDestination(fileDestination)
.withParameter(obj)
.run();
}
protected void docuRefToMemory()
{
DocuRef drExpMessage;
System.IO.StreamReader streamReader;
// Finds the created document
select firstonly drExpMessage order by createdDateTime desc
where drExpMessage.RefCompanyId == tst_tableApi.dataAreaId
&& drExpMessage.RefRecId == tst_tableApi.RecId
&& drExpMessage.RefTableId == tst_tableApi.TableId
&& drExpMessage.Name == nameExp;
if (!drExpMessage)
{
throw error("API body not found");
}
// Read the content of the document attachment into memory
streamReader = new System.IO.StreamReader(
DocumentManagement::getAttachmentStream(drExpMessage));
expBody = streamReader.ReadToEnd();
streamReader.Close();
streamReader.Dispose();
}
protected void sendCom()
{
str headerKey;
str headerValue;
System.Net.WebResponse response;
// Retrieve the API endpoint, user, and password from parameters
str endpoint = AssetParameters::find().TST_ApiUrl;
str password = AssetParameters::find().TST_ApipassNameEdit(false, "");
str user = AssetParameters::find().TST_APIuser;
System.Text.Encoding encoding = System.Text.Encoding::UTF8;
// Encode the user and password for basic authentication
System.Byte[] bytes = encoding.GetBytes(user + ":" + password);
System.String base64 = System.Convert::ToBase64String(bytes);
// Authorization header
headerKey = "Authorization";
headerValue = "Basic " + base64;
// Create the request
System.Net.WebRequest request = System.Net.WebRequest::Create(endpoint);
request.Method = "POST";
request.ContentType = "application/json";
// Add the authorization header
System.Net.WebHeaderCollection headers = request.Headers;
headers.Add(headerKey, headerValue);
// Write the JSON body to the request stream
using (var streamWriter = new System.IO.StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(expBody);
}
try
{
// Get the response from the API
response = request.GetResponse();
// Read the response stream and store the answer
using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))
{
answer = reader.ReadToEnd();
}
}
catch
{
throw error("Error communicating with API");
}
}
protected void importAnswer()
{
// Fills the user input parameters
ERmodelDefinitionInputParametersAction obj = new ERmodelDefinitionInputParametersAction();
obj.addParameter('$RecId', tst_tableApi.RecId);
// Integration point, this is found in the import mapping if the check
// of the integration point of the destination was selected
str integrationPoint = 'ERTableDestination#TST_TableAPI';
// Create a runner for the import format mapping using the integration point
// and user input parameters
ERIModelMappingDestinationRun runner
= ERObjectsFactory::createMappingDestinationRunByImportFormatMappingId(
AssetParameters::find().TST_ERImport, integrationPoint).withParameter(obj);
runner.init();
// Runs the import without user interaction
if (runner.promptsContractedModelMapping())
{
ERModelDefinitionParameters parameters = runner.getParameters();
ERModelDefinitionParametersTraverser traverser = new ERModelDefinitionParametersTraverser(parameters);
while (traverser.moveNext())
{
ERIImportFormatDataSourceContract current = ERCast::asAny(traverser.current()) as ERIImportFormatDataSourceContract;
if (current)
{
System.IO.MemoryStream stream;
stream = new System.IO.MemoryStream(System.Text.Encoding::UTF8.GetBytes(answer));
stream.Seek(0u, System.IO.SeekOrigin::Begin);
current.parmInputDataStream(stream);
}
}
runner.runUnattended();
}
}
protected void saveAnswerToDocRef()
{
DocuValue docuValue;
DocuRef drImpMessage;
// A new name based on the export name
nameImp = "Answer_" + nameExp;
// Convert the answer string to a byte array and then to a base64 string
System.Text.Encoding encoding = System.Text.Encoding::UTF8;
System.Byte[] bytes = encoding.GetBytes(answer);
System.String base64String = System.Convert::ToBase64String(bytes);
// Creates the docuValue table, where the attachment is stored and the
// DocuRef table, related to our record
ttsbegin;
docuValue.File = BinData::loadFromBase64(base64String);
docuValue.Name = nameImp;
docuValue.FileName = nameImp;
docuValue.FileType = "JSON";
docuValue.OriginalFileName = nameImp;
docuValue.insert();
drImpMessage.TypeId = DocuType::typeFile();
drImpMessage.Name = nameImp;
drImpMessage.Restriction = DocuRestriction::Internal;
drImpMessage.RefTableId = tst_tableApi.TableId;
drImpMessage.RefRecId = tst_tableApi.RecId;
drImpMessage.RefCompanyId = tst_tableApi.dataAreaId;
drImpMessage.ValueRecId = docuValue.RecId;
drImpMessage.insert();
ttscommit;
}
}
It’s also possible to work in memory; this example will return the content of the ER as a string:
protected str runErToMemory()
{
ERFileDestinationMemory fileDestinationMemory = new ERFileDestinationMemory();
ERModelDefinitionInputParametersAction obj = new ERModelDefinitionInputParametersAction();
obj.addParameter('model/$Id', tst_tableApi.Id);
ERObjectsFactory::createFormatMappingRunByFormatMappingId(
AssetParameters::find().TST_ERExport, "", false)
.withFileDestination(fileDestinationMemory)
.withParameter(obj)
.run();
System.Byte[] byteER = fileDestinationMemory.GetByteArray();
System.Text.Encoding encoding = System.Text.Encoding::UTF8;
return encoding.GetString(byteER);
}
Now we can test our API call:
And the attachments:
Leave a Reply