Database update notification using SignalR and Entity Framework - asp.net-mvc

I'm trying to make a website using asp.net mvc 4 and EF 6 where I want to update the messagebox of adminpanel if any user sends him any message. I'm using SignalR for live notification but I'm new to SignalR and for some reason I don't get the updates live, I've to refresh the page to get the newly added message. Here are my codes,
Hub Class
public class ChatHub : Hub
{
MyProj.Models.MsgToOwner messages = new MyProj.Models.MsgToOwner();
public void SendNotify(string username, string title, string datetimeNow)
{
var newName = messages.name;
var newTitle = messages.title;
var newTime = messages.addedtime;
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.All.getNotify(newName, newTitle, newTime);
}
}
View for All Messages
#{
var MsgList = (List<MyProj.Models.MsgToOwner>)ViewBag.MsgList;
}
<body>
<script src="~/Scripts/jquery.signalR-1.1.4.min.js"></script>
<script src="~/signalr/hubs"></script>
<script src="~/Scripts/LiveScript.js"></script>
<ul class="nav navbar-top-links navbar-right">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-envelope fa-fw"></i><i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-messages" id="newItem">
#foreach (var item in MsgList)
{
<li>
<a href="#">
<div>
<strong>#Html.DisplayFor(modelItem => item.title)</strong>
<span class="pull-right text-muted">
<em>#Html.DisplayFor(modelItem => item.addedtime)</em>
</span>
</div>
<div>Sent By : <strong>#Html.DisplayFor(modelItem => item.name)</strong></div>
</a>
</li>
<li class="divider"></li>
}
</ul>
</li>
</ul>
</body>
LiveScript.js (script for updating from SignalR)
$(function () {
var chat = $.connection.chatHub;
chat.client.getNotify = function (username, title, datetimeNow) {
$('#newItem').append(
'<li><div><strong>' + htmlEncode(title) + '</strong><span class="pull-right text-muted"><em>' + htmlEncode(datetimeNow) + '</em></span></div><div>Sent By : <strong>' + htmlEncode(username) + '</strong></div></li><li class="divider"></li>');
};
$.connection.hub.start().done(function () {
$('#btnSend').click(function () {
chat.server.SendNotify($('#getName').val(), $('#getTitle').val(), $('#getDate').val());
});
});
});
I must be doing something wrong here but I can't figure it out since I'm new to SignalR. How can I update the messagebox whenever a new message is saved in db? Any guidance will be helpful for me. Thanks.

Related

Why does HttpContext.User.Identity.Name contain the wrong name?

I have a .NET 5 MVC application that periodically checks access based on the HttpContext.User.Identity.Name value. The app uses Azure AD. Sometimes as I switch between users (Signing out and Signing in), the HttpContext.User.Identity.Name value will contain the previous user's name and the current user will have the access of the previous user.
Even more strange is the the login shown is correct.
This is just the boiler plate code generated by visual studio:
#using System.Security.Principal
<ul class="navbar-nav">
#if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<span class="navbar-text text-light">Hello #User.Identity.Name!</span>
</li>
<li class="nav-item">
<a class="nav-link text-light" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-light" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
</li>
}
</ul>
So #User.Identity.Name on the .cshtml is always correct, but HttpContext.User.Identity.Name on the controller is the previous (cached?) user.
Any clues to why the previous user gets cached?
Here is a sample of how I call it on the controller:
ViewData["User"] = HttpContext.User;
ViewData["Menu"] = await _menuService.GetReportMenuAsync(MenuService.ReportMenuItemOption.Genesis01, User.Identity.Name);
var userAccess = await _userAccessService.GetUserEntityAccessAsync(User.Identity.Name);
var model = new SomeModel
{
SearchDate = DateTime.Now.AddDays(-7),
Banks = userAccess.Banks,
ATMIds = userAccess.ATMs
};
return View(model);
This is in my StartUp:
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

Trying to create drop down login for Orchard CMS

I am new to Orchard and to ASP.NET MVC. I am trying to override the login process for users so that instead of going to a dedicated login page (the default process) they get a drop down form from the user menu that logs them in. I have created overrides in my custom theme for LogOn.cshtml and User.cshtml. The code is as follows:
//User.cshtml
#using System.Web.Mvc;
#using Orchard.ContentManagement;
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<ul class="nav navbar-nav pull-right">
#if (WorkContext.CurrentUser != null) {
<li class="dropdown">
<button id="userDropdown" class="btn btn-primary navbar-btn dropdown-toggle" data-toggle="dropdown">
Welcome #Html.ItemDisplayText(WorkContext.CurrentUser) <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>
#Html.ActionLink(T("Change Password").ToString(), "ChangePassword", new { Controller = "Account", Area = "Orchard.Users" })
</li>
<li>
#Html.ActionLink(T("Sign Out").ToString(), "LogOff", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl }, new { rel = "nofollow" })
</li>
#if (AuthorizedFor(Orchard.Security.StandardPermissions.AccessAdminPanel)) {
<li class="divider"></li>
<li>
#Html.ActionLink(T("Dashboard").ToString(), "Index", new { Area = "Dashboard", Controller = "Admin" })
</li>
}
</ul>
</li>
}
else {
<li class="dropdown">
<button class="btn btn-primary navbar-btn dropdown-toggle" data-toggle="dropdown">
Sign In <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li>
#Display.LogOn()
</li>
</ul>
</li>
}
</ul>
</div>
//LogOn.cshtml
#using System.Web.Mvc;
#using Orchard.ContentManagement;
<div>
#using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", new { ReturnUrl = Request.QueryString["ReturnUrl"] }))) {
<fieldset class="login-form group">
<legend>#T("Account Information")</legend>
<div class="form-group">
<label for="username-email">#T("Username")</label>
#Html.TextBox("userNameOrEmail", "", new { id = "username-email", autofocus = "autofocus", #class = "validate[required]" })
#Html.ValidationMessage("userNameOrEmail")
</div>
<div class="form-group">
<label for="password">#T("Password")</label>
#Html.Password("password", null, new { #class = "validate[required]" })
#Html.ValidationMessage("password")
</div>
<div class="checkbox">
<label class="forcheckbox" for="remember-me">
#Html.CheckBox("rememberMe", new { id = "remember-me" }) #T("Remember Me")
</label>
</div>
<div class="form-group">
<button class="primaryAction" type="submit">#T("Sign In")</button>
</div>
</fieldset>
}
</div>
The form displays fine in the dropdown, but when the submit button is clicked, I get a HTTP 404 error: Requested URL: /OrchardLocal/Contents/Item/LogOn.
I'm afraid that the default login process requires a separate view. I've been trying to figure out which existing override to use, but I'm just not seeing it. Any help would be greatly appreciated. Thanks.
You should be able to login properly by changing your form from
#using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", new { ReturnUrl = Request.QueryString["ReturnUrl"] })))
to something like this:
#using ( Html.BeginForm("LogOn", "Account", new { area = "Orchard.Users" /*other route values here*/ }, FormMethod.Post) )
{
#Html.AntiForgeryToken()
// ... your stuff here
}
This is the same for every other controller action. If in doubt: specify the area explicitly.

Meteor only trigger template after selecting item from list

I have a typical scenario where there is a list view and then there's a details view. You get to the details view by selecting a list item. There's data in the record that of course will inform the layout view of the details. What I see is that the subtemplate's helper function is being called too soon (during the list view rendering) to have the data for the list details . Furthermore, it's not being called when I click an item in the list. What am I doing wrong? I'm using Meteor 0.8.2 with jQM 1.4.3.
The HTML looks as follows:
<!-- details page -->
<div data-role="page" data-theme="q" id="listdetail">
<div data-role="header" data-position="fixed">
<a data-rel="back" href="#" data-transition="slideleft" class="baack fa fa-arrow-left"></a>
<div id="detailTitle" class="headertitle"></div>
</div>
<!-- /header -->
<div data-role="content" class="ma-req-detail" id="details">
{{> qDetails}}
</div>
</div>
<!-- /details page -->
<template name="qList">
{{#each items}}
{{>qListItems}}
{{/each}}
</template>
<template name="qListItems">
<li>
<div id="msg-container-{{requestId}}" class="processing-msg">
<i class="fa fa-2x fa-times-circle"></i>
<p class="msg-text-{{requestId}}">Action pending...</p>
</div>
<a id="requestId" href="#listdetail" data-name="{{additionalProperties}}" data-transition="slide" class="{{#if isProcessing}}ui-disabled{{/if}}">
<p class="requestor">{{additionalProperties.requestedForUid}}</p>
<p class="description">week of {{additionalProperties.workWeekOf}}</p>
<p class="reqdate">total hours: </p>
</a>
</li>
</template>
<template name="qDetails" >
<div role="main" class="q-details">
<div data-role="navbar" class="week-nav">
<ul>
{{#each days}}
{{>navElements}}
{{/each}}
</ul>
</div>
</div>
<div class="ma-buttons ui-fieldcontain ui-footer-fixed">
<div data-role="controlgroup" data-type="horizontal" class="" data-position-fixed="true" data-position="bottom">
<a data-mini="true" href="#" id="approve-request"
class="ui-btn ui-btn-c ui-corner-r ui-icon-check ui-btn-icon-left ma-btn approve">Approve</a>
</div>
</div>
</template>
<template name="navElements">
<li><a id="{{day}}Nav" href="#{{day}}">{{day}}<br><span class="digital-date">{{date}}</span></a></li>
</template>
The JS bits are:
Template.qDetails.rendered = function() {
$('#details').trigger('create');
};
Template.qDetails.helpers({
days: function() {
//TODO need a way to delay this function to call when details template is shown
var dt = Session.get("record").additionalProperties.workWeekOf;
var days = [];
var weekday = new Array(7);
weekday[0] = "SAT";
weekday[1] = "SUN";
weekday[2] = "MON";
weekday[3] = "TUE";
weekday[4] = "WED";
weekday[5] = "THU";
weekday[6] = "FRI";
var dtVal = dt.getDate();
for (var i = 0; i < 7; i++) {
var dayObj = {};
dayObj.date = dtVal + i;
dayObj.day = weekday[i];
days.push(dayObj);
}
return days;
}
});
Template.qDetails.record = function () {
return Session.get("record");
};
In the code above the "days" helper function is being called when the list page is shown which results in an error because it is trying to pull the "workWeekOf" date from a record that hasn't been selected yet. How can I get to this only call once a record has been selected?
This is slightly confusing, since there's nothing in the above that shows how yourqDetails template gets rendered in the first place. However, assuming it does, you can just use:
var dt = Session.get("record") ? Session.get("record").additionalProperties.workWeekOf : [default date]
[default date] could be anything sensible (like new Date()), but you need to return something to avoid the error being thrown. This is a pretty common but very easily solved problem in Meteor - you just need a suitable default for when your Session variable or Collection isn't yet ready.

Action Link in Knockout foreach data binding

I'm trying to bind data to Action Link within Knockoutjs foreach loop. This code works fine
<ul data-bind="foreach: ItemList">
<li>
<a data-bind="attr: { 'href': '#Url.Action("Items", "ItemController")' }" >
LinkText
</a>
</li>
</ul>
But I also need to bind a parameter and bind the LinkText with knockoutjs. I tried different code samples but nothing seems to work.
Final code should be something like,
<ul data-bind="foreach: ItemList">
<li>
<a data-bind="attr: { 'href': '#Url.Action("Items", "ItemController")', new { id = DataBindId)' }" >
DataBindName
</a>
</li>
</ul>
How can I make this work?
Try this...
<a data-bind="attr: { 'href': '#Url.Action("Items", "ItemController")?id=' + DataBindId }, text: DataBindName" >
</a>
Which should output something like...
<a data-bind="attr: { 'href': '/Item/Items?id=' + DataBindId }, text: DataBindName" >
</a>

Nested ListView In Jquery Mobile with mvc

I create nested list view in Asp.net mvc with jQuery mobile, it has 2 sub view, when i navigate to first subview1 i can return back to main view, but when i navigate from subview1 to subview2 i can not back to subview1, since subview1 is somehow null.
in my layout page i put this script
<script>
$(document).on('mobileinit', function () {
$.mobile.page.prototype.options.addBackBtn = true;
$.mobile.page.prototype.options.backBtnText = "Back";
$.mobile.page.prototype.options.backBtnTheme = "a";
$.mobile.defaultPageTransition = "slide";
});
</script>
the main page is :
<script>
$(document).on('click', '[data-rel=back]', function (e) {
e.preventDefault();
var activepage = $.mobile.activePage.attr("id");
if (activepage == "schedule")
$.mobile.changePage($('#flight'), { transition: "slide", reverse: false });
if (activepage == "dayFlight") {
$.mobile.changePage($('#schedule'), { transition: "slide", reverse: false });
}
});
<div data-role="page" id="flight" data-add-back-btn="true">
<div data-role="content">
<ul id="flightListView" data-role="listview" data-inset="false" data-filter="true">
#foreach (var item in Model)
{
<li>
<a href="#Url.Action("Schedules", new { from = item.DepartureFrom, to = item.Destination })" data-direction="reverse" data-transition="slide">
<span class="ui-li-count ui-btn-up-c ui-btn-corner-all">#item.NumberOfFlights</span>
</a>
</li>
}
</ul>
</div>
the subview1 is:
<div data-role="page" data-add-back-btn="true" id="schedule">
<div data-role="content">
<ul id="scheduleListView" data-role="listview" data-inset="false" data-filter="false">
#foreach (var item in Model)
{
<li>
<a href="#Url.Action("DayFlights", new { from = from, to = to, date = item.Date })" data-direction="reverse" data-transition="slide">
<span class="lg">#Html.DisplayFor(modelItem => item.Day)</span>
<span class="lg number laligned">#Html.DisplayFor(modelItem => item.Date)</span>
<span class="ui-li-count ui-btn-up-c ui-btn-corner-all">#item.Nof</span>
</a>
</li>
}
</ul>
</div>
the subview2 is :
<div data-role="page" data-add-back-btn="true" id="dayFlight">
<div data-role="content">
<ul id="dayListView" data-role="listview" data-inset="true" data-filter="false">
#foreach (var item in Model)
{
<li>
<a href="#item.AgencyUrl" rel="external" data-ajax="false">
<span class="ui-li-count ui-btn-up-c ui-btn-corner-all">#item.Cap</span>
</a>
</li>
}
</ul>
</div>
something that i figure out, it is when i navigate to subview1, the mainview and the subview1 both of them are in DOM but then when i navigate to subview2, subview1 will replaced by subview2, so it means when i am at subview2 the subview1 does not exist in DOM.
in all cases $.mobile.activePage.prev('.ui-page'); return null, that is the reason why i decided to use if clause to determine to which page i should navigate back to, however when i want to navigate back from subview2 to subview1 it does not work.
how can i implement this senario?
thanks in advance

Resources