Dynamics CRM Integration with Azure Service Bus–Part 2

In the first part of this series we discussed briefly about Microsoft Azure, Azure Service Bus and elements of Dynamics CRM-Azure integration.

Before going into the details of CRM-Azure integration, I would like to elaborate:

  1. What we want to achieve in this sample integration (our scenario); and
  2. What Service Bus feature we will use for the same

In this sample we will integrate Dynamics CRM Online with “Student Management System” that is running on-premises over a local network behind the firewall. We will have a Student ID field on CRM account entity form. If user will provide Student ID while creating a new account, the Dynamics CRM will post the data to the Azure Service Bus and the Service Bus Service hosted on on-premises (but with a Service Bus endpoint located in the cloud) will read the data. The service will then query the database locally and return student’s name and phone number to the Azure Service Bus and the Service Bus will send this information back to the CRM.

You may download the complete sample projects and Dynamics CRM solution at https://github.com/khadimali/DynamicsCrmAzureIntegration.

For this scenario, an Azure Service Bus relay service would be a perfect fit, because:

  • Relay service provide two-way communication that queues and topics do not provide.
  • Also relay service facilitates direct communication between the applications while queues and topics provide brokered messaging.

Here is how Microsoft Azure documentation article explains Service Bus relay:

The Service Bus relay enables you to host WCF services within your existing enterprise environment. You can then delegate listening for incoming sessions and requests to these WCF services to the Service Bus service running within Azure. This enables you to expose these services to application code running in Azure, or to mobile workers or extranet partner environments. Service Bus enables you to securely control who can access these services at a fine-grained level. It provides a powerful and secure way to expose application functionality and data from your existing enterprise solutions and take advantage of it from the cloud.

Register a Microsoft Azure Subscription

If you don’t have an Azure subscription already, you may register a free trial to play around Microsoft Azure apps and services. To register, you have to provide information about yourself, verification by phone and verification by credit card. Your credit card will not be charged automatically even after the trial expires unless you explicitly authorize the payment.

Creating a Microsoft Azure Service Bus Namespace

Once registered, you have to create a new Service Bus namespace. Normally you can create Service Bus namespace using Azure portal. But in case of integration with Dynamics CRM, you shouldn’t. This is because namespaces created using Azure portal use SAS authentication by default and, to date, Dynamics CRM integrates with Azure Service Bus namespace via ACS authentication only. To create an ACS namespace you have to use Azure PowerShell.

Although, I found this walkthrough in the MSDN that explains configuring Azure with SAS authentication for Dynamics CRM integration using the Plugin Registration Tool from v8.1, but when I downloaded the latest SDK and used the Plugin Registration Tool it turned to me that it still has that old interface as it was in the previous version of the tool that configures service bus ACS namespace, and not an SAS. I had also started a thread regarding this issue at MSDN forums that is still unanswered.

So to create an ACS service bus namespace you need to:

  1. Install Azure PowerShell from  web platform installer
  2. Start the PowerShell and execute the following command to login to your Azure subscription:

PS C:\ …. > Add-AzureAccount

This will open a dialog to ask your azure subscription credentials.

3.    Once authenticated, you can create a new ACS service bus namespace by issuing following command:

PS C:\ …. > New-AzureSBNamespace –Name democrmservicebus -Location “Central US” -CreateACSNamespace $true -NamespaceType Messaging

The namespace must be globally unique. So, you must use a namespace other than one mentioned in this tutorial.

Log in to your Azure portal and select “Service Bus” from left navigation panel. Select the newly created namespace and open the connection information (see images below). Note down the default issuer and default key in the ACS section that you will have to use ahead for CRM-Azure integration.

01. service bus namespace

02. connection information

Get a Public Certificate

Microsoft Dynamics CRM Online users can download a public certificate from within their online instance by visiting the Developer Resources page. To download a certificate:

  1. Log in to your Dynamics CRM Online instance
  2. Go to Settings > Customizations > Developer Resources
  3. Click the “Download Certificate” link in the “Connect this instance of Dynamics CRM to Azure Service Bus” section and save the certificate file on your disk
  4. Note down the issuer name that is written just above the download link on the same page

Configure Microsoft Dynamics CRM for Azure Integration

Dynamics CRM Online comes pre-configured to work with Microsoft Azure. However, if you are using Dynamics CRM on-premises or IFD deployment, you have to configure the server for Microsoft Azure integration. Refer to Walkthrough: Configure CRM for integration with Microsoft Azure to configure Azure integration for on-premises and IFD deployments.

Configure Azure for Microsoft Dynamics CRM Integration

Next, we have to configure Microsoft Azure Active Directory Access Control Services (ACS):

  • the rules and issuers to allow a listener application to read the CRM message posted to the Azure service bus
  • the service bus rules to accept the Dynamics CRM issuer claim

Although we can configure these settings in Azure’s ACS portal directly but the recommended way is to use Plugin Registration Tool in the Dynamics CRM SDK.

After connecting CRM organization in the Plugin Registration Tool, click on Register > Register New Service Endpoint. A Service Endpoint Registration dialog will appear. Fill the dialog as shown in the below image. (Leave the Claim dropdown to “None” to send standard claim to Microsoft Azure).

03.-service-endpoint-registration-di

Name Service Endpoint entity name
Description Something to describe this endpoint
Solution Namespace A Name of the service bus namespace
Path Name of a service bus queue or topic.In case of relays, the path of an endpoint that we will configure as WCF service’s relay endpoint. (More on this ahead)
Contract PersistentQueue Select this if you want to send an execution context to a service bus queue entityTopic To send an execution context to a service bus topic entity. Same as queue except that more than one listener can be subscribed to the topic.OneWay To send an execution context to a Relay endpoint. From there it should be read by an active Azure listener solutionTwoWay Similar to OneWay except that it can receive a string value returned from the listener to the plugin or custom workflow assembly that initiated the post

Rest Similar to TwoWay contract but on a REST endpoint

 

Now follow these steps to configure and verify the Service Bus authentication:

  1. Click “Save and Configure ACS”. The ACS configuration dialog box will appear.
  2. Fill in the Management Key with a default key that you have noted down while creating a service bus namespace in this tutorial
  3. Provide the public certificate file that you have obtained from the Dynamics CRM Online instance
  4. Fill in the Issuer Name with the issuer name of the certificate
  5. Click Configure ACS. Configuration process logs would be displayed.
  6. Click close to return to the Service Endpoint registration dialog
  7. Click Save and Verify Authentication. A Verifying Authentication progress dialog will appear.
  8. When success message appear, click close to return back to the Service Endpoint registration dialog
  9. Click Save. A new Service Endpoint would be saved and appeared in the Plugin Registration Tool.

image

(For steps 1-6 refer to this image)

Now if we don’t expect or don’t want to receive any string data back from an Azure service bus listener (that we will be coding ahead), we can just create a plugin step right directly inside the Service Endpoint. To do so, you may select the newly created Service Endpoint and click Register > Register New Step (or press Ctrl+T). Then configure the plugin step as usual. But in our example, as we need to pass Student ID and receive back a string data containing Student Name and Phone Number from an on-premises application having student records, we will write a custom Azure-aware plugin in the next section and will register it in the Dynamics CRM.

Write a Custom Azure-aware Plugin

Writing a custom Azure-aware plugin is similar to writing a usual Dynamics CRM plugin except that we have to include a code to initiate the posting of execution context to the Microsoft Azure Service Bus. This will make the CRM plugin an Azure-aware. To implement our scenario I have written a CRM Azure-aware plugin that I will explain here briefly.

You can see in the plugin code below that an AzureAwarePlugin class implements the same IPlugin interface (and an execute method) that any other Dynamics CRM plugin implements. Additionally, it receives an unsecure configuration string in the constructor and set it as serviceEndpointId. Then, if the plugin is invoked by the creation of account it calls the PostAccountContextToAzure() method.

The PostAccountContextToAzure() contains code that actually initiates posting of the execution context to the service bus through the service endpoint notification service (IServiceEndpointNotificationService). It creates an instance of the service endpoint notification service and then calls its Execute() method by providing Service Endpoint entity’s reference and an execution context as parameters. If our Service Endpoint was configured successfully in the Plugin Registration Tool, the Execute() method will post the context to the Service bus relay endpoint (as we had configured the Service Endpoint with a TwoWay (relay) contract). From there it will be read by an active CRM-aware Azure solution (that is a WCF service). We will discuss the Azure solution in the next section.

The Azure service bus will return the student’s name and phone number as a comma separated string. Upon receiving that string of information the plugin breaks the string to extract the two pieces of information and sets the relevant entity attributes – “name” and “telephone1”. The updated student info will be reflected on the account form’s Account Name and Phone attributes. To keep the plugin simple, we have used comma separated string to pass on the information from the service to the CRM. In your professional project you may use JSON’s serialization and deserialization to exchange data.

The full listing of the plugin is below:

using Microsoft.Xrm.Sdk;
using System;

namespace AzureAwareCrmPluginDemo
{
public class AzureAwarePlugin : IPlugin
{
#region Secure/Unsecure Configuration Setup
private string _unsecureConfig = null;
private Guid serviceEndpointId;

public AzureAwarePlugin(string unsecureConfig)
{
_unsecureConfig = unsecureConfig;

if (String.IsNullOrEmpty(_unsecureConfig) || !Guid.TryParse(_unsecureConfig, out serviceEndpointId))
{
throw new InvalidPluginExecutionException("Service endpoint ID should be passed as config.");
}
}
#endregion
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);

tracer.Trace("Execute > REV: 5");

try
{
Entity entity = (Entity)context.InputParameters["Target"];

//TODO: Do stuff
if (entity.LogicalName == "account" && context.MessageName.ToLower() == "create")
{
int studentId = entity.GetAttributeValue<int>("demo_studentid");

if (studentId > 0)
PostAccountContextToAzure(serviceProvider, tracer, context, entity);
else
tracer.Trace("Execute > account.create > Wont post the context to the Service Bus. Student ID not provided.");
}
}
catch (Exception e)
{
throw new InvalidPluginExecutionException(e.Message);
}
}

private void PostAccountContextToAzure(IServiceProvider serviceProvider, ITracingService tracer, IPluginExecutionContext context, Entity entity)
{
IServiceEndpointNotificationService cloudService = (IServiceEndpointNotificationService)serviceProvider.GetService(typeof(IServiceEndpointNotificationService));
if (cloudService == null)
throw new InvalidPluginExecutionException("Failed to retrieve the service bus service.");

try
{
tracer.Trace("Posting the execution context.");

string response = cloudService.Execute(new EntityReference("serviceendpoint", serviceEndpointId), context);

if (!String.IsNullOrEmpty(response))
{
tracer.Trace("Response = {0}", response);

if (response.StartsWith("false,"))
{
string[] errorInfo = response.Split(',');
string exceptionMessage = null;

if (errorInfo.Length > 1)
exceptionMessage = errorInfo[1];
else
exceptionMessage = "Unknown error.";

throw new InvalidPluginExecutionException(exceptionMessage);
}
else
{
string[] studentInfo = response.Split(',');

if (studentInfo.Length > 0)
{
if (entity.Attributes.Contains("name"))
entity.Attributes["name"] = studentInfo[0];
else
entity.Attributes.Add("name", studentInfo[0]);
}

if (studentInfo.Length > 1)
{
if (entity.Attributes.Contains("telephone1"))
entity.Attributes["telephone1"] = studentInfo[1];
else
entity.Attributes.Add("telephone1", studentInfo[1]);
}
}
}
tracer.Trace("Done.");
}
catch (Exception e)
{
tracer.Trace("Exception: {0}", e.ToString());
throw;
}
}
}
}

Write a Microsoft Azure Listener Solution

Finally, we have to write a listener solution that could listen to and read the CRM execution context from the Azure Service Bus. Azure listener solutions can be of two broad types:

  • Queue Listener
    • For reading and processing messages from Azure service bus Queues and Topics
    • Does not required to be an active listener (senders and receivers do not have to be sending or receiving messages at the same time)
  • OneWay, TwoWay or REST Listener
    • For reading and processing messages from Azure service bus Relay endpoints
    • Must be an active listener

To complete our tutorial we will write and discuss a two-way listener that uses the Windows Communication Foundation (WCF) service with Service Bus extensions to read CRM messages from cloud based Azure Service Bus Relay endpoint. To understand and write a listener for queue, one-way and REST contracts refer to Write a listener application for a Microsoft Azure solution.

We have two options to connect to the  Azure Service Bus: HTTP and TCP. As our custom Azure-aware Dynamics CRM plugin will run in sandbox mode we can only use HTTP to connect to the Azure Service Bus. Next we have to define the WCF endpoint. That endpoint in our example is made up of following ABC (Address, Binding, Contract):

Address – that specifies where the service could be found. In this example the full URI is https://democrmservicebus.servicebus.windows.net/Demo/TwoWay/. We can’t use the ‘sb://’ scheme as it is used for TCP protocols only.

Binding – that specifies how a client can communicate with the endpoint. Our WCF service uses WS2007HttpRelayBinding binding. The main difference between this binding and other WCF bindings is that this binding is not part of the .NET framework. It is defined by the Service Bus.

Contract – that specifies what operations (methods) a service supports. ITwoWayServiceEndpointPlugin is a service contract in our example that is applied with a ServiceContractAttribute. Each method within a service contract must have  OperationContractAttribute applied to it also. Execute() method in our example is an OperationContract for the WCF Service Bus service. (See in the image below, the ITwoWayServiceEndpointPlugin service contract is provided in Micorosft.Xrm.Sdk.dll).

05.-Service-Contract---Operation-Con[2]

So the complete ABC of our Service Bus service would look like as shown in the code snapshot below:

SNAGHTML5aa1754_thumb2

Next, using the TransportClientEndpointBehavior we have created a shared secret token provider by providing default issuer name and issuer key from the Azure Service Bus ACS connection information. This behavior object is added to the WCF endpoint behaviors to specify the Service Bus credentials.

We have created a ServiceHost object passing in the type of TwoWayEndpoint class that implements Execute() method. The Execute() is an operation contract  of a service. So, whenever the CRM execution context would be posted to Service Bus using this operation contract, the active Service Bus service will start reading that context and the TwoWayEndpoint.Execute(…) method will be invoked on the service. In our example, the Execute() method will call the GetStudentInfo() method that will query the SQL Server database “TestDb” to get student’s name and phone number. The Execute() method will then return the student information as a comma separated string to the CRM Azure-aware plugin. The Service Bus facilitates this communication between the CRM Online and a locally hosted WCF service with a cloud endpoint.

The full code listing for a WCF Service Bus Service is below:

using System;
using System.Collections.Generic;
using System.Text;

// This namespace is found in the Microsoft.Xrm.Sdk.dll assembly
// found in the SDK\bin folder.
using Microsoft.Xrm.Sdk;

// This namespace is found in Microsoft.ServiceBus.dll assembly
// found in the Windows Azure SDK
// Assembly can be found in C:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.6\ToolsRef if the SDK has been installed via WPI
using Microsoft.ServiceBus;

using System.ServiceModel;
using System.Data.SqlClient;

namespace AzureRelayListener
{
class Program
{
/// <summary>
/// Creates a two-way endpoint listening for messages from the Windows Azure Service
/// Bus.
/// </summary>
public class TwoWayListener
{
/// <summary>
/// Standard Main() method used by most SDK samples.
/// </summary>
static public void Main()
{
try
{
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;

string serviceNamespace = "democrmservicebus";
string issuerName = "owner";
string issuerKey = "<Your ACS Default Key Here>";
string servicePath = "Demo/TwoWay";

// Leverage the Azure API to create the correct URI.
Uri address = ServiceBusEnvironment.CreateServiceUri(
Uri.UriSchemeHttps,
serviceNamespace,
servicePath);

Console.WriteLine("The service address is: " + address);

// Using an HTTP binding instead of a SOAP binding for this endpoint.
WS2007HttpRelayBinding binding = new WS2007HttpRelayBinding();
binding.Security.Mode = EndToEndSecurityMode.Transport;

// Create the service host for Azure to post messages to.
ServiceHost host = new ServiceHost(typeof(TwoWayEndpoint));
host.AddServiceEndpoint(typeof(ITwoWayServiceEndpointPlugin), binding, address);

// Create the shared secret credentials object for the endpoint matching the
// Azure access control services issuer
var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior()
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerKey)
};

// Add the service bus credentials to all endpoints specified in configuration.
foreach (var endpoint in host.Description.Endpoints)
{
endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
}

// Begin listening for messages posted to Azure.
host.Open();

Console.WriteLine(Environment.NewLine + "Listening for messages from Azure" +
Environment.NewLine + "Press [Enter] to exit");

// Keep the listener open until Enter is pressed.
Console.ReadLine();

Console.Write("Closing the service host...");
host.Close();
Console.WriteLine(" done.");
}
catch (FaultException<ServiceEndpointFault> ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Message: {0}", ex.Detail.Message);
Console.WriteLine("Inner Fault: {0}",
null == ex.InnerException.Message ? "No Inner Fault" : "Has Inner Fault");
}
catch (System.TimeoutException ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Message: {0}", ex.Message);
Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
Console.WriteLine("Inner Fault: {0}",
null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
}
catch (System.Exception ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine(ex.Message);

// Display the details of the inner exception.
if (ex.InnerException != null)
{
Console.WriteLine(ex.InnerException.Message);

FaultException<ServiceEndpointFault> fe = ex.InnerException
as FaultException<ServiceEndpointFault>;
if (fe != null)
{
Console.WriteLine("Message: {0}", fe.Detail.Message);
Console.WriteLine("Inner Fault: {0}", null == ex.InnerException.Message ? "No Inner Fault" : "Has Inner Fault");
}
}
}

finally
{
Console.WriteLine("Press <Enter> to exit.");
Console.ReadLine();
}
}
}

#region How-To Sample Code

/// <summary>
/// The Execute method is called when a message is posted to the Azure Service
/// Bus.
/// </summary>
[ServiceBehavior]
private class TwoWayEndpoint : ITwoWayServiceEndpointPlugin
{
#region ITwoWayServiceEndpointPlugin Member

/// <summary>
/// This method is called when a message is posted to the Azure Service Bus.
/// </summary>
/// <param name="context">Data for the request.</param>
/// <returns>A string of information to be returned to the CRM Online Azure-aware plugin.</returns>
public string Execute(RemoteExecutionContext context)
{
string studentId = null;
string returnString = null;

if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
var entity = context.InputParameters["Target"] as Entity;
if (entity.Attributes.Contains("demo_studentid"))
{
studentId = entity.Attributes["demo_studentid"].ToString();
}
}

if (studentId != null)
{
returnString = GetStudentInfo(studentId);
}
else
{
returnString = "false,Student ID not provided.";
}

return returnString;
}

#endregion

/// <summary>
/// This method will extract student information from the LOB on-premises application's database directly
/// </summary>
/// <param name="studentId"></param>
/// <returns></returns>
string GetStudentInfo(string studentId)
{
string returnString = null;

SqlConnection connection = new SqlConnection("Data Source=<ServerName>Se;Initial Catalog=TestDb;Integrated Security=True");
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT Name, PhoneNumber FROM Student where studentid = " + studentId, connection);
connection.Open();

SqlDataReader reader = command.ExecuteReader();

if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetString(0),
reader.GetString(1));

var name = reader.GetString(0);
var phone = reader.GetString(1);

returnString = name + "," + phone;
}
}
else
{
Console.WriteLine("Student ID not found in student database.");
returnString = "false,Student ID not found in student database.";
}
reader.Close();
}

return returnString;
}
}

#endregion How-To Sample Code
}
}

To create an Azure listener solution project:

  1. Create a new console project and name it AzureRelayListener
  2. Add ‘Microsoft Azure Service Bus’ NuGet package to the project
  3. Add ‘Microsoft.Xrm.Sdk’ assembly to the project to make in CRM-aware.
  4. Replace the Program.cs code with the above code.

SQL Server database

To make this sample work, we need to have an SQL Server database in place. I have setup the database on my local SQL Server as described below:

  1. Database ‘TestDb’
  2. Table ‘Student’
  3. Fields
    • StudentId – int
    • Name – varchar(100)
    • PhoneNumber – varchar(100)

image_thumb45

 

Customize Dynamics CRM

I have created an unmanaged solution to customize the account entity. It is recommended to do all the customizations in a separate solution even for practice so that you can test deployment of the solution also. Below are the steps required to  customize the Dynamics CRM Online instance and to complete our sample:

  1. Create a new solution and save it.
  2. Click Entities > Add Existing. ‘Select solution components’ dialog box will appear.
    • Select ‘Account’ form of Form Type ‘Main’ from the Forms tab.
    • Select ‘Account Name’ field from the fields tab and click Finish to add an account entity to the solution with the minimum required assets.
  3. Create a new field ‘Student Id’ with Data Type as ‘Whole Number’.
  4. Change the ‘Field Requirement’ dropdown value of the ‘Account Name’ field to ‘Business Recommended’.
  5. Drag and drop the ‘Student Id’ field to the account form just above the ‘Account Name’ field.
  6. Register a CRM Azure-aware plugin (that we just discussed above) with a Plugin Registration tool, just like we register other CRM plugins.
  7. Register new step on the ‘Create’ of ‘account’
    • Set ‘Event Pipeline Stage of Execution’ as ‘Pre-operation’
    • Put the Service Endpoint ID  (that we have configured above) in the ‘Unsecure Configuration’ text box.
  8. Go to the solution’s window and Add Service Endpoint, Plugin Assembly and Plugin Step (SDK Message Processing Step) to the solution.

Snapshot of a plugin step for the creation of an account

image_thumb41

Snapshot of the solution components for this sample to work

image_thumb43

Test the integration

So our CRM-Azure integration is compelted now. To test this:

  1. Start the CRM-aware Azure solution (WCF console application) so that it can start listening to the relay endpoint
  2. Go to the Dynamics CRM web application and create new account
  3. Provide any valid Student ID on the account form (that you have entered in the TestDb.Student table) and save the account record

Dynamics CRM Azure-aware custom plugin will post the data context to the Azure Service Bus relay endpoint, will get the student information back and set it as “Account Name” and “Phone”.

Thank you for reading!

Advertisements
Posted in Dynamics CRM, Dynamics CRM - Customization and Configuration, Dynamics CRM - Development, Microsoft Azure, Microsoft Azure - Srevice Bus

Dynamics CRM Integration with Azure Service Bus–Part 1

Last month, one of my friend called me and asked me if I can help him integrating Dynamics CRM with an on-premises line of business (LOB) application using Azure Service Bus. He was a SharePoint expert, with reasonable experience of Dynamics CRM and Azure Service Bus also and he had to develop a POC for his client to win a project. By then I didn’t have any experience with Microsoft Azure. So, I looked it as an opportunity for me to learn something new, the Microsoft Azure Service Bus. I spent few days studying and watching concepts and demos regarding Microsoft Azure, Azure Service Bus and Dynamics CRM-Azure integration. Eventually, we both started working on the project. The project had few other challenges too, but mainly I learned enough about Azure Service Bus and Dynamics CRM integration while working on this project. In this two part series of blog post I would like to explain fundamentals of Dynamics CRM integration with Azure Service Bus.

In the first part, we will learn about:

  • Microsoft Azure (short introduction)
  • Microsoft Azure Service Bus (fundamentals)
  • Elements of Dynamics CRM-Azure integration

Microsoft Azure

Is it Windows Azure or Microsoft Azure? The word “Windows” or “Microsoft” before Azure should not confuse us as both are not a different product. In fact, in March 2014 Microsoft rebranded what was formerly called “Windows Azure” to “Microsoft Azure” as Azure was not all about Windows only.

Microsoft Azure is a cloud computing platform and infrastructure created by Microsoft that provides both PaaS and IaaS services. That means you can build, deploy and manage applications and services and you can also create virtual machines of which you have complete control. All these on Microsoft-managed datacenters just using your cloud clients.

image

Cloud Computing Layers accessible within a stack (image from Wikipedia)

Microsoft mentions about Azure as follows:

“Azure supports the broadest selection of operating systems, programming languages, frameworks, tools, databases and devices. Run Linux containers with Docker integration; build apps with JavaScript, Python, .NET, PHP, Java and Node.js; build back-ends for iOS, Android and Windows devices. Azure cloud service supports the same technologies millions of developers and IT professionals already rely on and trust.”

You can see in the image below – taken from my trial Azure portal – that for example, an Azure user can create VMs for not only Windows Server, but also for Red Hat, Ubuntu Server and many others.

image

The apps and services shown in the left navigation bar are few of the Azure offerings. You can see the complete list of these by clicking browse. Visit Wikipedia to see the complete list and short description of some of the prominent services.

Microsoft Azure Service Bus

You have probably heard about “bus” concept in computer hardware. In computer architecture, a bus refers to a communication system used to transfer data between components inside a computer, or between computers. Similarly, a software bus is a software architecture model that enables communication between software modules. A software bus is conceptually similar to the term “bus” used in computer hardware. It is also referred as an ESB (Enterprise Service Bus) product.

Microsoft Azure Service Bus is Microsoft’s ESB product that facilitates messaging between decoupled systems. As Microsoft mentioned:

“(Azure Service Bus) Runs anywhere and connects nearly anything.

Azure Service Bus is a generic, cloud-based messaging system for connecting just about anything—applications, services, and devices—wherever they are. Connect apps running on Azure, on-premises systems, or both. You can even use Service Bus to connect household appliances, sensors, and other devices like tablets or phones to a central application or to each other.”

Azure service bus supports four different communication mechanisms. Each mechanism connects applications differently.

Queues

  • provide one-directional communication
  • each message is received by a single recipient
  • store sent messages until they are received

Topics

  • provide one-directional communication using subscriptions
  • a single topic can have multiple subscriptions (a Pub/Sub model)
  • each subscription can use a filter to receive only messages that match specific criteria

Relays

  • provide bi-directional communication
  • do not store in-flight messages,
  • It just pass them to the destination application

Event Hubs

  • provide event and telemetry ingress to the cloud at massive scale, with low latency and high reliability

Creating a Service Bus Namespace

To begin using Service Bus, you have to create a service bus namespace. Then you can create named queues, topics, relays and event hubs inside a namespace. Applications want to connect to the service bus need to provide these information as an address for using service bus resources.

Service Bus Authentication

There are two ways for the applications to authenticate to Azure Service Bus. “Shared Access Signature (SAS)” authentication, or “Azure Active Directory Access Control Service (ACS)”. The SAS is now the default authentication.

When you used to create a service bus namespace, for example democrm.servicebus.windows.net, a companion ACS namespace was provisioned by default at democrm-sb.accesscontrol.windows.net. This was changed by August 2014. Now when you create a service bus namespace a SharedAccessAuthorizationRule with KeyName set to RootManageSharedAccessKey is created by default. How this change affected Dynamics CRM integration part, is discussed ahead.

Elements of Dynamics CRM-Azure Integration

Before we go to discuss and create a sample integration between Microsoft Azure Service Bus and Dynamics CRM it is worthwhile to go through how this integration works. This will help understanding the sample scenario.

Service Endpoint

To integrate Dynamics CRM with Azure service bus we need to register a service endpoint in CRM organization using plugin registration tool. Service endpoint represents a Microsoft Azure platform endpoint. When we register a service endpoint Dynamics CRM configures service identities, rule groups and number of other settings for us in Microsoft Azure that otherwise we would have to configure manually through our service bus’s ACS Management Portal.

Out-of-the-box Azure-aware Plugin

After registering a Service Endpoint, we need to register a plugin step inside the registered service endpoint to define what message and entity combination should trigger the plugin to execute. The service endpoint will then use the internal, out-of-the-box, Azure-aware plugin (ServiceBusPlugin) to post the execution context to the Azure Service Bus. Then the Azure listener solution will take charge of the execution context from the Azure Service Bus.

Custom Azure-aware Plugin

The OOB plugin can post execution context to the Azure but it can’t use any string data returned from the Azure Service Bus (where bi-directional relay service is used). If you need string data back from the listener you need to write your own custom plugin that is “Azure aware” instead of registering a step inside a Service Endpoint. Writing a custom plugin is just similar to writing an ordinary Dynamics CRM plugin except that the plugin must include code to initiate posting the execution context to the Azure service bus.

Whether you use OOB plugin or custom Azure-aware plugin, you have to register a Service Endpoint mentioned earlier because a custom Azure-aware plugin code will still use the Service Endpoint, configured with Azure Service Bus, to post the execution context to the Azure.

Azure listener solution

For the CRM-Azure integration there must be at least one listener solution in a Microsoft Azure Service Bus. For a relay endpoint contract, a listener application must be actively listening on the Service Bus endpoint for the CRM request. For a queue endpoint contract, a listener application doesn’t have to be actively listening.

A listener solution should be CRM-aware so that it can listen and read the CRM execution context from the service bus. We can made a listener “CRM-Aware” by adding Microsoft.Xrm.Sdk assembly so that we can define RemoteExecutionContext type.

Posted in Dynamics CRM, Dynamics CRM - Customization and Configuration, Dynamics CRM - Development, Microsoft Azure, Microsoft Azure - Srevice Bus

FetchXMLResultViewer–A Dynamics CRM tool

Hello everyone,

I recently released my first Dynamics CRM tool under MIT License. You may download FetchXMLResultViewer from GitHub. Here is the short description of it.

It’s a small windows application built on .NET Framework 4.5.2, that takes FetchXML string as an input and displays the resulting CRM data using Windows Form’s DataGridView. Once you fetched the CRM data, you may export it to a CSV file for various purposes.

The tool is very handy to quickly see the results of the given FetchXML in an easy readable grid format. You may use it to quickly tweak your FetchXML on “hit and try” basis.’

While exporting results to CSV file, I also included lookup name values as well as lookup GUIDs. This is something that was missing in built in “Export to Excel” functionality that we use from within Dynamics CRM application. The Export to Excel functionality (re-written in CRM 2015 Update 1) now only exports the GUID of primary entity and ignores the GUIDs of other lookup attributes. Thanks to the Joe Newstorm whose facebook post in the Dynamics CRM group inspired me to undertake this work.

I need your feedback about how you see the tool is useful for the developers. Also you can suggest more features or you may directly fork the project’s GitHub repository, work on your suggestion and submit it back to be synced in the master repository.

Upcoming improvements:

  • Error logging to a file.
  • Export as a Microsoft Excel file
  • Export as XML
  • Displaying the descriptions/text for Boolean (two options) and OptionSetValue (currently only values and true/false are being fetched for OptionSet and Two Option attributes)
  • Beautification of the application from (especially toolstrip icons that are bit unimpressive, due to the lack of my GD skills)
  • Paging of results

I would be more than happy for any contributions on this project.

Stay blessed and happy CRMing Smile

Credits: The FetchXMLResultViwer application is using MscrmTools.Xrm.Connection by MscrmTools

Download Link: https://github.com/khadimali/FetchXMLResultViewer

FetchXMLResultViewer - Snapshot

Posted in Dynamics CRM, Dynamics CRM - Development, Dynamics CRM - Tools & Utilities

Android Development – Fragments

In this post:

What is a fragment?

General Concepts

Creating a Fragment

Subclasses of fragments

Adding a User Interface

Adding a Fragment to an Activity

Adding a fragment without a UI

Managing Fragments

Performing Fragment Transactions

Communicating with the Activity

Creating event callbacks to the activity

Adding items to the Action Bar

Adding items to Context Menu

 

What is a fragment?

  • portion of user interface in an activity
  • modular section of an activity
    • that has it’s own lifecycle
    • receives its own input events
    • that you can add or remove from the activity while the activity is running
  • sort of like a “sub activity” that you can reuse in different activities

 

General concepts

  • Multiple fragments can be combined in a single activity to:
    • build a multi-pane UI
    • reuse a fragment in multiple activities

 

  • A fragment must always be embedded in an activity
  • It’s lifecycle is directly affected by the host activity’s lifecycle
    • when the activity is paused or destroyed, so are all the fragments in it
  • When the activity is running (in resumed lifecycle state) you can manipulate each fragment independently (e.g. add or remove them)
  • When you perform such a fragment transaction, you can also add it to a back stack that is managed by the activity

Back stack

The back stack allows user to reverse a fragment transaction (navigate backward) by pressing the Back button

 

  • Fragment lives in a ViewGroup inside the activity’s view hierarchy
  • defines its own view layout
  • can be inserted into the activity’s layout by declaring fragment in the activity’s layout file
    • as a <fragment> element
    • from your application code, by adding it to an existing ViewGroup

 

  • However, fragment is not required to be a part of the activity layout (UI screen), you may use a fragment as an invisible worker for the activity

 

Creating a Fragment

  • Create a sub class of Fragment
  • The Fragment class code looks a lot like Activity
    • callback methods similar to an activity – onCreate(), onStart(), onPause() ….
    • converting an existing android app to use fragments might simply be a moving of code from your activity’s callback methods into the respective callback methods of your fragment
  • Usually you should implement at least following lifecycle methods:
    • onCreate()
      • called when the fragment is being created
      • initialize here the essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed
    • onCreateView()
      • called when the fragment’s user interface is drawn for the first time
      • return a View from this method that is root of your fragments layout
      • or; return null if the fragment doesn’t provide a UI
    • onPause()
      • called (as the first indication) when the user is leaving the fragment
      • doesn’t always mean fragment is being destroyed
      • here you should persist the changes beyond the current user session (because the user might not come back
  • There are several other callback methods that you should implement to handle various stages of fragment lifecycle. Discussed in more detail in the section about Handling the Fragment Lifecycle

 

Subclasses of fragments

  • Few sub classes that you might want to extend instead of base Fragment class

 

Adding a User Interface

  • To provide a layout for a fragment, must implement the onCreateView() callback
    method

    • must return a View that is the root of your fragment’s layout
      • If your fragment is a subclass of ListFragment, the default implementation returns a ListView, so you don’t need to implement it
    • onCreateView() provides three parameters
      • a LayoutInflator object
        • to help inflate a layout
        • To return a layout, inflate it from a layout resource defined in XML
      • container parameter
        • is the parent ViewGroup (from the activity’s layout) in which your fragment layout will be inserted
      • savedInstanceState parameter
        • is a Bundle that provides data about the previous instance of the fragment, if the fragment
          is being resumed
    • The inflate() method takes three parameters
      • R.layout.example_fragment
        • The resource ID of the layout you want to inflate
      • container
        • The ViewGroup to be the parent of the inflated layout
        • important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it’s going
      • false
        • A boolean indicating whether the inflated layout should be attached to the ViewGroup
          during inflation (False because system is already inserting the inflated layout into the container)

 

Snippet

public static class ExampleFragment extends Fragment {

   @Override

   public View
onCreateView
(LayoutInflater inflater, ViewGroup
container
,

                            Bundle
savedInstanceState
) {

       //
Inflate the layout for this fragment

       return
inflater
.inflate(R.layout.example_fragment,
container
, false);

   }

}

 

Adding a Fragment to an Activity

  • Two ways
    • 1) Declare the fragment inside the activity’s layout file
      • specify layout properties for a fragment as if it were a view
      • example: a layout for an activity with two fragments

<?xml version=“1.0”
encoding
=“utf-8”?>

<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android&#8221;

   android:orientation=“horizontal”

   android:layout_width=“match_parent”

   android:layout_height=“match_parent”>

   <fragment android:name=“com.example.news.ArticleListFragment”

           android:id=“@+id/list”

           android:layout_weight=“1”

           android:layout_width=“0dp”

           android:layout_height=“match_parent” />

   <fragment android:name=“com.example.news.ArticleReaderFragment”

           android:id=“@+id/viewer”

           android:layout_weight=“2”

           android:layout_width=“0dp”

           android:layout_height=“match_parent” />

</LinearLayout>

      • android:name attribute specifies the Fragment class to instantiate in the layout
      • when system creates the activity layout
        • it instantiates each fragment specified in the layout
        • calls the onCreateView() method for each one, to retrieve each fragment’s layout
        • inserts the View returned by the fragment directly in place of <fragment> element
      • Each fragment requires a unique identifier
        • that the system can use to restore the fragment if the activity is restarted
        • that you can use to capture the fragment to perform transactions, such as remove it
        • Three ways to provide an ID for a fragment:
          • Provide the android:id attribute
          • Provide the android:tag attribute
          • If you provide neither of the two, the system uses the ID of the container view

 

    • 2) Programmatically add the fragment to an existing ViewGroup
      • You can add fragments to your activity layout any time while your activity is running
      • To make fragment transactions in your activity (add, remove, replace), you must use APIs from FragmentTransaction.
      • Get an instance of FragmentTransaction from you activity like this:

 

Snippet

FragmentManager fragmentManager = getFragmentManager();

FragmentTransaction
fragmentTransaction
= fragmentManager.beginTransaction();

 

      • Add a fragment using add() method.
        • Specify:
          • the ViewGroup in which to insert fragment (specify by resource ID
          • the fragment to add

 

Snippet

ExampleFragment fragment = new ExampleFragment();

fragmentTransaction.add(R.id.fragment_container, fragment);

fragmentTransaction.commit();

 

        • Must call commit() for the changes to take effect

 

Adding a fragment without a UI

  • You can add a fragment without a UI to provide a background behavior for the activity
  • To add a fragment without a UI
    • add the fragment from the activity using add(Fragment, string)
    • provide a unique string tag rather than a view ID
  • If the fragment doesn’t have a UI then the string tag is the only way to identify it using findFragmentByTag() method
  • This adds a fragment but doesn’t receive a call to onCreateView(), so don’t need to implement that method
  • FragmentRetainInstance.java sample in SDK (available through the SDK manager), located in your system as <sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java.

 

Managing Fragments

  • To manage fragments in your activity you need to use FragmentManager
  • call getFragmentManager() from your activity to get fragment manager
  • Things that you can do with FragmentManager include:
    • Get fragments that exist in the activity
      • with findFragmentById() – for fragments that have UI
      • findFragmentByTag() – for fragments that don’t have UI
    • Pop fragments off the back stack, with popBackStack() – simulating a Back command by user
    • Register a listener for changes to the back stack, with addOnBackStackChangedListener()
    • Open a fragment transaction that allows you to perform transactions such as add and remove fragments

            (For more information refer to FragmentManager class documentation)

 

Performing Fragment Transactions

  • Great feature about using fragments in your activity is the ability to add, remove, replace and perform other actions with them, in response to user interaction
  • Each set of changes that you commit to activity at the same time, is called a transaction (performed using APIs in FragmentTransaction)
  • Each transaction can be saved to a back stack managed by the activity, allowing user to navigate backward
  • Call commit() to apply the transaction to the activity
  • To add the transaction to a back stack you may call addToBackStack() before calling commit()

 

Snippet

//
Create new fragment and transaction

Fragment
newFragment
= new ExampleFragment();

FragmentTransaction
transaction
= getFragmentManager().beginTransaction();

 

//
Replace whatever is in the fragment_container view with this fragment,

//
and add the transaction to the back stack

transaction.replace(R.id.fragment_container,
newFragment
);

transaction.addToBackStack(null);

 

//
Commit the transaction

transaction.commit();

 

  • If you add multiple changes to the transaction [such as another add() or remove()] and call addToBackStack(), then
    • all the changes before you call commit() are added to the back stack as a single transaction
    • the Back button will reverse them all together
  • The order in which you add changes to a FragmentTransaction doesn’t matter, except:
    • You must call commit() last
    • The order in which you add fragments to the same container, determines the order they appear in the view hierarchy
  • If you do not call addToBackStack() when you perform a transaction that removes a fragment:
    • then that fragment is destroyed when the transaction is committed
    • the user cannot navigate back to it.
  • if you do call addToBackStack() when removing a fragment:
    • then the fragment is stopped
    • It will be resumed if the user navigates back.
  • Calling commit() does not perform the transaction immediately
    • (Rather) it schedules it to run on the activity’s UI thread (the “main” thread) as soon as the thread is able to do so
    • If necessary, however, you may call executePendingTransactions() from your UI thread to immediately execute transactions submitted by commit()
    • Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads

 

Communicating with the Activity

  • The fragment can access the Activity instance with getActivity() and easily perform tasks on the activity, such as finding a view in the activity layout

 

Snippet

View listView = getActivity().findViewById(R.id.list);

 

  • Similarly, your activity can call methods in the fragment by seeking a reference to the Fragment
    from FragmentManager by ID or by tag

 

Snippet

ExampleFragment
fragment
= (ExampleFragment)
getFragmentManager
().findFragmentById(R.id.example_fragment);

 

Creating event callbacks to the activity

  • To share fragment events with the activity
    • define a callback interface inside the fragment; and
    • require that the host activity must implement it
  • When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary
  • Example:
    • A news application that has two fragments in an activity – one to show a list of articles (fragment A) and another to display an article (fragment B)
    • Fragment A must tell the activity when a list item is selected
    • Activity (upon listening the fragment A) can tell the fragment B to display the article
    • In this case, the OnArticleSelectedListener interface is declared inside fragment A

 

Snippet

public static class FragmentA extends ListFragment {

   

   //
Container Activity must implement this interface

   public interface OnArticleSelectedListener {

       public void
onArticleSelected
(Uri articleUri);

   }

   

}

 

    • The activity that hosts the fragment implements the OnArticleSelectedListener interface and overrides onArticleSelected() to notify fragment B of the event from fragment A
    • To ensure that host activity implements this interface, fragment A’s onAttach() callback method instantiates an instance of OnArticleSelectedListener by casting the Activity that is passed into onAttach()

 

Snippet

public static class FragmentA extends ListFragment {

   OnArticleSelectedListener
mListener
;

   

   @Override

   public void
onAttach
(Activity activity) {

       super.onAttach(activity);

       try {

           mListener
= (OnArticleSelectedListener)
activity
;

       } catch (ClassCastException e) {

           throw new ClassCastException(activity.toString() +
must implement OnArticleSelectedListener”
);

       }

   }

   

}

 

    • If the activity has not implemented the interface, then the fragment will throw a ClassCastException
    • If the activity has implemented the interface, the mListener will hold a reference to activity’s implementation of OnArticleSelectedListener, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener interface
    • For example, if the fragment A is an extension of ListFragment, each time the user clicks a list item, the system calls onListItemClick() in the fragment which then calls mListener.onArticleSelected() to share the event with the activity

 

Snippet

 

public static class FragmentA extends ListFragment {

   OnArticleSelectedListener
mListener
;

   

   @Override    public void
onListItemClick
(ListView l, View v, int position, long id) {

       // Append the clicked item’s row ID with the content provider Uri

       Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);

       // Send the event and Uri to the host activity

       mListener.onArticleSelected(noteUri);

   }

   

}

 

    • The id parameter passed to onListItemClick() is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application’s ContentProvider
    • More information about content provider is availbe in the Content Providers document

 

Adding items to the Action Bar

  • To add menu items from fragment to the activity’s Option Menu and the Action Bar:
    • call setHasOptionsMenu during fragment’s onCreate(), to indicate that the fragment would like to add items to the Option Menu – otherwise, it will not receive a call to onCreateOptionsMenu()
    • implement the onCreateOptionsMenu()
  • Items added to the Options Menu from the fragment are appended to the existing menu items
  • Fragment receives callbacks to onOptionsItemSelected() when a menu item is selected

 

Adding items to Context Menu

  • To register a view in your fragment layout to provide a context menu, call registerForContextMenu()
  • When user opens context menu, the fragment receives a call to onCreateContextMenu()
  • When user selects an item, the fragment receives call to onContextItemSelected()

 

Keep in mind that:

  • First, the host activity receives an on-item-selected callback for Context Menu or Options Menu menu items
  • If activity doesn’t handle the selected item, then the event is passed to the fragment’s callback


Reference

http://developer.android.com/guide/components/fragments.html

 

Videos

 

Tagged with: ,
Posted in Android Development

Android Development – Detecting Common Gestures

Gestures allow users to interact with an app via touch gestures

Detecting Common Gestures


In this Post:

How touch gesture occurs?

Two phases of gesture detection

Support Library Classes

Gather Data about touch events

Capturing touch events (Custom gestures processing)

Capturing touch events for a single view

Detecting Gestures

Detecting all supported Gestures

Detecting a subset of supported Gestures

Caution

Useful resources


  • How touch gesture occurs on an Android phone?
    • When a user places one or more fingers on the screen, plus
    • Your application interprets that pattern of touches as a particular gesture
  • Two phases of gesture detection
    • Gathering data about touch event(s)
    • Interpreting the data to see if it meets the criteria for any of the gestures your app
      supports
  • Support Library Classes (in the Support Library)
    • Use Support Library classes where possible to provide compatibility with devices running Android 1.6 and higher
    • Examples below will use these classes:
      • GestureDetectorCompat
      • MotionEventCompat
        • Is not a replacement for MotionEvent class
        • Rather provides static utility methods to which you pass MotionEvent object in order to receive the desired action associated with that event

Gathering data about touch events

  • When user places one or more finger on the screen, the onTouchEvent() callback is triggered on the View that received the touch events
  • For each sequence of touch events (position, pressure, size, addition of another finger) that is ultimately identified as a gesture, onTouchEvent() is fired several times
  • Throughout a single interaction (when the user first touches the screen until leaving the screen), the MotionEvent
    delivered to onTouchEvent() provides the details of every interaction.

 

Capturing touch events for an Activity or View (Custom gestures)

  • A kind of processing you would have to do for custom gesture
  • Intercept touch events in an Activity or View, by overriding onTouchEvent() callback
  • Use getActionMasked() to extract the action the user performed from the event parameter.
    This gives you the raw data you need to determine if a gesture you care about occurred

 

Snippet

 

public class MainActivity extends Activity {

//
This example shows an Activity, but you would use the same approach if

//you were subclassing a View.

@Override

public boolean onTouchEvent(MotionEvent event){

      

   int action = MotionEventCompat.getActionMasked(event);

      

   switch(action) {

       case (MotionEvent.ACTION_DOWN) :

           Log.d(DEBUG_TAG,“Action was DOWN”);

           return true;

       case (MotionEvent.ACTION_MOVE) :

           Log.d(DEBUG_TAG,“Action was MOVE”);

           return true;

       case (MotionEvent.ACTION_UP) :

           Log.d(DEBUG_TAG,“Action was UP”);

           return true;

       case (MotionEvent.ACTION_CANCEL) :

           Log.d(DEBUG_TAG,“Action was CANCEL”);

           return true;

       case (MotionEvent.ACTION_OUTSIDE) :

           Log.d(DEBUG_TAG,“Movement occurred outside bounds of current screen element”);

           return true;

       default :

           return super.onTouchEvent(event);

   }

}

 

  • Do your own processing to determine if a gesture occurred
  • If your app uses common gestures you (such as double tap, long press and fling) you can take advantage of GestureDetector class
  • GestureDetector makes it easy for you to detect common gestures without processing individual touch events

 

Capturing touch events for a single view

  • As an alternative to onTouchEvent() you can attach View.OnTouchListener object to any view object using the
    setOnTouchListener() method
  • This makes it possible to listen for touch events without subclassing an existing View

 

Snippet  

 

View
myView
= findViewById(R.id.my_view);

myView.setOnTouchListener(new OnTouchListener() {

   public boolean
onTouch
(View v, MotionEvent event) {

       //
… Respond to touch events      

       return true;

   }

});

 

Beware

  • ACTION_DOWN event is the starting point for all the touch events
  • So creating a listener that returns false for the ACTION_DOWN event will stop the calling for
    subsequent ACTION_MOVE and ACTION_UP events

 

Detecting Gestures

  • Use GestureDetector class for detecting common gestures – onDown(), onLongPress(), onFling() and so on
  • Use GestureDetector in conjunction with onTouchEvent() method described above

 

Detecting all supported Gestures

  • GestureDetectorCompat object takes a class, that implements the GestureDetector.OnGestureListener interface, as a parameter
  • GestureDetector.OnGestureListener notifies users when a particular touch event has occurred
  • To enable your GestureDetector object to receive events, override the View or Activity’s onTouchEvent() method, and pass along all observed events to the detector instance.
  • In the following snippet, a return value of true from the individual on<TouchEvent> methods indicates that you have handled the touch event.
  • A return value of false passes events down through the view stack until the touch has been successfully handled
  • Run the following snippet to watch
    • Actions that are triggered when you interact with the touch screen
    • Contents of the MotionEvent for each touch event for even simple interactions

 

Snippet

 

public class MainActivity extends Activity implements

       GestureDetector.OnGestureListener,

       GestureDetector.OnDoubleTapListener{

  

   private static final String DEBUG_TAG = “Gestures”;

   private GestureDetectorCompat mDetector;

 

   // Called when the activity is first created.

   @Override

   public void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       // Instantiate the gesture detector with the

       // application context and an implementation of

       // GestureDetector.OnGestureListener

       mDetector = new GestureDetectorCompat(this,this);

       // Set the gesture detector as the double tap

       // listener.

       mDetector.setOnDoubleTapListener(this);

   }

 

   @Override

   public boolean onTouchEvent(MotionEvent event){

       this.mDetector.onTouchEvent(event);

       // Be sure to call the superclass implementation

       return super.onTouchEvent(event);

   }

 

   @Override

   public boolean
onDown
(MotionEvent event) {

       Log.d(DEBUG_TAG,“onDown: “ + event.toString());

       return true;

   }

 

   @Override

   public boolean
onFling
(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {

       Log.d(DEBUG_TAG, “onFling: “ + event1.toString()+event2.toString());

       return true;

   }

 

   @Override

   public void
onLongPress
(MotionEvent event) {

       Log.d(DEBUG_TAG, “onLongPress: “ + event.toString());

   }

 

   @Override

   public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,

           float distanceY) {

       Log.d(DEBUG_TAG, “onScroll: “ + e1.toString()+e2.toString());

       return true;

   }

 

   @Override

   public void onShowPress(MotionEvent event) {

       Log.d(DEBUG_TAG, “onShowPress: “ + event.toString());

   }

 

   @Override

   public boolean onSingleTapUp(MotionEvent event) {

       Log.d(DEBUG_TAG, “onSingleTapUp: “ + event.toString());

       return true;

   }

 

   @Override

   public boolean onDoubleTap(MotionEvent event) {

       Log.d(DEBUG_TAG, “onDoubleTap: “ + event.toString());

       return true;

   }

 

   @Override

   public boolean
onDoubleTapEvent
(MotionEvent event) {

       Log.d(DEBUG_TAG, “onDoubleTapEvent: “ + event.toString());

       return true;

   }

 

   @Override

   public boolean
onSingleTapConfirmed
(MotionEvent event) {

       Log.d(DEBUG_TAG, “onSingleTapConfirmed: “ + event.toString());

       return true;

   }

}

 

Detecting a Subset of Supported Gestures

  • If you only want to process a few gestures, you can extend GestureDetector.SimpleOnGestureListener
    interface
  • SimpleOnGestureListener provides an implementation for all of the on<TouchEvent> methods by returning
    false
    for all of them. You can override only the methods you care about
  • The example below creates a class that extends GestureDetector.SimpleOnGestureListener and overrides
    onFling() and onDown()

 

Snippet

 

public class MainActivity extends Activity {

  

   private GestureDetectorCompat
mDetector
;

 

   @Override

   public void
onCreate
(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       mDetector = new GestureDetectorCompat(this, new MyGestureListener());

   }

 

   @Override

   public boolean onTouchEvent(MotionEvent event){

       this.mDetector.onTouchEvent(event);

       return super.onTouchEvent(event);

   }

  

   class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

       private static final String DEBUG_TAG = “Gestures”;

      

       @Override

       public boolean onDown(MotionEvent event) {

           Log.d(DEBUG_TAG,“onDown: “ + event.toString());

           return true;

       }

 

       @Override

       public boolean onFling(MotionEvent event1, MotionEvent event2float velocityX, 

float velocityY) {

           Log.d(DEBUG_TAG, “onFling: “ + event1.toString()+event2.toString());

           return true;

       }

   }

}

 

Caution

  • App should not depend on touch gestures for basic behaviors because gestures may not be available to all the users in all contexts
  • Follow accepted android conventions for touch gestures

 

Useful resources

 

Reference

http://developer.android.com/training/gestures/detector.html

 

Training Videos found on YouTube

Tagged with: ,
Posted in Android Development

Microsoft Dynamics CRM 2013 – Real-time Workflows


Real-time workflows are a new feature in Dynamics CRM 2013. Concepts required to understand Real-time Workflows:

In this post:

Real-time Workflows

Infinite loop detection

Real-time workflow activation

When to use Real-time workflows?

Converting between real-time and background workflows

Initiating real-time workflows before or after status changes

Real-time Workflows

  • Real-time workflows run immediately (synchronously) as soon as the event is raised

  • They do not allow for wait conditions. Since they execute in the synchronous fashion they cannot wait for any periods of time

  • Background workflows can be converted to real-time workflows as long as they do not use wait conditions

  • Real-time workflows support pre and post pipeline stages (can additionally be configured to be run before or after certain events)

  • Real-time workflows can be executed in one of the two different security contexts:

    • Owner, or

    • The user who made changes to the record

  • To activate real-time workflows a user must have the Activate Real-time Processes privilege

  • Real-time workflow run in the same transaction as the event that they are being triggered for. So if there is any errors or issues the entire operation will be rolled back. This is in consistency with the plugins development.

Additionally,

  • Simple validation scenarios can be met with these real-time workflows because we can execute our conditions and actions in the pre-stage of the pipeline

  • Reduces dependency on writing synchronous plugins for enforcing different business processes

  • Saves effort that goes behind maintaining the code base for a plugin

  • Allows non-technical users to be able to enforce complex business processes without writing any code

Infinite loop detection

If there is a situation in which a workflow is executing within a short period of time more than eight times then the infinite loop detection would kick in and prevent any damage to the server resources as well as performance overhead. Workflow failure will also specifically state that the workflow job was cancelled due to the fact that the workflow had started an infinite loop.

Real-time workflow activation

After the activation the real-time workflow will be registered as a step in your SDK message processing and plugin will get fired during the main operation then. The step gets deleted as soon as the workflow gets deactivated by the user.

When to use Real-time workflows?

  • Real-time workflows should be used with care

  • Background workflows are generally recommended because

    • They allow the system to apply them as resources on the server are available

    • Help maintain the best performance for everyone using the system

    • They are fine for most automation of business processes because the people using the system don’t need to be consciously aware that the process is running

  • Background workflow drawback

    • Actions defined by background workflows are not immediate

    • Generally take few minutes to apply the workflow

  • Use real-time workflow

    • When a business process requires someone to immediately see the results of the process

      • For example, you want to set certain default values for a record the first time it is saved

      • Or you want to make sure that some records are not deleted

    • If you want the abilityto cancel an operation

Converting between real-time and background workflows

  • You can change a real-time workflow into a background workflow by choosing Convert to a background workflow on the toolbar.

  • You can change a background workflow into a real-time workflow by choosing Convert to a real-time workflow on the toolbar.

    • If the background workflow uses a wait conditions it will become invalid and you won’t be able to activate it until you remove the wait condition.

Initiating real-time workflows before or after status changes

  • When you configure Options for Automatic Processes for real-time workflows, the Start When options for the status changes event let you select After or Before for when status changes. The default option is After.

  • When you select Before you are saying that you want the logic in the workflow to be applied before data changing the status is saved.

    • This provides you with the ability to check the values before other logic has been applied after the operation and prevent further logic from being performed.

Using the Stop Workflow action with real-time workflows

  • When you apply a Stop Workflow action in a workflow you have the option to specify a status condition that can be either Succeeded or Canceled.

  • When you set the status to canceled, you prevent the operation. An error message containing the text from the stop action status message will be displayed to the user with the heading Business Process Error.


Reference:Microsoft Dynamics CRM 2013 Implementation Guide

Video: Real Time WorkFlows CRM 2013

(The video is although in Russian language, but while watching it you will somehow get the idea behind the Real-time workflows.)

Tagged with: , , , , , ,
Posted in Dynamics CRM, Dynamics CRM - Customization and Configuration

Dynamics CRM 2013 – Workflow Processes (Part 2)

This post is in continuation with the previous blog post Dynamics CRM 2013 – Workflow Processes (Part 1)

In this post:

Workflow stages and steps

Actions that workflow processes can perform

Setting record values

Setting conditions for workflow actions

Workflow stages and steps

  • While designing workflows you have the option to contain the workflow steps in stages

  • Stages

    • Makes the workflow logic easier to read

    • Explain the workflow logic

    • Do not affect the logic or behavior of workflows

    • If a process has stages all the steps within the process must be contained within a stage

  • Steps

    • Are a unit of business logic within a workflow

    • Steps can include conditions, actions, other steps or a combination of these elements

Actions that workflow processes can perform

Workflow processes can perform the actions listed in the following table (See figure 1 below)

Action

Description

Create Record

  • Creates a new record for an entity you choose and assigns values

Update Record

  • You can update

    • The record that the workflow is running on

    • Any of the records that are related to current record with an N:1 relationship

    • Any records created by earlier steps

Assign Record

  • You can assign

    • The record that the workflow is running on

    • Any of the records that are related to current record with an N:1 relationship

    • Any records created by earlier steps

Send Email

  • Sends an email

  • You can choose to create a new email message or use an email template configured for

    • the entity of the record that the workflow is running on

    • any entities that have an N:1 relationship with the entity

    • the entity for any records created by earlier steps

Start Child Workflow

  • Starts a workflow process that has been configured as a child workflow

Change Status

  • Changes the status of the record

    • that the process is running on

    • Any of the records that are related to current record with an N:1 relationship

    • Any records created by earlier steps

Stop Workflow

  • Stops the current workflow

  • You can set a status of either Succeeded or Canceled and specify a status message

Custom Step

Provides extensions to the logical elements available by default in CRM. Steps can include conditions, actions, other steps, or a combination of these elements. Developers can create custom workflow steps. By default, there are no custom steps available in CRM. For more information for developers, see the Microsoft Dynamics CRM SDK topicCustom workflow activities (workflow assemblies).

Actions that workflow processes can perform

1. Actions that workflow processes can perform

Setting record values

  • When you click Set Properties, a dialog opens showing you the default form for the entity

    • At the bottom of the dialog you can see a list of additional fields not present in the top portion of the form

  • When you create a record you can set values for the record

  • When you update a record you can set, append, increment, decrement, multiply, or clear values

  • For any field, you can set a static value and that will be set by the workflow

  • On the right side of the dialog the Form Assistant gives you the ability to set or append dynamic values from the context of the current record

    • This includes values from related records that can be accessed from the N:1 (many-to-one) relationships for the entity

    • The options available in the Form Assistant depend on the field you have selected in the form

    • When you set a dynamic value, you will see a yellow placeholder known as a ‘slug’ that shows where the dynamic data will be included

    • To remove the value, just select the slug and delete it

  • For text fields, you can use a combination of static and dynamic data

  • With dynamic values you don’t know for certain that a field or related entity has the value you want to set. So;

    • You can actually set a number of fields to try and set the value and sort them in order using the green arrows. If the first field doesn’t have data, the second field will be tried and so on. If none of the fields have data, you can specify a default value to be used.

Setting record values

2. Setting record values

Setting conditions for workflow actions

  • The actions that you will apply may depend on conditions

  • Several ways to set conditions and create branching logic to get the results you want

    • You can check values of the record that the workflow process is running on

    • Any of the records linked to that record with N:1 relationship

    • Values within the process itself (See figure 1 above)

Condition Type

Description

Check Condition

  • A logical “if-<condition> then” statement

  • You can check values for

    • The record that the workflow is running on

    • Any of the records related to the current record with an N:1 relationship

    • Any records created by earlier steps

  • Based on these values you can define additional steps when the condition is true

Conditional Branch

  • A logical “else-if-then” statement

  • You can add a conditional branch to define additional steps when the check condition returns false

Default Action

  • A logical “else” statement

  • To add a Default action in the workflow logic, select a check condition, conditional branch, wait condition, or parallel wait branch that you have previously defined

  • You can use a default action to define steps for all cases that don’t match the criteria defined in condition or branch elements

Wait Condition

  • Enables a background workflow to pause itself until the criteria defined by the condition have been met

  • Workflow starts again automatically when the criteria have been met

  • Real-time workflows can’t use wait conditions

Parallel Wait Branch

  • Defines an alternative wait condition for a background workflow with a corresponding set of additional steps that are performed only when the initial criterion is met

  • You can use parallel wait branches to create time limits in your workflow logic

  • They help prevent the workflow from waiting indefinitely until the criteria defined in a wait condition have been met

Custom Step

Provides extensions to the logical elements available by default in CRM. Steps can include conditions, actions, other steps, or a combination of these elements. Developers can create custom workflow steps. By default, there are no custom steps available in CRM. For more information for developers, see the Microsoft Dynamics CRM SDK topicCustom workflow activities (workflow assemblies).


Reference:Microsoft Dynamics CRM 2013 Implementation Guide

Video: Dynamics CRM 2011 Creating Workflows

(Video is although from 2011 version but comprehensive. Covering almost all the aspects of Workflows in Dynamics CRM 2013 except Real-time workflows.)

Tagged with: , , , , , ,
Posted in Dynamics CRM, Dynamics CRM - Customization and Configuration