【问题标题】:SignalR: Connection must be started before data can be sent. Call .start() before .send()SignalR:必须先启动连接,然后才能发送数据。在 .send() 之前调用 .start()
【发布时间】:2012-04-07 13:27:16
【问题描述】:

最近才开始使用 SignalR,几天前我开始使用它,现在无法解决问题所在。

我有我的中心:

[HubName("roleManagementHub")]
public class RoleManagementHub : GenericHub<RoleManagementRole>
{
    public RoleManagementHub(ICurrentlyViewingUserService service) : base(service)
    {
    }
}

扩展了我创建的通用集线器:

public class GenericHub<TEntity> : Hub where TEntity : class, IBusinessObject<TEntity>
{
    private readonly ICurrentlyViewingUserService service;

    public GenericHub(ICurrentlyViewingUserService service)
    {
        this.service = service;
    }

    public void ImViewing(string id)
    {
        string colour;
        service.AddCurrentlyViewingUser<TEntity>(id, HttpContext.Current.User.Identity.Name, out colour);
        Clients.handleImViewingMessage(HttpContext.Current.User.Identity.Name, colour, id);
    }

    public void ImLeaving(string id)
    {
        service.RemoveCurrentlyViewingUser<TEntity>(id, HttpContext.Current.User.Identity.Name);
        Clients.handleImLeavingMessage(HttpContext.Current.User.Identity.Name, id);
    }

    public void IHaveEdited(string id, string property, string content)
    {
        string colour = service.GetCurrentlyViewingUserColour<TEntity>(id, HttpContext.Current.User.Identity.Name);

        if (string.IsNullOrEmpty(colour))
            return;

        Clients.handleIHaveEdited(id, property, content);
    }
}

我包括&lt;script type="text/javascript" src="@Url.Content("~/signalr/hubs")"&gt;&lt;/script&gt;

现在到主要的 javascript。我创建了一个可重用的 Knockout JS 组件,该组件在集线器中附加相关的处理程序。其中很多是无关紧要的,但我想我会把它全部贴出来以防万一。我在关闭开始时开始连接,并创建我的淘汰赛组件,并传入 roleManagementHub。

var user_role_edit = {};

    (function (index) {

        user_role_edit = index;

        jQuery.connection.hub.start();

        var val = ko.setupValidation([], []);
        val.createErrorCollections({Name: 0, General: 0}, index, 'rename-role-form');
        var dmp = new diff_match_patch();

        index.Id = ko.observable();
        index.Name = ko.observable();
        index.currentViewersViewModel = new ko.currentlyViewingComponent.viewModel({
            hub: jQuery.connection.roleManagementHub,
            id: index.Id,
            modalSelector: '#user-role-edit-modal'
        });

        index.rename = function (form) {
            jQuery.post('" + @Url.Action("Rename", "RoleManagement") + @"', {
                'id': index.Id(),
                'name': index.Name()
            }, function (dataReturned) {
                if (dataReturned.IsValid) {
                    jQuery(document).trigger('userRoleUpdated', index);
                    index.editModal.modal('hide');
                }
                else {
                    val.rebindValidations({Name: 0, General: 0}, index, dataReturned.Errors);   
                }
            });
        };

        index.raiseClose = function () {
            index.editModal.modal('hide');
        };

        index.raiseDetails = function () {
            jQuery(document).trigger('userRoleDetails', [index]);
            index.editModal.modal('hide');
        }

        jQuery(document).bind('userRoleEdit', function (event, id) {

            jQuery.getJSON('" + @Url.Action("GetNewsArticleForUpdateOrDelete", "RoleManagement") + @"', { id: id }, function (data) {

                index.Id(data.Role.Id);
                index.Name(data.Role.Name);

                index.currentViewersViewModel.initialiseCurrentViewers(data.CurrentlyViewingUsers);

                val.clearValidations({Name: 0, General: 0}, index);
                index.editModal.modal('show');
            });
        });

        jQuery.connection.roleManagementHub.handleIHaveEdited = function(id, property, content) {
            if (index.Id() != id)
                return;

            if (index[property] == undefined)
                return;

            dmp.Match_Distance = 1000;
            dmp.Match_Threshold = 0.5;
            dmp.Patch_DeleteThreshold = 0.5;

            var patches = dmp.patch_make(index[property](), content);
            var results = dmp.patch_apply(patches, index[property]());
            index[property](results[0]);
        };

        jQuery(function () {
            ko.applyBindings(index, jQuery('#user-role-edit-container')[0]);
            index.editModal = jQuery('#user-role-edit-modal').modal({ backdrop: true, closeOnEscape: true, modal: true, show: false });

            jQuery('#rename-role-form > fieldset > div > div > input#Name').blur(function(event) {
                jQuery.connection.roleManagementHub.iHaveEdited(index.Id(), 'Name', index.Name());
            });
        });
    } (user_role_edit));");

这里是淘汰赛组件:

(function () {

function currentUserViewModel(username, colour) {
    this.Username = username;
    this.Colour = colour;
}

ko.currentlyViewingComponent = {
    // Defines a view model class you can use to populate a grid
    viewModel: function (configuration) {

        this.currentViewers = ko.observableArray([]);

        var index = this;

        this.initialiseCurrentViewers = function (currentUsers) {

            index.currentViewers.removeAll();

            ko.utils.arrayForEach(currentUsers, function (item) {
                index.currentViewers.push(new currentUserViewModel(item.Username, item.Colour));
            });
        };

        configuration.hub.handleImViewingMessage = function (username, colour, id) {
            if (configuration.id() != id)
                return;

            var findResult = ko.utils.arrayFirst(index.currentViewers(), function (item) {
                return item.Username == username;
            });

            if (findResult == null)
                index.currentViewers.push(new currentUserViewModel(username, colour));

            jQuery('a[rel=tooltip]').tooltip();
        };

        configuration.hub.handleImLeavingMessage = function (username, id) {
            if (configuration.id() != id)
                return;

            index.currentViewers.remove(function (item) {
                return item.Username == username;
            });
        };

        jQuery(configuration.modalSelector).bind('show', function () {
            configuration.hub.imViewing(configuration.id());
        });

        jQuery(configuration.modalSelector).bind('hide', function () {
            configuration.hub.imLeaving(configuration.id());
        });
    }
};

// Templates used to render the grid
var templateEngine = new ko.nativeTemplateEngine();

templateEngine.addTemplate = function (templateName, templateMarkup) {
    document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
};

templateEngine.addTemplate("ko_currentlyViewing", "<div data-bind=\"foreach: currentViewers\" class=\"pull-left\"><a data-bind=\"attr: { title: Username, 'class': Colour }\" rel='tooltip'>&nbsp;</a></div>");

ko.bindingHandlers.currentlyViewingComponent = {
    init: function () {
        return { 'controlsDescendantBindings': true };
    },
    // This method is called to initialize the node, and will also be called again if you change what the grid is bound to
    update: function (element, viewModelAccessor, allBindingsAccessor) {
        var viewModel = viewModelAccessor(), allBindings = allBindingsAccessor();

        // Empty the element
        while (element.firstChild)
            ko.removeNode(element.firstChild);

        // Allow the default templates to be overridden
        var currentlyViewingTemplateName = allBindings.currentlyViewingTemplate || "ko_currentlyViewing";

        // Render the main grid
        var currentlyViewingContainer = element.appendChild(document.createElement("DIV"));
        ko.renderTemplate(currentlyViewingTemplateName, viewModel, { templateEngine: templateEngine }, currentlyViewingContainer, "replaceNode");
    }
};

})();

正如您在模态显示事件中看到的那样,它使用集线器发送一条消息,告诉其他连接的用户用户已开始查看该项目。

但是我现在收到“SignalR:必须先启动连接才能发送数据。在 .send() 之前调用 .start()”。

我已经开始连接了!即使我尝试;

jQuery(function() {
        jQuery.connection.hub.start();
        jQuery.connection.userManagementHub.imViewing("1");
    });

我得到 Connection must be started before data can be sent 消息。

有什么想法吗??

提前致谢!

乔恩

【问题讨论】:

    标签: c# knockout.js signalr


    【解决方案1】:

    start() 的调用不是即时的,可能是您的问题的原因。您可能希望将启动后应该发生的代码移动到启动方法中的回调中,例如:

    jQuery(function(){
        jQuery.connection.hub.start(function(){
             jQuery.connection.userManagementHub.imViewing("1");
        });
    });
    

    【讨论】:

    • 感谢您的建议。我明天在家的时候试试这个。但是我很确定我昨晚尝试了这个,但连接似乎永远不会开始。您是否遇到连接未启动的情况?
    • 嘿,试过了,还是不行。调试代码似乎 signalR 正在向 signalR/negotiate 发出请求,但从未得到响应。
    • @JonathanStowell 好奇,你在使用依赖注入吗?如果是这样,它可能无法正确解析集线器。
    • 嗨乔纳森,你能在哪里找到这个的底部?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多