Monday, March 17, 2014

Lumia 520 As iPod Replacement

I do not know of too many people who regularly use an iPod, most seem to use their phone for music, apps etc. Kids seem to love to use phones, tablets as well.  You probably do not want to shell out a few hundred dollars for an iPod for a 5 years old.  I suggest getting the $59 Nokia Lumia 520.  It works just fine without a SIM card and is inexpensive enough that you can feel comfortable letting a child use it.  All of the music and video you could want is available from the Xbox Store.  While it is still lacking in apps, there are still plenty of apps for children including the Mickey Mouse Clubhouse.

Check out the Nokia Lumia 520 GoPhone on Amazon, still $59.

List of Windows Phone Apps for Kids / Families - http://www.windowsphone.com/en-us/store/top-free-apps/kids-family/kidsandfamily

Convergence 2014–Sessions Posted!

All of the Convergence Sessions have been posted!

Here is a subset I would recommend watching.  There are plenty more that are excellent as well. 

CRM Leo Release (Spring Update 1)

Leo: Transform your Customer Service with Microsoft Dynamics CRM - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122780&ShowKey=18130

Microsoft Dynamics CRM: Product roadmap and future vision - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122791&ShowKey=18130

CRM Mobility

Mobility Options in CRM - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122802&ShowKey=18130

Microsoft Dynamics CRM: Building and customizing mobile applications - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122803&ShowKey=18130

CRM Development / Engineering

Developer's guide to integration with Microsoft Dynamics CRM - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122886&ShowKey=18130

Microsoft Dynamics CRM 2013: Key platform enhancements - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122796&ShowKey=18130

Microsoft Dynamics CRM 2013: Upgrade considerations - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122794&ShowKey=18130

Microsoft Dynamics CRM: Customizing the user interface - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122885&ShowKey=18130

Microsoft Dynamics CRM: Performance planning, tuning and optimization - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122883&ShowKey=18130

CRM Social

Getting started with a social strategy - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122799&ShowKey=18130

Harnessing social technologies with Microsoft Dynamics CRM - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122798&ShowKey=18130

Social listening deep dive - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122880&ShowKey=18130

CRM Online

How Microsoft delivers your Microsoft Dynamics CRM online services - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122797&ShowKey=18130

CRM Unified Service Desk

Unified Service Desk: Enabling a super-agent! - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122779&ShowKey=18130

Dynamics AX

If you want to see something cool that is not CRM specific, check out this AX presentation on manufacturing.  Customer Orders from Web Site, Processed by AX, AX triggers a 3D printer to create the product.

https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122864&ShowKey=18130

Business Leadership Sessions

A colleague and I wondered into one of these classes during some unscheduled time.  These are sessions I did not even think about attending but turned out to be amazing.  Not about technology but about building business / personal skills.  Below are a few courses but I would recommend checking them all out. 

Dale Carnegie Workshop: 20 ways to build trust and credibility with your team/leadership development - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122487&ShowKey=18130

Dale Carnegie Workshop: Build a better retention mousetrap and keep the people who have what it takes to raise performance to the next level - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122486&ShowKey=18130

Dale Carnegie Workshop: Leading effective virtual meetings - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122490&ShowKey=18130

Dale Carnegie Workshop: Producing results with people - https://vts.inxpo.com/Launch/Event.htm?DisplayItem=E122492&ShowKey=18130

Virtual Convergence Home Page –

Go to https://presentations.inxpo.com/Shows/microsoft/MSConvergence/3-14/Login/index.html

Sign in on the right side of the page to access the Sessions.

Friday, March 14, 2014

CRM 2013 Rollups and Version Numbers

One of the pain points with patching CRM is the risk of new feature breaking your existing code.  Microsoft has changed there strategy a bit when it comes to releasing rollups.

Going forward, rollups will only contain bug fixes and security patches.  This is great news given most of us have experienced a breaking change in a rollup!

Service Packs such as the upcoming Spring Update for CRM 2013 will contain new features.  The new features will be enabled by default but can be disabled with configuration.

Going forward, version numbers in CRM will follow this pattern:
6.0.0.* [Major.ServicePack/minor.RollupNumber.buildnumber]

So after you apply rollup 1, the version will be 6.0.1.*.  This is a nice change and we can finally put away our build number / rollup mapping charts.

Thanks for this CRM Product Team!

CRM 2011–IFD, Calling the SOAP Endpoint from Another Application Using JavaScript with Single Sign On

 

Recently, I was helping some developers trying to use the CRM 2011 SOAP Endpoint with JavaScript and also getting single sign on.  Both apps are in the same domain but the CRM endpoint in an IFD (External URL) requires a username and password login.

A little background, we have a large group of users who access CRM and other internal apps remotely.  Typically, users access CRM using the External URL that requires them to enter there credentials, even from a domain joined machine.  The application that is calling CRM, is using integrated authentication so they are not directly capturing the users credentials. 

There are a few things that need to be in place to get this to work.  First, DirectAccess.  DirectAccess is like an always connected VPN and is awesome, more companies should consider using it especially with a large remote user base.  More info on DirectAccess here http://technet.microsoft.com/en-us/network/dd420463.aspx.  Publishing CRM’s internal URL via DirectAccess is key to getting SSO to work.  After the URL is published, remote users can browse to CRM’s internal URL and Single Sign on will work.  As a side note, you must make sure your ADFS URL is also published over DirectAccess or be externally available.  It usually is if you are using ADFS / Claims but it should be checked.  DirectAccess is not required if your users can access your internal CRM URL otherwise (always in the corporate network).

Next up the code approach.  This is a rather crude example but it works and can be modified to be much more robust.   When we make a call to the web service the first time, the response will be the ADFS login page.  Usually, when you browse to CRM’s internal URL, this page is submitted automatically.  See below response script.

<script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script></body></html>



So how do we submit the form to get the MSISAuth and MSISAuth1 cookies? The answer is an iFrame. 


First, we add a placeholder <div> and an Iframe to the page that needs to call CRM’s web service. (A more robust solution would create the iFrame on the fly and keep it hidden.  For simplicity, we will leave it on the form.

<div id="placeHolder"></div>
<iframe name="iframe1"></iframe>



When we get the ADFS login page back in the response, we set the contents of the placeholder div = to the response form.  We then grab the form for the document model, change its target to the iFrame, and submit the form.  This allows use to get the MSISAuth and MSISAuth1 cookies.  Our next call to the web service will return the appropriate response.  In this example, we are just retrieving the entity metadata and displaying the SOAP response on the form.


Full Example HTML Page -

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CRM Test</title>
</head>
<body>
<div id="placeHolder"></div>
<iframe name="iframe1"></iframe>
<script type="text/javascript">

function GetCRMToken()
{

var request = [
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">",
"<soapenv:Body>",
"<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">",
"<request i:type=\"a:RetrieveAllEntitiesRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">",
"<a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">",
"<a:KeyValuePairOfstringanyType>",
"<b:key>EntityFilters</b:key>",
"<b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity</b:value>",
"</a:KeyValuePairOfstringanyType>",
"<a:KeyValuePairOfstringanyType>",
"<b:key>RetrieveAsIfPublished</b:key>",
"<b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>",
"</a:KeyValuePairOfstringanyType>",
"</a:Parameters>",
"<a:RequestId i:nil=\"true\" />",
"<a:RequestName>RetrieveAllEntities</a:RequestName>",
"</request>",
"</Execute>",
"</soapenv:Body>",
"</soapenv:Envelope>"].join("");
var req = new XMLHttpRequest();
req.open("POST", "{INTERNAL_CRM_URL_GOES_HERE}/XRMServices/2011/Organization.svc/web", false);
try { req.responseType = 'msxml-document' } catch (e) { }
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.withCredentials = true;
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.onreadystatechange = function ()
{
if (req.readyState == 4 /* complete */)
{
req.onreadystatechange = null; //Addresses potential memory leak issue with IE
if (req.status == 200)
{
//Success
var doc = req.responseXML;
debugger;
//Submit the initial request to the iframe
var placeHolder = document.getElementById('placeHolder');
placeHolder.innerHTML = req.responseText;
document.forms[0].target = "iframe1";
document.forms[0].submit();


}
else
{
errorCallBack(_getError(req));
}
}
};
req.send(request);
}

function GetMetaData()
{

var request2 = [
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">",
"<soapenv:Body>",
"<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">",
"<request i:type=\"a:RetrieveAllEntitiesRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">",
"<a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">",
"<a:KeyValuePairOfstringanyType>",
"<b:key>EntityFilters</b:key>",
"<b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity</b:value>",
"</a:KeyValuePairOfstringanyType>",
"<a:KeyValuePairOfstringanyType>",
"<b:key>RetrieveAsIfPublished</b:key>",
"<b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>",
"</a:KeyValuePairOfstringanyType>",
"</a:Parameters>",
"<a:RequestId i:nil=\"true\" />",
"<a:RequestName>RetrieveAllEntities</a:RequestName>",
"</request>",
"</Execute>",
"</soapenv:Body>",
"</soapenv:Envelope>"].join("");
var req2 = new XMLHttpRequest();

req2.open("POST", "{INTERNAL_CRM_URL_GOES_HERE}/XRMUAT/XRMServices/2011/Organization.svc/web", false);
try { req.responseType = 'msxml-document' } catch (e) { }
req2.setRequestHeader("Accept", "application/xml, text/xml, */*");
req2.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req2.withCredentials = true;
req2.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req2.onreadystatechange = function ()
{
if (req2.readyState == 4 /* complete */)
{
req2.onreadystatechange = null; //Addresses potential memory leak issue with IE
if (req2.status == 200)
{
//debugger;
var placeHolder2 = document.getElementById('placeHolder2');
placeHolder2.innerText = req2.responseText;
}
else
{
errorCallBack(_getError(req));
}
}
};
req2.send(request2);

}

function _getError(resp)
{
///<summary>
/// Private function that attempts to parse errors related to connectivity or WCF faults.
///</summary>
///<param name="resp" type="XMLHttpRequest">
/// The XMLHttpRequest representing failed response.
///</param>

//Error descriptions come from http://support.microsoft.com/kb/193625
if (resp.status == 12029)
{ return new Error("The attempt to connect to the server failed."); }
if (resp.status == 12007)
{ return new Error("The server name could not be resolved."); }
var faultXml = resp.responseXML;
var errorMessage = "Unknown (unable to parse the fault)";
if (typeof faultXml == "object")
{

var faultstring = null;
var ErrorCode = null;

var bodyNode = faultXml.firstChild.firstChild;

//Retrieve the fault node
for (var i = 0; i < bodyNode.childNodes.length; i++)
{
var node = bodyNode.childNodes[i];

//NOTE: This comparison does not handle the case where the XML namespace changes
if ("s:Fault" == node.nodeName)
{
for (var j = 0; j < node.childNodes.length; j++)
{
var testNode = node.childNodes[j];
if ("faultstring" == testNode.nodeName)
{
faultstring = _getNodeText(testNode);
}
if ("detail" == testNode.nodeName)
{
for (var k = 0; k < testNode.childNodes.length; k++)
{
var orgServiceFault = testNode.childNodes[k];
if ("OrganizationServiceFault" == orgServiceFault.nodeName)
{
for (var l = 0; l < orgServiceFault.childNodes.length; l++)
{
var ErrorCodeNode = orgServiceFault.childNodes[l];
if ("ErrorCode" == ErrorCodeNode.nodeName)
{
ErrorCode = _getNodeText(ErrorCodeNode);
break;
}
}
}
}

}
}
break;
}

}
}
if (ErrorCode != null && faultstring != null)
{
errorMessage = "Error Code:" + ErrorCode + " Message: " + faultstring;
}
else
{
if (faultstring != null)
{
errorMessage = faultstring;
}
}
return new Error(errorMessage);
};

//Get the MSISAuth cookies
//Ideally, the code would check for the presence of the auth cookies before making this call. If they already exist, skip this step
GetCRMToken();

//Set the timeout to make sure the ADFS post occurs before making the next call
setTimeout(GetMetaData, 400, null);


</script>

<div id="placeHolder2"></div>
</body>
</html>



You can also download the sample from here https://onedrive.live.com/redir?resid=FFCD1C6BBDDCB813!2669&authkey=!rWUBUZ81Dc0%24&ithint=file%2c.zip 


There are obviously a lot of changes that can be made to make this more robust but this should be enough to get started.


Below is the metadata SOAP response after the ADFS form is submitted.


image


This is my first post in a long time and there will be more to come.


Happy Coding!