I have the following script:
function OpenIdLogon(e) {
$.post("/Account/OpenIdLogOn/", { token: e }, function (data) {
$("#userNavigation").html(data);
$(".auth_box").hide();
$(".kb_fading").hide();
});
}
This is the action:
public ActionResult OpenIdLogOn(string token)
{
WebClient cli = new WebClient();
string json = cli.DownloadString(new Uri("http://ulogin.ru/token.php?token=" + Request.Params["token"] + "&host=" + Request.Url.Host));
var obj = JObject.Parse(json);
if (obj["error"] == null)
{
var userName = obj["nickname"].Value<string>();
var email = obj["email"].Value<string>();
FormsAuthentication.SetAuthCookie(userName, true);
}
return PartialView("UserNavigation");
}
And, my UserNavigation:
#if (Request.IsAuthenticated)
{
<span>#Context.User.Identity.Name</span><i class="icon iUser"></i>
<ul class="headLine_link">
<li>Profile</li>
<li>
#Html.ActionLink("Logg Off", "LogOff", "Account", null, new { #class = "exit" })</li>
</ul>
}
else
{
<ul class="headLine_link">
<li><a id="regLink">Register</a></li>
<li><a id="authLink">Log On</a></li>
</ul>
}
The problem in that Request.IsAuthenticated equals true only after refresh page.
The problem is the following:
At the time of making the request ($.post("/Account/OpenIdLogOn/"...) the user it not authenticated.
Then in your action method you authenticate the user, but on the Request object that represents the request the user made before you create the Auth cookie, the user was not authenticated. However, as you say on the next request it works since at that time the user has the Authentication cookie when he makes the request.
One solution here can be to create a viewmodel object to send from your controllers action method to your view. This viewModel can have a field called authenticated, and you can set it properly from the action method. Then check this value instead inside your view. I haven't checked this in Visual Studio, but it should be something like this:
Create the viewmodel:
public class LoginViewModel{
public bool Authenticated{ get; set; }
}
Your action method:
public ActionResult OpenIdLogOn(string token)
{
WebClient cli = new WebClient();
string json = cli.DownloadString(new Uri("http://ulogin.ru/token.php?token=" + Request.Params["token"] + "&host=" + Request.Url.Host));
var obj = JObject.Parse(json);
var viewModel = new LoginViewModel{ Authenticated = Request.IsAuthenticated };
if (obj["error"] == null)
{
var userName = obj["nickname"].Value<string>();
var email = obj["email"].Value<string>();
FormsAuthentication.SetAuthCookie(userName, true);
viewModel.Authenticated = true;
}
return PartialView("UserNavigation");
}
And your view
#model LoginViewModel
#if (Model.Authenticated)
{
<span>#Context.User.Identity.Name</span><i class="icon iUser"></i>
<ul class="headLine_link">
<li>Profile</li>
<li>
#Html.ActionLink("Logg Off", "LogOff", "Account", null, new { #class = "exit" })</li>
</ul>
}
else
{
<ul class="headLine_link">
<li><a id="regLink">Register</a></li>
<li><a id="authLink">Log On</a></li>
</ul>
}
Creating a viewmodel instead of just sending a bool as model is just because I like to always put the data I send to a view inside a viewmodel. Makes it much easier to extend later on, and makes it easier to read inside the view (you can write #if (Model.Authenticated) instead of #if (Model) for example)
Related
I need to add an active class with the .nav-link
<ul class="sidebar-nav" id="sidebar-nav">
<li class="nav-item">
<a asp-area="DemoArea" class="nav-link" asp-controller="Dashboard" asp-action="Index">Dashboard</a>
</li>
</ul>
I have used the static class MenuStateHelper and static method MakeActiveClass along with that I have passed controller name and action method name when both passed values and RouteData value match then it will return active class else it will be null.
public static class MenuStateHelper
{
public static string MakeActiveClass(this IUrlHelper urlHelper, string controller, string action)
{
try
{
string result = "active";
if (!String.IsNullOrEmpty(Convert.ToString(urlHelper.ActionContext.RouteData.DataTokens["area"])))
{
string areaName = urlHelper.ActionContext.RouteData.DataTokens["area"].ToString();
}
if (urlHelper.ActionContext.RouteData.Values != null)
{
string controllerName = urlHelper.ActionContext.RouteData.Values["controller"].ToString();
string methodName = urlHelper.ActionContext.RouteData.Values["action"].ToString();
if (string.IsNullOrEmpty(controllerName)) return null;
if (controllerName.Equals(controller, StringComparison.OrdinalIgnoreCase))
{
if (methodName != null && methodName.Equals(action, StringComparison.OrdinalIgnoreCase))
{
return result;
}
}
}
return null;
}
catch (Exception)
{
return null;
}
}
}
And I have called MakeActiveClass method on Anchor Tag Helper
<a asp-area="#menu.Area" asp-controller="#menu.ControllerName" asp-action="#menu.ActionMethod" class="nav-link #Url.MakeActiveClass(menu.ControllerName, menu.ActionMethod)">
<i class="far fa-circle nav-icon"></i>
<p>
#menu.MenuName
</p>
</a>
You can use jquery to do this, Not the best answer but it works too. And you can add menu levels as you want... see the code below:
<script>
$(document).ready(function () {
var currentUrl = document.location.pathname;
var elementLevelZero = $('.nav-main a[href="' + currentUrl + '"]');
$(elementLevelZero).addClass('active');
var elementLevelZeroList = $(elementLevelZero).closest('ul');
var elementLevelOne = $(elementLevelZeroList).prev("a");
$(elementLevelOne).addClass('active');
var elementLevelOneList = $($(elementLevelOne).parent()).closest('ul');
var elementLevelTwo = $(elementLevelOneList).prev("a");
$(elementLevelTwo).addClass('active');
var elementLevelTwoList = $($(elementLevelTwo).parent()).closest('ul');
var elementLevelThree = $(elementLevelTwoList).prev("a");
$(elementLevelThree).addClass('active');
});
</script>
You can use .each function to loop on each parent item in your list.
Here is a simple demo for dynamic add class by ViewBag value:
<ul class="sidebar-nav" id="sidebar-nav">
<li class="nav-item">
<a asp-area="DemoArea" class="#(ViewBag.Class==true?"nav-link":"")" asp-controller="Dashboard" asp-action="Index">Dashboard</a>
</li>
</ul>
Backend:
public async Task<IActionResult> Index()
{
ViewBag.Class = true;
return View();
}
As Asked Question1, Question2 from other users but there is no any proper answer got so I asked here.
I am using ASP.NET MVC and trying to load social logins providers by partial view.
But I can't it gives me an error.
This is my code from where I return my partial view:
public async Task<PartialViewResult> GetProviders()
{
string apiUrl = "mywebsite";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("Account/externalloginpathhere");
//var result = Task.Run(async () => { await client.GetAsync("Account/externalloginpathhere"); }).Result;
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var providers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ViewModel>>(data);
foreach(var provider in providers)
{
if (provider.Name == "Google")
{
//code come here
}
else if (provider.Name == "Facebook")
{
//code come here
}
else if (provider.Name == "Microsoft")
{
//code come here
}
}
return PartialView("~/Views/Account/_ExternalLoginsListPartial.cshtml", providers);
}
return null;
}
}
View calling from Home Controller View:
#{Html.RenderAction("GetProviders", "Account");}
This is what I have done please correct me whereever I goes wrong!
I have just figured it out don't know correct or not but I got the solution hope it helps someone.
I have just created one partial view and bind that partialview inside the page where I want login or signup process.
Bind the partial view:
#Html.Partial("~/Views/Account/_ExternalLoginsListPartial.cshtml")
External Providers Partial View:
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
if (loginProviders.Count() >= 0)
{
using (Html.BeginForm("ExternalLogin", "Account", FormMethod.Post, new { id = "externalLogin" }))
{
#Html.AntiForgeryToken()
<ul>
#foreach (var p in loginProviders)
{
<li>
<button value="#p.Caption" title="Login using #p.Caption account" name="provider" id="#p.Caption.ToLower()" type="submit" class="social-button">
<i class="fa fa-#p.Caption.ToLower()" id="#p.Caption"></i>
</button>
</li>
}
</ul>
}
}
}
Please see code below that creates menu items. Now how can I show/hide/access a menu item that is created as below. Also I want to make sure user do not directly access page. I want to do this based on value in one my table( no default table). I know we can use [Authorize(Roles = "Admin")] based on roles, but like I mentioned I want to manually look for a value in a custom table then show/hide/allow access of page.
Thanks.
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>#Html.ActionLink("Roles", "Index", "AspNetRoles", new { }, new { #style = "color:#21ce99;" }) </li>
<li>#Html.ActionLink("Users", "Index", "AspNetUsers", new { }, new { #style = "color:#21ce99;" })</li>
<li>#Html.ActionLink("User Groups", "Index", "UserGroupRoles", new { }, new { #style = "color:#21ce99;" })</li>
</ul>
#Html.Partial("_LoginPartial")
</div>
Note: After getting help from Stephen ,I managed to write below code. But now I am getting error
"The controller for path '/' was not found or does not implement IController."
Controller Code
using System.Web.Mvc;
using .Models;
namespace TestProj.Controllers
{
public class NavigationVMController : Controller
{
[ChildActionOnly]
public ActionResult Navigation()
{
NavigationVM NavItems = new NavigationVM();
NavItems.CanViewRoles = true; //setting all true temporarily for testing
NavItems.CanViewUsers = true;
NavItems.CanViewUserGroups = true;
//return View(Alex);
return View("_Navigation", NavItems);
}
// GET: NavigationVM
public ActionResult Index()
{
return View();
}
}
}
Model Code
namespace TestProj.Models
{
public class NavigationVM
{
public bool CanViewRoles { get; set; }
public bool CanViewUsers { get; set; }
public bool CanViewUserGroups { get; set; }
}
}
Partial view Code
#model TestProj.Models.NavigationVM
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
#if (Model.CanViewRoles)
{
<li>#Html.ActionLink("Roles", "Index", "AspNetRoles", new { }, new { #style = "color:#21ce99;" }) </li>
}
<li>#Html.ActionLink("Users", "Index", "AspNetUsers", new { }, new { #style = "color:#21ce99;" })</li>
<li>#Html.ActionLink("User Groups", "Index", "UserGroupRoles", new { }, new { #style = "color:#21ce99;" })</li>
</ul>
#Html.Partial("_LoginPartial")
</div>
Calling code from _Layout.cshtml
#Html.Action("Navigation", "NavigationVMController")
Create a partial view for the navigation links and call a ChildActionOnly method that initializes a view model based on some parameters that you can use to conditionally check which links should be displayed
View model
public class NavigationVM
{
public bool CanViewRoles { get; set; }
public bool CanViewUsers { get; set; }
public bool CanViewUserGroups { get; set; }
}
Controller (probably in a BaseController so its available everywhere
[ChildActionOnly]
public ActionResult Navigation
{
NavigationVM model = new NavigationVM();
model.canViewRoles = ?? // call a service which returns the value based on the current user
....
return PartialView("_Navigation", model)
}
Partial View (_Navigation.cshtml)
#model yourAssembly.NavigationVM
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
#if (Model.CanViewRoles)
{
<li>#Html.ActionLink("Roles", "Index", "AspNetRoles", new { }, new { #style = "color:#333;" })</li>
}
.... // ditto for CanViewUsers and CanViewUserGroups
</ul>
</div>
and in the main view or layout
#Html.Action("Navigation") // renders the navigation links
#Html.Partial("_LoginPartial")
This will only display the appropriate links, but of course a user could still type in the address to try and access the pages so your controller methods still need to perform validation
AspNetRolesController
public ActionResult Index()
{
// Check permissions based on user
bool canView = ?? // call a service which returns the value based on the current user
if (!canView)
{
return new HttpUnauthorizedResult();
}
....
}
i am working on mvc project. In my controller i am calling my stored procedure from terms class and I am returning Index page if it returns true or return terms page if it returns false.
Calling stored procedure in terms page :
public class Accept
{
public void Check()
{
using (var ctx = new termsEntities())
{
ctx.usp_ChkTerms(8, new ObjectParameter("Accepted", typeof(bool)));
ctx.SaveChanges();
}
}
}
Now i am calling this in my controller :
public ActionResult App()
{
// calling Stored procedure from Model to class
var accept = new Accept();
accept.Check();
// checking if accepted is true then return view else return another view
AppEntities Accepted = new AppEntities();
AppTerm user = new AppTerm();
AppHist history = new AppHist();
user = (from AppTerm app in Accepted.AppTerms
where app.userID == 8
select app).ToList().FirstOrDefault();
if (user != null)
{
if (user.Accepted)
{
return View("Index");
}
else
{
return View("terms");
}
}
And this is the code i am using in my terms view :
#{
ViewBag.Title = "terms";
}
<html>
<body>
<ul>
#foreach ( var item in Model)
{
<div class="Page" onclick="location.href='#Url.Action("Info", new { id = item.ID })'">
span class="Col1">
<br />
#item.ID
</span>
<span class="Title">#item.Name</span>
}
</ul>
</body>
</html>
Here when condition is true it is displaying Index page but when condition falls and when it tries to display terms page i am getting Object reference not set to an instance of an object and error is pointing to foreach loop. so what mistake i am doing here? i need help..
It is ugly, but you may try
<div class="Page" onclick='location.href="#Url.Action("Info", new { id = item.ID })"'>
<div class="Page" onclick="location.href='#Url.Action("Info", new { id = item.ID })'">
Change this to:
<div class="Page" onclick="location.href='#Url.Action('LinkText','Info', new { id = item.ID })'">
Note the quote marks around Info
edit:
Added extra argument to link.
I am just trying to update the cart using jQuery POST. It's success with the first request. However, it's seem to throw a 500 server error within the second request. The problem is after I debug it. The Action Result at the second time it's try to render the view instead of sending the JSON object to the callback function. Here is my code bellow.
Here is my Action Result inside my cart
[HttpPost]
public ActionResult UpdateResultCart(int productId)
{
// Retrieve the album from the database
var addedProduct = _db.Products
.Single(pr => pr.ProductID == productId);
// Add it to the shopping cart
var cart = ShoppingCartModel.GetCart(this.HttpContext);
cart.AddToCart(addedProduct);
// Set up our ViewModel
var shoppingCartData = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
return Json(shoppingCartData);
}
Here is my JavaScript function
$(function () {
$("#AddCartProduct").click(function () {
var productId = $(this).attr("data-id");
if (productId != '') {
// Perform the ajax post
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post("/Cart/UpdateResultCart", { "productId": productId }, function(data) {
alert("success");
$('#cart-item').text(": " + data.CartItems.length + " Items");
$('#total-price').text("Total Price:" + numberToCurrency(data.CartTotal));
})
.done(function() { alert("second success"); })
.fail(function() { alert("error"); });
}
});
});
Finally,Here is my HTML Element in the partial view that needs to be updated
#if (Request.IsAuthenticated) {
<ul>
<li>
#using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" }))
{
#Html.AntiForgeryToken()
Log off
}
</li>
|
<li>Account</li>
|
<li>
Cart
<label class="cart-item">: 0 Items</label>|
<label class="total-price">$0.00</label>
</li>
</ul>
} else {
<ul>
#*<li>#Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>*#
<li>#Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>|
<li>Account</li>|
<li>
Cart
<label class="cart-item">: 0 Items</label>|
<label class="total-price">$0.00</label>
</li>
</ul>
}
Thanks