Search code examples
c#pluginsdynamics-crmmicrosoft-dynamicsmicrosoft-dynamics-webapi

Dynamics C# Plugin fails when run, but succeeds when Debugging


Overview

I am on Dynamics 2016 on premise.

I have a Business Process Flow in Microsoft Dynamics to handle creation of a new client. When the process finishes, I am attaching a workflow that kicks off an action which calls a plugin to do some custom processing. I am following this article to set up this process. When this plugin is triggered in Dynamics, it appears to run successfully, but does not create the records I am expecting it to create. However, when I profile the plugin and run it through the Plugin Registration Tool/Visual Studio the records are created that I expect to see.

When I added trace logs to my plugin, I noticed that it appears I am receiving a 401 - Unauthorized error from Dynamics when I call the Web API. When I looked at the network traffic while debugging it looks like I receive an initial 401 error, but then a retry successfully gets the records I am trying to get.

Code

This is the section of code I think the 401-Unauthorized error is coming from

private void GetGlobalFieldNameMapsAsync(String url = "ccseq_globalfieldnamemaps?$select=ccseq_system,ccseq_entitytype,ccseq_fieldtype,ccseq_name,ccseq_datatype")
{
    HttpClient client = new HttpClient(new HttpClientHandler() { Credentials = new NetworkCredential("admin", "password", "domain") });
    HttpResponseMessage responseMessage = new HttpResponseMessage();
    try
    {
        client.BaseAddress = new Uri(Helpers.GetSystemUrl(APIConnector.Application.Dynamics));
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
        client.DefaultRequestHeaders.Add("OData-Version", "4.0");    

        responseMessage = client.GetAsync(url).Result;    

        JObject responseData = JObject.Parse(responseMessage.Content.ReadAsStringAsync().Result);

        if (responseData["@odata.nextLink"] != null)
        {
                    GetGlobalFieldNameMapsAsync(Convert.ToString(responseData["@odata.nextLink"]));
        }

        foreach (var v in responseData["value"])
        {
            GlobalFieldNameMap newGFNM = new GlobalFieldNameMap();
            newGFNM.System.Value = Convert.ToInt32(v["ccseq_system"]);
            newGFNM.EntityType.Value = Convert.ToInt32(v["ccseq_entitytype"]);
            newGFNM.FieldType.Value = Convert.ToInt32(v["ccseq_fieldtype"]);
            newGFNM.FieldName.Value = Convert.ToString(v["ccseq_name"]);
            newGFNM.DataType.Value = Convert.ToInt32(v["ccseq_datatype"]);
            FieldNameMap.Add(newGFNM);
        }

    }
    catch (Exception e)
    {
        throw new Exception(e.Message + " - " + responseMessage.Content.ReadAsStringAsync().Result);
    }
}

Network Traffic

Network Traffic

I can't seem to puzzle out how I am seeing the plugin successfully run during debugging, but seeing it fail when running directly in dynamics. The plugin appears to be running under the same user regardless of whether it's running in Dynamics or on my local machine. I'm passing in admin credentials so they should have full permissions to do anything in the system. Any thoughts?

I have asked this question and this question which may be related, but don't quite cover this issue.


Update

I noticed this error message in the trace logs

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>IIS 8.5 Detailed Error - 401.1 - Unauthorized</title> 
<style type="text/css"> 
<!-- 
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;} 
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;} 
.config_source code{font-size:.8em;color:#000000;} 
pre{margin:0;font-size:1.4em;word-wrap:break-word;} 
ul,ol{margin:10px 0 10px 5px;} 
ul.first,ol.first{margin-top:5px;} 
fieldset{padding:0 15px 10px 15px;word-break:break-all;} 
.summary-container fieldset{padding-bottom:5px;margin-top:4px;} 
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;} 
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px; 
font-weight:bold;font-size:1em;} 
a:link,a:visited{color:#007EFF;font-weight:bold;} 
a:hover{text-decoration:none;} 
h1{font-size:2.4em;margin:0;color:#FFF;} 
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;} 
h4{font-size:1.2em;margin:10px 0 5px 0; 
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif; 
color:#FFF;background-color:#5C87B2; 
}#content{margin:0 0 0 2%;position:relative;} 
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;} 
.content-container p{margin:0 0 10px 0; 
}#details-left{width:35%;float:left;margin-right:2%; 
}#details-right{width:63%;float:left;overflow:hidden; 
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF; 
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal; 
font-size:1em;color:#FFF;text-align:right; 
}#server_version p{margin:5px 0;} 
table{margin:4px 0 4px 0;width:100%;border:none;} 
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;} 
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;} 
thead th{background-color:#ebebeb;width:25%; 
}#details-right th{width:20%;} 
table tr.alt td,table tr.alt th{} 
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;} 
.clear{clear:both;} 
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;} 
--> 
</style> 

</head> 
<body> 
<div id="content"> 
<div class="content-container"> 
<h3>HTTP Error 401.1 - Unauthorized</h3> 
<h4>You do not have permission to view this directory or page using the credentials that you supplied.</h4> 
</div> 
<div class="content-container"> 
<fieldset><h4>Most likely causes:</h4> 
<ul> <li>The username supplied to IIS is invalid.</li> <li>The password supplied to IIS was not typed correctly. </li> <li>Incorrect credentials were cached by the browser.</li> <li>IIS could not verify the identity of the username and password provided.</li> <li>The resource is configured for Anonymous authentication, but the configured anonymous account either has an invalid password or was disabled.</li> <li>The server is configured to deny login privileges to the authenticating user or the group in which the user is a member.</li> <li>Invalid Kerberos configuration may be the cause if all of the following are true:</li> <ul> <li>Integrated authentication was used.</li> <li>the application pool identity is a custom account.</li> <li>the server is a member of a domain.</li> </ul> </ul> 
</fieldset> 
</div> 
<div class="content-container"> 
<fieldset><h4>Things you can try:</h4> 
<ul> <li>Verify that the username and password are correct, and are not cached by the browser.</li> <li>Use a different username and password.</li> <li>If you are using a custom anonymous account, verify that the password has not expired.</li> <li>Verify that the authenticating user or the user's group, has not been denied login access to the server.</li> <li>Verify that the account was not locked out due to numerous failed login attempts.</li> <li>If you are using authentication and the server is a member of a domain, verify that you have configured the application pool identity using the utility SETSPN.exe, or changed the configuration so that NTLM is the favored authentication type.</li> <li>Create a tracing rule to track failed requests for this HTTP status code. For more information about creating a tracing rule for failed requests, click <a href="http://go.microsoft.com/fwlink/?LinkID=66439">here</a>. </li> </ul> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>Detailed Error Information:</h4> 
<div id="details-left"> 
<table border="0" cellpadding="0" cellspacing="0"> 
<tr class="alt"><th>Module</th><td>&nbsp;&nbsp;&nbsp;WindowsAuthenticationModule</td></tr> 
<tr><th>Notification</th><td>&nbsp;&nbsp;&nbsp;AuthenticateRequest</td></tr> 
<tr class="alt"><th>Handler</th><td>&nbsp;&nbsp;&nbsp;ExtensionlessUrlHandler-Integrated-4.0</td></tr> 
<tr><th>Error Code</th><td>&nbsp;&nbsp;&nbsp;0xc000006d</td></tr> 

</table> 
</div> 
<div id="details-right"> 
<table border="0" cellpadding="0" cellspacing="0"> 
<tr class="alt"><th>Requested URL</th><td>&nbsp;&nbsp;&nbsp;https://crminternal.cohencpa.com:443/COHEN/api/data/v8.2/ccseq_globalfieldnamemaps?$select=ccseq_system,ccseq_entitytype,ccseq_fieldtype,ccseq_name,ccseq_datatype</td></tr> 
<tr><th>Physical Path</th><td>&nbsp;&nbsp;&nbsp;C:\Program Files\Microsoft Dynamics CRM\CRMWeb\COHEN\api\data\v8.2\ccseq_globalfieldnamemaps</td></tr> 
<tr class="alt"><th>Logon Method</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 
<tr><th>Logon User</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 

</table> 
<div class="clear"></div> 
</div> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>More Information:</h4> 
This error occurs when either the username or password supplied to IIS is invalid, or when IIS cannot use the username and password to authenticate the user. 
<p><a href="http://go.microsoft.com/fwlink/?LinkID=62293&amp;IIS70Error=401,1,0xc000006d,9600">View more information &raquo;</a></p> 
<p>Microsoft Knowledge Base Articles:</p> 
<ul><li>907273</li><li>871179</li><li>896861</li></ul> 

</fieldset> 
</div> 
</div> 
</body> 
</html> 

Solution

  • Upon investigating the 401.1 Unauthorized error, I came across this article. Here's the relevant piece:

    When you use the fully qualified domain name (FQDN) or a custom host header to browse a local Web site that is hosted on a computer that is running Microsoft Internet Information Services (IIS) 5.1 or a later version, you may receive an error message that resembles the following:

    HTTP 401.1 - Unauthorized: Logon Failed

    This issue occurs when the Web site uses Integrated Authentication and has a name that is mapped to the local loopback address.

    Note You only receive this error message if you try to browse the Web site directly on the server. If you browse the Web site from a client computer, the Web site works as expected.

    The article provides several methods for resolving the issue, but here is the one that worked for us (must be done on the server):

    1. Use regedit to navigate to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanmanServer\Parameters and add a value called DisableStrictNameChecking (REG-DWORD, Decimal) with a value of 1
    2. Use regedit to navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 and add a Multi-String value called BackConnectionHostNames with a value of your hostname of the web api endpoint
    3. Open the command line and type iisreset (must be run as administrator)
    4. Restart the server