SignalR客户端方法触发多次

本文关键字:客户端 方法 SignalR | 更新日期: 2023-09-27 18:06:27

我正在玩SignalR,试图在谷歌地图上创建一个热图覆盖。然而,我的方法是触发多次,我不知道为什么。

从SQL返回的数据被格式化为JSON,所以我可以使用这个插件- http://www.patrick-wied.at/static/heatmapjs/

将其绘制到覆盖上

我一直在跟随在http://techbrij.com/database-change-notifications-asp-net-signalr-sqldependency上找到的web api演示,但没有运气。我的代码如下:

视图(剪辑以显示相关代码)

<script type="text/javascript">
    var map;
    var heatmap;
    var testData;
    $(function () {
        // Proxy created on the fly
        var sales = $.connection.productSalesHub;
        // Declare a function on the product sales hub so the server can invoke it
        sales.client.displaySales = function () {
            getSalesData();
        };
        // Start the connection
        $.connection.hub.start();
        getSalesData();
    });
    function getSalesData() {
        $.ajax({
            url: '../api/values',
            type: 'GET',
            datatype: 'json'
        })
            .done(function (res) {
            if (res.length > 0) {
                var myLatlng = new google.maps.LatLng(48.3333, 16.35);
                // sorry - this demo is a beta
                // there is lots of work todo
                // but I don't have enough time for eg redrawing on dragrelease right now
                var myOptions = {
                    zoom: 2,
                    center: myLatlng,
                    mapTypeId: google.maps.MapTypeId.SATELLITE,
                    disableDefaultUI: false,
                    scrollwheel: true,
                    draggable: true,
                    navigationControl: true,
                    mapTypeControl: false,
                    scaleControl: true,
                    disableDoubleClickZoom: false
                };
                testData = res;
                map = new google.maps.Map(document.getElementById("heatmapArea"), myOptions);
                heatmap = new HeatmapOverlay(map, {
                    "radius": 15,
                    "visible": true,
                    "opacity": 60,
                    legend: {
                        position: 'br',
                        title: 'Amount of items sold'
                    }
                });

                google.maps.event.addListenerOnce(map, "idle", function() {
                    heatmap.setDataSet(testData);
                });
            }
            })
            .fail(function () {
                alert("error");
            })
            .always(function() {
                alert("complete");
            });
    }
</script>

值控制器:

public class ValuesController : ApiController
{
    ProductSalesRepository repo = new ProductSalesRepository();

    // GET api/values
    public JObject Get()
    {
        var data = repo.GetProductSalesData();
        return repo.BuildJson(data);
    }

}

ProductSalesHub.cs

public class ProductSalesHub : Hub
{
    public static void Show()
    {
        IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ProductSalesHub>();
        context.Clients.All.displaySales();
    }
}

最后,我的repo

public class ProductSalesRepository
{
    public IEnumerable<ProductSalesInfo> GetProductSalesData()
    {
        using (
            var connection =
                new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(@"SELECT top 10 [lat],[lng],[count]
           FROM [dbo].[ProductSales]", connection))
            {
                // Make sure the command object does not already have
                // a notification object associated with it.
                command.Notification = null;
                SqlDependency dependency = new SqlDependency(command);
                dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
                if (connection.State == ConnectionState.Closed)
                    connection.Open();
                using (var reader = command.ExecuteReader())
                    return reader.Cast<IDataRecord>()
                        .Select(x => new ProductSalesInfo()
                            {
                                Lat = x.GetString(0),
                                Long = x.GetString(1),
                                Count = x.GetInt32(2)
                            }).ToList();
            }
        }
    }
    public JObject BuildJson(IEnumerable<ProductSalesInfo> data )
    {
        IEnumerable<ProductSalesInfo> productSalesInfos = data as List<ProductSalesInfo> ?? data.ToList();
        int max = (from d in productSalesInfos.ToList() select d.Count).Max();
        JObject o = new JObject(
            new JProperty("max", max),
            new JProperty("data",
                          new JArray(from d in productSalesInfos
                                     select new JObject(
                                         new JProperty("lat", d.Lat),
                                         new JProperty("lng", d.Long),
                                         new JProperty("count", d.Count)))));
        return o;
    }
    private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        ProductSalesHub.Show();
    }
}

我已经盯着这个几个小时了,没有弄清楚为什么ajax调用被触发多次。

任何想法?

SignalR客户端方法触发多次

我也遇到过同样的问题。我正在注入我的存储库类,并且有它的多个实例。这里每次调用GetProductSalesData()方法时都添加事件。我会在构造函数中添加一次事件,并使用单例模式来确保它只被调用一次。

因为每个打开页面的客户端都通过signalR和signalR响应向所有客户端请求服务器,这就是为什么你会看到多个响应和请求。使用

this.Clients.Client(this.Context.ConnectionId).displaySales();
不是

 context.Clients.All.displaySales();

欢呼。