.NET WCF RIA + Услуги; Могу ли я иметь все это? - PullRequest
2 голосов
/ 09 ноября 2011

Мне бы хотелось, чтобы «обычные» вызовы службы WCF отвечали на мой корневой URL, а также обычные вещи RIA.Кажется простым, но оказывается немного болезненным.RIA работает, в том числе ODATA JSON и SOAP, но традиционные веб-службы не хотят запускать корневой URL.

См. Следующий код:

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();
        }
    }
}

Доступ к http://localhost:999/Test должно привести к отображению только теста, но вместо этого я получу:

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

Кто-нибудь может увидеть, что мне не хватает?

Заранее спасибо!

1 Ответ

0 голосов
/ 10 ноября 2011

Мне просто нужно было возвращать необработанные строки в этой конечной точке, поэтому я реализовал свои собственные HttpBehavior и DispatchFormatter следующим образом:

    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());
        }
    }

и изменилось

ep.Behaviors.Add(new WebHttpBehavior());
...