Saturday, July 18, 2009

CRM 4.0 Setting a Picklist Default Value


Currently Dynamics supports setting default values for two attribute types: PicklistAttributeMetaddata (Picklist) and BooleanAttributeMetadata (bit fields). If you intend to set the default using custom code you need to follow the below process:

1. Retrieve the attribute metadata (unless you’re creating a new one) using RetrieveAttributeRequest
2. Cast the returned AttributeMetadata to a PicklistAttributeMetadata.
3. Set the picklist metadata Default value to an integer of you choice.
4. Update the attribute metadata using UpdateAttribute Request.
5. Publish the changes using PublishXml Request.

The bellow code is a working example which sets the account Relationship Type (customertypecode) picklist to Customer (value = 3).


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.SdkTypeProxy.Metadata;

namespace GI.Sendbox
{
class Program
{
static void Main(string[] args)
{
try
{
/* Create Authenticatio Token */
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = 0;
token.OrganizationName = "MicrosoftCRM";

/* Create a CrmService end point */
CrmService crmService = new CrmService();
crmService.UnsafeAuthenticatedConnectionSharing = true;
crmService.Url = "http://localhost:5555/mscrmservices/2007/crmservice.asmx";
crmService.UseDefaultCredentials = true;
crmService.CrmAuthenticationTokenValue = token;

/* Create a MetadataService end point */
MetadataService metaService = new MetadataService();
metaService.Url = "http://localhost:5555/mscrmservices/2007/metadataservice.asmx";
metaService.UseDefaultCredentials = true;
metaService.UnsafeAuthenticatedConnectionSharing = true;
metaService.CrmAuthenticationTokenValue = token;

/* Retrieve the attribute metadata */
RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest();
attributeRequest.EntityLogicalName = "account";
attributeRequest.LogicalName = "customertypecode"; //Relationship Type picklist

RetrieveAttributeResponse attributeResponse =
(RetrieveAttributeResponse)metaService.Execute(attributeRequest);

/* Cast the attribute metadata to a picklist metadata */
PicklistAttributeMetadata picklist =
(PicklistAttributeMetadata)attributeResponse.AttributeMetadata;

/* set the default value to "customer" (3) */
picklist.DefaultValue = (object)3;

/* update the attribute metadata */
UpdateAttributeRequest updateRequest = new UpdateAttributeRequest();
updateRequest.Attribute = picklist;
updateRequest.EntityName = "account";
updateRequest.MergeLabels = false;

metaService.Execute(updateRequest);

/* Publish the changes */
PublishXmlRequest request = new PublishXmlRequest();

request.ParameterXml = @"<importexportxml>
<entities>
<entity>account</entity>
</entities>
<nodes/>
<securityroles/>
<settings/>
<workflows/>
</importexportxml>";


PublishXmlResponse response =
(PublishXmlResponse)crmService.Execute(request);
}
catch(System.Web.Services.Protocols.SoapException sex)
{
Console.WriteLine(sex.Detail.OuterXml);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

Tuesday, July 14, 2009

CRM 4.0 Logging user login information


Following is a simple example on how-to log a user interaction with CRM. The sample uses a simple plug-in that references the System.Web assembly. Once you create a reference to this assembly you’re able to read the HttpContext and consequently read the information you wish to log.

The plug-in hooks into the execute message which in most cases is the first event to fire (grid event). The plug-in also writes a cookie back to the browser to mark the logging operation so it only happens once while the main crm application is opened.

In the example I also create a simple logInfo entity with fields I’m interested in logging.

Please not that while reading information from the httpcontext and other objects like Request might be considered supported, reading information that CRM uses like httpcontext.items[“organizationName”] or writing information to a cookie might break your support. So when you write values back to the browser make sure you’re using a well defined naming convention that will always stay unique. And instead of reading the orgname from the items collection get it from the request url.


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using System.Web;

namespace GI.SandBox
{
public class LoginHandler : IPlugin
{
#region IPlugin Members

public void Execute(IPluginExecutionContext context)
{
if (context.MessageName != "Execute")
{
return;
}

if (context.Stage != MessageProcessingStage.BeforeMainOperationOutsideTransaction)
{
return;
}

if (!(context.CallerOrigin is ApplicationOrigin))
{
return;
}

HttpContext webContext = HttpContext.Current;
HttpCookie logInfo = webContext.Request.Cookies.Get("loginfo");

if (logInfo == null)
{
DynamicEntity logInfoEntry = new DynamicEntity();
logInfoEntry.Name = "gi_loginfo";

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_userhostaddress",
webContext.Request.UserHostAddress
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_useridentity",
webContext.User.Identity.Name
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_starturl",
webContext.Request.Path
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_hostname",
webContext.Request.Url.Host
)
);

if (webContext.Items["organizationName"] != null)
{
logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_userhostaddress",
webContext.Items["organizationName"].ToString()
)
);
}

logInfoEntry.Properties.Add
(
new CrmDateTimeProperty
(
"gi_datetime",
new CrmDateTime(webContext.Timestamp.ToString())
)
);

TargetUpdateDynamic targetRecord = new TargetUpdateDynamic();
targetRecord.Entity = logInfoEntry;

UpdateRequest updateRequest = new UpdateRequest();
updateRequest.Target = targetRecord;

context.CreateCrmService(true).Execute(updateRequest);

logInfo = new HttpCookie("loginfo");
logInfo.Value = DateTime.Now.ToString();
webContext.Response.Cookies.Add(logInfo);
}
}

#endregion
}
}

Sunday, July 12, 2009

CRM 4.0 Cascading wizard




The Cascading wizard is a complementary add-on to dynamic mapping facility. Currently dynamics only supports mapping when a user creates a new child entity within a parent context (form). Knowing that many partners invest quite a bit of energy developing solutions that require cascading and having to deal with these types of requirements ourselves we decided to create a fully featured mapping / cascading wizard that enable us to complete these tasks with just a few clicks.

The CAW wizard has the following features which can save you hours of tedious development.

1.Mapping fields from a parent entity when a child entity is created outside of the parent form. For example: A common requirement might be to inherit account information when you create a new contact from dynamics contacts grid (view). Currently the account fields are only mapped if you create the contact from the account form.

2.Mapping fields from multiple parents. For example: you might have an entity that has lookups to more the 1 entity. When you create the entity you might want to inherit fields from any parent.

3.Cascading parent modifications to all children. For example: you might want to update all contacts under a certain account when the account main phone field (contact business phone) changes.

4.The ability to decide whether to inherit parent attributes only when the child field is empty. For example: you might want to inherit account information when the contact is created but want to enable the user to change the contacts fields afterwards. The CAW wizard enables you to decide whether field changes are cascaded when the child attribute is empty.

5.Cascading drilldown. One of the nicest features of this wizard is that it enables you to drill down the changes from the root entity to the bottom leaf.
For example: if you define an account to contact cascading rules and then define a contact to invoice cascading rule on the same fields. And then change the field on the account form the change is carried out to the invoice entity.

6.The wizard integrates seamlessly with the current mapping facility. And you can choose to utilize both or just use the CAW wizard.

Common CAW features: The wizard supports –
1. Both on-premise and partner hosted environments.
2. IFD – Internet facing deployment
3. 32 and 64 bit servers
4. Multi-Tenancy
5. All Languages
6. All Rollups

We made a video to illustrate the above features.
In order to play back the video, right click on the flash movie then click rewind and play.



If you have question regarding the wizard functionality you can ask them here of send your enquiry to support@gicrm.com