Product_Order verifyOrder API fails when adding guest_disks - c#

I have a C# application in which I imported API methods using wsdl, as described in the Softlayer guidelines.
I'm editing virtual guests by passing a Container_Product_Order_Virtual_Guest_Upgrade structure to the Product_Order service.
Everything works great except for when adding item price IDs for guest_disks, scenario in which after about 6-7 seconds the following exception is thrown:
"The request was aborted: The connection was closed unexpectedly."
This happens with both verifyOrder and placeOrder methods.
I checked Virtual_Guest::getUpgradeItemPrices in order to make sure that the guest disk values are valid(even though passing invalid itempriceIds for the VM results in an specific error response, not in a generic exception such as the one described above).
I can't find any details in the documentation that could give me hints as why I can upgrade anything except guest_disks.
EDIT:
Stripped code as requested:
SoftLayer_Virtual_Guest[] _VMtoEditList = new SoftLayer_Virtual_Guest[1] { -- Vm instance details are retrieved from SL according to the passed VM ID; };
List<SoftLayer_Product_Item_Price> _itemPriceList = new List<SoftLayer_Product_Item_Price>();
foreach (-- collection of properties to be upgraded )
{
SoftLayer_Product_Item_Category _category = new SoftLayer_Product_Item_Category();
_category.categoryCode = -- retrieved from the collection on which I iterate (eg "guest_disk0", "ram", etc.);
SoftLayer_Product_Item_Price _itemPrice = new SoftLayer_Product_Item_Price();
_itemPrice.id = -- the item priceID for the current item;
_itemPrice.idSpecified = true;
_itemPrice.categories = new SoftLayer_Product_Item_Category[1] { _category };
_itemPriceList.Add(_itemPrice);
}
SoftLayer_Product_Item_Price[] _itemPricesArray = _itemPriceList.ToArray();
SoftLayer_Container_Product_Order_Property _property1 = new SoftLayer_Container_Product_Order_Property();
_property1.name = "NOTE_GENERAL";
_property1.value = -- order's description;
SoftLayer_Container_Product_Order_Property _property2 = new SoftLayer_Container_Product_Order_Property();
_property2.name = "MAINTENANCE_WINDOW";
_property2.value = "now";
// Build SoftLayer_Container_Product_Order_Property
SoftLayer_Container_Product_Order_Property[] properties = new SoftLayer_Container_Product_Order_Property[2] { _property1, _property2 };
-- create container
SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade _upgradeContainer = new SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade();
_upgradeContainer.virtualGuests = _VMtoEditList;
_upgradeContainer.prices = _itemPricesArray;
_upgradeContainer.properties = properties;
_upgradeContainer.packageId = 46;
_upgradeContainer.packageIdSpecified = true;
SoftLayer_Product_OrderService service = new SoftLayer_Product_OrderService();
-- authentication structure is created here
SoftLayer_Container_Product_Order _verifiedOrder = service.verifyOrder(_upgradeContainer);
service.placeOrder(_verifiedOrder, false);

Here a have an example to upgrade which works see below. I see that in your code you are adding the packageId which is not required, removed and try again.
Also when you are creating the web references try using the last version of the api in the WSDL url (v3.1)
e.g. https://api.softlayer.com/soap/v3.1/SoftLayer_Hardware_Server?wsdl
//-----------------------------------------------------------------------
// <copyright file="PlaceOrderUpgrade.cs" company="Softlayer">
// SoftLayer Technologies, Inc.
// </copyright>
// <license>
// http://sldn.softlayer.com/article/License
// </license>
//-----------------------------------------------------------------------
namespace VirtualGuests
{
using System;
using System.Collections.Generic;
class PlaceOrderUpgrade
{
/// <summary>
/// Order an upgrade for Virtual Guest
/// This script orders an upgrade for Virtual Guest, in this case we will upgrade the ram for a Virtual Guest,
/// It uses SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade container and SoftLayer_Product_Order::placeOrder
/// method for it.
/// For more information, review the following links:
/// </summary>
/// <manualPages>
/// http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/placeOrder
/// http://sldn.softlayer.com/reference/datatypes/SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade/
/// http://sldn.softlayer.com/reference/services/SoftLayer_Product_Item_Price/
/// </manualPages>
static void Main(String [] args)
{
// You SoftLayer username
string username = "set me";
// Your SoftLayer API key.
string apiKey = "set me";
// Define the virtual guest id to place an upgrade
int virtualId = 13115425;
// Creating a connection to the SoftLayer_Product_Order API service and
// bind our API username and key to it.
authenticate authenticate = new authenticate();
authenticate.username = username;
authenticate.apiKey = apiKey;
SoftLayer_Product_OrderService orderService = new SoftLayer_Product_OrderService();
orderService.authenticateValue = authenticate;
// Build a SoftLayer_Product_Item_Price objects with the ids from prices that you want to order.
// You can retrieve them with SoftLayer_Product_Package::getItemPrices method
int[] prices = {
1645
};
List<SoftLayer_Product_Item_Price> pricesList = new List<SoftLayer_Product_Item_Price>();
foreach (var price in prices)
{
SoftLayer_Product_Item_Price newPrice = new SoftLayer_Product_Item_Price();
newPrice.id = price;
newPrice.idSpecified = true;
pricesList.Add(newPrice);
}
// Build SoftLayer_Container_Product_Order_Property object for the upgrade
SoftLayer_Container_Product_Order_Property property = new SoftLayer_Container_Product_Order_Property();
property.name = "MAINTENANCE_WINDOW";
property.value = "NOW";
List<SoftLayer_Container_Product_Order_Property> propertyList = new List<SoftLayer_Container_Product_Order_Property>();
propertyList.Add(property);
// Build SoftLayer_Virtual_Guest object with the id from vsi that you wish to place an upgrade
SoftLayer_Virtual_Guest virtualGuest = new SoftLayer_Virtual_Guest();
virtualGuest.id = virtualId;
virtualGuest.idSpecified = true;
List<SoftLayer_Virtual_Guest> virtualGuests = new List<SoftLayer_Virtual_Guest>();
virtualGuests.Add(virtualGuest);
// Build SoftLayer_Container_Product_Order object containing the information for the upgrade
//SoftLayer_Container_Product_Order orderTemplate = new SoftLayer_Container_Product_Order();
SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade orderTemplate = new SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade();
orderTemplate.containerIdentifier = "SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade";
orderTemplate.prices = pricesList.ToArray();
orderTemplate.properties = propertyList.ToArray();
orderTemplate.virtualGuests = virtualGuests.ToArray();
try
{
// We will check the template for errors, we will use the verifyOrder() method for this.
// Replace it with placeOrder() method when you are ready to order.
SoftLayer_Container_Product_Order verifiedOrder = orderService.verifyOrder(orderTemplate);
Console.WriteLine("Order Verified!");
}
catch (Exception e)
{
Console.WriteLine("Unable to place an upgrade for Virtual Guest: " + e.Message);
}
}
}
}
Let me know if this helps
Regards

Related

Download/Read Google Ad Manager Reports using Google Ad Manager Api in C# console Application

I am trying to read/download some of the reports i created in Google Ad Manager account using Google Ad Manager Api https://developers.google.com/ad-manager/api/reporting
But couldn't get the results
Also tried NetworkService and InventoryService services of the api to grab some of the data from my google ad manager account which is working correctly as follows:
using Google.Api.Ads.AdManager.Lib;
using Google.Api.Ads.AdManager.Util.v201911;
using Google.Api.Ads.AdManager.v201911;
using Google.Api.Ads.Common.Util.Reports;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Google.Api.Ads.AdManager.Examples.CSharp.v201911
{
/// This example gets all ad units.
public class GetAllAdUnits : SampleBase
{
public string orderId;
/// Returns a description about the code example.
public string Description => "This example gets all ad units.";
/// Main method, to run this code example as a standalone application.
public static void Main()
{
GetAllAdUnits codeExample = new GetAllAdUnits();
Console.WriteLine(codeExample.Description);
try
{
codeExample.Run(new AdManagerUser());
}
catch (Exception e)
{
Console.WriteLine("Failed to get ad units. Exception says \"{0}\"", e.Message);
}
}
private string filePath = "/Users/fazeem/";
/// Run the code example.
public void Run(AdManagerUser user)
{
using (NetworkService networkService = user.GetService<NetworkService>())
{
var network = networkService.getCurrentNetwork();
Console.WriteLine(
$"Current network has the network code {network.networkCode} and " +
$"display name \"{network.displayName}\" and Currency {network.currencyCode}."
);
}
using (InventoryService inventoryService = user.GetService<InventoryService>())
{
// Create a statement to select ad units.
int pageSize = StatementBuilder.SUGGESTED_PAGE_LIMIT;
StatementBuilder statementBuilder1 =
new StatementBuilder().OrderBy("id ASC").Limit(pageSize);
// Retrieve a small amount of ad units at a time, paging through until all
// ad units have been retrieved.
int totalResultSetSize = 0;
do
{
AdUnitPage page =
inventoryService.getAdUnitsByStatement(statementBuilder1.ToStatement());
// Print out some information for each ad unit.
if (page.results != null)
{
totalResultSetSize = page.totalResultSetSize;
int i = page.startIndex;
foreach (AdUnit adUnit in page.results)
{
Console.WriteLine(
"{0}) Ad unit with ID \"{1}\" and name \"{2}\" was found.", i++,
adUnit.id, adUnit.name);
}
}
statementBuilder1.IncreaseOffsetBy(pageSize);
} while (statementBuilder1.GetOffset() < totalResultSetSize);
Console.WriteLine("Number of results found: {0}", totalResultSetSize);
}
/////////////////////////////////////////////////////////////////////
// Create report job.
/////////////////////////////////////////////////////////////////////
using (ReportService reportService = user.GetService<ReportService>())
{
ReportJob reportJob = new ReportJob();
reportJob.reportQuery = new ReportQuery();
reportJob.reportQuery.dimensions = new Dimension[]
{
Dimension.ORDER_ID,
Dimension.ORDER_NAME
};
reportJob.reportQuery.dimensionAttributes = new DimensionAttribute[]
{
DimensionAttribute.ORDER_TRAFFICKER,
DimensionAttribute.ORDER_START_DATE_TIME,
DimensionAttribute.ORDER_END_DATE_TIME
};
reportJob.reportQuery.columns = new Column[]
{
Column.AD_SERVER_IMPRESSIONS,
Column.AD_SERVER_CLICKS,
//Column.TOTAL_ACTIVE_VIEW_MEASURABLE_IMPRESSIONS,
//Column.AD_SERVER_CPM_AND_CPC_REVENUE,
//Column.AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM
};
// Set a custom date range for the last 8 days
reportJob.reportQuery.dateRangeType = DateRangeType.CUSTOM_DATE;
System.DateTime endDateTime = System.DateTime.Now;
reportJob.reportQuery.startDate = DateTimeUtilities
.FromDateTime(endDateTime.AddDays(-8), "Australia/Sydney").date;
reportJob.reportQuery.endDate = DateTimeUtilities
.FromDateTime(endDateTime, "Australia/Sydney").date;
// Create statement object to filter for an order.
StatementBuilder statementBuilder = new StatementBuilder().Where("ORDER_ID = :id")
.AddValue("id", orderId);
reportJob.reportQuery.statement = statementBuilder.ToStatement();
// Run report job.
reportJob = reportService.runReportJob(reportJob);
// Download the report
ReportUtilities reportUtilities =
new ReportUtilities(new ReportService(), reportJob.id);
// Set download options.
ReportDownloadOptions options = new ReportDownloadOptions();
options.exportFormat = ExportFormat.CSV_DUMP;
options.useGzipCompression = true;
reportUtilities.reportDownloadOptions = options;
// Download the report.
using (ReportResponse reportResponse = reportUtilities.GetResponse())
{
reportResponse.Save(filePath);
}
Console.WriteLine("Report saved to \"{0}\".", filePath);
}
}
}
}
But the reportService section of the code(which is for downloading/reading reports) is throwing this exception: "Faied to get ad units. Exception says "AdManagerApiException: Exception of type 'Google.api.ads.adManager.lib.adManagerApiException' was thrown"
Any help/Suggestion will be highly appreciated. TIA
P.S I was initially looking for directly reading some of the reports from Ad Manager account but couldn't find any detailed documentation about it so end up downloadig then reading it..So If any one have correct way of directly reading reports from ad manager account, Please share that as well.

ObjectAttributes instance returned from the OPC .NET server is incorrectly identifying the IsCollectingHistory property as false

I am using the Xi interface to retrieve data from an OPC .NET server. The issue that I am having though is that the server seems to be incorrectly identifying a parameter as not being historized.
Even though all the information from DeltaV indicates that the corresponding parameter for the ObjectAttributes object returned from the server should indicate that it is collecting history, the IsCollectingHistory property actually indicates that it is false.
History collection is enabled:
The parameter in question is in the history collection:
I won't include the screenshot but I can also open the historical trend for that parameter. But as you can see below, when I inspect the retrieved object while debugging, it says that it is not being historized.
Here is some of the code that I am using:
FindCriteria criteria = createCriteria(path, false);
List<Parameter> parameters = new List<Parameter>();
IEnumerable<ObjectAttributes> enumerableObject;
int i = 0;
try
{
enumerableObject = iContext.FindObjects(criteria, 50);
}
catch (System.ServiceModel.FaultException)
{
//This error is thrown when no data is returned.
return null;
}
A few lines down, I then do some object initialization for my Parameter object, assigning it the properteries from the object that was received from the server. It is not shown below but I then add my Parameter object to a collection if it is being historized. It never gets added to the collection because the IsCollectingHistory property is always false.
enumerableObject = enumerableObject.Skip(1);
foreach (ObjectAttributes oa in enumerableObject)
{
Parameter _parameter = new Parameter
{
IsHistorized = oa.IsCollectingHistory,
IsLeaf = oa.IsLeaf
};
//...
Any ideas on where I am going wrong?
Edit:
After trying MotteAndBailey's answer, an error is thrown at the call to AddNewDataObjectToDataJournalList. The message associated with it is "The OPC HDA Create Browse failed".
Below is a screenshot of the error in a message box when using HDAprobe:
Some info on properties in OPC.NET -
The Xi server wraps the OPCDA and OPCHDA servers. The item properties (attributes) available on each server and the means of accessing them using Classic (DCOM) OPC vary considerably.
OPCDA
The OPCDA server provides a method for determining item properties:
IOPCItemProperties::GetItemProperties()
This call provides the client with a way to read all an item’s attribute values using the item ID (string path for the item in the Server’s address space) and propertyID. The Xi server uses this call when performing a FindObjects() call. FindObjects() returns all the properties exposed by the OPCDA server for an item.
OPCHDA
The OPCHDA server has a method for determining item properties, but it requires the item handle not the ItemID/path:
IOPCHDA_SyncRead::ReadAttribute()
As a result, the FindObjects() call for an OPCHDA server through Xi only returns the item ID property. The other attributes are set to defaults. To determine what the actual values of the other properties are a user must add the item to a list and call ReadAttribute() on the specific property they wish to see.
In summary, the OPCDA server works pretty much like you would expect and returns the object properties in a single method call; however, the OPCHDA server requires an additional step to get all the object properties.
The sample code will produce an Xi Journal list with only the on-scan history items.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xi.Client.Base.API;
using Xi.Client.Base;
using Xi.Contracts;
using Xi.Contracts.Data;
using Xi.Contracts.Constants;
using System.ServiceModel.Description;
using Xi.Client.CommonDialogs;
using System.Runtime.Serialization;
namespace ConsoleFindObjectsHDA
{
public class DotNetSupport
{
IXiEndpointDiscovery iEndpointDiscovery;
IXiContext iContext;
IXiEndpointBase readEndpoint;
ServiceEndpoint RMSvcEndpt;
//the list of items the user is trying to read
IXiDataJournalList iDataJournalList;
public void GetSomeData()
{
//get a connection to an OPC.NET server
if (Connect())
{
//we have to have a list to add a tag to and hold returned datasets
if (CreateJournalList())
{
//now use the list to add items and read their attributes - only "good" ones will be left on the list
ListAllHDAItemsOnScan();
if (iDataJournalList.Count() > 0)
{
//at this point we <should> have a DataJournalList containing only the HDA items on scan
//we can use the normal data read methods to get history for the items if we wish
// <do some history thing here>
}
else
{
Console.WriteLine("\nThere were no points on-scan in the historian");
}
Console.WriteLine("\nPress <return> to exit program");
Console.ReadLine();
}
////clean up if we have open connections/contexts
Cleanup();
}
}
//we will use FindObjects to browse all the leaves in the HDA server, then add them one-by-one to a datalist
//when we query their on-scan property and it is true we leave them on the list
//...if not, we remove them (giving us a list of the good HDA points)
void ListAllHDAItemsOnScan()
{
FindCriteria criteria = GetLeafCriteria();
IEnumerable<ObjectAttributes> enumerableObject;
try
{
//ask the server for a list of leaves...up to 50 max returned in this call
enumerableObject = iContext.FindObjects(criteria, 50);
//for each string itemID: add it to the list, read the attribute, and remove it from the list if not on-scan
foreach (ObjectAttributes oa in enumerableObject)
{
//we do not have to commit this because we have indicated the operation is NOT prep-only
Console.WriteLine("Adding OPCHDA item {0}.", oa.InstanceId.LocalId);
IXiHistoricalDataObject ixObject = iDataJournalList.AddNewDataObjectToDataJournalList(oa.InstanceId, false);
//we are getting the CURRENT (from NOW -to- NOW) item status
FilterCriterion fc1 = GetFilterCriteriaDateTime(DateTime.Now);
//tell the server what property (attribute) we want to read
List<TypeId> lstp = new List<TypeId>();
TypeId typeit = new TypeId("", "", DVServerAttributes.DELTAV_DVCH_ON_SCAN.ToString());
lstp.Add(typeit);
//read the property from the server
iDataJournalList.ReadJournalDataProperties(fc1, fc1, ixObject, lstp);
//find the current item and check it for "on-scan"
if (ixObject != null)
{
if (ixObject.PropertyValues.First().PropertyValues.UintValues.First() == 1)
{
Console.WriteLine("OPCHDA item {0} is on-scan.\n", oa.InstanceId.LocalId);
}
else
{
if (ixObject.PrepForRemove())
{
Console.WriteLine("OPCHDA item {0} is not on-scan. Removing item.\n", oa.InstanceId.LocalId);
iDataJournalList.CommitRemoveableElements();
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception in FindObjects(). The exception is:{0}\n", ex.Message);
}
}
//create a filtercriterion for a specific date time - this is an EQUAL (not > or <) comparison operator
public FilterCriterion GetFilterCriteriaDateTime(DateTime dtChosenTime)
{
//simple timestamp filter which is used by the read call
FilterCriterion filterCriterion = null;
// this is a timestamp
string filterOperand = FilterOperandNames.Timestamp;
//make the given time with UTC/Local set to local time just to be sure
DateTime dtTmp1 = DateTime.SpecifyKind(dtChosenTime, DateTimeKind.Local);
object comparisonValue = dtTmp1;
//timestamp equal to this one
uint oper = FilterOperator.Equal;
//create the filter
filterCriterion = new FilterCriterion()
{
OperandName = filterOperand,
Operator = oper,
ComparisonValue = comparisonValue,
};
return filterCriterion;
}
//create a filtercriterion for leaves (OPCHDA items)
public FilterCriterion GetLeafFilterCriterion()
{
//simple filter for leaves
FilterCriterion filterCriterion = null;
// what this criterion applies to
string filterOperand = FilterOperandNames.BranchOrLeaf;
//Must equal "LEAF" to match
uint oper = FilterOperator.Equal;
//create the filter
filterCriterion = new FilterCriterion()
{
OperandName = filterOperand,
Operator = oper,
ComparisonValue = "LEAF",
};
return filterCriterion;
}
//set up the FindCriteria search of the server
public FindCriteria GetLeafCriteria()
{
FindCriteria findCriteria = null;
findCriteria = new FindCriteria();
//our browse starts at the root - NULL means "continue browsing from where you are"
findCriteria.StartingPath = new ObjectPath("//", "HDA");
//a list of OR-ed filter criteria (we have only one)
ORedFilters orthefilters = new ORedFilters();
//the FilterCriteria list (there is only one criterion)
orthefilters.FilterCriteria = new List<FilterCriterion>();
orthefilters.FilterCriteria.Add(GetLeafFilterCriterion()); //we want leaves
//add our OR-ed filter to the filterset filters list (whew!)
findCriteria.FilterSet = new FilterSet();
findCriteria.FilterSet.Filters = new List<ORedFilters>();
findCriteria.FilterSet.Filters.Add(orthefilters);
return findCriteria;
}
//connect to the OPC.NET server and get a read endpoint
public bool Connect()
{
//set this to point to your OPC.Net server
string serverUrl = "http://localhost:58080/XiServices/ServerDiscovery";
bool bReturnVal = false;
try
{
Console.WriteLine("Getting Endpoint Discovery from server:\n{0}\n", serverUrl);
//This class is used to locate a server and obtain its list of ServiceEndpoints.
iEndpointDiscovery = new XiEndpointDiscovery(serverUrl) as IXiEndpointDiscovery;
//we have the server...now check for endpoints
//there should always be TCP endpoints for a DeltaV OPC.NET server so we do not search HTTP and Named Pipes to find one
//and we do not consider choosing the fastest option between the three (TCP/HTTP/NamedPipes). We just use the TCP/IP one.
// GetServiceEndpointsByBinding searches the list of endpoints on the XiEndpointDiscovery connection with the specified contractType and binding type.
// We use the ResourceManagement endpoint to find the the other open endpoints on the server (some might be disabled)
IEnumerable<ServiceEndpoint> resourceEndpoints = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IResourceManagement).Name, typeof(System.ServiceModel.NetTcpBinding));
//use the first (probably only) resource endpoint for TCP/IP to open a context between client and server
if ((resourceEndpoints != null) && (resourceEndpoints.Count() > 0))
{
var serviceEndpoints = resourceEndpoints as IList<ServiceEndpoint> ?? resourceEndpoints.ToList();
//pick the first RM endpoint we found
RMSvcEndpt = ((IList<ServiceEndpoint>)serviceEndpoints).First();
//Open the Context using the RM endpoint and some other values including timeout, what we want to read (HDA), and the GUID for this context
Console.WriteLine("Opening Client Context with Initiate\n");
iContext = XiContext.Initiate(RMSvcEndpt,
iEndpointDiscovery.ServerEntry,
300000,
(uint)ContextOptions.EnableJournalDataAccess, //HDA
(uint)System.Threading.Thread.CurrentThread.CurrentCulture.LCID,
Guid.NewGuid().ToString());
if (iContext != null)
{
//find a read endpoint using the XiEndpointDiscovery connection
IEnumerable<ServiceEndpoint> readseps = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IRead).Name, RMSvcEndpt.Binding.GetType());
//if we found at least one read endpoint, connect the context to it
readEndpoint = null;
if (readseps != null)
{
Console.WriteLine("Adding Read endpoint to Context\n");
ServiceEndpoint sep = readseps.ElementAt<ServiceEndpoint>(0);
readEndpoint = iContext.OpenEndpoint(sep, 30000, new TimeSpan(5000));
if (readEndpoint != null)
{
bReturnVal = true; //everything went OK
}
else
{
Console.WriteLine("Unable to add Read endpoint to Context\n");
bReturnVal = false; //failed
}
}
}
else
{
Console.WriteLine("Unable to open Client Context\n");
bReturnVal = false;
}
}
}
catch (Exception)
{
bReturnVal = false;
}
return (bReturnVal);
}
public bool CreateJournalList()
{
bool retval = false;
try
{
//create a new list of HDA objects for this read
// update buffer
// rate rate filterset(not used here)
iDataJournalList = iContext.NewDataJournalList(1000, 1000, null);
if (iDataJournalList != null)
{
//we need to add the list to a read endpoint to give it data access
iDataJournalList.AddListToEndpoint(readEndpoint);
//enable the list so we can connect the items we add to it and read data
iDataJournalList.EnableListUpdating(true);
retval = true;
}
}
catch (Exception)
{
retval = false;
}
return retval;
}
public void Cleanup()
{
if (iContext != null)
{
iContext.Dispose();
}
}
} //class DotNetSupport
}
namespace ConsoleFindObjectsHDA
{
public class DVServerAttributes
{
//some DeltaV-specific OPCHDA attributes
public static uint DELTAV_DESC = 2147483650;
public static uint DELTAV_ENG_UNITS = 2147483651;
public static uint DELTAV_EU100 = 2147483666;
public static uint DELTAV_EU0 = 2147483667;
public static uint DELTAV_DVCH_LAST_DOWNLOAD = 2147483682;
public static uint DELTAV_DVCH_ON_SCAN = 2147483683;
public static uint DELTAV_NAMED_SET = 2147483698;
}
}

Open new mail interaction window in Genesys Interaction Workspace

I got the task to show the "new outbound mail" dialog in Genesys IWS upon an external event from a webservice. I put my IWS extension in place and it loads and can provide a webservice interface.
My main problem now is that I don't understand how I can open the interactions window from my code. I tried to get an instance of it by using:
IInteractionsWindow interactionsView = Container.Resolve<IInteractionsWindow>();
interactionsView.Create();
interactionsView.ShowView();
This actually works only halfway, as I get a new window, but it's completely empty. Do I need to load every single region on its own? Is there a simpler way to achieve my goals in a fully integrated way?
UPDATE: I have now tried to achieve things using the Platform SDK although I have no idea if this really helps me in showing the "new mail" window to the agent. I tried with the following code:
interactionServerProtocol = new InteractionServerProtocol(new Endpoint(new Uri("tcp://ixnServer:7319")));
interactionServerProtocol.ClientName = "CRMIntegrationModule";
interactionServerProtocol.ClientType = InteractionClient.AgentApplication;
contactServerProtocol = new UniversalContactServerProtocol(new Endpoint(new Uri("tcp://ucsServer:5130")));
contactServerProtocol.ClientName = "CRMIntegrationModule";
interactionServerProtocol.Open();
contactServerProtocol.Open();
RequestSubmit request = RequestSubmit.Create();
request.InteractionType = "Outbound";
request.InteractionSubtype = "OutboundNew";
request.MediaType = "email";
request.Queue = "default";
EventAck response = interactionServerProtocol.Request(request) as EventAck;
if (response != null)
{
string id = Convert.ToString(response.Extension["InteractionId"]);
RequestInsertInteraction insertRequest = RequestInsertInteraction.Create();
insertRequest.InteractionAttributes = new InteractionAttributes
{
Id = id,
MediaTypeId = "email",
TypeId = "Outbound",
SubtypeId = "OutboundNew",
TenantId = 101,
Status = new NullableStatuses(Statuses.Pending),
Subject = "Testmail",
EntityTypeId = new NullableEntityTypes(EntityTypes.EmailOut)
};
insertRequest.EntityAttributes = new EmailOutEntityAttributes()
{
FromAddress = "dummy#gmx.net",
ToAddresses = "dummy#gmx.net",
};
insertRequest.InteractionContent = new InteractionContent()
{
Text = "This is the e-mail body."
};
contactServerProtocol.Send(insertRequest);
RequestPlaceInQueue queueRequest = RequestPlaceInQueue.Create();
queueRequest.InteractionId = id;
queueRequest.Queue = "default";
interactionServerProtocol.Send(queueRequest);
}
interactionServerProtocol.Close();
contactServerProtocol.Close();
The bad thing is the response from the interaction server which is:
attr_ref_id [int] = 2
attr_error_code [int] = 34
attr_error_desc [str] = "Client is not logged in"
I think this could be related to not being logged in correctly somehow but I have not a single clue how to achieve this. Any help?
UPDATE 2 I could send an e-mail using the Platform SDK, but this is not what I really want. The initial question is still valid, as I just want to invoke the interactions window and that's it. The other stuff is up to the user. Is it possible?
You need to use PlatformSDK. add Genesyslab.platform.webmedia.protocols.dll
After that you can use *webmedia.tserver.request, under that tab there is requestWeb or sth.
channelService.RegisterEvents(tServerChannel, new Action<Genesyslab.Enterprise.Model.Channel.IClientChannel>
In your main module(have Initialize method), need to registerevent like that. You can put a button or sth, then you can trigger event or you can use commandchain after logon, is up to you.
Good luck.
I made use of the given command chains:
public IObjectContainer Container { get; set; }
public void NewItem(string contactId, string emailAddress)
{
IAgent agent = Container.Resolve<IAgent>();
IRoutingBasedManager routingManager = Container.Resolve<IRoutingBasedManager>();
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("CommandParameter", agent.FirstMediaEmail);
parameters.Add("TargetId", contactId);
parameters.Add("OwnerId", agent.ConfPerson.EmailAddress);
parameters.Add("Destination", emailAddress);
parameters.Add("RecentIndex", contactId);
bool todo = routingManager.RequestToDo("CreateNewOutboundEmail", RoutingBasedTarget.Contact, parameters);
if (todo && parameters.ContainsKey("RoutingBaseCommand"))
{
IChainOfCommand chainOfCommand = parameters["RoutingBaseCommand"] as IChainOfCommand;
if (chainOfCommand != null)
{
chainOfCommand.Execute(parameters["RoutingBaseCommandParameters"]);
}
}
}

NetSuite custom record search through suiteTalk using C#

We are having an issue with searching a custom record through SuiteTalk. Below is a sample of what we are calling. The issue we are having is in trying to set up the search using the internalId of the record. The issue here lies in in our initial development account the internal id of this custom record is 482 but when we deployed it through the our bundle the record was assigned with the internal Id of 314. It would stand to reason that this internal id is not static in a site per site install so we wondered what property to set up to reference the custom record. When we made the record we assigned its “scriptId’ to be 'customrecord_myCustomRecord' but through suitetalk we do not have a “scriptId”. What is the best way for us to allow for this code to work in all environments and not a specific one? And if so, could you give an example of how it might be used.
Code (C#) that we are attempting to make the call from. We are using the 2013.2 endpoints at this time.
private SearchResult NetSuite_getPackageContentsCustomRecord(string sParentRef)
{
List<object> PackageSearchResults = new List<object>();
CustomRecord custRec = new CustomRecord();
CustomRecordSearch customRecordSearch = new CustomRecordSearch();
SearchMultiSelectCustomField searchFilter1 = new SearchMultiSelectCustomField();
searchFilter1.internalId = "customrecord_myCustomRecord_sublist";
searchFilter1.#operator = SearchMultiSelectFieldOperator.anyOf;
searchFilter1.operatorSpecified = true;
ListOrRecordRef lRecordRef = new ListOrRecordRef();
lRecordRef.internalId = sParentRef;
searchFilter1.searchValue = new ListOrRecordRef[] { lRecordRef };
CustomRecordSearchBasic customRecordBasic = new CustomRecordSearchBasic();
customRecordBasic.recType = new RecordRef();
customRecordBasic.recType.internalId = "314"; // "482"; //THIS LINE IS GIVING US THE TROUBLE
//customRecordBasic.recType.name = "customrecord_myCustomRecord";
customRecordBasic.customFieldList = new SearchCustomField[] { searchFilter1 };
customRecordSearch.basic = customRecordBasic;
// Search for the customer entity
SearchResult results = _service.search(customRecordSearch);
return results;
}
I searched all over for a solution to avoid hardcoding internalId's. Even NetSuite support failed to give me a solution. Finally I stumbled upon a solution in NetSuite's knowledgebase, getCustomizationId.
This returns the internalId, scriptId and name for all customRecord's (or customRecordType's in NetSuite terms! Which is what made it hard to find.)
public string GetCustomizationId(string scriptId)
{
// Perform getCustomizationId on custom record type
CustomizationType ct = new CustomizationType();
ct.getCustomizationTypeSpecified = true;
ct.getCustomizationType = GetCustomizationType.customRecordType;
// Retrieve active custom record type IDs. The includeInactives param is set to false.
GetCustomizationIdResult getCustIdResult = _service.getCustomizationId(ct, false);
foreach (var customizationRef in getCustIdResult.customizationRefList)
{
if (customizationRef.scriptId == scriptId) return customizationRef.internalId;
}
return null;
}
you can make the internalid as an external property so that you can change it according to environment.
The internalId will be changed only when you install first time into an environment. when you deploy it into that environment, the internalid will not change with the future deployments unless you choose Add/Rename option during deployment.

QAS Pro. Problems with certain addresses

I work for a call centre that has been using QAS Pro for near 2 years now. We use a resource DLL inside access databases to talk to the internally hosted QAS server. Its only use is to gather address details based on postcode. So the first function gets a list of address from that postcode, inserts them into a combo box in access. After the operator can select the appropriate address and it inserts it into the correct fields.
This was written by a developer who is no longer with us. Its my job to fix the code. With some testing I've been able to verify it is the c# code we use and not the addresses. As the test harness works fine.
The resource DLL uses the c# test code from QAS with an extra file for a few functions. I'm new to c# and have never worked on something like this before. Any help is appreciated.
This is the code written by an old colleague.
namespace MangoQAS
{
using com.qas.proweb;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[ComVisible(true)]
public class QAS
{
public QAS()
{
QuickAddress address = new QuickAddress("http://10.10.15.7:2021") {
Engine = QuickAddress.EngineTypes.Singleline,
Flatten = true
};
this.searchService = address;
}
private string GetMoniker(string p)
{
return this.searchService.Search("GBR", p, PromptSet.Types.Default, "Database layout").Picklist.Items[0].Moniker;
}
public string[] RefinePostcode(string p)
{
string moniker = this.GetMoniker(p);
FormattedAddress formattedAddress = this.searchService.GetFormattedAddress(moniker, "Database Layout");
return new string[] { formattedAddress.AddressLines[0].Line, formattedAddress.AddressLines[1].Line, formattedAddress.AddressLines[2].Line, formattedAddress.AddressLines[3].Line, formattedAddress.AddressLines[4].Line, formattedAddress.AddressLines[5].Line, formattedAddress.AddressLines[6].Line };
}
public string[] SearchPostcodes(string postCode)
{
SearchResult result = this.searchService.Search("GBR", postCode, PromptSet.Types.OneLine, "Database layout");
string[] strArray = new string[result.Picklist.Length];
for (int i = 0; i < result.Picklist.Length; i++)
{
strArray[i] = result.Picklist.Items[i].Text;
}
return strArray;
}
private QuickAddress searchService { get; set; }
}
}
SearchPostcodes - Brings back a list of addresses based on the postcode.
RefinePostcode - takes the address line and sends back a formatted address.
The problem seems to be with RefinePostcode. I have tried formatting the address string as my first thought was it didn't like forward slashes. This did not work.
For example, Using the Postcode: PA169AE.
This gives me: 0/1 15 Brachelston Street, GREENOCK, Renfrewshire, at the top of the combobox.
If I click on this address it will send back: 1 Crossgates, Greenock Road, PA7 5JU.
Changing everything including the postcode I entered.
I believe the problem is with RefinePostcode or GetMoniker. The 2 blocks below are from the sample code and unchanged, but may be required to diagnose.
public FormattedAddress GetFormattedAddress(string sMoniker, string sLayout)
{
Debug.Assert((sMoniker != null) && (sLayout != null));
QAGetAddress qAGetAddress = new QAGetAddress {
Layout = sLayout,
Moniker = sMoniker,
QAConfig = this.m_Config,
Language = this.m_LanguageString
};
FormattedAddress address2 = null;
try
{
address2 = new FormattedAddress(this.SearchService.DoGetAddress(qAGetAddress).QAAddress);
}
catch (Exception exception)
{
this.MapException(exception);
}
return address2;
}
public SearchResult Search(string sDataID, string sSearch, PromptSet.Types tPromptSet, string sLayout)
{
Debug.Assert(sDataID != null);
Debug.Assert(sSearch != null);
QASearch qASearch = new QASearch {
Country = sDataID,
Engine = this.m_Engine
};
qASearch.Engine.PromptSet = (PromptSetType) tPromptSet;
qASearch.Engine.PromptSetSpecified = true;
qASearch.Layout = sLayout;
qASearch.QAConfig = this.m_Config;
qASearch.Search = sSearch;
qASearch.Language = this.m_LanguageString;
SearchResult result = null;
try
{
result = new SearchResult(this.SearchService.DoSearch(qASearch));
}
catch (Exception exception)
{
this.MapException(exception);
}
return result;
}
I've thoroughly searched Google and cant seem to find any reason this would happen. I can post more code samples if required.
did you figure this out?
From the looks of it, I think the problem you have here is the context of the search. Both the QAS server, and QuickAddress class are stateless - they have no history of previous searches.
Because of this at the moment there is nothing linking your first search for postcodes, and your second search on the address line. So, when you call RefinePostcode you are not refining at all. You are instead performing a brand new search UK wide on "0/1 15 Brachelston Street, GREENOCK, Renfrewshire". Whilst QAS pro can handle this, this search generates a few possibilities so the result you are after is not the first one returned.
There are a few possibilities here to improve your workflow. To avoid making any changes to your VBA code and just limit the changes to the sample above you could introduce state to this class and change the workflow so that you are passing in the postcode with your search. Similar to the following:
public class QAS
{
public QAS()
{
// Create a new soap proxy that can talk to QAS Pro Web
QuickAddress address = new QuickAddress("http://10.10.15.7:2021")
{
Engine = QuickAddress.EngineTypes.Singleline,
Flatten = true
};
this.searchService = address;
}
/// <summary>
/// For the supplied search, get the moniker which can then be used to format the address.
/// </summary>
private string GetMoniker(string p)
{
return this.searchService.Search("GBR", p, PromptSet.Types.Default, "Database layout").Picklist.Items[0].Moniker;
}
/// <summary>
/// Return a formatted address from the supplied search.
/// </summary>
public string[] RefinePostcode(string p)
{
// Append the postcode to our address to speed up and improve searches.
string search = p + "," + Postcode;
SearchResult result = this.searchService.Search("GBR",
postCode,
PromptSet.Types.OneLine,
"Database layout");
if ( result.Picklist.Items.Length > 0 )
{
}
else
{
// What is your workflow if an address is not found?
}
string moniker = this.GetMoniker(search);
FormattedAddress formattedAddress = this.searchService.GetFormattedAddress(moniker, "Database Layout");
return new string[] { formattedAddress.AddressLines[0].Line, formattedAddress.AddressLines[1].Line, formattedAddress.AddressLines[2].Line, formattedAddress.AddressLines[3].Line, formattedAddress.AddressLines[4].Line, formattedAddress.AddressLines[5].Line, formattedAddress.AddressLines[6].Line };
}
/// <summary>
/// Once a postcode is captured by the operator, return a list of potential addresses.
/// </summary>
public string[] SearchPostcodes(string postCode)
{
Postcode = postcode;
SearchResult result = this.searchService.Search("GBR",
postCode,
PromptSet.Types.OneLine,
"Database layout");
string[] strArray = new string[result.Picklist.Length];
for (int i = 0; i < result.Picklist.Length; i++)
{
strArray[i] = result.Picklist.Items[i].Text;
}
return strArray;
}
private QuickAddress searchService { get; set; }
/// <summary>
/// Gets or sets the postcode from the initial search.
/// </summary>
private string Postcode
{
get;
set;
}
}
If you have the time though, it would be better to go a little further and properly fix your workflow. Context between searches in QAS Pro Web is handled through monikers. These are tokens that Pro Web provides after all interactions with the server that you can then use to either get formatted addresses or perform further searching with. There are more details on this in the documentation provided.
After your initial search on the postcode, you get a list of addresses and each of these has a moniker associated with it. If you are able to store these monikers and associate these with the list you put into you combo box then when an operator selects one you can pass the moniker straight into GetFormatted address and you should be able to capture addresses quicker, more accurately and with less code!
Hope that helps!
Al.
This is the code access uses.
Private Sub cmdSelect_Click()
Dim thisOne As String
thisOne = Me.lkupAddressList.Value
Dim objQAS As MangoQAS.QAS
Set objQAS = New MangoQAS.QAS
Dim finalAddress As Variant
finalAddress = objQAS.RefinePostcode(thisOne)
Form_Script.txtAddress1 = finalAddress(0)
Form_Script.txtAddress2 = finalAddress(1)
Form_Script.txtAddress3 = finalAddress(2)
Form_Script.txtTown = finalAddress(3)
Form_Script.txtCounty = finalAddress(4)
Form_Script.txtPostcode = finalAddress(5)
Set objQAS = Nothing
DoCmd.Close acForm, "frmSelectAddress_qas"
End Sub
Private Sub Form_Load()
Dim postcodeToSearch As String
postcodeToSearch = Form_Script.txtPostcode
Dim objQAS As MangoQAS.QAS
Set objQAS = New MangoQAS.QAS
Dim results As Variant
results = objQAS.SearchPostcodes(postcodeToSearch)
Dim howMany As Integer
howMany = UBound(results)
For i = 0 To howMany
Me.lkupAddressList.AddItem ("'" & results(i) & "'")
Next
Set objQAS = Nothing
End Sub

Categories

Resources