Social Networking and ISA Server (proxy authentication)

Jan 18, 2010 at 11:32 PM
Edited Jan 18, 2010 at 11:33 PM

I've been investigating a problematic Social Networking installation where everything would install, but the workflow woudl encounter an error while attempting to get updates from Twitter. After a lot of debugging and trying different things, I realised that there could be an authentication issue with the ISA proxy server. I added a little bit of test code in msa_twitter.cs in the SendRequest() method, as follows:

case "GET":
    WebClient wCli = new WebClient();
    if (_creds != null)
    {
         wCli.Credentials = _creds;
     }
     //[TPL] Configure web proxy
     IWebProxy proxy = new WebProxy("sbs", 8080);
     proxy.Credentials = new NetworkCredential(@"DOMAIN\user", "password");
     wCli.Proxy = proxy;
                    try
                    {

And lo and behold, status information started flowing. So, if you;re behind an ISA proxy/firewall server, you;re probably going to have to modify the code along similar lines.

Jan 20, 2010 at 1:48 AM

As a follow-up to my earlier comments about needing to configure a proxy if running behind ISA server, there are also two more bug fixes that I had to add before I could get MSA_SN to work properly.

First, the code as supplied does not correctly parse Twitter timestamps. DateTime.ParseExact chokes on the slightly odd time zone value, which in my zone (GMT/UK) comes from twitter with the value "+0000". DateTime.ParseExact can use a format dtring of "z", "zz", or "zzz", corresponding to "+0", "+00" or "+00:00" respectively, none of which match the Twitter format. In fact, the .Net documentation recommends not using those format strings with DateTime values, but to use a DateTimeOffset object instead. True enough, DateTimeOffset does seem to work better. So, I've changed the code in teh BuildDynEntity method, in msa_datapump.cs, as follows:

  case "CrmDateTimeProperty":
	//[TPL] Twitter timestamps contain a slightly odd timezone specifier "+0000" that doesn;t work
	// well with DateTime.ParseExact(). So we parse it with a DateTimeOffset.ParseExact() instead,
	// but then that produces a string format that CRM doesn't like, so we convert it to a
	// regular DateTime in local time, then create the CrmDateTime item using the static
	// CrmDateTime.FromUser() method. At no time do we convert the DateTime to a string.
	// Everyone is happy!
         CrmDateTimeProperty crmDateTimeProperty = new CrmDateTimeProperty();
         CrmDateTime crmDateTimeValue = new CrmDateTime();
	DateTimeOffset parsedDateTime =	  DateTimeOffset.ParseExact(CRMAttrValue, "ddd MMM dd HH:mm:ss zzz yyyy", null);
	DateTime localDateTime = new DateTime(parsedDateTime.Ticks, DateTimeKind.Local);
         crmDateTimeProperty.Value = CrmDateTime.FromUser(localDateTime);
         crmDateTimeProperty.Name = CRMAttrName;
         crmEntity.Properties.Add(crmDateTimeProperty);
         break;

Second, the MSA_snstatus entity is completely missing an attribute, called MSA_snContributors. The missing attribute trips up the data pump when it tries to create new status records in the CRM system, the CRM server rejects the Create request with an error. This missing attribute needs to be added into the Register.xml file in the msa_sn_installer project. Add the following XML segment around line 1564, just after MSA_snGeo and before MSA_snid:

            <attribute PhysicalName="MSA_snContributors">
              <Type>nvarchar</Type>
              <Length>200</Length>
              <ValidForCreateApi>1</ValidForCreateApi>
              <ValidForUpdateApi>1</ValidForUpdateApi>
              <ValidForReadApi>1</ValidForReadApi>
              <IsCustomField>1</IsCustomField>
              <AttributeTypeId>00000000-0000-0000-00aa-11000000001e</AttributeTypeId>
              <DisplayMask>ValidForAdvancedFind|ValidForForm|ValidForGrid</DisplayMask>
              <Descriptions>
                <Description description="" languagecode="1033" />
              </Descriptions>
              <ImeMode>auto</ImeMode>
              <RequiredLevel>none</RequiredLevel>
              <Format>text</Format>
              <MaxLength>100</MaxLength>
              <displaynames>
                <displayname description="Contributors" languagecode="1033" />
              </displaynames>
            </attribute>

I've also made some changes to the installer project the enable it to work with IFD and multi-tennant installations. Ping me if you need more information on that.

--Tim Long www.livecrm.biz

Jan 22, 2010 at 2:04 AM
Edited Jan 22, 2010 at 2:07 AM

Tim, I had a very problematic installation of Social Networks Accelerator too. And your post solved part of my problem. Thanks.

First I'd like to make a little correction on your last post. I believe the xml you refer that needs to be updated is msa_sn_customizations.xml.

I'm still facing some problems in my IFD installation. I can now post statuses to Twitter, but even after CRM posts, the workflow remains with the status waiting. I still can't get updates from twitter. What changes have you made to the project to enable it to work with IFD?

Aldo Giovani
twitter.com/aldogiovani

Jan 22, 2010 at 2:28 AM

You're correct about the XML file - my mistake!

I found several problems that were preventing SN from retrieving updates, they are documented above. I was able to diagnose this by attaching my debugger to the CRM server and single stepping through the code. I think it's the only way you'll really figure out what is going on. To do this, you need to install the Visual Studio remote debugging components on the CRM server, then you need to build the code in visual studio in Debug configuration, and copy the PDB files to the server (you can find notes on this in the CRM SDK). I also dounf the plugin registration tool very handy for quickly uploading new versions of the msa_twitter.dll add-in.

I don't have the code available right now so I can't provide the actual code, but IIRC I think the trick is to use the discovery service to find the correct organization, obtain the CrmService URL and also obtain a security token. These items are then stored in the CrmService object and from there on the installation would proceed as normal.

--Tim

 

Jan 25, 2010 at 4:13 AM

Thanks Tim for pointing out the missing attribute 'MSA_snContributors.' My workflows are now running to completion.

Feb 10, 2010 at 11:06 AM

Hi all:

I get an error too while workflow called "MSA-Social Networking: Twitter - Update" tries to "Announce" my status message to Twitter.

I managed to get this error:

>Workflow terminated: {1AEE15E1-9115-DF11-8F32-000E7FFFB0B7} - System.Net.WebException: The remote server returned an error: (407) Proxy Authentication Required.
at System.Net.HttpWebRequest.GetResponse()
at MSA.SocialNetworking.msa_twitter.SendRequest(Uri _URL, CredentialCache _creds, String _type, String _message)
at MSA.SocialNetworking.msa_twitter.Update(String _announcement, String _source)
at MSA.SocialNetworking.Announce.Execute(ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime)
at System.Workflow.Runtime.Scheduler.Run()

-------------------

which seems to be the proxy problem that NameOfTheDragon says. But I don't have the SendRequest() method in the same file than him. I have this method in msa_CallURL.cs file. Which contains:

 

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

 

</font></font><font size="2" color="#0000ff">

 

</font>

 

public string SendRequest(string _URL, CredentialCache _creds, string _method, string _message)
        {
            string response = String.Empty;
            //if (_method == "GET" && _message != "")
            //{
            //    _URL = string.Format("{0}/?{1}", _URL, _message);
            //}
            try
            {
                HttpWebRequest wReq = (HttpWebRequest)WebRequest.Create(_URL);
                wReq.Method = _method;
                wReq.Credentials = _creds;
                wReq.Timeout = 100000;
                wReq.ServicePoint.Expect100Continue = false;
                if (_method == "POST")
                {
                    wReq.ContentType = "application/x-www-form-urlencoded";
                    byte[] bytes = Encoding.ASCII.GetBytes(_message);
                    wReq.ContentLength = bytes.Length;
                    using (Stream str = wReq.GetRequestStream())
                    {
                        str.Write(bytes, 0, bytes.Length);
                        str.Close();
                    }
                }
                using (WebResponse wResp = wReq.GetResponse())
                {
                    using (StreamReader reader = new StreamReader(wResp.GetResponseStream()))
                    {
                        response = reader.ReadToEnd();
                    }
                    wReq = null;
                    wResp.Close();
                }
                wReq = null;
            }
            catch (WebException e)
	........

 What should I do?

Thanks in advance

Feb 10, 2010 at 3:28 PM

Ok I got it. I fixed the SendRequest() method with the proxy configuration. I compile the project, get the MSA_twitter.dll and with the pluginRegistrationTool I update the plugin called "MSA_Twitter" providing it this new .dll, stored in Disk, in Server/bin/assembly. ¿Is this enough?

Thanks

Mar 24, 2010 at 3:28 PM
Edited Mar 24, 2010 at 3:28 PM

I have also tried to install this nice feature. Installation seemed to be successful, but I've got an error message when trying to sent a tweet.

I have changed the customizations file as NameOfTheDragon suggested, but still unsuccessful in sending tweets. Switching off the standard Windows Firewall did not resolve anything.

Below you'll find the error description. Any ideas?

(I run it on a Virtual Machine with Windows Server Enterprise 2008 SP2 and MS CRM 4.0 RU8)

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="ASP.NET 2.0.50727.0" />
  <EventID Qualifiers="32768">1309</EventID>
  <Level>3</Level>
  <Task>3</Task>
  <Keywords>0x80000000000000</Keywords>
  <TimeCreated SystemTime="2010-03-24T14:11:11.000Z" />
  <EventRecordID>6911</EventRecordID>
  <Channel>Application</Channel>
  <Computer>MSCRM4.crm4.mscrm.com</Computer>
  <Security />
  </System>
- <EventData>
  <Data>3005</Data>
  <Data>An unhandled exception has occurred.</Data>
  <Data>24-3-2010 15:11:11</Data>
  <Data>24-3-2010 14:11:11</Data>
  <Data>5355878a1b4d405fa14bef98bb2cf6f6</Data>
  <Data>329</Data>
  <Data>8</Data>
  <Data>0</Data>
  <Data>/LM/W3SVC/2/ROOT-1-129139096185839760</Data>
  <Data>Full</Data>
  <Data>/</Data>
  <Data>C:\Program Files\Microsoft Dynamics CRM\CRMWeb\</Data>
  <Data>MSCRM4</Data>
  <Data />
  <Data>2512</Data>
  <Data>w3wp.exe</Data>
  <Data>CRM4\Administrator</Data>
  <Data>FormatException</Data>
  <Data>Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).</Data>
  <Data>http://localhost:5555/CRM/userdefined/edit.aspx?etc=10015</Data>
  <Data>/CRM/userdefined/edit.aspx</Data>
  <Data>::1</Data>
  <Data>CRM4\Administrator</Data>
  <Data>True</Data>
  <Data>Negotiate</Data>
  <Data>CRM4\Administrator</Data>
  <Data>3</Data>
  <Data>CRM4\Administrator</Data>
  <Data>False</Data>
  <Data>at System.Guid..ctor(String g) at Microsoft.Crm.Application.Platform.EntityProxy.SetData(String value) at Microsoft.Crm.Application.Platform.EntityProxy.set_Data(String value) at Microsoft.Crm.Application.Forms.EndUserForm.RetrieveParams() at Microsoft.Crm.Application.Forms.EndUserForm.Initialize(Entity entity) at Microsoft.Crm.Application.Forms.CustomizableForm.Execute(Entity entity, String formType) at Microsoft.Crm.Application.Forms.CustomizableForm.Execute(Entity entity) at Microsoft.Crm.Application.Pages.UserDefined.DetailPage.ConfigureForm() at Microsoft.Crm.Application.Controls.AppUIPage.OnPreRender(EventArgs e) at System.Web.UI.Control.PreRenderRecursiveInternal() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)</Data>
  </EventData>
  </Event>

Sep 14, 2010 at 4:22 AM

Clearly, from the error message, you're trying to pass a malformed Guid to the CRM server. The only way you'll really figure out what is going on is to use the Visual Studio remote debugger on your CRM server and single step through the code to see where the bad Guid is coming from. Read the Crm Sdk documentation on "debugging a workflow assembly".