<$G+$> Strange characters appearing in ASP.NET MVC5 Helper - c#

My helper in the view, which is intended to display the full name of a user who is registered in the application, and the username if logged in via 3rd party authentication.
#using MyApp.Models;
#helper GetUserName()
{
if (User.Identity.AuthenticationType == "Application")
{
using (var db = new MyAppDbContext())
{
#db.Users.Find(User.Identity.GetUserId()).FullName
}
}
else
{
#User.Identity.GetUserName()
}
}
Then I use this helper:
#if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-form pull-right" }))
{
#Html.AntiForgeryToken()
<ul class="nav">
<li>
#Html.ActionLink("Hello " + GetUserName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li>Log off</li>
</ul>
}
}
The name of my user is Proba234, and it displays like this:
Why are those strange characters (<$G+$>) appear, and how to get rid of them?

It is probably some kind of feature or bug related with usage of helpers within Visual Studio Page Inspector, you probably won't see those tags under external browser. I reproduced it easily in VS 2013. A thread about it can be found for example on ASP.NET forum

It seems like those funny characters are generated by helper. The probleem seems to be that the output of the helper is not meant to be consumed as regular string. Apparently it generates some control characters, which are meant to be there for Razor, but if we try to use the output as regular string (as #Html.ActionLink() expects its argument) they become visible.
To get rid of them, I shouldn't use the GetUserName() helper inside the #Html.ActionLink(), but get the UserName in the controller, and pass it via a property of the viewmodel. I shouldn't have that kind of logic in my view anyway.

Related

The parameters dictionary contains a null entry for parameter

I'm attempting to, on the click of a button, complete a to-do item, therefore removing it from the list.
I'm using an ActionLink for the button:
#foreach (var item in Model)
{
<li class="#item.Priority">
#item.Text
<div class="agile-detail">
#Html.ActionLink("Done", "Complete", "Home", new { id = item.ToDoId }, new { #class = "pull-right btn btn-xs btn-primary" })
<i class="fa fa-clock-o"></i> #item.Date
</div>
</li>
}
And a very short action for the processing in the controller:
public ActionResult Complete(int todoId)
{
using (var db = new KnightOwlContext())
{
DashboardHelper dashboardHelper = new DashboardHelper(db);
dashboardHelper.CompleteToDo(todoId);
return RedirectToAction("Index", "Home");
}
}
Clicking the button generated a URL of:
http://site/Home/Complete/1
I've looked up a solution and so far it looks like it could be any number of issues. Also the ActionLink button is inside a partial view so I'm not sure if that changes anything in terms of incorrect routing setup? For routing too I'm just using the default config that comes with an MVC project in Visual Studio.
Just having trouble narrowing down the cause of the issue so where to check first?
The parameter in your method is int todoId but you not passing any value for that - your only passing a value for a parameter named id.
Change the method to
public ActionResult Complete(int id)
or change the link to use new { todoId = item.ToDoId }, but that will add a query string value, not a route value, unless you create a specific route definition with url: "Home/Complete/{todoId}"

PartialView Navigation not returning parameters

I've setup a partialview to handle navigation throughout multiple views. Some of these views use a different model so I'm passing that model in like this
#Html.Partial("~/Views/Navigation/_PartialTabs.cshtml", new xxx.OpenAccess.OBProfiles())
It load up my partialview just fine
#using xxx.Helpers;
#model xxx.OpenAccess.OBProfiles
<ul class="nav nav-tabs">
<li role="presentation" class="#Html.IsActive("Edit", "OBProfile")">#Html.ActionLink("Edit", "Edit", "OBProfile", new { id = Model.ProfileID }, null)</li>
<li role="presentation" class="#Html.IsActive("Index", "OBProfileTasks")">#Html.ActionLink("Tasks", "Index", "OBProfileTasks", new { id = Model.ProfileID }, null)</li>
<li role="presentation">Messages</li>
However when I mouse over the links, the parameters (Model.ProfileID) return 0 regardless of what screen i'm on. So the tab URLs look like this http://localhost:55129/OBProfileTasks/Index/0
What am I missing that it isn't returning the /Number of whatever profileid ive selected?
You need to prepopulate OBProfiles. Here are two ways:
Constructor:
In the OBProfiles class add:
public OBProfiles(){
ProfileID = *some value*;
}
Static method:
public static OBProfiles GetProfiles(){
return new OBProfiles{ProfileId = *Some value*};
}
The for static method call:
#Html.Partial("~/Views/Navigation/_PartialTabs.cshtml", OBProfiles.GetProfiles())
I believe TheDizzle hit the nail on the head. When you pass the model in as new, you're passing in a clean version of that model. Try just passing the model in without using the new keyword.

Is it possible to use #model in _LoginPartial.cshtml?

I need to get some data from my DB from _LoginPartial.cshtml. Is it possible to use #model in _LoginPartial.cshtml? Or how is it done? Just by #using WebApp.Services and then directly retrieve the data from the service? Or it there a more elegant way doing this?
I tried to do it with #model but didn't work because the #model in _LoginPartial.cshtml got overridden by another #model. _LoginPartial.cshtml is "injected" into every page/view.
Views/Shared/_LoginPartial.cshtml
#model WebApp.ViewModels.LoginPartialViewModel
#Html.ActionLink("" + User.Identity.Name + " (" + Model.Email + ")", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
ViewModels/ManageViewModels.cs
public class LoginPartialViewModel
{
public string Email = new UserService().ReadCurrent().Email;
}
And the Views/Shared/_LoginPartial.cshtml is used in Views/Shared/_Layout.cshtml like this:
#Html.Partial("_LoginPartial")
Could this be done with #model or would i have to do some nasty thing in Views/Shared/_LoginPartial.cshtml like this:
#using WebApp.Services
var userService = new UserService();
var email = userService.Read(User.Identity.GetUserId()).Email;
#Html.ActionLink("" + User.Identity.Name + " (" + email + ")", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
Every page that uses #Html.Partial("_LoginPartial") needs to do one of two things.
Pass a LoginPartialViewModel object into #Html.Partial("_LoginPartial") as the model e.g. #Html.Partial("_LoginPartial", loginModel)
The model of the view that calls _LoginPartial needs to inherit from LoginPartialViewModel
Using #Html.Partial("_LoginPartial") without the model override causes the partial view to inherit the view context of the parent view. So _LoginPartial wants to inherit whatever model type the calling view uses.
You can pass model object as a second parameter to #Html.Partial invocation.
But if this partial is used at every page, I suggest to move it to layout.

Using Html.Action causes query string too long error

I have a _LayoutView:
#{
Layout = "~/Views/Shared/_NavLayout.cshtml";
}
#section styles
{
#RenderSection("styles", required: false)
}
<div class="container" style="padding-top: 60px;">
<div class="row">
<div class="col-md-12">
#Html.Action("AccountNavigation")
</div>
</div>
#RenderSection("InlineTitle", required:false)
#RenderBody()
</div>
#section scripts {
#Scripts.Render("~/bundles/jqueryval")
#RenderSection("scripts", required: false)
}
That renders fine if I remove the
#Html.Action("AccountNavigation")
Otherwise I get:
The action method is:
[ChildActionOnly]
public ActionResult AccountNavigation()
{
var roles = UserManager.GetRoles(User.Identity.GetUserId());
ViewBag.IsAdmin = roles.Contains("Admin");
return PartialView("_AccountNavigatorPartial");
}
And Ive tried stripping it back to just:
[ChildActionOnly]
public ActionResult AccountNavigation()
{
ViewBag.IsAdmin = false;
return null;
}
But it makes no difference.
One of the child views that uses the layout is Login.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.OidLoginFailed = false;
ViewBag.ReturnUrl = returnUrl;
return View();
}
If I put a break piont in there I can see its being called multiple times per request and building up the ReturnUrl until it fails hence the error message. This is why I stripped back the AccountNavigation ActionMethod.
I thought maybe an anon request was causing a post back via some config setting that says if Anon redirect to Login and round and round it would go but I cant see where that is being triggered.
The account _AccountNavigatorPartial is just:
<ul class="nav navbar-nav navbar-Left">
<li>#Html.ActionLink("Manage Credentials", "Credentials", "Account",
routeValues: null, htmlAttributes: new { id = "credentialsLink" })</li>
<li>#Html.ActionLink("Manage Profile", "Profile", "Account",
routeValues: null, htmlAttributes: new { id = "credentialsLink" })</li>
</ul>
So all I'm trying to do is inject some html for account navigation. I'm using ASP.Identity for membership but I cant see how that makes any difference as I'm requesting an Anon accessible page.
It's hard to tell without seeing the controller and knowing how you are handling authorization, however, since your login page is using that Layout, you may be experiencing a circular call due to failure of authorization on you child action.
Have you tried adding the attribute [AllowAnonymous] to your child action?
We were getting similar UriFormatException: Invalid URI: The Uri string is too long. - we found the solution was to pass the model in as an explicit parameter instead of just the typical approach.
Not Working
#Html.Action("MyChildAction", "Path", Model)
Working
#Html.Action("MyChildAction", "Path", new { viewModel = Model} )
This seems to be triggered by using a very large view model - this must wrap it and bypass the encoding issue UriHelper.EscapeString which overflows the buffer.

Razor view engine - How can I add Partial Views

I was wondering what, if it is possible, is the best way to render a partial using the new razor view engine. I understand this is something that wasn't finished completely by the time
Right now I am using RenderPage to render the user control:
#RenderPage("~/Views/Shared/LocaleUserControl.cshtml",ViewData.Model)
The page calling RenderPage uses a layout (master) page with three sections defined: TitleContent, HeadContent and Maincontent. When I attempt to render my locale control from this page it appears that these sections are also required - they should only be required in the calling page and are present. I receive the following message, regardless of whether or not I include the sections in my partial view (obviously I dont want to include these sections but it seemed like an interesting debugging point...).
The following sections have been
defined but have not been rendered on
the layout page
'~/Views/Shared/LocaleUserControl.cshtml':
TitleContent; HeadContent; MainContent
My partial view is as follows (adapted from the following link):
#inherits System.Web.Mvc.WebViewPage<LocaleBaseModel>
#using System.Web.UI;
<p>
#Html.LabelFor(model => Model.CountryName)
<br />
#Html.DropDownListFor(model => Model.CountryName,null, string.Empty, new { #class = "text", accesskey="u"})
</p>
<p>
#Html.LabelFor(model => Model.StateProvince)
<br />
#Html.DropDownListFor(model => Model.StateProvince, null, string.Empty, new { #class = "text", accesskey="t" })
</p>
<script type="text/javascript">
$(function () {
var countries = $("#CountryName");
var statesprovinces = $("#StateProvince");
countries.change(function () {
statesprovinces.find('option').remove();
var url = '#Url.Action("GetStatesProvinces", "Base")';
$.getJSON(url, { countryId: countries.val() }, function (data) {
$(data).each(function () {
$("<option value=" + this.ID + ">" + this.Name + "</option>").appendTo(statesprovinces);
});
});
});
});
</script>
You partial looks much like an editor template so you could include it as such (assuming of course that your partial is placed in the ~/views/controllername/EditorTemplates subfolder):
#Html.EditorFor(model => model.SomePropertyOfTypeLocaleBaseModel)
Or if this is not the case simply:
#Html.Partial("nameOfPartial", Model)
If you don't want to duplicate code, and like me you just want to show stats, in your view model, you could just pass in the models you want to get data from like so:
public class GameViewModel
{
public virtual Ship Ship { get; set; }
public virtual GamePlayer GamePlayer { get; set; }
}
Then, in your controller just run your queries on the respective models, pass them to the view model and return it, example:
GameViewModel PlayerStats = new GameViewModel();
GamePlayer currentPlayer = (from c in db.GamePlayer [more queries]).FirstOrDefault();
[code to check if results]
//pass current player into custom view model
PlayerStats.GamePlayer = currentPlayer;
Like I said, you should only really do this if you want to display stats from the relevant tables, and there's no other part of the CRUD process happening, for security reasons other people have mentioned above.

Categories