Wednesday, February 28, 2007

Callouts in Service Provider Edition of Microsoft CRM 3

Finally!
I got it to work, and it actually wasn't too difficult when I got hold of the correct DLL:s. So, first hot tip, right out the furnace:

"When developing for CRM Service Provider Edition, make sure you got CRM Service Provider Edition versions of your dll:s".

This can actually be a bit problematic when working in a development environment on a VPC since it is quite rare to have the entire Hosted Environment, like Hosted AD, Hosted Exchange etc on your virtal machines. If you do, great, use it, but I would guess that most of you don't.

I will give you a short walkthrough of how to create a post callout using the CRM Service Provider Edition. I will focus mainly on the differences between developing a normal callout and one for for CRM SPE.

First off, copy the file Microsoft.Crm.Platform.Callout.Base.dll from the CRM SPE CD 1 (\bin\Assembly). Put it somewhere where it is possible to add a reference to it. Like c:\temp.
Now, add a reference to it in the project.

Modify the callout.config.xml file just like you usually do, for instance:
<callout.config version="3.0" xmlns=" http://schemas.microsoft.com/crm/2006/callout/">
<callout entity="account" event="PostUpdate">
<subscription assembly="CalloutLibrary.dll" class="CalloutLibrary.AcctCallouts" />
</callout>
</callout.config>

Create a class file called AcctCallouts in the namespace CalloutLibrary and make sure the dll is called "CalloutLibrary.dll". (If you name your project CalloutLibrary, this will be default).

using System;using Microsoft.Crm.Callout;
using System;using System.Data;
using System.Net;
using System.Web;
using MSAB.CalloutLibrary.CRMSDK;
using Microsoft.Crm.Callout;
using System.Globalization;
using System.IO;


namespace CalloutLibrary
{
public class mbaktivitet: CrmCalloutBase
{
private CrmService service;
private WhoAmIRequest userRequest;
private WhoAmIResponse user;

public override void PostCreate(
CalloutUserContext userContext,
CalloutEntityContext entityContext,
string postImageEntityXml)
{
string usr = "
username@test.local";
string pwd = "1m0rePassword";
string HostedCRMurl ="http://crmserver.hostingcompany.com";
service = new CrmService();
service.Url = HostedCRMurl + "/mscrmservices/2006/crmservice.asmx";
service.CookieContainer = new CookieContainer();

service.CookieContainer.Add(GetCRMCookie(HostedCRMurl, usr, pwd));

//Make sure the webservice works
userRequest = new WhoAmIRequest();
user = (WhoAmIResponse) service.Execute(userRequest);
}
}
}

The important call here is the GetCRMCookie(HostedCRMurl, usr, pwd), a method that I will describe bellow which returns an authentication cookie that can be used to authenticate against the web service. Here is its definition, it is more or less what Arash has written on his blog concerning how to write web services for CRM SPE.

public Cookie GetCRMCookie(string url, string userName, string password)
{
DebugText("Start of GetCRMCookie");
Cookie authCookie;
try
{
Uri serverUri = new Uri(url);
Uri logonServerUri = new Uri(serverUri, @"LogonServer/Logon.aspx");

string encodedUserName = HttpUtility.UrlEncode(userName);
string encodedPassword = HttpUtility.UrlEncode(password);
string logonServerUrl = String.Format(CultureInfo.InvariantCulture, "{0}?UserName={1}&Password={2}", logonServerUri.ToString(), encodedUserName, encodedPassword);

// Make a web request that does not allow redirection
HttpWebRequest logonRequest = (HttpWebRequest)WebRequest.Create(logonServerUrl);
logonRequest.AllowAutoRedirect = false;
logonRequest.CookieContainer = new CookieContainer();
HttpWebResponse logonResponse = (HttpWebResponse)logonRequest.GetResponse();
authCookie = null;

using (logonResponse)
{
if (HttpStatusCode.Found != logonResponse.StatusCode)
{
// throw new CrmException(logonServerUrl, ErrorCodes.InvalidOperation);
}

if (null == (authCookie = logonResponse.Cookies["CRMAuthCookie"]))
{
// throw new CrmException(logonServerUrl, ErrorCodes.InvalidOperation);
}
}

// Now we have the cookie, make sure the credential is valid by passing the cookie back to CRM
logonRequest = (HttpWebRequest)WebRequest.Create(serverUri);

// The following user agent is required by CRM
logonRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)";
logonRequest.AllowAutoRedirect = false;
logonRequest.CookieContainer = new CookieContainer();
logonRequest.CookieContainer.Add(authCookie);

logonResponse = (HttpWebResponse)logonRequest.GetResponse();

using (logonResponse)
{
if (HttpStatusCode.OK != logonResponse.StatusCode)
{
throw new InvalidOperationException(logonServerUrl);
}
}
return (authCookie);
}
catch (Exception err)
{
return null;
}
}

That’s about it. Using this technique, you should be able to get your SPE Callouts to work.

Make sure that the callout.base is exists in the servers GAC, if not, copy it there.

Note that post-callouts, won’t break the execution if there is an error but they will leave the error exception sprecification in the eventlog so make sure you have a look at it.

So, in short, there are two main differences when developing callouts that use web services when comparing normal CRM with SPE CRM, they are:

- DLL:s are unique. The version number for SPE is 3.0.5745.0 while the version for the normal CRM is: 3.0.5300.0.

- To authenticate, you cannot use the normal System.Net.CredentialCache.DefaultCredentials but, you have to use the “slightly” more complicated method of capturing the authentication cookie and using it to log in.

As you might have noticed in the code, the user is hard-coded, which means that there will not be any impersonation in the way it works in normal CRM. I have an idea of how this might be solved; by creating a new aspx-page to capture the username and password, creating a cookie using these credentials and then storing it in the session variable to enable further loggin in later with the webservice. One would also have to make sure that the cookie can be used by the normal IE klient as well. As you might understand, there are some question marks here that I will try to straighten out. If I find a solution to impersonation in CRM SPE, I will be sure to create a post about it!


Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Tuesday, February 27, 2007

Service Provider Edition / Hosted CRM

I'm currently working with a customer who's got a service provider edition of Microsoft CRM.

I am developing callouts and will write some more about what the differences are, for now I will leave you with a reference to a blog that actually mentiones something about this.

For one, there is a different version of Microsoft.Crm.Platform.Callout.Base.dll and there is a different way of authenticating when using the webservice. I will write I bit more about it later.

Have a look at this blog for now: Microsoft.Crm.Platform.Callout.Base.dll

http://crm.davidyack.com/journal/2006/7/21/callouts-and-the-service-provider-edition.html

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Import of customizations not working in IE 7

As Sonoma Partner, one of the most competent CRM partners, has noticed, as I have also done, there is a problem and a fix for it. The problem being that the progress dialog that shows up when importing customizations doesn't go away when using IE 7. Please read more at the Sonoma partner blog:

http://blog.sonomapartners.com/2007/01/importing_custo.html

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Wednesday, February 21, 2007

How to create many-to-many relationships in CRM

As many of you know, only one-to-many and many-to-one relationships can be created in Microsoft CRM 3. To create many-to-many relationships, the most commonly used technique is a "middle" entity, or mapping entity. However, there are several other options for the more pragmatic customizer. Please refer to the CRM-Team blog post:

http://blogs.msdn.com/crm/archive/2007/02/15/many-to-many-relationships-in-ms-dynamics-crm-3-0.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

CRM Analytics foundation

The analytics foundation for Microsoft CRM has been released. It is a platform for business intelligence based on CRM Data. It contains OLAP cubes, dashboards and more. Please have a look at the codeplex homepage for more information:
http://www.codeplex.com/crmanalytics

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Monday, February 19, 2007

MOSS and CRM Webparts

I was reading around a bit and found a blog posting concerning how to make the CRM-webparts work in MOSS. It seems you have to install them the same way you installed the CRM-webparts in the Swedish SharePoint v.2, earlier, i.e. by extracting the files from the cab and installing them manually.

Please click this posts heading to go to the posting I found.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

IFrame security problems

I recently wanted to show a dynamic SQL RS report in CRM using customization of the sitemap.

I had some problems with the dymanic functionalities of the report, which didn't work. After some work, I found that it was due to the fact that the Reporting Server had the wrong security settings in IE, and hence was prohibited to fully use the JavaScripts that controlled the drill-down of the reports. The simple solution was to add the reporting server to Local Intranet Sites in IE.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Monday, February 05, 2007

How to create .NET-class files from xsd files

XML is great! But most of you who have worked with it probably pull your hair out due to all the navigational problems and code needed to navigate through the xml-structure. Wouldn't it be neat if there was some way to create a .NET class from an xsd-schema and load it up with the contents of a specific xml-structure? Well, guess what, there is, and it is provided by our very good friends in Redmond, WA, Microsoft.

To some of you, this might be yesterday’s news, but for those of you who havn't tried it, you should.

I will try to explain how to do it here. In this example, we'll be basing the .NET class on a InfoPath form. InfoPath is, as you might know, just a front-end to XML, ie. a user friendly way of creating xml-data.

Create you xml-form in any way you like. I won't go into how exactly you do that, but
That will create a schema in the background. To export it to an xsd-file, select “Save as source files…” from the file menu and direct it to a directory of your choice, for instance, “c:\temp”.

Use the file explorer, go to the directory where you just saved the files, and you will find a file with the name of your different data sources followed by the extension “.xsd” in this directory. Remember the name of the xsd-file, let’s call it “source.xsd” in this example.

Then, start up a “Visual Studio 2005 Command Prompt”, go to the directory where you saved the source files, for instance:

cd c:\temp

Then, using the command xsd you can create the cs-file containing the .NET-class with the following command:

xsd source.xsd /c

This will create a new file called “source.cs”. This is the file that contains the .NET class.

Now open your development project and add the file source.cs to the project. This will now give you access to the .NET class in you project. Open the file and you can see the name of your class, it should be “myFields”.

Now we want to instantiate the class with some xml-data. This is done in the following manner using c#-code.

XmlSerializer serializer = new XmlSerializer(typeof(myFields));
XmlTextReader reader = new XmlTextReader(“c:\XmlInstanceOfSourceXsd.xml”);
myFields fields = (myFields)serializer.Deserialize(reader);

Now, you can access the xml-data using the instance fields of the class myFields.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se