如何使用 WCF 异步消费基于 REST 的服务?

发布于 2024-11-26 12:17:50 字数 768 浏览 2 评论 0原文

我想创建一个支持针对基于 REST 的服务的异步操作的代理类。

为了便于讨论,假设我有一个服务,IService

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebGet(UriTemplate = "{a}/{b}")]
    void Action(string a, string b);
}

我可以轻松地创建一个同步代理类:(

class Client: ClientBase<IService>, IService
{
    public void Action(string a, string b)
    {
        Channel.Action(a, b);
    }
}

该技术来自此 文章

是否有类似的直接制作方法代理支持异步操作(BeginAction/EndActionActionAsync 模式)?或者是我自己手动推出的最佳实践?

请注意,我无法在 Visual Studio 中添加服务引用,因为没有可用的元数据。

I want to create a proxy class that supports asynchronous operations against a REST-based service.

For the sake of discussion, let's say I have a service, IService:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebGet(UriTemplate = "{a}/{b}")]
    void Action(string a, string b);
}

I am able to easily create a synchronous proxy class with:

class Client: ClientBase<IService>, IService
{
    public void Action(string a, string b)
    {
        Channel.Action(a, b);
    }
}

(this technique is from this article)

Is there a similarly straightforward way to make the proxy support asynchronous operations (either the BeginAction/EndAction or ActionAsync patterns)? Or is the best practice to roll my own manually?

Note that I am unable to add a Service Reference in Visual Studio because there is no metadata available.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故人如初 2024-12-03 12:17:51

如果将操作合约替换为相应的开始/结束对,它也应该适用于基于 REST 的合约。您甚至可以在客户端上同时拥有同步和异步版本的操作(但在这种情况下,您只需要在同步版本上拥有 [WebGet] 属性)。

public class StackOverflow_6846215
{
    [ServiceContract(Name = "ITest")]
    public interface ITest
    {
        [OperationContract]
        [WebGet]
        int Add(int x, int y);
    }
    [ServiceContract(Name = "ITest")]
    public interface ITestClient
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state);
        int EndAdd(IAsyncResult asyncResult);

        [OperationContract]
        [WebGet]
        int Add(int x, int y);
    }
    public class Client : ClientBase<ITestClient>, ITestClient
    {
        public Client(string baseAddress)
            :base(new WebHttpBinding(), new EndpointAddress(baseAddress))
        {
            this.Endpoint.Behaviors.Add(new WebHttpBehavior());
        }

        public IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state)
        {
            return this.Channel.BeginAdd(x, y, callback, state);
        }

        public int EndAdd(IAsyncResult asyncResult)
        {
            return this.Channel.EndAdd(asyncResult);
        }

        public int Add(int x, int y)
        {
            return this.Channel.Add(x, y);
        }
    }
    public class Service : ITest
    {
        public int Add(int x, int y)
        {
            return x + y;
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        Client client = new Client(baseAddress);
        Console.WriteLine("Sync result: {0}", client.Add(66, 77));
        client.BeginAdd(44, 55, delegate(IAsyncResult ar)
        {
            int result = client.EndAdd(ar);
            Console.WriteLine("Async result: {0}", result);
        }, null);

        Console.WriteLine("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

If you replace the operation contract with a corresponding Begin/End pair, it should work for REST-based contracts as well. You can even have both sync and async versions of the operation on the client (but in this case you need to have the [WebGet] attribute on the synchronous version only).

public class StackOverflow_6846215
{
    [ServiceContract(Name = "ITest")]
    public interface ITest
    {
        [OperationContract]
        [WebGet]
        int Add(int x, int y);
    }
    [ServiceContract(Name = "ITest")]
    public interface ITestClient
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state);
        int EndAdd(IAsyncResult asyncResult);

        [OperationContract]
        [WebGet]
        int Add(int x, int y);
    }
    public class Client : ClientBase<ITestClient>, ITestClient
    {
        public Client(string baseAddress)
            :base(new WebHttpBinding(), new EndpointAddress(baseAddress))
        {
            this.Endpoint.Behaviors.Add(new WebHttpBehavior());
        }

        public IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state)
        {
            return this.Channel.BeginAdd(x, y, callback, state);
        }

        public int EndAdd(IAsyncResult asyncResult)
        {
            return this.Channel.EndAdd(asyncResult);
        }

        public int Add(int x, int y)
        {
            return this.Channel.Add(x, y);
        }
    }
    public class Service : ITest
    {
        public int Add(int x, int y)
        {
            return x + y;
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        Client client = new Client(baseAddress);
        Console.WriteLine("Sync result: {0}", client.Add(66, 77));
        client.BeginAdd(44, 55, delegate(IAsyncResult ar)
        {
            int result = client.EndAdd(ar);
            Console.WriteLine("Async result: {0}", result);
        }, null);

        Console.WriteLine("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文