您的位置:首页 > 其它

MSCRM 通过Ajax调用WCF服务

2017-03-02 18:22 295 查看

Call WCF Service from Dynamics CRM using AJAX

A couple of days back, I had one of my ex-colleagues call me regarding a problem he had been facing when making jQuery AJAX calls to JSON WCF Services from Dynamics CRM. I had encountered this same problem some years back, when I had just started my career as a CRM Developer. And since I toiled hard to find a resolution for that back then, it’s something that remains quite vibrant in my brain. I told him the solution only to get an appreciation the next day that it had worked for him. I was glad to have helped someone fix this without having to scour through the internet for solutions; and hence decided to put it up in my blog when a different friend of mine called me a few days back again with the same problem (except this time there was no Dynamics CRM involved). Now, to the problem. The problem was while making jQuery Ajax calls to a custom RESTful (JSON) WCF Service from Dynamics CRM, a network related error popped up. Even setting “cors: true” in the client jQuery code didn’t help. In case you’re wondering what “cors” refers to, it means Cross Origin Resource Sharing. By enabling it, you are allowing cross-domain communication from the browser. Anyways, since that didn’t help, this is where the following solution comes into play. The trick here is to make some changes in the server side, that is, in the WCF Service code to make the request happen successfully. The changes – that’s exactly what we’re going to see in this article. But instead of going straight to the solution, let’s try to reproduce the issue and then apply the fix.

Call WCF Service from Dynamics CRM – The Problem

Let’s start with a very basic JSON WCF Service. Just one simple method, that takes in a single argument and prepends a fixed string “MyWCFResponse” to it. This is just for demonstration, so to keep it simple it’s GET, so the parameter is passed in the URL itself.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 01

The contents of “IService.cs” being as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestWcfService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(UriTemplate = "getdata/{value}", Method = "GET", ResponseFormat =WebMessageFormat.Json)]
Response GetData(string value);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestWcfService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(UriTemplate = "getdata/{value}", Method = "GET", ResponseFormat =WebMessageFormat.Json)]
Response GetData(string value);
}
}

The implemented class “Service.svc.cs” has the following contents:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestWcfService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
public class Service : IService
{
public Response GetData(string value)
{
return new Response()
{
Data = "MyWCFResponse" + value,
Status = "OK"
};
}
}

public class Response
{
public string Data { get; set; }
public string Status { get; set; }
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestWcfService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
public class Service : IService
{
public Response GetData(string value)
{
return new Response()
{
Data = "MyWCFResponse" + value,
Status = "OK"
};
}
}

public class Response
{
public string Data { get; set; }
public string Status { get; set; }
}
}

And a simple “web.config” to enable JSON behavior:

<?xml version="1.0"?>
<configuration>

<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="RestWcfService.Service">
<endpoint address="" binding="webHttpBinding" contract="RestWcfService.IService"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>

</configuration>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

<?xml version="1.0"?>
<configuration>

<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="RestWcfService.Service">
<endpoint address="" binding="webHttpBinding" contract="RestWcfService.IService"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>

</configuration>

Now, after you have built the solution and deployed it in IIS, we are going to try and invoke it from Dynamics CRM using a jQuery Ajax call. One thing to be noted here is that, the Dynamics CRM is installed in a different server than the one where we have hosted the WCF Service. Although, some development environments follow everything-inside-a-single-box nomenclature, when it comes to production environments, Dynamics CRM servers are always maintained separately from additional custom components. So, we are going to simulate a production environment nomenclature here.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 02

We are going to be using the following piece of code On Load of Contact form in Dynamics CRM to fill up a particular field with the value returned from the WCF Service.

function ContactOnLoad()
{
var fname = Xrm.Page.getAttribute("firstname").getValue();

if(fname != null || fname != 'undefined' || fname != "")
{
jQuery.support.cors = true;
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: 'http://192.168.164.139/RestWcfService/Service.svc/getdata/' + fname,
processData: false,
dataType: "json",
success: function (response) {
if(response != null || response != 'undefined')
{
var respData = response.Data;
Xrm.Page.getAttribute("lastname").setValue(respData);
}
},
error: function (a, b, c) {
alert(a.responseText);
}
});
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

function ContactOnLoad()
{
var fname = Xrm.Page.getAttribute("firstname").getValue();

if(fname != null || fname != 'undefined' || fname != "")
{
jQuery.support.cors = true;
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: 'http://192.168.164.139/RestWcfService/Service.svc/getdata/' + fname,
processData: false,
dataType: "json",
success: function (response) {
if(response != null || response != 'undefined')
{
var respData = response.Data;
Xrm.Page.getAttribute("lastname").setValue(respData);
}
},
error: function (a, b, c) {
alert(a.responseText);
}
});
}
}

For demo purposes, we are simply fetching the First Name of the Contact record, passing it to the WCF Service and updating the Last Name of the Contact with the response received from the Service. The code looks okay, except when you run it, it encounters an error.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 03

Debugging the code shows that it’s going directly to the error callback, contrary to what we had expected.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 04

You might be clueless about what’s going on. This where F12 (IE developer tools) comes to aid. Popping it up by pressing F12 shows the actual cause behind the problem – “Network Error, Access is denied”.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 05

Call WCF Service from Dynamics CRM – The Solution

Now that we have been reproduce the issue, let’s go ahead and fix it. Open up your WCF Service code in Visual Studio. Add the “Global.asax” file to your project by right clicking on the Project > Add > New Item > Global Application Class.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 06




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 07

Open up the “Global.asax” file and add the following piece of code:

protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}

1
2
3
4
5
6
7
8
9
10
11
12

protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}

Save the file, recompile your Service code and re-deploy it to IIS. That’s it! Now head back to Dynamics CRM and try opening up a Contact record, you should be able to see the effect of the code!




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 08

See how the last name is replaced with (“MyWCFResponse” + First Name) which was returned by the WCF Service. Opening up the Developer Tools (F12) shows that there are no network related errors as were shown earlier.




Call WCF Service from Dynamics CRM 2013 using AJAX – Image 09

Well, that’s it. If you’re reading it right now, I hope this saved some of your time and helped you! =) And this is not something specific for Dynamics CRM, it’s something that works for any jQuery ajax calls.

来源:http://mscrmhacks.com/call-wcf-service-from-dynamics-crm/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: