Pregunta

What I'd like to have is "regular" WCF service calls responding on my root URL as well as the regular RIA stuff. Seems simple, but is turning out to be a bit of a pain. The RIA stuff works including ODATA JSON and SOAP, but the traditional web services doesn't want to run off the root URL.

See the following code:

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.ServiceModel.Web;
using Microsoft.ServiceModel.DomainServices.Hosting;

namespace ConsoleApplication1
{
    public partial class Program
    {
        [EnableClientAccess, ServiceContract]
        public class TestDomainService : DomainService
        {
            [Query(IsDefault = true)]
            public IQueryable<Foo> GetAllFoos()
            {
                return new Foo[] { new Foo { Id = 1, Name = "Jonathan" } }.AsQueryable();
            }

            [WebInvoke(Method="GET"), OperationContract]
            public Message Test()
            {
                return WebOperationContext.Current.CreateTextResponse("Test");
            }
        }

        public class Foo
        {
            [Key]
            public int Id { get; set; }
            public string Name { get; set; }
        }

        static void Main(string[] args)
        {
            var baseUri = new Uri("http://localhost:999");

            var svc = new DomainServiceHost(typeof(TestDomainService), new Uri[] { baseUri });
            svc.Description.Behaviors.RemoveAll<AspNetCompatibilityRequirementsAttribute>();
            svc.Description.Behaviors.OfType<ServiceMetadataBehavior>().First().HttpGetEnabled = true;

            var svcDescription = DomainServiceDescription.GetDescription(typeof(TestDomainService));
            var odataEndpoints = new ODataEndpointFactory().CreateEndpoints(svcDescription, svc);
            var soapEndpoints = new SoapXmlEndpointFactory().CreateEndpoints(svcDescription, svc);
            var jsonEndpoints = new JsonEndpointFactory().CreateEndpoints(svcDescription, svc);

            var odata = odataEndpoints.First();
            odata.Contract.Namespace = new Uri(baseUri, "ODATA").ToString();
            odata.Address = new System.ServiceModel.EndpointAddress(new Uri(baseUri, "ODATA"));

            var soap = soapEndpoints.First();
            soap.Contract.Namespace = new Uri(baseUri, "SOAP").ToString();
            soap.Address = new System.ServiceModel.EndpointAddress(new Uri(baseUri, "SOAP"));

            var json = jsonEndpoints.First();
            json.Contract.Namespace = new Uri(baseUri, "JSON").ToString();
            json.Address = new System.ServiceModel.EndpointAddress(new Uri(baseUri, "JSON"));

            var ep = new ServiceEndpoint(svc.Description.Endpoints[0].Contract, new WebHttpBinding(), new EndpointAddress(baseUri));
            ep.Behaviors.Add(new WebHttpBehavior());
            var cd = ContractDescription.GetContract(typeof(TestDomainService));
            foreach (var op in cd.Operations)
            {
                if (ep.Contract.Operations.Any(o => o.Name == op.Name) == false)
                {
                    ep.Contract.Operations.Add(op);
                }
            }
            svc.Description.Endpoints.Add(ep);

            svc.Description.Endpoints.Add(odata);
            svc.Description.Endpoints.Add(soap);
            svc.Description.Endpoints.Add(json);

            svc.Open();

            foreach (var endpoint in svc.Description.Endpoints)
            {
                Console.WriteLine("Domain service started on: {0}", endpoint.Address.Uri);
            }

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}

Accessing http://localhost:999/Test should result in just Test being displayed, but instead I get:

<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>

Can anyone see what I'm missing?

Thanks in advance!

¿Fue útil?

Solución

For me, I just needed to return raw strings on that endpoint so I implemented my own HttpBehavior and DispatchFormatter as such:

    public class WebHttpBehaviorEx : WebHttpBehavior
    {
        protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            return new DynamicFormatter();
        }
    }

    public class DynamicFormatter : IDispatchMessageFormatter
    {
        public void DeserializeRequest(Message message, object[] parameters)
        {
            throw new NotImplementedException();
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            return WebOperationContext.Current.CreateTextResponse((result ?? string.Empty).ToString());
        }
    }

and changed

ep.Behaviors.Add(new WebHttpBehavior());
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top