thexRMGuru.com
The power of "x", Anything is possible
The power of "x", Anything is possible
Jun 10th
“The Microsoft CRM Plug-In Debugger” is the tool I am putting forward this week.
Over the past few weeks I found myself in some lengthy discussions on a project I am currently working on and one of the major topics of conversation was around unit testing of code, something which I don’t believe typically gets done very well by Microsoft CRM Developers.
The CRM Developer Toolkit (mentioned a while ago on my blog) provides the capability to incorporate Unit Testing into your Development and Build processes, however Unit Testing of the actual plug-in calls can’t be done as it stands as you invariably need to have the CRM Plug-in Context…. enter “The Microsoft CRM Plug-In Debugger”
This little Class allows you to create a Mock CRM Plug-in Interface in order to test your plug-in code without the need to deploy it to CRM.
Check it out, it can save hours in debugging time.
P.S. Watch this space as I am finally finding the time to write the promised posts on the CRM Developer Toolkit.
May 24th
Amid some fantastic xRM deals and all the extra effort my team and I have had to put in over the last month while facilitating the phenomenal growth of my company, my “Tool of the Week” as was very nicely pointed out to me by one of my colleagues has unfortunately not been so weekly…. we can dream though
…. and continue to persevere at trying to maintain the regular routine of these ideas.
So…. in the spirit of trying to get back on track I will dive straight into the next “Tool of the week”
This tool review is as a result of a recommendation from @seanvowles though I must say that I agree with him that it is a really great tool and also a rather apt time to mention it as it has just recently had a new release.
The tool is the CRM Configuration Manager, currently v1.50.
The CRM Configuration Manager is designed to help you work better with the Customisations in your CRM environments, overcoming some of the limitations of the “out-of-the-box” capability.
The most notable advantages are the ability to export just the modifications in a CRM system (compared to an earlier customisation export) as well as the ability to extract and export (and then re-import) the JavaScript associated within the entities, allowing you to more easily modify these scripts using an external editor like Visual Studio.
Additionally you can write your own, or purchase additional add-ins for the product an example of which is the Microsoft Word Add-In which can be used for various scenarios including :
“Documentation
•Document your work after it’s finished, removing any possible mismatch from the specifications.
•Understand the work of others when taking ownership of a CRM instance without any documentations provided (Using the filters to export only Custom Entities, Attributes and Relationships)
•Presents all your ISV Configuration changes in one place, that usually are hard to get a good overview of.
Daily work routines
•Development Aid, use a complete export document as a reference.
By searching in the document for a specific entity you can quickly see available picklist values, implemented JavaScript, published attributes on form and attributes schema name including data type restrictions.
•Architect Aid, Cut & Paste attribute, forms or relationships Tables to your specifications, and extend them with new values or describe changes”
I hope you find the same value in the tool as I have.
May 23rd
I have been playing over the last week and a bit with the newly released Customer Portal Accelerator for Microsoft Dynamics CRM 4.0 in conjunction with the CRM SDK 4.0.12 which contains some new libraries called Advanced Developer Extensions as well as the Portal Development Framework.
In my opinion the Customer Portal Accelerator is a fantastic accelerator and a vast improvement over the previous eService, Events Management and Portal Integration Accelerators (It is now all of these combined).
One of the only drawbacks is that the out of the box accelerator only works with Windows Live Authentication, which is great, but there is definitely quite a few scenarios where this is not ideal.
The accelerator was actually created by the guys at ADXStudio and is essentially a lightweight version of their ADXStudio xRM product, so the simplest way to get other authentication mechanism would be to upgrade to their full ADXStudio xRM product, which I would highly recommend as there are some really fantastic components available.
However if that is not an option then it is actually pretty straight forward to modify the existing Customer Portal Accelerator to use CRM to authenticate the user and I will go through an example of how you could do it in this post.
I am going to assume you have already deployed the “Out of the Box” Customer Portal Accelerator as per the instructions provided in the download.
So you should be starting off with a CRM environment that looks like this :
and a Customer Portal site that looks like this :
with the sign in screen showing Windows Live ID sign in :
The great thing is that pretty much everything we need to handle the authentication from the CRM side of things is already there. We can use the fields that are imported by the Customer Portal Accelerator on the Web Authentication Tab of the contact record.
The one change I made though was to remove the “Reset Password To” field and put the actual “Password” (adx_password) field onto the form in it’s place.
I then added the following JavaScript code to the Contact_OnLoad event to modify the password field to replace the text characters with a normal password mask so that the password is not visible to users.
//Password Field
var pwd = document.createElement("<input type='password' tabIndex='1911'>");
pwd.value = crmForm.all.adx_password.DataValue;
if (crmForm.all.adx_password.DataValue == null)
{
pwd.value = '';
}
crmForm.all.adx_password_d.appendChild(pwd);
pwd.onkeyup = function()
{
crmForm.all.adx_password.DataValue = pwd.value;
};
crmForm.all.adx_password.style.display = 'none';
You could go a step further and add a plug-in to the Contact Pipeline to encrypt the password, but that is the topic for another post.
That’s about it for CRM. The next step is to start modifying the “Customer-Portal-R2” website.
Modify the Web.config file and replace the current <authentication> section with the following :
<authentication mode="Forms"> <forms name=".ASPXAUTH" loginUrl="login" defaultUrl="default.aspx" protection="All" timeout="30" path="/" requireSSL="false" slidingExpiration="true" cookieless="UseDeviceProfile" domain="" enableCrossAppRedirects="false"> </forms> </authentication>
Comment out the exiting “CrmMembershipProvider” and replace it with the code snippet below.
<!--<membership defaultProvider="CrmMembershipProvider"> <providers> <add name="CrmMembershipProvider" type="Microsoft.Xrm.Portal.Web.Security.LiveIdMembershipProvider" liveIdConnectionStringName="Live"/> </providers> </membership>--> <membership defaultProvider="CustomCRMProvider"> <providers> <clear/> <add name="CustomCRMProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="Xrm" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0"/> </providers> </membership>
Modify the Pages/Login.aspx page be replacing the Live Login Control with the standard ASP.Net login control.
<asp:Content ContentPlaceHolderID="ContentBottom" runat="server"> <%--<crm:LiveIdLoginStatus ID="LiveIdLink" runat="server" LoginImageUrl="http://www.passportimages.com/1033/signin.gif" LogoutImageUrl="http://www.passportimages.com/1033/signout.gif" />--%> <asp:Login ID="Login1" runat="server" onauthenticate="Login1_Authenticate"> </asp:Login> </asp:Content>
Modify / Replace the code in the Login.aspx.cs page as detailed below :
public partial class Login : System.Web.UI.Page { private XrmDataContext _crmContext; private contact _loginContact; protected XrmDataContext CrmContext { get { return _crmContext ?? (_crmContext = new XrmDataContext()); } } protected contact LoginContact { get { return _loginContact ?? (_loginContact = CrmContext.contacts .FirstOrDefault(c => c.adx_username == Login1.UserName && (c.adx_password == Login1.Password))); } } protected void Page_Load(object sender, EventArgs e) { if ((User != null && User.Identity != null) && User.Identity.IsAuthenticated) { var redirectUrl = !string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]) ? Request["ReturnUrl"] : !string.IsNullOrEmpty(Request.QueryString["URL"]) ? Request["URL"] : "/"; Response.Redirect(redirectUrl); } else { //var inviteQueryString = string.IsNullOrEmpty(Request["InvitationCode"]) ? string.Empty : "?InvitationCode=" + Request["InvitationCode"]; //var registrationUrl = SiteContext.Current.Website.GetPageBySiteMarkerName("Live User Registration").GetUrl(); //LiveIdLink.RegistrationUrl = registrationUrl + inviteQueryString; } } protected void Login1_Authenticate(object sender, System.Web.UI.WebControls.AuthenticateEventArgs e) { if (LoginContact == null) { e.Authenticated = false; } else { if (LoginContact.adx_username == Login1.UserName) { if (LoginContact.adx_changepasswordatnextlogon.Value) { var page = SiteContext.Current.Website.GetPageBySiteMarkerName("ChangePassword") as Xrm.adx_webpage; string redirectURL = page.GetUrl() + "?UserName=" + Server.UrlEncode(Login1.UserName) + "&Password=" + Server.UrlEncode(Login1.Password); Response.Redirect(redirectURL); } else { LoginContact.adx_lastsuccessfullogon = DateTime.Now.Date; var coreContext = new CoreDataContext(); coreContext.UpdateObject(LoginContact); coreContext.SaveChanges(); e.Authenticated = true; FormsAuthentication.RedirectFromLoginPage(Login1.UserName, true); } } else { e.Authenticated = false; } } } }
Ensure your “using” declarations include the following :
using System; using System.Linq; using System.Web; using System.Web.Profile; using System.Web.Security; using Microsoft.Xrm.Portal.Cms; using Microsoft.Xrm.Portal.Core; using Microsoft.Xrm.Portal.Web; using Xrm;
Modify “MasterPages/Default.master” to replace the Live Login Control with an ASP.Net Loginstatus control and comment out the LiveLoginStatus command in the Page_Load event.
<div id="hd-links"> <asp:LoginView runat="server"> <LoggedInTemplate> <%= SiteContext.Current.CurrentUserContact.GetPropertyValue<string>("fullname") %> – <asp:HyperLink NavigateUrl='<%$ CrmSiteMap: SiteMarker=Profile, Url %>' Text='<%$ Snippet: Profile Link Text, Manage Account %>' runat="server" /> – </LoggedInTemplate> </asp:LoginView> <%--<crm:LiveIdLoginStatus ID="LiveLoginStatus" runat="server" />--%> <%--<asp:Login ID="Login1" runat="server"> </asp:Login>--%> <asp:LoginStatus ID="LoginStatus1" runat="server" LogoutPageUrl="logout"></asp:LoginStatus> </div>
I then added a Logout.aspx page to the Pages folder, the contents of which is just the following in the .cs file.
using System; using System.Linq; using Microsoft.Xrm.Portal.Access; using Microsoft.Xrm.Portal.Cms; using Microsoft.Xrm.Portal.Core; using Microsoft.Xrm.Portal.Web; using Xrm; using System.Web.UI.WebControls; using Site.Library; using System.Web.Security; namespace Site.Pages { public partial class Logout : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { FormsAuthentication.SignOut(); var page = SiteContext.Current.Website.GetPageBySiteMarkerName("Home") as Xrm.adx_webpage; Response.Redirect(page.GetUrl()); } } }
You may have noticed in the updated Login.aspx page that there is reference to a Change Password page, this would allow us to ensure that our users change their password at next logon (a flag that already exists on the Web Authentication tab in CRM). To facilitate this we need to add an additional page called ChangePassword.aspx which should ideally be based on our existing master page to ensure a consistent look and feel. The ChangePassword.aspx page has a standard ASP.Net Change Password control.
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPages/Default.master" AutoEventWireup="true" CodeBehind="ChangePassword.aspx.cs" Inherits="Site.Pages.ChangePassword" %> <asp:Content ID="Content3" ContentPlaceHolderID="ContentBottom" runat="server"> <asp:ChangePassword ID="ChangePassword1" runat="server" onchangedpassword="ChangePassword1_ChangedPassword" onchangingpassword="ChangePassword1_ChangingPassword"> </asp:ChangePassword> </asp:Content>
and the code-behind is as follows :
using System; using Microsoft.Xrm.Portal.Cms; using Microsoft.Xrm.Portal.Web; using System.Linq; using Xrm; using System.Web.Security; using System.Web; using System.Web.Profile; using Microsoft.Xrm.Portal.Core; using System.Web.UI.WebControls; namespace Site.Pages { public partial class ChangePassword : System.Web.UI.Page { private XrmDataContext _crmContext; private contact _loginContact; protected XrmDataContext CrmContext { get { return _crmContext ?? (_crmContext = new XrmDataContext()); } } protected contact LoginContact { get { return _loginContact ?? (_loginContact = CrmContext.contacts .FirstOrDefault(c => c.adx_username == Server.UrlDecode(Request.QueryString["UserName"].ToString()) && (c.adx_password == Server.UrlDecode(Request.QueryString["Password"].ToString())))); } } protected void Page_Load(object sender, EventArgs e) { } protected void ChangePassword1_ChangedPassword(object sender, EventArgs e) { Response.Redirect("../login"); } protected void ChangePassword1_ChangingPassword(object sender, LoginCancelEventArgs e) { LoginContact.adx_password = ChangePassword1.NewPassword; LoginContact.adx_lastpasswordchange = DateTime.Now.Date; LoginContact.adx_changepasswordatnextlogon = false; var coreContext = new CoreDataContext(); coreContext.UpdateObject(LoginContact); coreContext.SaveChanges(); Response.Redirect("login"); } } }
You may have noticed in some of the code that we are using the same URL rewriting that the Customer Portal Accelerator already uses for our new pages
var page = SiteContext.Current.Website.GetPageBySiteMarkerName("Change Password") as Xrm.adx_webpage;
this will require us to add these pages under the content management section inside CRM in order for the site to work correctly. The 2 pages we need to add are the ChangePassword.aspx and the Logout.aspx page, these pages are added as follows (repeat the below steps for each of the pages)
Create a new Page Template for each of the pages
Create a new Web Page for each of the pages
Create a new Site Marker for each of the pages
Next you can create a contact in CRM, fill in the minimum required fields as well as the Username, Password and Logon Enabled checkbox on the Web Authentication tab. You can also check the “User must change password at next logon” to force that.
You may also want to modify the standard Portal signup workflows that ship with the Customer Portal Accelerator to mimic your environments requirements.
I have attached copies of all the modified files below, including an export of the Customer Portal website from CRM, using the new WebsiteCopy tool
Apr 12th
The Microsoft CRM 4.0 Configuration Data Utility is a tool that I downloaded from MSDN. As with a lot of the tools that I download, getting around to actually playing with them doesn’t always happen as quickly as I would like.
When I finally got around to playing with this tool it definitely has some great potential, both as a Configuration Data migration utility as well as an Import / Export utility for data that you may need to move around or pre-populate into your CRM system for testing purposes during UAT etc, as well as working very well for exporting and importing data from entities that you typically cant access using the Built-In Import capabilities of CRM, like Subjects.
I did however make one small change to the source code of this tool as by default it only allows you to Export and Import data from Custom Entities in the system, so I modified line 206 of ExportDataForm.cs as follows :
Original Code :
IEnumerable<EntityMetadata> entities = response.CrmMetadata .Cast<EntityMetadata>() .Where(entity => entity.IsIntersect.Value == false && entity.IsImportable.Value entity.IsCustomEntity.Value ) .OrderBy(entity => entity.DisplayName.UserLocLabel.Label) .ToList();
Altered Code:
IEnumerable<EntityMetadata> entities = response.CrmMetadata .Cast<EntityMetadata>() .Where(entity => entity.IsIntersect.Value == false && entity.IsImportable.Value ) //&& entity.IsCustomEntity.Value .OrderBy(entity => entity.DisplayName.UserLocLabel.Label) .ToList();
Aside from this the tool is pretty easy to use.
You either Export Data to “.Data” files or you Import the “.Data” files back into your system.
Export then requires a Server URL and Organisation name
You then get a list of available entities
Add the entities you want, select an Output file destination
and Presto!!!
The Import process is even simpler.
Jan 27th
xRMVirtual.co.za, South Africa’s first official Microsoft Dynamics CRM/xRM User group community, offering both Virtual and In-Person user groups went live on Monday 18 January 2010. Membership numbers grew to 104 in the 10 days leading up to their inaugural in-person event held on the 27th January 2010.
The event was a huge success. Read my post about the event on xRMVirtual.co.za here
Jan 23rd
South Africa finally has it’s own Virtual (and In-Person) user group community for Microsoft Dynamics CRM and xRM Technologies build on the Dynamics Platform.
The user group community takes the form of xRMvirtual.co.za an online virtual community site which will host rich content in the form of Blogs from some of the top CRM / xRM Resources including the members of Microsoft South Africa’s newly launched xRM Rangers program, Webcasts and a Forum that is overseen by the xRM Rangers.
xRMvirtual.co.za is affiliated with the site of the same name in the United States (xRMVirtual.com) and will be having it’s Inaugural In-Person event on the 27th January 2010 which will be attended by xRMVirtual.com founder Julie Yack. Register for this event here
Add the site to your list of favourites and check back regularly as there will be great new content posted every month.
Jan 6th
I have found it rather surprising how many people I have spoken to who are not aware of the existence of the CRM Developer toolkit that was created by the Microsoft Dynamics CRM Engineering for Enterprise (CRM E2) team.
The toolkit was released on the 7th April 2009 and essentially enables the customisation of CRM via an integrated environment in Visual Studio as well as an entire framework for developing and deploying custom code.
A brief excerpt of the functionality is as follows :
“…To provide developers with the ability to create and manage on-premise CRM solutions in an integrated Visual Studio environment, the Microsoft Dynamics CRM Engineering for Enterprise (CRM E2) team initiated and sponsored the development of the Microsoft Dynamics CRM Developer Toolkit. The Toolkit has been designed to make it easier for developers to customize, extend, and maintain an on-premise CRM solution, all from within an integrated Visual Studio environment. Key benefits for developers include the ability to:
Unfortunately the documentation available for the toolkit explaining how to use it and how to make changes to it is not very detailed. I have been working with it for quite a few months now and have spent a reasonable amount of time figuring out how it all fits together and will be writing a number of posts over the coming weeks detailing the in’s and out’s of this toolkit.
Watch this space…….
Jan 5th
Create lots of documents or user manuals that require screenshots and step by step processes?
View Pat’s blog post here for detailed information on using the Windows 7 Problem Steps Recorder….. it is AWESOME !!!!
Jan 5th
In Windows 7 Microsoft have significantly improved on the built in Backup and Restore capability.
One of the great new features is the ability to create a System Image (and recovery disk) from the Backup Console. This basically creates a snapshot of your partitions and stores them on an external hard drive or DVD, the idea being that should you wish to either restore your entire system to an original state or recover from a system failure you can quickly restore the entire partition.
What you may NOT know about the System Image backup is that is actually creates a VHD file of each of your partitions. The VHD is located under a folder called Backup <Date> in the WindowsImageBackup folder on your removable media.
The other great new feature with the Windows 7 and Windows Server 2008 R2 Bootloader is that it has the capability to boot from VHD, this means that if you need to quickly access something in your backup image you can just boot from the VHD and access it.
To configure the Boot from VHD option, copy the VHD file to a local hard drive and rename it to something short like Win7.vhd (as the backup name is a long name). For the purposes of this blog lets place the file in C:\VHD.
Open a command windows and execute the following commands :
where “Windows 7 Backup Image” is the name you wish to see from your boot menu
where <GUID> is the GUID generated in the previous command
and presto. Reboot you machine and you should be prompted with a boot menu that has the additional boot option in it to boot the VHD.
If you are doing this for a Windows Server 2008 (or 2008 R2) image then you may want to add the following as well :
this will ensure that you are able to use the Hyper-V functionality in Windows Server 2008.
Nov 9th
The CRM SDK has been updated to version 4.0.10 in line with the recent Rollup 7 Updates to the Dynamics CRM Platform. Get it here.
The Microsoft Dynamics CRM 4.0 Software Development Kit (SDK) is for developers, system customizers, and report writers. This SDK documentation contains information for developers writing server side code, custom business logic, integration modules, workflow assemblies, and plug-ins. It provides an architectural overview of Microsoft Dynamics CRM, the entity model, security model, and Web services. Sample code and walkthroughs are provided to guide you through the new features. It also contains information for developers customizing the Web client or Microsoft Dynamics CRM for Microsoft Office Outlook, including scripting, integration of custom Web pages, sample code, and a detailed user interface style guide.
In addition to the documentation, this download package includes the projects for all sample code found in the documentation, and full featured samples that are not included in the documentation. The package includes a visual style guide you can use to make your customizations fit in smoothly, and a style sheet you can use as a basis for your work. There are also tools and helper code provided in this package. Look for regular updates to this SDK!
If you need assemblies or schema files prior to Microsoft Dynamics CRM Update Rollup 7 and the Microsoft Dynamics CRM Online November 2009 Service Update, you can download the SDK 4.0.9 from this location: http://download.microsoft.com/download/D/E/C/DECA6FF2-2683-4E7A-B9A2-1CEB8AF971AE/CrmSdk4.0.9.exe