« Client-side Web Service Calls for Microsoft Dynamics CRM 4.0: Parsing The Results | Main | Side-by-Side IFRAMES »
June 08, 2009
CRM Helper Class for Custom ISV ASPX Pages
Most of my development work these days consists of creating custom ASPX pages that reside within the ISV subfolder of CRM. Anyone who’s done more than a couple of CRM-related projects probably has found a need to create some sort of "helper” class to make all of that easy (ain’t that part of the point of object-oriented programming???). The CRM SDK does have some helper code included that does a little bit of work for you, but I find it to be lacking. At Customer Effective, we have an extensive library that we’ve built up over time (we call it our API) that really makes interacting with the CRM web service pretty easy and efficient. Separately, I’ve also compiled a more lightweight version that is really easy to implement. Most of the code in this class follows the sample code found within the SDK and is intended to be fully multi-tenant and IFD compliant.
Setup
As a rule, I try to avoid making references to the CRM web services. It is entirely possible to develop ISV solutions using the SDK DLL files as long as you are willing to use the DynamicEntity class versus strong-typed entity classes (for any custom entities & attributes at least). I don’t like to use strong-typed entity classes, but that’s just my preference. Since I use the dynamic entities, I really just need to reference the Microsoft.Crm.Sdk.dll and Microsoft.Crm.Sdktypeproxy.dll files. Also, my goal is to avoid having to create “config” files to store connection information. While that may not always be possible for other systems, you can certainly do that with CRM connection information.
Class Constructor & Variables
Here’s how I set up the helper class:
/// <summary>
/// Class containing CRM helper methods.
/// </summary>
public class MyCrmHelper
{
HttpContext _context;
string _baseUrl = "";
string _serviceUrl = "";
string _metadataServiceUrl = "";
string _orgName = "";
bool _isOffline = false;
bool _isIfd = false;
int _authType = 0;
/// <summary>
/// Helper class for querying the CrmService and MetedataService objects. This class is IFD compliant.
/// </summary>
/// <param name="context"></param>
public MyCrmHelper(HttpContext context)
{
_context = context;
InitializeCrmSettings();
}
I have some basic global variables that store the relevant information needed by the class to connect to CRM. When initialized, you need to pass the HttpContext from the ASPX page. The class then utilizes information from the context of the page to determine certain parameters. The bulk of the setup is done in the InitializeCrmSettings() method (duh….).
/// <summary>
/// Set up CRM settings (url, organization, etc.)
/// </summary>
/// <param name="context"></param>
private void InitializeCrmSettings()
{
// SET CRM SERVICE STUFF
string url = _context.Request.Url.ToString().ToLower();
int start = url.IndexOf("://") + 3;
if (_context.Request.Url.Host.ToString() == "127.0.0.1")
{
_isOffline = true;
}
if (_isOffline)
{
// get organization
RegistryKey regkey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\MSCRMClient");
_orgName = regkey.GetValue("ClientAuthOrganizationName").ToString();
// get crm url
string portnumber = regkey.GetValue("CassiniPort").ToString();
_serviceUrl = "http://localhost:" + portnumber + "/mscrmservices/2007/crmservice.asmx";
}
else
{
// get organization
string orgquerystring = _context.Request.QueryString["orgname"];
if (string.IsNullOrEmpty(orgquerystring))
{
_orgName = string.Empty;
}
else
{
_orgName = orgquerystring;
}
if (string.IsNullOrEmpty(_orgName))
{
//Windows Auth URL
if (_context.Request.Url.Segments[2].TrimEnd('/').ToLower() == "isv")
{
_orgName = _context.Request.Url.Segments[1].TrimEnd('/').ToLower();
}
//IFD URL
if (string.IsNullOrEmpty(_orgName))
{
_orgName = url.Substring(start, url.IndexOf(".") - start);
}
}
// detect if we are ifd
if (_orgName.ToLower() == url.Substring(start, url.IndexOf(".") - start))
{
_isIfd = true;
_authType = 2;
}
// get crm url
RegistryKey regKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM");
_baseUrl = regKey.GetValue("ServerUrl").ToString();
_serviceUrl = _baseUrl + "/2007/crmservice.asmx";
_metadataServiceUrl = _baseUrl + "/2007/metadataservice.asmx";
}
}
The code above is pretty much ripped straight from the SDK documentation on Authentication from ASPX pages. The code uses the Request url as well as certain registry settings to determine the service url, IFD mode, organization and even if we are in offline mode.
Functions
Now, we could just utilize our helper by referencing the variables we’ve calculated, but what I want to do is have the helper class also handle the service requests – mainly to help ensure IFD compliance, etc. The easiest way to do this is to simply create some wrapper service functions that mirror the CrmService functions. I’ll illustrate a couple below:
/// <summary>
/// Execute a service request.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Response Execute(Request request)
{
using (new CrmImpersonator())
{
CrmAuthenticationToken token;
if (IsOffline)
{
token = new CrmAuthenticationToken();
}
else
{
token = CrmAuthenticationToken.ExtractCrmAuthenticationToken(_context, _orgName);
}
token.OrganizationName = _orgName;
token.AuthenticationType = 0;
//Create the Service
CrmService service = new CrmService();
service.Credentials = CredentialCache.DefaultCredentials;
service.CrmAuthenticationTokenValue = token;
service.Url = _serviceUrl;
Response response = service.Execute(request);
return response;
}
}
/// <summary>
/// Retrieves a CRM record as a dynamic entity
/// </summary>
/// <param name="entityName">Name of the entity from which the record is retrieved.</param>
/// <param name="id">Record Id.</param>
/// <returns></returns>
public DynamicEntity Retrieve(string entityName, Guid id)
{
try
{
TargetRetrieveDynamic target = new TargetRetrieveDynamic();
target.EntityName = entityName;
target.EntityId = id;
RetrieveRequest request = new RetrieveRequest();
request.Target = target;
request.ColumnSet = new AllColumns();
request.ReturnDynamicEntities = true;
RetrieveResponse response = (RetrieveResponse)Execute(request);
return (DynamicEntity)response.BusinessEntity;
}
catch (SoapException ex)
{
throw ex;
}
}
Looking at the above code, what I’ve done is simply wrap the Execute service function within the CrmImpersonator class to ensure IFD-compliance. The Retrieve function serves the same purpose of the normal CrmService.Retrieve, but this one leverages the existing Execute function. You can also get pretty funky with your own code and do some custom functions that make retrieving/updating/creating CRM records super-easy and efficient wihtin your pages.
Using the Class
Using the class is pretty straightforward – just initialize it into a global page variable during a page load and you’ve got it available pretty much anytime you need it:
public partial class MyPage : System.Web.UI.Page
{
MyCrmHelper _helper;
protected void Page_Load(object sender, EventArgs e)
{
// initialize helper
_helper = new MyCrmHelper(this.Context);
}
}
Simple Retrieve:
Guid accountId = new Guid("some account's id goes here");
DynamicEntity myEntity = _helper.Retrieve("account", accountId);
Now you’ve got your DynamicEntity object that you can do your thing with.
I will say that this class is close to the one I use, but we’ve built-in a ton of shortcuts/features like diagnostics (Application logging), Metadata service functions, and exposed several of the global variables as class properties. Hopefully the example I’ve given will help you get some creative juices of your own so you can simplify your own development with the SDK.
Cheers!
Posted by Will Wilson on June 08, 2009 at 04:57 PM | Permalink
TrackBack
TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00e54fb34b6f883301156fe65cc5970c
Listed below are links to weblogs that reference CRM Helper Class for Custom ISV ASPX Pages:
Comments
Verify your Comment
Previewing your Comment
Posted by: |
This is only a preview. Your comment has not yet been posted.
The letters and numbers you entered did not match the image. Please try again.
As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.
Having trouble reading this image? View an alternate.




I had a dream to make my own business, but I did not have got enough of money to do it. Thank heaven my close friend suggested to use the home loans. Thence I used the credit loan and made real my desire.
Posted by: LancasterLourdes22 | March 29, 2010 at 05:50 PM