SignalR客户端方法多次触发

时间:2014-06-02 11:33:36

标签: c# jquery asp.net signalr asp.net-web-api

我正在使用SignalR,尝试在Google地图上创建热图叠加层。但是,我的方法多次触发,我无法弄清楚原因。

从SQL返回的数据被格式化为JSON,因此我可以使用此插件将其绘制到叠加层上 - http://www.patrick-wied.at/static/heatmapjs/

我一直在关注http://techbrij.com/database-change-notifications-asp-net-signalr-sqldependency发现的网络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();
    }
}

最后,我的回购

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通话。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

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

而不是

 context.Clients.All.displaySales();

欢呼声。