using WCF Callback and asp.net to implement publis

2019-04-16 09:28发布

问题:

This is my first web application with WCF. So please guide me as a new guy.

I'm trying to use WCF Callback to implement publish/subscribe pattern. I would like to send the message from UserA to UserB or UserA to every client at the moment. I got an example from here .

In my app, I use ASP.NET as a client to connect WCF service instead and I found a problem when I subscribe to WCF service.

The WCF service does not hold any other clients object. So when I call GetAllClients(_guid), it will return only 1 client which is itself.

Here is the code in ASP.NET page (I put every control inside updatePanel)

public partial class _Default : System.Web.UI.Page, AlertServiceCallback
{
    private AlertServiceClient _client;
    private Guid _guid = Guid.NewGuid();

    protected void Page_Load(object sender, EventArgs e)
    {
        InstanceContext context = new InstanceContext(this);
        _client = new AlertServiceClient(context);
        _client.RegisterClient(_guid);
    }

    protected void btnGetClients_Click(object sender, EventArgs e)
    {
        //Try to retrive all active clients
        Client[] cs = _client.GetAllClients(_guid);
        List<Client> list = new List<Client>(cs);
        //Bind to dropDownList to display all active clients
        ddlClients.DataSource = list;
        ddlClients.DataBind();
    }

    #region "CallBack"

    public void OnRegister(string message)
    {
        throw new NotImplementedException();
    }

    public void OnMessageSending(string message)
    {
        throw new NotImplementedException();
    }

    #endregion

}

Here is the IService and Service on WCF respectively.

[ServiceContract(Name = "AlertService",Namespace = "http://www.testWcf.com/",
CallbackContract = typeof(IAlertCallBack),SessionMode = SessionMode.Required)]
public interface IAlertService
{       
    [OperationContract(IsOneWay = true)]
    void RegisterClient(Guid id, string name);

    [OperationContract(IsOneWay = false)]
    List<Client> GetAllClients(Guid id);

    [OperationContract(IsOneWay = true)]
    void SendMessage(Guid fromId, Guid toId, string message);
}

public interface IAlertCallBack
{
    [OperationContract(IsOneWay = true)]
    void OnRegister(string message);

    [OperationContract(IsOneWay = true)]
    void OnMessageSending(string message);
}


public class AlertService : IAlertService
{

    private object locker = new object();

    private Dictionary<Client, IAlertCallBack> clients = new Dictionary<Client, IAlertCallBack>();

    public AlertService() { }

    public void RegisterClient(Guid guid)
    {
        IAlertCallBack callback = OperationContext.Current.GetCallbackChannel<IAlertCallBack>();

        //---prevent multiple clients adding at the same time---
        lock (locker)
        {
            clients.Add(new Client { Id = guid, Name = name }, callback);
        }

    }

    public List<Client> GetAllClients(Guid guid)
    {
        //---get all the clients in dictionary---
        return (from c in clients
                where c.Key.Id != guid
                select c.Key).ToList();
    }

    ...
}

Questions are:

  1. Is it possible to implement this publish/subscribe with ASP.NET and WCF callback? (I already tried on window app and it worked fine)

  2. If it is possible, how can I keep all clients that is connecting to WCF Service so I can use those GuId to call callback method.

Thank you.

回答1:

I don't know why you don't get list of clients - you should but there are much worse problems with your code.

You can't use WCF callback in ASP.NET application. It cannot work because page lives only to serve single HTTP request - it means it most probably lives only for fraction of second and so also your registration. Even If you will be able to get list of clients you will not be able to call OnRegister or OnMessageSending because there will be no proxy listening for these calls.

Even if you force proxy to live after request processing it will still notify only code behind, not your pages rendered in client browser.

Another problem is that it can work only with net.pipe or net.tcp binding. It will not work with wsDualHttp. It is very problematic to open multiple duplex clients from the same machine when using wsDualHttp.

You are doing it completely wrong. What you need is AJAX polling from client browser to asp.net which will call simple service in your chat system.