Search code examples
silverlightwcfweb-configcross-domainwcf-configuration

Crossdomain WCF - Silverlight configuration error a:ActionNotSupported


I tried to run WCF functions from SilverLight Code. WCF is runing on site www.my-site.com Silverlight application is downloaded from site www.my-site.com as < IFrame/> part of html page which is downloaded from site www.vkontakte.ru. I have received an a:ActionNotSupported error.
What is wrong?

Here is request that was sent by my silverlight application:

POST http://www.my-site.com/MyService.svc HTTP/1.1
Accept: /
Referer: http://www.my-site.com/ClientBin/MySlApp.xap
Accept-Language: ru-RU
Content-Length: 153
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IMyService/Add"
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: www.my-site.com
Connection: Keep-Alive
Pragma: no-cache

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <Add xmlns="http://tempuri.org/">
      <a1>1</a1>
      <a2>1</a2>
    </Add>
  </s:Body>
</s:Envelope>

As result I have recieved folowing response:

HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Length: 710
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sun, 11 Sep 2011 16:34:19 GMT

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
  <Code>
    <Value>Sender</Value>
    <Subcode>
      <Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">
        a:ActionNotSupported
      </Value>
    </Subcode>
  </Code>
  <Reason>
    <Text xml:lang="en-US">
      The message with Action '' cannot be processed at the receiver,
      due to a ContractFilter mismatch at the EndpointDispatcher.
      This may be because of either a contract mismatch
      (mismatched Actions between sender and receiver)
      or a binding/security mismatch between the sender and the receiver.
      Check that sender and receiver have the same contract and the same binding
      (including security requirements, e.g. Message, Transport, None).
    </Text>
  </Reason>
</Fault>

Silverlight request code:

        BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
        EndpointAddress endpointAddress =
            new EndpointAddress("http://www.my-site.com/MyService.svc");
        IDbService service =
            new ChannelFactory<IDbService>(basicHttpBinding, endpointAddress)
                .CreateChannel();
        AsyncCallback asy = delegate(IAsyncResult result)
                                {
                                    Trace.WriteLine(service.EndAdd(result));
                                };
        service.BeginAdd(1, 1, asy, null);

Silverlight operation contract interface:

[ServiceContract]
public interface IMyService
{
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginAdd(long a1, long a2, AsyncCallback callback, object state);

    long EndAdd(IAsyncResult result);
}

WCF operation contract interface:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    long Add(long a1, long a2);
}

WCF Service code:

[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService: IMyService
{
    public long Add(long a1, long a2)
    {
        return a1 + a2;
    }
}

part of web.config:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior name="MySlApp.Web.ServiceMyServiceAspNetAjaxBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="MySlApp.Web.MyServiceAspNetAjaxBehavior">
        <enableWebScript />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true" />
  <services>
    <service name="MySlApp.Web.DbService"
             behaviorConfiguration="MySlApp.Web.ServiceMyServiceAspNetAjaxBehavior">
      <endpoint address=""
          binding="webHttpBinding" contract="MySlApp.Web.IMyService" />
    </service>
  </services>
</system.serviceModel>

clientaccesspolicy.xml:

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="http://www.my-site.com" />
        <domain uri="http://www.vkontakte.ru" />
        <domain uri="http://*.vkontakte.ru" />
        <domain uri="http://www.vk.com" />
        <domain uri="http://*.vk.com" />
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

crossdomain.xml:

<?xml version="1.0" encoding="utf-8" ?>
<cross-domain-policy>
  <allow-access-from domain="www.my-site.com" />
  <allow-access-from domain="www.vkontakte.ru" />
  <allow-access-from domain="*.vkontakte.ru" />
  <allow-access-from domain="www.vk.com" />
  <allow-access-from domain="*.vk.com" />
</cross-domain-policy>

Solution

  • That is not a cross-domain problem. The issue is that you're sending a request which conforms to the basicHttpBinding, while the server endpoint uses the webHttpBinding. If you change the web.config to the one listed below, it should work.

    <system.serviceModel>
      <behaviors>
        <serviceBehaviors>
          <behavior name="MySlApp.Web.ServiceMyServiceAspNetAjaxBehavior">
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
          </behavior>
        </serviceBehaviors>
      </behaviors>
      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
          multipleSiteBindingsEnabled="true" />
      <services>
        <service name="MySlApp.Web.DbService"
                 behaviorConfiguration="MySlApp.Web.ServiceMyServiceAspNetAjaxBehavior">
          <endpoint address=""
              binding="basicHttpBinding" contract="MySlApp.Web.IMyService" />
        </service>
      </services>
    </system.serviceModel>
    

    If you can't change your service, then you'll need to change the client. webHttpBinding endpoints also known as WCF WebHttp endpoints, or (somehow overusing the 'REST' term) WCF REST endpoints, can't be accessed directly via SL using the WCF programming model (client class, ChannelFactory<T>, etc). It can be done (see the post about consuming REST/POX services via SL, and the post about consuming REST/JSON services via SL), but it's not something too easy (most people use simple classes such as WebClient or HttpWebRequest to consume those services.