直到最近才开始使用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);
}
}
我包括<script type="text/javascript" src="@Url.Content("~/signalr/hubs")"></script>
。
现在主要是javascript。我创建了一个可重用的Knockout JS组件,它接收集线器以连接相关的处理程序。很多这都是无关紧要的,但我想我会把它全部发布。我在闭包开始时开始我的连接,并创建我的knockout组件传递给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'> </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必须在数据发送之前启动消息。
任何想法??
先谢谢!
乔恩
答案 0 :(得分:10)
对start()
的来电不是即时的,可能是您问题的原因。您可能希望将启动后应该发生的代码移动到start方法中的回调中,如:
jQuery(function(){
jQuery.connection.hub.start(function(){
jQuery.connection.userManagementHub.imViewing("1");
});
});