I've been trying to run several procedural code on server with parameter that i put on form and execute with MVC Controller. I want every step (method / function) on controller that have been called will update information to the client Web real-time.
I've been trying to use SignalR to update realtime push notification / information to client, its work with client trigger but when i trying to call hub from controller it doest work.
here is my Controller Code :
[HttpPost]
public string data (Models.ExModel data)
{
var hub = GlobalHost.ConnectionManager.GetHubContext<Hubs.MyHub1>();
//Execute Code
//send to client
hub.Clients.All.Message(data.apaAja);
return "success";
}
here is my client code :
<h2>Index</h2>
#Ajax.BeginForm("data", "Home", FormMethod.Post, null) {
<div class="input-group">
<span>Apa Aja</span>
#Html.EditorFor(model => model.apaAja, new { htmlhtmlAttributes = new { #id = "apaAja" } })
</div>
<div class="input-group">
<span> Boleh </span>
#Html.EditorFor(model => model.boleh, new { htmlhtmlAttributes = new { #id = "boleh" } })
</div>
<button id="subm" type="submit">Submit</button>
<div id="container">
</div>
#section scripts{
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(document).ready(function () {
var c = $.connection.myHub1;
c.client.messageSend = function (message) {
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#container').append('<li> < strong >' + 'Info Message : ' +
'</strong >: ' + encodedMsg + '</li >');
};
$.connection.hub.start();
});
</script>
and here is my Hub Class :
namespace SignalR1.Hubs
{
public class MyHub1 : Hub
{
public void Message(string message)
{
Clients.All.messageSend(message);
}
}
}
You have a client-side callback called messageSend, then in your hub you rightly have Clients.All.messageSend, however when you use the GlobalHost.ConnectionManager.GetHubContext you are accessing the hub context not the hub class itself.
So change it to:
var hub = GlobalHost.ConnectionManager.GetHubContext<Hubs.MyHub1>();
//you don't actually have access to the MyHub1 class at this point
// instead of
// hub.Clients.All.Message(data.apaAja);
// you need
hub.Clients.All.messageSend(data.apaAja);
In fact, the hub class method becomes slightly redundant when using this mechanism. I normally use the hub class for managing connections and clients using the overrides for onconnected etc...
Related
I am attempting to implement a Dragula Drag and Drop feature to the part of my application that allows an Admin to assign users to certain roles. The .cshtml is implemented and displaying correctly but am having trouble figuring out how to write the Ajax call so that I can pass parameters to my method in the controller that utilizes a helper class to add and remove. Can parameters be passed into the ajax $.post(url) that are derived from the location where it was dropped? Included below should be all relevant code. I also understand Viewbags aren't the best way to do this, but if i can get it functioning i will write a viewmodel and pass the data through that way instead.
.cshtml Code
there are 4 of these, one for each of the 3 assignable roles, and one for those not assigned to any role. They're populating correctly currently.
<div class="col-3 h-100">
<div class="bg-secondary p-4">
<h6 class="card-title">Developers</h6>
<div id="dragula-developers" class="py-2">
#foreach (var user in ViewBag.Developers)
{
<div class="card rounded mb-2">
<div class="card-body p-3">
<div class="media">
<div class="media-body">
<h6 class="mb-1">#user.FirstName #user.LastName</h6>
<p class="mb-0 text-muted"> #user.Email </p>
</div>
</div>
</div>
</div>
}
Controller Method
public JsonResult ManageRoles(string id, string role)
{
var message = "User Not Assigned To Role";
if (id != null)
{
userRolesHelper.RemoveUserFromRole(id, role);
if (!string.IsNullOrEmpty(role))
{
userRolesHelper.AddUserToRole(id, role);
message = "User Assigned To Role Successfully!";
}
}
return Json(message);
}
and finally the bare bones of my dragula script where my ajax should go i believe, after the .on('drop').
(function ($) {
'use strict';
dragula([document.getElementById("dragula-noRole"), document.getElementById("dragula-submitters"),
document.getElementById("dragula-developers"), document.getElementById("dragula-managers")])
.on('drop', function (el) {
console.log($(el));
})
})(jQuery);
There are 4 boxes, and ideally when a user's card is dropped into a dragula container, their id and the role associated with the dragula would be shot to the post and their role would be changed, returning a message. This isn't a feature that would be used heavily, so i shouldnt need websockets, but i can't figure out how to implement it. Any help would be greatly appreciated!
After much longer than I care to admit, I've finally figured it out. Just in case it helps anyone else in the future, I had to change my controller to accept an Array. It ended up looking like this before Abstraction.
[HttpPost]
public JsonResult ReassignToDev(Array userIds)
{
var message = "";
if (userIds == null)
{
message = "No Users to Change Roles Of";
}
if (userIds != null)
{
foreach (var user in userIds)
{
userRolesHelper.RemoveAllRoles(user.ToString());
userRolesHelper.AddUserToRole(user.ToString(), "Developer");
message = "Role Change Successful";
}
}
return Json(message);
}
and my ajax call finally wound up looking like this:
var developerIds = new Array();
$('.developer .hidden').each(function (i) {
developerIds.push($(this).text());
})
console.log(developerIds);
$.ajax({
type: "POST",
url: '#Url.Action("ReassignToDev", "Admin")',
dataType: 'JSON',
data: { userIds: developerIds },
success: function (response) {
alert(message);
},
error: function (response) {
alert(message);
}
});
4 different methods and 4 different calls, submitted through a button click that fires an ajax request. not the most elegant solution i'm sure, but it is functional and fast.
I am building(still learning) a web application in ASP.NET WebForms with C#.We have a Centralized Database and all Clients are connected to the Database through a same static IP.Each of the Clients have their own
Unique Office ID.We have 16 Offices each having their own office ID.Every Day we update new features with new build.Instead of sending chat message
to individual client about the new changes/updates/features, can we make it send as a broadcast message like from all the offices i have mentioned
there is a corporate office with OfficeId=14.So the moment the User from other office Logs in, he/she should see a pop-up notification message
about the changes.Is it possible to make say a form to enter the details about the changes and the moment the user from the corporte office saves it, it shows in the index page of
all the clients?
I did a lot of research on this, but couldnt get a solid explanation.This might be a duplicate or lame question for all the experts out here,please
bear with me.
Check this link ASP.Net SignalR: Building a Simple Real-Time Chat Application
from the ChatHub class and Use following Code.
public class ChatHub : Hub
{
static ConcurrentDictionary<string, string> dic = new ConcurrentDictionary<string, string>();
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
public void Notify(string name, string id)
{
if (dic.ContainsKey(name))
{
Clients.Caller.differentName();
}
else
{
dic.TryAdd(name, id);
foreach (KeyValuePair<String, String> entry in dic)
{
Clients.Caller.online(entry.Key);
}
Clients.Others.enters(name);
}
}
public override Task OnDisconnected()
{
var name = dic.FirstOrDefault(x => x.Value == Context.ConnectionId.ToString());
string s;
dic.TryRemove(name.Key, out s);
return Clients.All.disconnected(name.Key);
}
}
And in HTML + javascript
<script type="text/javascript">
$(function () {
showModalUserNickName();
});
function showModalUserNickName() {
$("#dialog").dialog({
modal: true,
buttons: {
Ok: function () {
$(this).dialog("close");
startChartHub();
}
}
});
}
function startChartHub() {
var chat = $.connection.chatHub;
// Get the user name.
$('#nickname').val($('#nick').val());
chat.client.differentName = function (name) {
showModalUserNickName();
return false;
// Prompts for different user name
$('#nickname').val($('#nick').val());
chat.server.notify($('#nickname').val(), $.connection.hub.id);
};
chat.client.online = function (name) {
// Update list of users
if (name == $('#nickname').val())
$('#onlineusers').append('<div class="border" style="color:green">You: ' + name + '</div>');
else {
$('#onlineusers').append('<div class="border">' + name + '</div>');
}
};
chat.client.enters = function (name) {
$('#chatlog').append('<div style="font-style:italic;"><i>' + name + ' joins the conversation</i></div>');
$('#onlineusers').append('<div class="border">' + name + '</div>');
};
// Create a function that the hub can call to broadcast chat messages.
chat.client.broadcastMessage = function (name, message) {
//Interpret smileys
message = message.replace(":)", "<img src=\"/images/smile.gif\" class=\"smileys\" />");
message = message.replace("lol", "<img src=\"/images/laugh.gif\" class=\"smileys\" />");
message = message.replace(":o", "<img src=\"/images/cool.gif\" class=\"smileys\" />");
//display the message
$('#chatlog').append('<div class="border"><span style="color:red">' + name + '</span>: ' + message + '</div>');
};
chat.client.disconnected = function (name) {
//Calls when someone leaves the page
$('#chatlog').append('<div style="font-style:italic;"><i>' + name + ' leaves the conversation</i></div>');
$('#onlineusers div').remove(":contains('" + name + "')");
}
// Start the connection.
$.connection.hub.start().done(function () {
//Calls the notify method of the server
chat.server.notify($('#nickname').val(), $.connection.hub.id);
$('#btnsend').click(function () {
// Call the Send method on the hub.
chat.server.send($('#nickname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
}
</script>
<div id="container">
<input type="hidden" id="nickname" />
<div id="chatlog"></div>
<div id="onlineusers">
<b>Online Users</b>
</div>
<div id="chatarea">
<div class="messagelog">
<textarea spellcheck="true" id="message" class="messagebox"></textarea>
</div>
<div class="actionpane">
<input type="button" id="btnsend" value="Send" />
</div>
<div class="actionpane">
</div>
</div>
<div id="dialog" title="Enter your name to start a chat.">
<input type="text" id="nick" />
</div>
I'm trying to write CRUD operations using ajax. Here some code:
These are my View classes:
//PhotoSummary
#model PhotoAlbum.WEB.Models.PhotoViewModel
<div class="well">
<h3>
<strong>#Model.Name</strong>
<span class="pull-right label label-primary">#Model.AverageRaiting.ToString("# stars")</span>
</h3>
<span class="lead">#Model.Description</span>
#Html.DialogFormLink("Update", Url.Action("UpdatePhoto", new {photoId = #Model.PhotoId}), "Update Photo", #Model.PhotoId.ToString(), Url.Action("Photo"))
</div>
//Main View
#model PhotoAlbum.WEB.Models.PhotoListViewModel
#{
ViewBag.Title = "My Photos";
}
#foreach (var p in #Model.Photos)
{
<div id=#p.PhotoId>
#Html.Action("Photo", new {photo = p})
</div>
}
The sript:
$('.dialogLink').on('click', function () {
var element = $(this);
var dialogTitle = element.attr('data-dialog-title');
var updateTargetId = '#' + element.attr('data-update-target-id');
var updateUrl = element.attr('data-update-url');
var dialogId = 'uniqueName-' + Math.floor(Math.random() * 1000)
var dialogDiv = "<div id='" + dialogId + "'></div>";
$(dialogDiv).load(this.href, function () {
$(this).dialog({
modal: true,
resizable: false,
title: dialogTitle,
close: function () { $(this).empty(); },
buttons: {
"Save": function () {
// Manually submit the form
var form = $('form', this);
$(form).submit();
},
"Cancel": function () { $(this).dialog('close'); }
}
});
$.validator.unobtrusive.parse(this);
wireUpForm(this, updateTargetId, updateUrl);
});
return false;
});});
function wireUpForm(dialog, updateTargetId, updateUrl) {
$('form', dialog).submit(function () {
if (!$(this).valid())
return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$(dialog).dialog('close');
$(updateTargetId).load(updateUrl);
} else {
$(dialog).html(result);
$.validator.unobtrusive.parse(dialog);
wireUpForm(dialog, updateTargetId, updateUrl);
}
}
});
return false;
});
}
And here my Tag builder:
public static MvcHtmlString DialogFormLink(this HtmlHelper htmlHelper, string linkText, string dialogContentUrl,
string dialogTitle, string updateTargetId, string updateUrl)
{
TagBuilder builder = new TagBuilder("a");
builder.SetInnerText(linkText);
builder.Attributes.Add("href", dialogContentUrl);
builder.Attributes.Add("data-dialog-title", dialogTitle);
builder.Attributes.Add("data-update-target-id", updateTargetId);
builder.Attributes.Add("data-update-url", updateUrl);
builder.AddCssClass("dialogLink");
return new MvcHtmlString(builder.ToString());
}
So, I have major problem if the dialog was called twice without the calling page being refreshed:
it just redirects me to the action page.
The question is how to update #Html.Action without reloading the page?
Could anyone help me?
Your #foreach loop in the main view is generating a partial view for each Photo which in turn is creating a link with class="dialogLink".
Your script handles the click event of these links and replaces it with a new link with class="dialogLink". But the new link does not have a .click() handler so clicking on the new (replacement) link does not activate your script.
Instead you need to use event delegation to handle events for dynamically generated content using the .on() method (refer also here for more information on event delegation). Note also that your current use of $('.dialogLink').on('click', function () { is the equivalent of $('.dialogLink').click(function () { and is not using event delegation. It attaches a handler to elements that exist in the DOM at the time the page is loaded, not to elements that might be added in the future.
Change your html to
<div id="photos">
#foreach (var p in #Model.Photos)
{
<div class="photo">#Html.Action("Photo", new { photo = p })</div>
}
</div>
and then modify the script to
$('#photos').on('click', '.dialogLink', function() {
....
});
Side note: There is no real need to add an id=#p.PhotoId to the containing div element and you could use <div class="photo"> as per above, and then reference it by using var updateTargetId = $(this).closest('.photo'); and delete the builder.Attributes.Add("data-update-target-id", updateTargetId); line of code from your DialogFormLink() method
I am trying to run my first SignalR v2 project but with no luck, $.connection is undefined.
Here is the error from web console:
Uncaught TypeError: Cannot read property 'chatHub' of undefined (anonymous function)
k
l.fireWith
p.extend.ready
D
My hub:
using Microsoft.AspNet.SignalR;
namespace InstantMessage
{
public class ChatHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
}
}
Startup.cs
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(InstantMessage.Startup))]
namespace InstantMessage
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Fontend:
<head>
.....
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<!--Reference the SignalR library. -->
<script src="~/Scripts/jquery.signalR-2.0.0.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="~/signalr/hubs"></script>
</head>
<body>
<h2>Instant Message Demo</h2>
<div class="container">
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion">
</ul>
</div>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
console.log($.connection);
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
</script>
</body>
It seems like the js code in /signalr/hubs is correct, chathub is there and the autogeneration of the file works fine.
$.hubConnection.prototype.createHubProxies = function () {
var proxies = {};
this.starting(function () {
// Register the hub proxies as subscribed
// (instance, shouldSubscribe)
registerHubProxies(proxies, true);
this._registerSubscribedHubs();
}).disconnected(function () {
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
// (instance, shouldSubscribe)
registerHubProxies(proxies, false);
});
proxies.chatHub = this.createHubProxy('chatHub');
proxies.chatHub.client = { };
proxies.chatHub.server = {
hello: function () {
return proxies.chatHub.invoke.apply(proxies.chatHub, $.merge(["Hello"], $.makeArray(arguments)));
}
};
return proxies;
};
Should also mention that I installed Signalr from nuget and I am using VS2012.
Removing BundleConfig.RegisterBundles(BundleTable.Bundles); from Global.asax.cs fixed this for me. I encountered this problem because jQuery was being included twice.
Place a metatag like the following just before your ChatHub Class definition
[HubName("chatHub")]
Is your reference to jquery correct? The SignalR package currently installs 1.6.4--
Im doing a web application in C# and ASP.NET MVC4.
Im having a problem with loading a map on one of my view pages...
I have the map on my Details page and the you go from Index page to Details page.
This is some of my code:
<div id='myMap' style="position:relative; width:400px; height:400px;">
</div>
<div>
<input type="button" value="createWalkingRoute" onclick="createDirections();" />
</div>
<div id='directionsItinerary'> </div>
#section scripts{
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
var directionsManager;
var directionsErrorEventObj;
var directionsUpdatedEventObj;
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('myMap'), { credentials: 'mykey' });
}
function createDirectionsManager() {
var displayMessage;
if (!directionsManager) {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
displayMessage = 'Directions Module loaded\n';
displayMessage += 'Directions Manager loaded';
}
alert(displayMessage);
directionsManager.resetDirections();
directionsErrorEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', function (arg) { alert(arg.message) });
directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', function () { alert('Directions updated') });
}
function createWalkingRoute() {
if (!directionsManager) { createDirectionsManager(); }
directionsManager.resetDirections();
// Set Route Mode to walking
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.walking });
var seattleWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Seattle, WA' });
directionsManager.addWaypoint(seattleWaypoint);
var redmondWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Redmond, WA', location: new Microsoft.Maps.Location(47.678561, -122.130993) });
directionsManager.addWaypoint(redmondWaypoint);
// Set the element in which the itinerary will be rendered
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('directionsItinerary') });
alert('Calculating directions...');
directionsManager.calculateDirections();
}
function createDirections() {
if (!directionsManager) {
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: createWalkingRoute });
}
else {
createWalkingRoute();
}
}
getMap();
</script>
}
When you go first go on the Details page the map doesn't load. However if the page is then refreshed, then the map loads after. So to me this is some sort of loading problem. But after trying for few hours Im absolutely stuck.
Can anyone help? thanks
put the getMap() call into some place where it will be called after the page is loaded, for example the body onload event. If you are using jquery, $(document).ready().