Monday, December 10, 2012

CRM 2011, Authenticate With No Help



Since Office 365 authentication appeared, I had some troubles to authenticate from C# to CRM, (On premise, Online), but a few days ago, I found this helper that allows you to connect to any type of CRM environment, (On premise, Online with windows live id, or Online with office 365), enjoy :).
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Reflection;

// These namespaces are found in the Microsoft.Xrm.Sdk.dll assembly
// located in the SDK\bin folder of the SDK download.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using Microsoft.Crm.Sdk.Messages;

namespace Microsoft.Crm.Sdk.Samples
{
    /// <summary>
    /// Demonstrate how to do basic authentication using IServiceManagement and SecurityTokenResponse.
    /// </summary>
    class AuthenticateWithNoHelp
    {
        #region Class Level Members
        // To get discovery service address and organization unique name, 
        // Sign in to your CRM org and click Settings, Customization, Developer Resources.
        // On Developer Resource page, find the discovery service address under Service Endpoints and organization unique name under Your Organization Information.
        private String _discoveryServiceAddress = "https://disco.crm.dynamics.com/XRMServices/2011/Discovery.svc";
        private String _organizationUniqueName = "crmue";
        // Provide your user name and password.
        private String _userName = "sdk@crmue.onmicrosoft.com";
        private String _password = "ITG2install!";

        // Provide domain name for the On-Premises org.
        private String _domain = "mydomain";

        #endregion Class Level Members

        #region How To Sample Code
        /// <summary>
        /// 
        /// </summary>
        public void Run()
        {
            IServiceManagement<IDiscoveryService> serviceManagement =
                        ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
                        new Uri(_discoveryServiceAddress));
            AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;

            // Set the credentials.
            AuthenticationCredentials authCredentials = GetCredentials(endpointType);


            String organizationUri = String.Empty;
            // Get the discovery service proxy.
            using (DiscoveryServiceProxy discoveryProxy =
                GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
            {
                // Obtain organization information from the Discovery service. 
                if (discoveryProxy != null)
                {
                    // Obtain information about the organizations that the system user belongs to.
                    OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
                    // Obtains the Web address (Uri) of the target organization.
                    organizationUri = FindOrganization(_organizationUniqueName,
                        orgs.ToArray()).Endpoints[EndpointType.OrganizationService];

                }
            }


            if (!String.IsNullOrWhiteSpace(organizationUri))
            {
                IServiceManagement<IOrganizationService> orgServiceManagement =
                    ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
                    new Uri(organizationUri));

                // Set the credentials.
                AuthenticationCredentials credentials = GetCredentials(endpointType);

                // Get the organization service proxy.
                using (OrganizationServiceProxy organizationProxy =
                    GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
                {
                    // This statement is required to enable early-bound type support.
                    organizationProxy.EnableProxyTypes();

                    // Now make an SDK call with the organization service proxy.
                    // Display information about the logged on user.
                    Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
                        new WhoAmIRequest())).UserId;
                    SystemUser systemUser = organizationProxy.Retrieve("systemuser", userid,
                        new ColumnSet(new string[] { "firstname", "lastname" })).ToEntity<SystemUser>();
                    Console.WriteLine("Logged on user is {0} {1}.",
                        systemUser.FirstName, systemUser.LastName);
                }
            }

        }

        /// <summary>
        /// Obtain the AuthenticationCredentials based on AuthenticationProviderType.
        /// </summary>
        /// <param name="endpointType">An AuthenticationProviderType of the CRM environment.</param>
        /// <returns>Get filled credentials.</returns>
        private AuthenticationCredentials GetCredentials(AuthenticationProviderType endpointType)
        {

            AuthenticationCredentials authCredentials = new AuthenticationCredentials();
            switch (endpointType)
            {
                case AuthenticationProviderType.ActiveDirectory:
                    authCredentials.ClientCredentials.Windows.ClientCredential =
                        new System.Net.NetworkCredential(_userName,
                            _password,
                            _domain);
                    break;
                case AuthenticationProviderType.LiveId:
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    authCredentials.SupportingCredentials = new AuthenticationCredentials();
                    authCredentials.SupportingCredentials.ClientCredentials =
                        Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                    break;
                default: // For Federated and OnlineFederated environments.                    
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    // For OnlineFederated single-sign on, you could just use current UserPrincipalName instead of passing user name and password.
                    // authCredentials.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;  //Windows/Kerberos
                    break;
            }

            return authCredentials;
        }

        /// <summary>
        /// Discovers the organizations that the calling user belongs to.
        /// </summary>
        /// <param name="service">A Discovery service proxy instance.</param>
        /// <returns>Array containing detailed information on each organization that 
        /// the user belongs to.</returns>
        public OrganizationDetailCollection DiscoverOrganizations(
            IDiscoveryService service)
        {
            if (service == null) throw new ArgumentNullException("service");
            RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
            RetrieveOrganizationsResponse orgResponse =
                (RetrieveOrganizationsResponse)service.Execute(orgRequest);

            return orgResponse.Details;
        }

        /// <summary>
        /// Finds a specific organization detail in the array of organization details
        /// returned from the Discovery service.
        /// </summary>
        /// <param name="orgUniqueName">The unique name of the organization to find.</param>
        /// <param name="orgDetails">Array of organization detail object returned from the discovery service.</param>
        /// <returns>Organization details or null if the organization was not found.</returns>
        /// <seealso cref="DiscoveryOrganizations"/>
        public OrganizationDetail FindOrganization(string orgUniqueName,
            OrganizationDetail[] orgDetails)
        {
            if (String.IsNullOrWhiteSpace(orgUniqueName))
                throw new ArgumentNullException("orgUniqueName");
            if (orgDetails == null)
                throw new ArgumentNullException("orgDetails");
            OrganizationDetail orgDetail = null;

            foreach (OrganizationDetail detail in orgDetails)
            {
                if (String.Compare(detail.UniqueName, orgUniqueName,
                    StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    orgDetail = detail;
                    break;
                }
            }
            return orgDetail;
        }

        /// <summary>
        /// Generic method to obtain discovery/organization service proxy instance.
        /// </summary>
        /// <typeparam name="TService">
        /// Set IDiscoveryService or IOrganizationService type to request respective service proxy instance.
        /// </typeparam>
        /// <typeparam name="TProxy">
        /// Set the return type to either DiscoveryServiceProxy or OrganizationServiceProxy type based on TService type.
        /// </typeparam>
        /// <param name="serviceManagement">An instance of IServiceManagement</param>
        /// <param name="authCredentials">The user's Microsoft Dynamics CRM logon credentials.</param>
        /// <returns></returns>
        private TProxy GetProxy<TService, TProxy>(
            IServiceManagement<TService> serviceManagement,
            AuthenticationCredentials authCredentials)
            where TService : class
            where TProxy : ServiceProxy<TService>
        {
            Type classType = typeof(TProxy);

            if (serviceManagement.AuthenticationType !=
                AuthenticationProviderType.ActiveDirectory)
            {
                AuthenticationCredentials tokenCredentials =
                    serviceManagement.Authenticate(authCredentials);
                // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
                // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
                return (TProxy)classType
                    .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
                    .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
            }

            // Obtain discovery/organization service proxy for ActiveDirectory environment.
            // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
            return (TProxy)classType
                .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
                .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
        }

        #endregion How To Sample Code

        #region Main method

        /// <summary>
        /// Standard Main() method used by most SDK samples.
        /// </summary>
        /// <param name="args"></param>
        static public void Main(string[] args)
        {
            try
            {
                AuthenticateWithNoHelp app = new AuthenticateWithNoHelp();
                app.Run();
            }
            catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
            {
                Console.WriteLine("The application terminated with an error.");
                Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
                Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
                Console.WriteLine("Message: {0}", ex.Detail.Message);
                Console.WriteLine("Trace: {0}", ex.Detail.TraceText);
                Console.WriteLine("Inner Fault: {0}",
                    null == ex.Detail.InnerFault ? "Has Inner Fault" : "No 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 ? "Has Inner Fault" : "No Inner Fault");
            }
            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<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException
                        as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
                    if (fe != null)
                    {
                        Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
                        Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
                        Console.WriteLine("Message: {0}", fe.Detail.Message);
                        Console.WriteLine("Trace: {0}", fe.Detail.TraceText);
                        Console.WriteLine("Inner Fault: {0}",
                            null == fe.Detail.InnerFault ? "Has Inner Fault" : "No Inner Fault");
                    }
                }
            }
            // Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
            // SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.

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

You can find the original post here.

Tuesday, November 6, 2012

Xrm.Utility

Well, I was not aware of this new object created by Microsoft, since Microsoft Dynamics CRM 2011 Update Rollup 8. (http://msdn.microsoft.com/en-us/library/jj602956.aspx)

It has 2 function (both open a new browser window) called:

openEntityForm 
  Xrm.Utility.openEntityForm(name,id,parameters) 

Examples:
Open a new account record
Xrm.Utility.openEntityForm("account");
Open an existing account record
Xrm.Utility.openEntityForm("account","A85C0252-DF8B-E111-997C-00155D8A8410");

Open a new account record with a specific form and setting default values
var parameters = {};
parameters["formid"] = "b053a39a-041a-4356-acef-ddf00182762b";
parameters["name"] = "Test";
parameters["telephone1"] = "(425) 555-1234";
Xrm.Utility.openEntityForm("account", null, parameters);
Open a new contact record, move it to the top left corner of the screen, and set the size of the window 
NoteYou cannot use window object methods such as moveTo or resizeTo in scripts that will run in Microsoft Dynamics CRM for Microsoft Office Outlook.
var newWindow = Xrm.Utility.openEntityForm("contact");
newWindow.moveTo(0,0);
newWindow.resizeTo(800,600);
openWebResource

    Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)
Examples:
Open an HTML web resource named “new_webResource.htm”:Xrm.Utility.openWebResource("new_webResource.htm");
Open an HTML web resource including a single item of data for the data parameter”Xrm.Utility.openWebResource("new_webResource.htm","dataItemValue");
Open an HTML web resource passing multiple values through the data parameter
var customParameters = encodeURIComponent("first=First Value&second=Second Value&third=Third Value"); Xrm.Utility.openWebResource("new_webResource.htm",customParameters); 
NoteThese values have to be extracted from the value of the data parameter in the HTML web resource. For more information, see Sample: Pass Multiple Values to a Web Resource Through the Data Parameter.
Open an HTML web resource with the parameters expected by HTML web resources:
Xrm.Utility.openWebResource("new_webResource.htm?typename=account&userlcid=1033");




Wednesday, October 31, 2012

CRM 2011 Recurring workflows - Running only one instance at the same time

Maybe some of you already read the post of how to implement a recurring workflow in Dynamics CRM 2011, I have read it from http://crmbusiness.wordpress.com/2011/05/24/crm-2011-how-to-schedule-recurring-workflows-in-crm-2011/ , the article is copied below.

When I implemented this approach with a client, I had the next problem, The user was clicking on a ribbon button and that button was calling a JScript code that performed a call to a workflow using something similar to this: (http://andreaswijayablog.blogspot.com/2011/07/crm-2011-custom-button-on-custom-entity.html)

function callworkfow(id) {
    try {
        var guid;

        if (id == null) {
            guid = Xrm.Page.data.entity.getId();
        }
        else
            guid = id;

        // assign workflow guid
        var WorkflowId = "89BA3166-948E-4B12-8A55-4BE01DEDAB0B";

        var xml = "" +
    "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
    "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
    Xrm.Page.context.getAuthenticationHeader() +
    "<soap:Body>" +
    "<execute xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
    "<request xsi:type=\"ExecuteWorkflowRequest\">" +
    "<entityid>" + guid + "</EntityId>" +
    "<workflowid>" + WorkflowId + "</WorkflowId>" + //WorkflowId = guid of the workflow
    "</Request>" +
    "</Execute>" +
    "</soap:Body>" +
    "</soap:Envelope>";

        var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
        xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/Execute");
        xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
        xmlHttpRequest.send(xml);

        var resultXml = xmlHttpRequest.responseXML;

        if (id == null)
            alert("Success");
        return (resultXml.xml);
    }
    catch (e) {
        alert("Failed to Execute");
    }
}


But, the problem here was that I needed to have only one instance of the workflow running at the same time, and the way it was implemented was creating a new instance of the workflow everytime the button was clicked, and as far as I know the CRM webservice does not have a way to retrieve Async Operations in case I need to be sure that any instance of the workflow was running before calling it, and neither the Plugins can be attached to Async Operations, so.. (If you already followed the tutorial from http://crmbusiness.wordpress.com/2011/05/24/crm-2011-how-to-schedule-recurring-workflows-in-crm-2011/ ), what I did to solve this problem is the next:


Change the workflow to run only as Child and on i.e. Appointments CREATION

---------------  USER ---------------------------------------------------------------------------------------------------------------------
- User clicks on the ribbon button, this will trigger the jscript code
-------------------------------------------------------------------------------------------------------------------------------------------------

--------------- JSCRIPT Code that will be called from the ribbon button------------------------------------------------
- A jscript code searches for an appointment with subject "Only one workflow instance"
   - If the appointment is found, then do nothing.. (Because this means that the workflow is running already)
   - But if the appointment was not found, then  CREATE an appointment with subject "Only one workflow instance", this will trigger the workflow.
--------------------------------------------------------------------------------------------------------------------------------------------------

--------------  WORKFLOW process -------------------------------------------------------------------------------------------------
- Workflow starts
- Do the work that needs to do..
- Waits X time
- Calls itself as again (This starts a new iteration)..
- Workflow ends..
--------------------------------------------------------------------------------------------------------------------------------------------------

Also you can manage it using a plugin that triggers on the pre-create of i.e. Appointment.

I hope this helps!

Tuesday, September 4, 2012

Resco - Mobile CRM for Microsoft Dynamics

If you need to create mobile clients for Dynamics CRM, this is a complete solution to do that, is called Resco (http://www.resco.net/MobileCRM/).

I am currently learning how to use it and to develop with its SDK, I will try to set a tutorial when I have learned it.


6 Key reasons why Resco Mobile CRM
is the best solution in the market


1 - Best features, always ahead of its competitors

Mobility has been a key specialization for Resco since 1999. We have worked with over 3,500 customers on their various mobile projects. We are pioneers in this fast growing segment with the most experience in mobile software from the consumer, developer and business perspective. This is the main reason why Resco Mobile CRM is the best featured and technologically the most rapidly evolving mobile CRM solution in the world.

2 - Flexibility with frequent updates

We listen to our partners and customers and realize most of their suggestions in a reasonable timeframe. We usually release at least 4 major releases a year while all major releases bring significant new features. In the meantime there are many updates and bug fixes based on the requests from our customers, so they have a fix available in hours or days, instead of months or years.

3 - Platform independent solution with consistent UI

All competitive products have been developed for each mobile platform separately. This resulted in multiple effort and the final applications have huge differences in UI and supported features.
Instead of that, Resco has used its platform independent technology and only one developer team concentrating on CRM features instead of dealing with platform specific issues. This resulted in significantly lower development time needed, and the final application has the same UI and supported features on all mobile platforms.

4 - Assurance, the only SDK with source code

Although our solution provides the same configurator tool allowing configuration of the mobile app as all other competitors, Resco Mobile CRM is the only solution which can provide its customers also with a platform independent SDK. This .NET based developer platform allows unlimited customizations of the mobile app and can be understood also as a customer assurance. Thanks to this tool, our customers become independent from Resco, the solution vendor, since they can make any changes or add new features anytime they need them.

5 - HTML5, the future technology is already available

While the others only speak, Resco acts. Resco Mobile CRM is the only solution in its segment with real support of HTML5. Thanks to this promising technology we allow our partners and customers to extend the UI and functionality of Resco Mobile CRM by web technologies and designs.

6 - Rapid deployment, no middleware

Resco Mobile CRM doesn´t require any server component to be installed on the CRM server, which significantly simplifies the solution installation and setup. Instead of that, Microsoft Dynamics CRM Web Services are used, which allow straightforward and secure integration of the mobile app with the CRM server. Customers only download the mobile app and sync it with their Microsoft Dynamics CRM. All customizations performed with Resco configurator are downloaded during the synchronization and applied automatically to the mobile app, which updates its UI and behavior immediately.


Have a nice day!

Thursday, March 29, 2012

First.. well second post


Hello all!, well this is my first blog, I will try to post interesting things about Dynamics CRM, my apologies about my english, actually my native language is spanish but I will try to put everything in english.

I hope this blog can help other developers just how others developers blogs have helped me in the bad times xD.

Stay tunned!

CRM 2011 SDK 5.0.3 is now available

Yup, the new version of the CRM 2011 SDK is available now for download at microsoft downloads site:

here

Happy coding!