Examples
Examples for webservices configuration.
In the "Samples" subdirectory you can find a Visual Studio 2012 solution containing six sample projects covering how to use CRUD web services (Insert, Query, Update and Delete), Custom Query service and an example illustrating the chunked read feature.
Additionally the solution contains the CookieManagerLib
project with classes allowing for passing cookies between different instances of services
(WCF equivalent of passing CookieContainer
between instances in previous
version).
General settings
To use these projects you have to follow the instruction below:
- The service generator can be found at the following
url:
http://<your server>/<your path to web services>
Open the service generator and create a Custom CRUD service, naming it "Companies" and using "Abstract Types".
Create "Company" and "Person" data types.
Edit the fields for both data types and select all available fields.
Edit the links for the Person data type and create a link to Company (Link Id, 0; Type, Parent).
Create the default methods for the Person and Company data types.
- You need to update/recreate service references of each project to point them to
Companies service you generated in previous step.You can do it by one of the following ways:
- Deleting existing reference and using Visual Studio wizard via the "Add
service reference" context menu where you have to enter URL to svc file
of your newly created service.
Adding a Service Reference
-
Modification of service configuration in
app.config
file (changes are in green font color)<client> <endpoint address="http://localhost/ws8.0/admin/Companies.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICompaniesWebService" contract="CompaniesServiceReference.ICompaniesWebService" name="BasicHttpBinding_ICompaniesWebService"/> </client>
- Setting the URL to the entry point of service in code
var client = new CompaniesServiceClient(); client.Endpoint.Address = new EndpointAddress("http://localhost/ws8.0/admin/Companies.svc");
- Deleting existing reference and using Visual Studio wizard via the "Add
service reference" context menu where you have to enter URL to svc file
of your newly created service.
You can get the URL of your generated service by clicking the one of the links in the CRUD generator as depictured below.
Retrieving the URL of a generated service
Login and session cookie management
Each CRUD service and CommonServicesWcf
has
Login
Logout
IsLoggedIn
methods. But since WCF services using basic http protocol are
stateless the next method called after Login
returns error message
"Session is null. Login missing?".
To have a possibility of sustaining session cookies between subsequent calls into the services we can use two approaches:
- Configure the service to use cookie transmission between server and client. In
app.config
file we need to add the attributeallowCookies="true"
attribute in binding section.<bindings> <basicHttpBinding> <binding name="BasicHttpBinding_ICompaniesWebService" allowCookies="true"/> </basicHttpBinding> </bindings>
- Use WCF service’s behavior extension infrastructure to intercept cookies returned
by server and pass them between each service client configured to use that
extension.Note: This mechanism is equivalent of passing
CookieContainer
instances between Common Services and other services in update.seven webservices.An example of the implementation of such behavior extension is located in the CookieManagerLib project and it's usage is illustrated in the Custom Query sample project.
Note: You have to remove theallowCookies
attribute or set it tofalse
otherwise behavior extension won’t be able to intercept cookies.
Insert
This example shows how to create a company record and a person record linked to that company.
The program contains the following distinct parts.
- We create an instance of the web service
(
CompaniesWebServiceClient
) which is used to perform a login and create records. - We create a
Company
object and assign it Company Name, any other data you require can also be added to the appropriate fields. The default Company name is "Test Company
". - Using the
InsertCompany
method ofCompaniesWebServiceClient
, we insert the Company into the database. - After the insert is completed we check that it was successful and if so we display the Id of the new Company record and continue creating a Person record to link to the Company. If the insert failed we display the error message.
- We create a
Person
object and assign it a First and Last name, any other data you require can also be added to the appropriate fields. The default name is "Test
" "Person
". Set the link objectCompany_0
to our Test Company. - Using the
InsertPerson
method ofCompaniesWebServiceClient
, we insert the Person into the database. - After the insert is completed we check that it was successful and if so we display the Id of the new Person record. If the insert failed we display the error message.
Query
This example returns all company records matching the defined
condition; as a search value we use "Test Company
", the company we
created in the insert example above.
- We create an instance of the web service
(
CompaniesWebServiceClient
) which is used to perform a login and to query for the records. - We create a
Sort
object; the example’s default sort order is by the "Street" attribute of the returned Companies. - We create a
ComparisonCondition
object; this defines the query conditions we require. The sample’s default condition is to find any companies called "Test Company
". You can customize the condition to suit your database contents. - We create a
Company
object, for our query and assign our sort and condition objects to the Sort andCustomCondition
attributes. - Using the
QueryCompany
method ofCompaniesWebServiceClient
, we query the database for Companies that match our condition. - After the query is completed we check that if it was executed successfully and if any matching companies are returned we display their Name and Street. If the query failed we display the error message.
This sample has a simple condition; more complex conditions can also be used. See the Conditions section later in this chapter.
Update
In this example we update a company which satisfies the search condition. If more than one record is found, none of the records are updated and an error message, "Parent record not unique" is returned. If no record is found, a new record with the specified fields is created.
- We create an instance of the web service
(
CompaniesWebServiceClient
) which is used to perform a login and to update the record. - We create a
ComparisonCondition
object; this defines the query conditions we require. The example's default condition is to find any companies with a Synonym called "Test Synonym
". - We create a
Company
object, for our update and assign our condition object to theCustomCondition
attribute and set the street field to "New Test Street" to update the value. - Using the
UpdateCompany
method ofCompaniesWebServiceClient
, we update the Company that matches our condition. - The response indicates if the record that was updated or contains an error message if no record or more than one record was found.
To update multiple records it would be necessary to update every record individually.
Delete
This example deletes all matching company records from database.
- We create an instance of the web service
(
CompaniesWebServiceClient
) which is used to perform a login and to delete the records. - We create two instances of
ComparisonCondition
. We search for a company with a company name equal to "Test Company
" and synonym equal to "Test Synonym
". Combine the comparison conditions using aLogicalCondition
with an And operation. - We create a
Company
object, for our delete and assign our logical condition object to theCustomCondition
attribute. - Using the
DeleteCompany
method ofCompaniesWebServiceClient
, we delete Companies that match our condition from the database. - After the deletion is completed we check if it was successful and if any companies have been deleted we display their Record Ids. If the query failed we display an error message.
Custom Query
This example shows how to execute a (web) query via webservices. It is possible to pass parameters to the query.
- Please create a query called "CompanyTest". Add the Company Info Area to this query, including some output fields (Company, Synonym, Street and City are used in the example). Add a (parameter) condition for companies by company name and click "Use as Parameter (requires user input)".
- In the example we create a query service "CompanyTest" with the service generator create.
- We create an instance of
CommonServicesWcfClient
and perform a login. - We create an instance of the web service
(
CompanyTestQueryServiceClient
) which is used to execute the query. Due to usage of behavior extension intercepting cookies (seeapp.config
file) the session created by Login method ofCommonServicesWcfClient
is maintained for the query service client. - We create an instance of
CompanyTest
which represents the query and set the value of our parameter to find the company called “Test Company”. - Using the Query method of
CompanyTestQueryServiceClient
, we execute the CompanyTest query. - After the query is completed we check if it was executed successfully and if any companies are returned we display their Company, Synonym, Street and City attributes. If the query failed we display the error message.
Chunked Query
A chunked query allows for splitting the results of a query into parts and process them as such. The chunked query is initialized by setting the "Chunked" request option property to true; you can either provide your own unique identifier or retrieve the automatically assigned one from the response. To retrieve any subsequent chunks of the query you need to provide the identifier in the query request options.
RequestOptions
object that
is used for creating the chunked query, for a retrieving more chunks, you need to
set the "Chunked" property to false and update the unique identifier if one has been
automatically assigned. Otherwise you get an error saying that a Chunked operation
with that identifier already exists.The Chunked Query example shows how to get all company records in chunks of 10 records.
- We create an instance of the web service
(
CompaniesWebServiceClient
) which is used to perform a login an read the data. - We create a
Company
object, for our query. - We create
RequestOptions
object with Chunked property set to true andChunkSize
property set to 10. - Using the
QueryCompany
method ofCompaniesWebServiceClient
we query the database for first chunk of records (passRequestOptions
object as second parameter ofQueryCompany
method). - After the query is completed we check if was executed successfully. If any matching companies are found we display their Name and Street. If the query failed we display the error message.
- Before we can query for next chunk of records we need to set
ChunkQid
property ofRequestOptions
to the value ofChunkQid
from response object and set Chunked property ofRequestOptions
object to false. - We continue to query for chunks of records and displaying Name and Street values until query won’t return more data.
Tenant Catalogs
// create tenant objects
Tenant oCountryTenant = new Tenant();
oCountryTenant.Field = "Country";
oCountryTenant.TenantNumber = 100;
Tenant oAreaTenant = new Tenant();
oAreaTenant.Field = "Area";
oAreaTenant.TenantNumber = 123;
// the tenant objects are put in an array
Tenant[] oTenants = new Tenant[] { oCountryTenant, oAreaTenant };
// create an object assigning the tenants array
// to the CustomTenants property
Company oCompany = new Company();
oCompany.CompanyField = "Test Company";
oCompany.Synonym = "Test Synonym";
oCompany.Country = "Austria";
oCompany.Area = "Test Area";
oCompany.CustomTenants = oTenants;
Conditions
CRM.webservices support two types of conditions
Condition
andConcreteConditions
.
Condition
is an abstract base class type for
ComparisonCondition
and LogicalCondition
, which
implements the functionality to define complex conditions.
ConcreteConditions
offer the same functionality but
without the use of abstract classes.
Some program languages do not support the use of abstract types. You can therefore use this option to omit abstract types in your custom CRUD services.
The following example illustrates to implement conditions using both condition types. The example condition is to find Person objects with a First Name “test” and Last Name “person”.
The main difference between the conditions is
ComparisonCondition
and LogicalCondition
have an
Operator property, whereas ConcreteConditions
has
ComparsionOperator
and LogicalOperator
properties, only on these must be set to indicate what kind of condition the
ConcreteConditions
represents.
Using Condition
ComparisonCondition oCondition1 = new ComparisonCondition();
oCondition1.TableName = "Person";
oCondition1.FieldName = "FirstName";
oCondition1.Value = "test";
oCondition1.Operator = ComparisonOperator.Equal;
ComparisonCondition oCondition2 = new ComparisonCondition();
oCondition2.TableName = "Person";
oCondition2.FieldName = "LastName";
oCondition2.Value = "person";
oCondition2.Operator = ComparisonOperator.Equal;
LogicalCondition oConditions = new LogicalCondition();
oConditions.Operator = LogicalOperator.And;
oConditions.Conditions = new Condition[] { oCondition1, oCondition2 };
Person oPerson = new Person();
oPerson.CustomConditions = oConditions;
Response oResponse = companiesService.QueryPerson(oPerson, null);
Using ConcreteConditions
ConcreteConditions oConcreteCondition1 = new ConcreteConditions();
oConcreteCondition1.TableName = "Person";
oConcreteCondition1.FieldName = "FirstName";
oConcreteCondition1.Value = "test";
oConcreteCondition1.ComparisonOperator = ComparisonOperator.Equal;
ConcreteConditions oConcreteCondition2 = new ConcreteConditions();
oConcreteCondition2.TableName = "Person";
oConcreteCondition2.FieldName = "LastName";
oConcreteCondition2.Value = "person";
oConcreteCondition2.ComparisonOperator = ComparisonOperator.Equal;
ConcreteConditions oConcreteConditions = new ConcreteConditions();
oConcreteConditions.LogicalOperator = LogicalOperator.And;
oConcreteConditions.Conditions = new ConcreteConditions[] {
oConcreteCondition1, oConcreteCondition2 };
Person oPerson = new Person();
oPerson.ConcreteConditions = oConcreteConditions;
Response oResponse = companiesService.QueryPerson(oPerson, null);
Parent Catalog condition
To create a condition to find a record by a catalog and its parent catalog use the value2 attribute of the comparison condition to specify the parent catalog value.
// condition with a catalog and it's parent catalog
ComparisonCondition oComparisonCondition = new ComparisonCondition();
oComparisonCondition.Operator = ComparisonOperator.Equal;
oComparisonCondition.TableName = "Interests";
oComparisonCondition.FieldName = "Interest";
oComparisonCondition.Value = "catalog value";
oComparisonCondition.Value2 = "parent catalog value";
External Key Catalogs
Allows catalog values are specified by external key (as opposed to their textual value). This can be set at request level and/or for individual conditions.
The following example shows how to use external catalog keys at the request level. All catalog values must be specified as external keys and all catalog values returned are their external key values.
The 2nd condition (oCondition2
) in the example
illustrates how to override that behavior for a single condition.
// create request options
RequestOptions oRequestOptions = new RequestOptions();
oRequestOptions.CatExKeys = true;
oRequestOptions.VisibleFields = "my catalog field";
// create conditions
ComparisonCondition oCondition1 = new ComparisonCondition();
oCondition1.TableName = "Company";
oCondition1.FieldName = "my catalog field";
oCondition1.Value = "external_key_1";
oCondition1.Operator = ComparisonOperator.Equal;
ComparisonCondition oCondition2 = new ComparisonCondition();
oCondition2.TableName = "Company";
oCondition2.FieldName = "my catalog field";
oCondition2.Value = "my catalog text value";
oCondition2.Operator = ComparisonOperator.Equal;
oCondition2.ExtKey = false;
LogicalCondition oConditions = new LogicalCondition();
oConditions.Operator = LogicalOperator.Or;
oConditions.Conditions = new Condition[] { oCondition1, oCondition2 };
// create an object to query
Company oCompany = new Company();
oCompany.CustomConditions = oConditions;
// create an object to query
Response oResponse = companiesService.QueryCompany(oCompany, oRequestOptions);
// create condition
ComparisonCondition oCondition = new ComparisonCondition();
oCondition.TableName = "Company";
oCondition.FieldName = "my catalog field";
oCondition.Value = "external_key_1";
oCondition.Operator = ComparisonOperator.Equal;
oCondition2.ExtKey = true;
Request Options
Chunked
ChunkSize
) of
records by referencing the original query via a query-ID
(ChunkQid
).const long English = 1;
// Login
var companiesService = new CompaniesWebServiceClient();
companiesService.Login("TestUser", "TestPassword", English);
Company company = new Company();
RequestOptions oRequestOptions = new RequestOptions();
oRequestOptions.Chunked = true;
oRequestOptions.ChunkSize = 10;
// get the first chunk of results
Response oResponse = companiesService.QueryCompany(company, oRequestOptions);
Console.WriteLine("Succeeded: " + !oResponse.Error);
// check the results, to see if the query has completed
if (!oResponse.Error)
{
// output the first chunk
int nCount = 0;
const string outputFormat = "Company: {0}; Street: {1};";
foreach (var companyInResponse in oResponse.Objects.Cast<Company>())
{
Console.WriteLine(outputFormat,
companyInResponse.CompanyField, companyInResponse.Street);
}
// **** important ****
// update the request options for getting the next chunks
// set returned qid and switch off Chunked attribute
oRequestOptions.ChunkQid = oResponse.ChunkQid;
oRequestOptions.Chunked = false;
bool bContinue = true;
// continue getting chunks while they are available
while (bContinue)
{
// get the next chunk of results
oResponse = companiesService.QueryCompany(company, oRequestOptions);
Console.WriteLine("Succeeded: " + !oResponse.Error);
// check the results, to see if the query has completed
if (!oResponse.Error)
{
nCount = 0;
foreach (var companyInResponse in oResponse.Objects.Cast<Company>())
{
Console.WriteLine(outputFormat,
companyInResponse.CompanyField, companyInResponse.Street);
}
}
else
{
// if the query ends or there is an error output terminate the loop
Console.WriteLine("ErrorText: " + oResponse.ErrorText);
Console.WriteLine("Description: " + oResponse.Description);
bContinue = false;
}
}
}
else
{
// if there is an error with the initial query output the reason
Console.WriteLine("ErrorText: " + oResponse.ErrorText);
Console.WriteLine("Description: " + oResponse.Description);
}
Chunk size
Defines the maximum number of records to be read in one chunk.
For further details see chapter Chunked above.
ChunkQid
A unique ID for a "chunked read" operation, The
ChunkQid
(query id) can be used to read subsequent chunks of
data.
For further details see chapter Chunked above.
CreateNewCatalogValue
An indicator of whether unknown catalog values should be automatically created. It is recommended that new catalog values is not created using this flag due to risk of unwanted duplicates. It works only in the catalog base language.
Matchup
An indicator of whether the matchup is to be done for records during an insert.
MaxRecords
The maximum number of records to be read in a query. The default value is 9999.
RecordId
A 64-bit record id specified in hexadecimal notation and prefixed with an 'x' character.
SkipRecords
Sets the number of records to be skipped, before returning records from a query.
The following example shows how to skip 10 records.
// create request options
RequestOptions oRequestOptions = new RequestOptions();
oRequestOptions.SkipRecords = 10;
// create an object to query
Company oCompany = new Company();
// create an object to query
Response oResponse = companiesService.QueryCompany(oCompany, oRequestOptions);
Visible Fields
An indicator, which fields should be retrieved by the layer beyond web services.
RESTSample
This sample illustrates how to implement a client for RESTful service
endpoints. The example loads the request templates (e.g.
queryrequest.xml
, insertrequest.xml
,
json_queryrequest.txt
etc.) and sends it to the service.