Call synchronous WCF operation contract methods as

2019-04-30 00:10发布

We are consuming wcf services on the silverlight application trough creating proxies using ChanellFacotry.

The Operation and Data contracts are exposed to silverlight trough assembly, which is consist of shared files from serverside Data and Operation contract libriary. (omg I hope you understand what I am saying).

So server and client are using same operation and data contracts.

Silverlight wcf client lib has a restriction to not be able to call wcf methods synchronously, as you know, so shared operation contract file has to expose asyn versions of each operation.

Writing async WCF service would make some sense if they were not containing blocking operations, but as we are using EF, asyncrhony is achieved by delegating blocking work to thread pool. This is what WCF do for synch methods anyway. And this fact makes me want to tear my eyes out (#@%!^%!@%).

Our project consultant has power to not allow generate dynamic proxies on the client to call synch operation contract methods (google Yevhen Bobrov Servelat Pieces if you are interested). So we have to write senseles implementations of async methods on serverside, without any performance gain (blocking calls as you remember).

Is it possible to call wcf web service synchronous method from silverlight using its data contract?

Have you ever faced this problem before, if so how did you solve it?

At the momment I am looking forward for generating async contracts for client side only using serverside contracts as a transformation source. Maybe there are some t4 template that can nicely do it for me?

Sorry for the wall of text, just to mix some code to my question, this is how async contract implementation looks at the momment:

    /// <summary>
    /// Subscribes to users of the specified organization.
    /// </summary>
    /// <param name="organizationId">The organization id.</param>
    public void Unsubscribe(int organizationId)
    {
        var clientId = this.OperationContext.GetClientId();
        if (string.IsNullOrEmpty(clientId))
        {
            return;
        }

        this.InternalUnsubscribe(organizationId, clientId);
    }

    /// <summary>
    /// Begins an asynchronous operation to Unsubscribe.
    /// </summary>
    /// <param name="organizationId">The organization id.</param>
    /// <param name="callback">The callback.</param>
    /// <param name="passThroughData">The pass through data.</param>
    /// <returns>
    /// An implementation of <see cref="IAsyncResult"/> that provides access to the state or result of the operation.
    /// </returns>
    public IAsyncResult BeginUnsubscribe(int organizationId, AsyncCallback callback, object passThroughData)
    {
        var clientId = this.OperationContext.GetClientId();
        if (string.IsNullOrEmpty(clientId))
        {
            return null;
        }

        var asyncResult = new VoidAsyncResult(callback, passThroughData);
        Task.Factory.StartNew(() =>
            {
                try
                {
                    this.InternalUnsubscribe(organizationId, clientId);
                    asyncResult.SetAsCompleted(false);
                }
                catch (Exception ex)
                {
                    asyncResult.SetAsCompleted(ex, false);
                }
            });
        return asyncResult;
    }

    /// <summary>
    /// Ends an existing asynchronous operation to Unsubscribe.
    /// </summary>
    /// <param name="result">The <see cref="IAsyncResult"/> provided by the BeginUnsubscribe operation.</param>
    public void EndUnsubscribe(IAsyncResult result)
    {
        var response = result as VoidAsyncResult;
        if (response != null)
        {
            response.EndInvoke();
        }
    }

1条回答
放荡不羁爱自由
2楼-- · 2019-04-30 00:48

You do not need to write the WCF service to be Async. You simple need to make a ServiceContract for your service that defines the Async methods. Here's a quick example

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    int Foo(string input);
}

//tell wcf that this contract applies to IMyService
[ServiceContract(Name = "IMyService")]
public interface IMyServiceAsync
{
    //setting AsyncPattern = true allows WCF to map the async methods to the sync ones.
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginFoo(string input, AsyncCallback callback, object asyncState);

    int EndFoo(IAsyncResult result};
}

// you only need to implement the sync contract
public class MyService : IMyService
{
    public int Foo(string input)
    {
        return input.Length;
    }
}

Now use IMyServiceAsync with your ChannelFactory and everything should work.

查看更多
登录 后发表回答