I am trying to understand how this ASP.NET MVC thing works compared to webforms, so I tried to simply call any method that will do the most basic thing, print some text into console, or change the text of a label.
Turns out it's nearly damn impossible to do, so I tried to look it up, everything I could find requires to first make the method in the controller which can be fine, but then it requires to add the corresponding cshtml file, put some tags over there and when you click that thing you will get the page from the new cshtml, but that's not what I want, an example how it's done from what I was able to find.
In HomeController:
namespace WebApplication9.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult ClickTest()
{
ViewBag.Message = "ClickTest.";
Debug.WriteLine("Damn...");
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
In Views -> Shared -> _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" title="more options">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
#Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { #class = "navbar-brand" })
</div>
<div id="test-nav" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
<li>#Html.ActionLink("Click", "ClickTest", "Home")</li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
#RenderBody()
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
</html>
The last step is to add ClickTesty.cshtml in Views -> Home, but that's not at all what I want to do, and all the examples of a click that I was able to find show this approach, except they do other things, but what if I just want to change a label text or hide something on a current page not a new one? I couldn't find any info how to do it using C#, in webforms there's no problem to change some text or hide something on the current page, even using javascript, but here I can't find a way.
To see a Debug.WriteLine in Visual Studio here's what you can do:
Add this code:
<input type="button" value="Click here to debug log" onclick="location.href='#Url.Action("ClickTest", "Home")'" />
Inside the "main" tag on your application
HomeController should look something like this:
public IActionResult ClickTest()
{
Debug.WriteLine("Damn...");
return View("Index");
}
Run the application in Debug mode (F5 by default)
Go to the Home page, click the button 'Click here to debug log'
You will see at the Output pane your Debug.WriteLine
What you are doing right now on your code is to redirect to a different view that doesn't exists. So, returning the View("Index") is doing the trick to not have an error and see your log.
Related
I've built a small Blazor website for myself, using a free template which has a bunch of javascript files with it.
Everything seems to be working fine except for one thing.
When a user reloads (F5) a project detail page, all the html markup dissapears and the console shows a bunch of error logs, indicating that it cannot find the related javascript files. Reloading any other page works fine.
Here is the razor page
#page "/project/{Slug}"
#using DOGA.Data
#using DOGA.Services
#inject ProjectService projectService
#inject NavigationManager navigationManager
#if (_project == null)
{
<p><em>Loading...</em></p>
}
else
{
<section id="pricing" class="pricing-area">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="section-title text-center pb-20">
<h3 class="title">#_project.Name</h3>
<p class="text">
#((MarkupString)_project.Description)
#if (_project.BulletPointList.Items.Any())
{
<br />
#_project.BulletPointList.Name
<br />
<br />
<ul style="text-align:left;">
#foreach (var item in _project.BulletPointList.Items)
{
<li>
<i class="lni-check-mark-circle"></i> #item
</li>
}
</ul>
}
</p>
</div> <!-- section title -->
</div>
</div> <!-- row -->
#foreach (var image in _project.DetailImages)
{
<div class="row justify-content-center">
<div class="col-lg-12 col-md-7 col-sm-9">
<div class="pricing-style-one mt-40 wow fadeIn" data-wow-duration="1.5s" data-wow-delay="0.2s">
<div class="pricing-header text-center">
<h5 class="sub-title">#image.ImageName</h5>
</div>
<div class="text-center">
<img src="#image.ImageLink" alt="#image.ImageName">
</div>
<div class="text-center top-buffer">
<br />
#image.ImageDescription
</div>
#if (image.BulletPoints.Any())
{
<br />
<div class="pricing-list">
<ul>
#foreach (var item in image.BulletPoints)
{
<li><i class="lni-check-mark-circle"></i> #item</li>
}
</ul>
</div>
}
</div>
</div>
</div>
}
</div>
</section>
}
#code {
[Parameter]
public string Slug { get; set; }
private Project _project { get; set; }
protected override async Task OnInitializedAsync()
{
_project = await projectService.GetProjectAsync(Slug);
if (_project == null)
{
navigationManager.NavigateTo("/");
}
}
}
The error appears both locally and on a published azure site.
The site is deployed on azure for now. Mind you it is in Dutch.
The error appears when going to portfolio page, clicking on one of the three projects and then hard refreshing.
https://dogasolutions.azurewebsites.net/
EDIT: after fixing the references by adding a '/' (thanks to gsharp), the page seems to reload fine except for the blazor javascript file.
In the _host.cshtml inside the body tags:
<app>
#(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<script src="/_framework/blazor.server.js"></script>
I found out what the culprit was. I used an online template to replace most of my _Host.cshtml file. By doing so I had overwritten the base tag in my head tag.
Simply adding the following code inside my head tag fixed the issue completely.
<base href="~/" />
Without this, blazor cannot correctly resolve the connection when going into detail pages (e.g. domain/page/{parameter})
I have a view named Index and a PartialView named '_Addbook' that shown as a bootstrap modal. In the partialView insert data into database using ajax form.
Index view :
<div class="panel panel-primary">
<div class="panel-body">
<div class="btn-group">
<a class="btn btn-primary marginbutoon" id="showBookgroup" data-toggle="modal" asp-action="AddBook"
data-target="#modal-book">
<i class="glyphicon glyphicon-plus"></i>
Add Book
</a>
</div>
</div>
Partialview :
#model WebApplication1.Models.Book
<form asp-controller="Home" asp-action="AddBook" id="myform"
data-ajax="true" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#myform">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Add Book</h4>
</div>
<div class="modal-body form-horizontal">
<div class="row">
<div class="form-group">
<label asp-for="BookName" class="col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="BookName" class="form-control" />
<span asp-validation-for="BookName" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
Controller :
[HttpGet]
public IActionResult AddBook()
{
var book = new Book();
return PartialView("_AddBooks", book);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddBook(Book model)
{
if (ModelState.IsValid)
{
using (var db = _Context.GetRequiredService<ApplicationDbContext>())
{
db.bookgroups.Add(model);
db.SaveChanges();
}
return RedirectToAction("Index");
}
else
{
return PartialView("_Addbooks", model);
}
}
The data is stored correctly in the database and modal hide after submit but index view shows Mixed up.
How can i Redirect after ajax submit?
Your current form is setup to do ajax form post. So when the response is received from the server, it will replace the inner html of the form tag. So with your current code, it will basically makes a GET call to the Index action and the response of that will be loaded to the form tag.
If you want to do a redirect, but still want to have the model validation works, You may return a view result back, which has some javascript code which does the redirection.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddBook(Book model)
{
if (ModelState.IsValid)
{
//Your code to store data
return PartialView("_AddedSuccessfully");
}
return PartialView("_AddBooks", model);
}
And in the _AddedSuccessfully.cshtml partial view will have only the below content, which is the javascript for redirect to /Home/Index
<script>
window.location.href = '#Url.Action("Index","Home")';
</script>
EDIT : As per the comment
how can i make it dynamically. because i have several partial view in
my project and i want pass ControllerName and ActionName as a
parameters to _AddedSuccessfully.cshtml?
You can pass it from your view to the action method and from there to the partial view
Just add a hidden input element to the Add form, just above your submit button and use Url.Action helper method to generate the url you want to redirect to, after saving successfully.
<input type="hidden" name="redirectUrl" value="#Url.Action("Index","Home")" />
<input type="submit" class="btn btn-primary" value="Submit"/>
Now, add a new parameter to your action method with the same name as the hidden input. Pass that string value as the model of the view when you call the PartialView method for _AddedSuccessfully view.
[HttpPost]
public IActionResult AddBook(Book model,string redirectUrl)
{
if (ModelState.IsValid)
{
// to do : Save
return PartialView("_AddedSuccessfully", redirectUrl);
}
return PartialView("_AddBook", model);
}
Now you need to udpate the partial view to be strongly typed to string and use the model of the view for redirect.
#model string
<script>
window.location.href = '#Model';
</script>
You can use FormHelper to create ajax forms, ajax redirects, showing notifications and to do many things on ASP.NET Core. Also, FormHelper helps you to transform server-side validations to client-side.
It's so easy to use. You just need to add asp-formhelper="true" to your form tag.
<form asp-formhelper="true" asp-controller="Home" asp-action="Save">
// <input...
// ...
</form>
You can check it's documentation on FormHelper GitHub Page. And you can download that package from Nuget.
I have view which name is thanks and I want to show this view after click submit , but its encounter with error like this:The webpage cannot be found
Here is my code:
public class HomeController : Controller
{
public ViewResult Index()
{
int hour = DateTime.Now.Hour;
ViewBag.greeting = hour < 12 ? "Good Morning" : "Good Afternoon";
return View ("MyView");
}
[HttpGet]
public ViewResult RsvpForm()
{
return View("RsvpForm");
}
[HttpPost]
public ViewResult RsvpForm(GuestRespons GuestRespons)
{
Repository.AddResponse(GuestRespons);
return View("Thanks", GuestRespons);
}
}
and this is my view :
#{Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>
Thanks
</title>
</head>
<body>
<p>
<h1>
thank you,#Model.Name!
</h1>
#if (Model.WillAttend== true)
{
#:it's great that you are comming.we will see you soon.
}
else
{
#:Sorry to hear that, but Thanks for letting us to know.
}
</p>
<p >
click <a asp-action="ListResponses">here</a> to see who is coming.
</p>
</body>
</html>
And this one is my button which should show thanks view:
#model FuturGoals_partyinvites_.Models.GuestRespons
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>RsvpForm</title>
</head>
<body>
<form asp-action="RcvpForm" method="post">
<p>
<label asp-for="Name">Your Name:</label>
<input asp-for="Name" />
</p>
<p>
<label asp-for="Email">Your Email:</label>
<input asp-for="Email" />
</p>
<p>
<label asp-for="phone">Your Phone:</label>
<input asp-for="phone" />
</p>
<p>
<label>Will you come?</label>
<select asp="WillAttend">
<option value="">Choose an option</option>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</p>
<button type="submit">Submit RSVP</button>
</form>
</body>
</html>
well I don't know how get exception in mvc , I think problem should be with this line:
<button type="submit">Submit RSVP</button>
Thanks in advance.
Your form action attribute value should be a valid url in your app. If you are using the form tag helper, you need to make sure you are passing the valid HttpPost action method name you want to submit to, as the asp-action attribute value.
In your case, your http post action method name is RsvpForm, But in your form you had RcvpForm which is not a valid action method. So fix your form tag helper to use the correct action method and now it should work.
<form asp-action="RsvpForm" method="post">
<!-- Your existing form elements goes here-->
</form>
Do it something like:
<p>
<label asp-for="Name">Your Name:</label>
<input asp-for="Name" />
</p>
<p>
<label asp-for="Email">Your Email:</label>
<input asp-for="Email" />
</p>
<p>
<label asp-for="phone">Your Phone:</label>
<input asp-for="phone" />
</p>
<p>
<label>Will you come?</label>
<select asp="WillAttend">
<option value="">Choose an option</option>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</p>
<button type="Button" id="submitme" data-url="#Url.Action("RsvpForm","Home")">Submit RSVP</button>
Ajax form like:
$("#submitme").on("click", function () {
var url = $(this).data('url');
$.ajax({
type: 'post',//this can be change to get or post
url: url,
success: function (response) {
if (response != null && response.success) {
Alert("Success");
window.location.href = "/Home/ActionNameHere"; //You can redirect any action name here....
} else {
// DoSomethingElse()
Alert("something wrong");
}
}
});
});
I'm using MVC 5 and Visual Studio 2015. I have a very simple thing I want to do...
I have a page with a controller and NO MODEL. I don't believe I need a model, I'm not accessing or capturing any data; I simply want to display different information (views) based on what a user clicks.
I have an icon bar on the top of the page (which is its own partial) and when you click on an icon, it corresponds to a specific partial view. Click another icon, the previous info disappears and the new info displays. Easy peasy right? I'm not having any luck.
I've found at least a gazillion articles explaining how to do it for ONE partial. but what if I want to conditionally display info that isn't in a list and isn't in a database, but is simply a partial view connected to a link?
Here's some of the code...
My Controller
public class MyController : Controller {
public ActionResult Index() {
return View();
}
public ActionResult _about() {
return View();
}
public ActionResult _business() {
return View();
}
public ActionResult _finance() {
return View();
}
public ActionResult _jobs() {
return View();
}
public ActionResult _locations() {
return View();
}
public ActionResult _marketing() {
return View();
}
public ActionResult _programming() {
return View();
}
}
}
My Markup for the Index View (the main view for this page):
#using System.Configuration
#{ViewBag.Title = "Index";}
#Html.Partial("_cteIconBar") <!-- This is the row of icons -->
<div class="padding-top-50" id="partial">
#Html.Partial("_about") <!-- I do want to display the "about" partial when a user first lands on the page.-->
</div>
<div class="padding-top-50" id="partial" style="display: none"> <!-- this is not working... *sigh* -->
#{Html.RenderAction("_business"); }
#{Html.RenderAction("_programming"); }
#{Html.RenderAction("_finance"); }
#{Html.RenderAction("_marketing"); }
</div>
My Markup for the icon bar:
<div class="row">
<div class="col-lg-12 col-xs-12">
<div class="text-center margin-bottom icon-container">
<ul>
<li class="icon-bar-cte" id="about">
<a role="button" href="#Url.Action("_about", "CTE")">
<i class="icon-aboutInfo cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte" id="business">
<a role="button" class="cte-icon" href="#Url.Action("_business", "CTE")">
<i class="icon-business cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte">
<a role="button" href="#Url.Action("_finance", "CTE")">
<i class="icon-finance cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte">
<a role="button" href="#Url.Action("_marketing", "CTE")">
<i class="icon-marketing cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte">
<a role="button" href="#Url.Action("_programming", "CTE")">
<i class="icon-programming cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte">
<a role="button" href="#Url.Action("_jobs", "CTE")">
<i class="icon-jobs cte-icon"></i>
</a>
</li>
<li class="icon-bar-cte">
<a role="button" href="#Url.Action("_locations", "CTE")">
<i class="icon-location-marker cte-icon"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
My markup for one of the partials (they're all the same with different words). I substituted a little "Hippie Ipsum" for your pleasure.
<div class="container collapse in" id="about" aria-expanded="true">
<div class="row padding-bottom-50">
<div class="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-12">
<h2 class="green">Some Hippie Ipsum for You!</h2>
<p><strong>What is Career Technical Education?</strong></p>
<p>Equinox plant consciousness midwifery embracing and moving towards djembe craniosacral, dolphin Hafiz ecstatic dance higher cosmic force spoken word. Prayer flags fair trade what quantum theory says, healing tonic non-profit co-create impermanent hemp seed.</p>
<br />
<p><strong>Why is Hippie Ipsum important?</strong></p>
<p>Closing circle himalayan sea salt multi-dimensional honoring your truth, forest birth name. Tofurkey native american ancestry diva cup human potential yoni, bioneers the buddha sunset. Animal totem deep cleansing emotional release one taste life coach compostable toilet, be the change astrological mercury retrograde holistic.</p>
</div>
</div>
</div>
.padding-top-50{
padding-top:50px;
}
The easiest solution for what you'd like to achieve is to use AJAX so you can inject the views into the container.
So let's start from the beginning:
1) You have to return PartialView() instead of regular View()
public ActionResult _about() {
return PartialView();
}
2) Not needed, but I'd change some things in your menu markup. Note the data-url instead of href.
<li class="icon-bar-cte" id="business">
<a href="#" role="button" class="cte-icon" data-url="#Url.Action("_business", "CTE")">
<i class="icon-business cte-icon"></i>
</a>
</li>
3) Most important part is the following jQuery. Depending of what you need you can use append instead of html when injecting the view.
$(document).on('click','.cte-icon',function(e){
e.preventDefault();
var url = $(this).data('url');
$.ajax({
url: url,
type: 'GET'
}).done(function(response){
$('#partial').html(response);
});
});
Yet another way, if you wanna go more "vanilla" .NET MVC is to use actionlinks and return partial views from your controller actions.
Something like this:
public ActionResult _programming()
{
PartialView("~/Views/YourPartialsPath/_programming.cshtml");
}
And in your views put this:
#Html.ActionLink("Html element text",
"_programming",
"MyController",
new { controller = "MyController" },
new { #class = "MaybeYouWantAClassOnTheHtmlElement" })
And if you want you could structure your site to be a single page app by initially loading a single view to be your "base structure" container. This page would then load a set of partials consisting of maybe side/top menu bars and maybe a "main page" container.
This main page could also be in charge of loading of some javascripts you want to run across all of your later loaded partials (maybe a function showing/hiding an ajax.gif image)
Lets say you put this in your initial page load.
Maybe you put this in your: \Views\Home\index.cshtml
Or even your: \Views_Layout.cshtml
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-left">
#{ Html.RenderAction("TopMenuRenderer", "Menu");}
</ul>
<ul class="nav navbar-nav navbar-right">
#{ Html.RenderAction("UserMenuRenderer", "Menu");}
</ul>
</div>
Then you create a controller called Menu
namespace WebPortal.Web.Controllers
{
public class MenuController : Controller
{
[ChildActionOnly] //for ajax call to controller remove this annotation
public ActionResult TopMenuRenderer()
{
//return PartialView();
if (User.IsInRole(Role.Admin.ToString()) ||
User.IsInRole(Role.SuperAdmin.ToString()))
{
return PartialView("~/Views/Menu/_TopMenu.cshtml");
}
return null;
}
[ChildActionOnly]
public ActionResult UserMenuRenderer()
{
if (User.Identity.IsAuthenticated)
return PartialView("~/Views/Menu/_UserMenuAuthenticated.cshtml");
else
return PartialView("~/Views/Menu/_UserMenuNotAuthenticated.cshtml");
}
[ChildActionOnly]
public ActionResult SideMenuRenderer()
{
//you could put some user checks here if you want to limit some of the loaded meny options depending on the user type.
if (User.IsInRole(Role.Admin.ToString()) ||
User.IsInRole(Role.SuperAdmin.ToString()))
{
return PartialView("~/Views/Menu/_SideMenu.cshtml");
}
return null;
}
}
}
In my _Layout.cshtml view I have
#using SiteNET.Utilities
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>"SomeTitle"</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
<!-- Favicons -->
<link rel="apple-touch-icon-precomposed"
sizes="256x256"
href="#Url.Content("~/Content/Images/SiteRetro256.png")">
<link rel="shortcut icon"
href="#Url.Content("~/Content/Icons/SiteRetro.ico")">
</head>
<body>
<div class="container">
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button"
class="navbar-toggle"
data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
#Html.ActionLink(SiteNET.Utilities.Constants.Site,
"Index", "Home", null, new { #class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="#Url.MakeActive("Home")">
#Html.ActionLink("Home", "Index", "Home")
</li>
<li class="#Url.MakeActive("Index", "Contacts")">
#Html.ActionLink("Contacts", "Index", "Contacts")
</li>
</ul>
#Html.Action("_LoginPartial", "Account") <- THIS LINE
</div>
</div> <!--container-fluid-->
</div> <!--navbar-->
#RenderBody()
<hr />
...
</div>
</body>
</html>
My aim is be able to load a view model into my _LoginPartial view. So I have added the following to my AccountController class
[ChildActionOnly]
public ActionResult _LoginPartial()
{
ApplicationUser user = null;
ManageUserViewModel model = null;
string userID = User.Identity.GetUserId() ?? String.Empty;
if (!String.IsNullOrEmpty(userID))
{
user = UserManager.FindById(userID);
model = new ManageUserViewModel();
model.IsAdmin = user.IsAdmin;
}
return PartialView(model);
}
But this does not call this method from
#Html.Action("_LoginPartial", "Account")`
I have read this answer and have swapped the
#Html.Action("_LoginPartial", "Account")
to
#Html.Action("_LoginPartial", "Account", new { area = "" })
as the controller is not in the "Shared" folder. I have also tried
#Html.Action("_LoginPartial", "Account", new { area = "Controllers" })`
but I am just getting a browser error:
The page isn't redirecting properly
What am I doing wrong here?
Thanks for your time.
Edit. following #markpSmith's suggestion, I have attempted to use
#{ Html.RenderAction("_LoginPartial", "Account"); }
_but this give the same error. _
Use #Html.Partial("_LoginPartial")
You don't need to specify action in Controller as you can access User.Identity in View so update _LoginPartial with User.Identity instead of Model.
I can't see if you have attempted the:
#Html.RenderPartial()
ActionMethod (see MSDN)
making yours look similar to:
View:
#Html.RenderPartial("_LoginPartial","Account")
Controller:
(within AccountController)
public ActionResult _LoginPartial()
{
ApplicationUser user = null;
ManageUserViewModel model = null;
string userID = User.Identity.GetUserId() ?? String.Empty;
if (!String.IsNullOrEmpty(userID))
{
user = UserManager.FindById(userID);
model = new ManageUserViewModel();
model.IsAdmin = user.IsAdmin;
}
return PartialView(model);
}
Other than that, I would suggest removing the underscore and see if you can run it instead (since it is a partial view, I don't think it will be navigateable anyway)