ASP.NET Core - controller will not return a view - asp.net-core

I have a problem with my controller - it doesn't return a view. I am sending some data to the same controller, creating a new object with this data and I would like to send this object to the Create view but for some kind of reason I am staying on the same page.
View name: Create.cshtml
Controller name: ReservationController
Here is my controller action:
public IActionResult Create(int selectedTime, string selectedDate, int selectedRoomId)
{
TimeSpan time = TimeSpan.Parse($"{selectedTime}:00:00");
DateTime date = DateTime.ParseExact(selectedDate, "MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture);
DateTime combine = date + time;
Reservation reservation = new Reservation();
reservation.RoomId = selectedRoomId;
reservation.ReservationTime = combine;
return View(reservation);
}
And my view:
#model Escape.Models.Reservation
#{
ViewBag.Title = "title";
}
<h2>My create reservation view</h2>
This is the original view I am coming from:
#using Escape.Controllers
#model Escape.Models.Room
#{
ViewData["Title"] = "Details";
}
<h4 class="title">Booking for room: #Model.Name</h4>
<div>
<p>#Model.Description</p>
<a class="btn btn-link" asp-action="Index">Back to all rooms</a>
<hr />
</div>
<div>
<input id="datepicker" type="text" name="datepicker"
onchange="onDateChange(#Model.Id)" />
</div>
<div>
<div id="displayTimes"></div>
<a id="btn-create" class="btn btn-sm"></a>
</div>
#section Scripts {
<script>
var dateToday = new Date();
$(function () {
$("#datepicker").datepicker({
minDate: dateToday
});
});
</script>
}
Ajax function on my btn-create:
function onButtonClick(val, date, room) {
var btnBack = document.getElementById("btn-create");
btnBack.innerHTML = "Create reservation";
$(btnBack).addClass('btn-outline-primary');
btnBack.addEventListener("click",
function () {
$.ajax({
type: "GET",
data: { selectedTime: val, selectedDate: date, selectedRoomId: room },
url: "/Reservation/Create",
contentType: "application/json",
dataType: "json"
});
});
}

If the link <a id="btn-create" class="btn btn-sm"></a> is supposed to make a call to the Create method of the ReservationController, then it is incomplete, and this is what you would need to change it to:
<a asp-controller="Reservation"
asp-action="Create"
id="btn-create" class="btn btn-sm">Create</a>
Update:
Your click handler does seem to send a request to the Controller, but nothing happens after that request, and the response (which contains the HTML from the View) is discarded.
Since you want to show the HTML, maybe you shouldn't even be using AJAX, and use my original answer above instead.
If for some reason you need the AJAX, then you need to create a success handler that displays the HTML:
btnBack.addEventListener("click",
function () {
$.ajax({
type: "GET",
data: { selectedTime: val, selectedDate: date, selectedRoomId: room },
url: "/Reservation/Create",
contentType: "application/json",
dataType: "json",
success: function (data) {
// ... put processing here
}
});
}
);

Related

How to return a partial view and invoke the model's constructor with DI system

I have a parent view, and want to call a handler with ajax that will return a partial view. The problem I'm having is that my partial view needs it's model also which has all its own OnGet, OnPost etc methods.
When calling:
public PartialViewResult OnGetPartialView(Guid Id)
{
return Partial("MyPartialView");
}
I don't know how to add the model for this view, as its only constructor takes several services that usually the DI systems takes care of for me. I also need to pass the Id to the partial view as its used in the OnGet method (which I'm assuming will be invoked when this works properly).
Thanks!
To pass the model to the partial view in razor pages, you need to add the second parameter as the model you need to pass when returning to the Partial:
return Partial("MyPartialView", model);
It should be noted that in MyPartialView, you need to delete the #Page in the first line of the page and add the model reference you passed.
This will ensure that MyPartialView receives the model data, otherwise there will be an error that model is null.
Regarding the OnGet and OnPost methods of the MyPartialView page you mentioned, if you delete #Page, they will lose their actual contact meaning.
My suggestion is that if you have some post or get methods that need to be used in MyPartialView, you can write these methods to other pages.
Here is a complete example:
TestModel.cshtml.cs:
public class TestModel : PageModel
{
public void OnGet()
{
}
public PartialViewResult OnGetPartialView(Guid Id)
{
List<Person> persons = new List<Person>()
{
new Person(){ Age = 12,
FirstName = "dd",
LastName = "aa" },
new Person(){ Age = 13,
FirstName = "bb",
LastName = "ff" },
new Person(){ Age = 14,
FirstName = "ggr",
LastName = "rwe" },
};
return Partial("MyPartialView", persons);
}
public IActionResult OnPostTest()
{
return Content("aa");
}
}
TestModel.cshtml:
#page
#model WebApplication_razorpage_new.Pages.TestModel
#{
ViewData["Title"] = "Test";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>Test</h1>
<input id="Button1" type="button" value="Get partial view" /><br /><br /><br />
<div id="partial" class="border"></div>
#section Scripts{
<script>
$(function () {
$("#Button1").click(function () {
$.ajax({
type: "get",
url: "/Test?handler=PartialView",
data: { Id: "780cd7ce-91b2-40fd-b4c8-7efa6b7c84a5" },
success: function (data) {
$("#partial").html(data);
}
});
});
})
</script>
}
MyPartialView.cshtml:
#model List<Person>
<form method="post">
<input id="Button1" type="button" value="button" onclick="Click()" />
<input id="Text1" type="text" />
<table class="table table-bordered">
#foreach (var item in Model)
{
<tr>
<td>#item.Age</td>
<td>#item.FirstName</td>
<td>#item.LastName</td>
</tr>
}
</table>
</form>
<script>
function Click() {
$.ajax({
type: "POST",
url: "/Test?handler=test",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
contentType: "application/json; charset=utf-8",
success: function (data) {
$("#Text1").val(data);
}
});
}
</script>
Here is the test result:

Switching Google reCaptcha Version 1 from 2

I have successfully designed and implemented Google reCaptcha Version 2 but now my Manager wants that to be of version 1 with numbers to be entered and validated. Is there a way to switch from later to former i.e.- from 2 to 1. I am using following library for reCaptcha:
<script src='https://www.google.com/recaptcha/api.js'></script>
Update..
To implement Captcha inside form i am using following HTML..
<form class="contact_form" action="#" method="post" name="contact_form">
<div class="frm_row">
<label id="lblmsg" />
<div class="clear">
</div>
</div>
<div class="g-recaptcha" data-sitekey="6Lduiw8TAAAAAOZRYAWFUHgFw9_ny5K4-Ti94cY9"></div>
<div class="login-b">
<span class="button-l">
<input type="button" id="Captcha" name="Submit" value="Submit" />
</span>
<div class="clear"> </div>
</div>
</form>
As i need to get the Captcha inside the above form to Validate and get the response on button click but as now i am using <script src="http://www.google.com/recaptcha/api/challenge?k=6Lduiw8TAAAAAOZRYAWFUHgFw9_ny5K4-Ti94cY9"></script> , so not getting the Captcha inside the form ..Please help me to get that ..Also here is the Jquery Ajax code to send the request on Server side code..
$(document).ready(function () {
alert("hii1");
$('#Captcha').click(function () {
alert("Hii2");
if ($("#g-recaptcha-response").val()) {
alert("Hii3");
var responseValue = $("#g-recaptcha-response").val();
alert(responseValue);
$.ajax({
type: 'POST',
url: 'http://localhost:64132/ValidateCaptcha',
data: JSON.stringify({ "CaptchaResponse": responseValue }),
contentType: "application/json; charset=utf-8",
dataType: 'json', // Set response datatype as JSON
success: function (data) {
console.log(data);
if (data = true) {
$("#lblmsg").text("Validation Success!!");
} else {
$("#lblmsg").text("Oops!! Validation Failed!! Please Try Again");
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("Error");
}
});
}
});
});
Please help me ..Thanks..
You have to verify the reCaptcha at "http://www.google.com/recaptcha/api/verify" on Server side.
The parameters of this are:
privatekey: Your Private Key
remoteip: User's IP Address
challenge: Value of input[name=recaptcha_response_field]
response: Value of input[name=recaptcha_challenge_field]
Therefore, you have to post them on your server-side method like this:
cshtml file:
var recaptchaResponseField=$("input[name=recaptcha_response_field]").val();
var recaptchaChallengeField=$("input[name=recaptcha_challenge_field]").val();
// ajax block
$.ajax({
url: '/api/VerifyReCaptcha/', // your Server-side method
type: 'POST',
data: {
ipAddress: '#Request.ServerVariables["REMOTE_ADDR"]',
challengeField: recaptchaChallengeField,
responseField: recaptchaResponseField
},
dataType: 'text',
success: function (data) {
// Do something
},
Since you are using .NET so an example of C# code is as follows:
cs file:
using System.Net;
using System.Collections.Specialized;
[HttpPost]
public bool VerifyReCaptcha(string ipAddress, string challengeField, string responseField)
{
string result = "";
using (WebClient client = new WebClient())
{
byte[] response =
client.UploadValues("http://www.google.com/recaptcha/api/verify", new NameValueCollection()
{
{ "privatekey", "{Your private key}" },
{ "remoteip", ipAddress },
{ "challenge", challengeField },
{ "response", responseField },
});
result = System.Text.Encoding.UTF8.GetString(response);
}
return result.StartsWith("true");
}

MVC4 Ajax bouble result when submit

I code web MVC4 by VS2012. I use Ajax to paging in list page, when ajax working is double result. Below is my code:
This is View:
<div id="result">
<% using (Ajax.BeginForm("Paging","pa",new AjaxOptions{UpdateTargetId="result"})){ %>
<table>...<table>
<div class="Paging"><%= ViewBag.PhanTrang %></div>
<%} %></div>
<script>
$(function () {
$('.a_pt').click(function () {
var _val = $(this).data("id");
$.ajax({
url: this.action,
type: this.method,
data: { id: _val },
success: function (result) {
$('#result').html(result);
}
});
return false;
});
});
</script>
This is Controller:
public ActionResult Paging(string id)
{
demoMVC4Entities db = new demoMVC4Entities();
var _listProvince = db.T_Provinces;
ViewBag.ddl_Province = new SelectList(_listProvince, "Province_ID", "Province_Name");
var _listStudent = db.T_Student.OrderBy(n => n.MA).Skip((_pageIndex - 1) * pageSize).Take(pageSize);
return View(_listStudent);
}
And this is first result:
<body>
<p>...</p>
<div id="result">
<form action=.............></form>
</div>
And this í second result:
<body>
<p>...</p>
<div id="result">
<form action=.............>
___<body>
___<p>...</p>
___<div id="result">
___<form action=.............></form>
___</div>
</form>
</div>
Plese help me.! Thanks.!
I think you are updating the target id (#result) twice. Either remove the success function in the javascript or remove the UpdateTargetId in the Ajax Options.
hth
O
Create a Partial View named: WhateverList.cshtml
Put this is in a Partial View:
<% using (Ajax.BeginForm("Paging","pa",new AjaxOptions{UpdateTargetId="result"})){ %>
<table>...<table>
<div class="Paging"><%= ViewBag.PhanTrang %></div>
<%} %></div>
Keep this in the current view you have:
<div id="result"></div>
Then in Controller do this:
public ActionResult WhateverList(string id)
{
demoMVC4Entities db = new demoMVC4Entities();
var _listProvince = db.T_Provinces;
ViewBag.ddl_Province = new SelectList(_listProvince, "Province_ID", "Province_Name");
var _listStudent = db.T_Student.OrderBy(n => n.MA).Skip((_pageIndex - 1) * pageSize).Take(pageSize);
return PartialView(_listStudent);
}
And you only need either the jQUery Ajax OR the Ajax.BeginForm not both:
I suggest you use jQuery in this Case:
<script>
$(function () {
$('.a_pt').click(function () {
var _val = $(this).data("id");
$.ajax({
url: this.action,
type: this.method,
data: { id: _val },
success: function (result) {
$('#result').html(result);
}
});
return false;
});
});
</script>
And remove the Ajax.BeginForm from your PartialView:
So Partial View is only:
#model SelectList
<table>...<table>
<div class="Paging"><%= ViewBag.PhanTrang %></div>
When you return View(), it will render the _Layout.cshtml of the Page , and return the <html>, <body> tags. But return PartialView() only returns the HTML content of the Partial View without Layout.cshtml

Single file upload using Ajax, MVC 5 and jQuery

I am using asp.net MVC 5 to do a simple single file upload using the HTML element.I make an AJAX post request.The form has other fileds in addition to the file element.I tried diffrent methods available on the internet ,but nothing seems to be working.Is this really possible using the element?Using a jQuery plugin is my last option.I like to make things simple in my application
my HTML
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "form-person-edit-modal", enctype = "multipart/form-data" }))
{
<div class="row">
<div class="row">
<div class="small-4 columns">
#Html.GenericInputFor(m => m.Name, Helpers.HtmlInputType.Text, new { id = "input-name" })
</div>
<div class="small-4 columns">
#Html.GenericInputFor(m => m.Description, Helpers.HtmlInputType.TextArea, new { id = "input-description" })
</div>
<div class="small-4 columns">
<label>Choose File</label>
<input type="file" name="attachment" id="attachment" />
</div>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<input type="submit" id="image-submit" value="Save"/>
</div>
</div>
}
-- C# ViewModel
public class Person
{
Public string Name{get;set;}
Public string Description{get;set;}
public HttpPostedFileBase Attachment { get; set; }
}
-- Jquery Ajax Post:
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
success: function (data, textStatus, jqXHR) {
if (data.Success) {
success(data, textStatus, jqXHR);
} else {
if (error) {
error();
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (error)
error();
}
});
-- Javacsript where I try to get the file content,before passing that data to the above method
function getData(){
return {
Name:$('#input-name').val(),
Description:$('#input-description').val(),
Attachment:$('#form-ticket-edit-modal').get(0).files[0]
};
}
But the Attachment on the controller is null.I tried this as below,but doesnt seem to be working
[HttpPost]
public ActionResult Edit(ViewPerson person,HttpPostedFileBase attachment)
{
}
Is this still possible,or should I use a jQuery plugin(If so,which one do you recommend?)
I have used your code to show how to append image file,Please use Formdata() method to append your data and File and send through ajax.
Try Changing as per your requirement.
$("#SubmitButtonID").on("click",function(){
var mydata=new Formdata();
mydata.append("Name",$("#name").val());
mydata.append("Image",Image.files[0]);
alert(mydata);
$.ajax({
url: "#url.Action("ActionMethodName","ControllerName")",
type: 'POST',
contentType:false,
processData;false,
data: mydata,
dataType: 'json',
success: function (data, textStatus, jqXHR) {
if (data.Success) {
success(data, textStatus, jqXHR);
} else {
if (error) {
error();
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (error)
error();
}
});
});
<input type="file" id="Image" name="file">
<input type="button" id="SubmitButtonID" value="submit"/>

knockout.js binding issue when trying to refresh data

I am using knockout.js data binding. At the page load the binding works fine and data is shown on the page correctly. Then I try to push data back to the database and the push is successful. The database receives the data OK.
The problem comes when I try to reload the data upon push success. At this time the binding already happen once (at the page load). If I don't bind it again the data on the page does not refresh. If I do the binding again knockout.js issues an error "cannot bind multiple times". If I do a cleanup before rebinding I receive an error "nodeType undefined".
Can anyone tell me what I have missed here? I am using ASP.NET MVC 4.0 with knockout.js 3.0.0.
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplJSON.Controllers
{
public class KnockoutController : Controller
{
//
// GET: /Knockout/
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetProductList()
{
var model = new List<Product>();
try
{
using (var db = new KOEntities())
{
var product = from p in db.Products orderby p.Name select p;
model = product.ToList();
}
}
catch (Exception ex)
{ throw ex; }
return Json(model, JsonRequestBehavior.AllowGet);
}
// your controller action should return a JsonResult. There's no such thing as a controller action that returns void. You have specified dataType: 'json' so return JSON. That's it. As far as what parameter this controller action should take, well, from the JSON you are sending ({"Name":"AA"}) it should be a class that has a Name property of type string.
// modify your action signature to look like this: [HttpPost] public ActionResult SaveProduct (Product product) { ... return Json(new { success = true }); }. Or get rid of this dataType: 'json' attribute from your AJAX request if you don't want to return JSON. In this case you could return simply status code 201 (Created with empty response body): return new HttpStatusCodeResult(201);.
[HttpPost]
public ActionResult SaveProduct(Product product)
{
using (var db = new KOEntities())
{
db.Products.Add(new Product { Name = product.Name, DateCreated = DateTime.Now });
db.SaveChanges();
}
return Json(new { success = true });
}
}
}
View:
#{
ViewBag.Title = "Knockout";
}
<h2>Knockout</h2>
<h3>Load JSON Data</h3>
<div id="loadJson-custom" class="left message-info">
<h4>Products</h4>
<div id="accordion" data-bind='template: { name: "product-template", foreach: product }'>
</div>
</div>
<h3>Post JSON Data</h3>
<div id="postJjson-custom" class="left message-info">
<h4>Add Product</h4>
<input id="productName" /><br />
<button id="addProduct">Add</button>
</div>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/livequery")
<script src="/Scripts/jquery.livequery.min.js"></script>
<style>
#accordion { width: 400px; }
</style>
<script id="product-template" type="text/html">
<h3><a data-bind="attr: {href:'#', title: Name, class: 'product'}"><span data-bind="text: Name"></span></a></h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span> </p>
</div>
</script>
<script>
var isBound;
function loadJsonData() {
$.ajax({
url: "/knockout/GetProductList",
type: "GET",
contentType: "application/json",
dataType: "json",
data: {},
async: true,
success: function (data) {
var loadJsonViewModel = {
product: ko.observableArray(),
init: function () {
loadAccordion();
}
};
var a = $('loadJson-custom');
loadJsonViewModel.product = ko.mapping.fromJS(data);
if (isBound) { }
else
{
ko.applyBindings(loadJsonViewModel, $('loadJson-custom')[0]);
isBound = true;
}
loadJsonViewModel.init();
}
});
}
// push data back to the database
function pushJsonData(productName) {
var jData = '{"Name": "' + productName + '"}';
$.ajax({
url: "/knockout/SaveProduct",
type: "POST",
contentType: "application/json",
dataType: "json",
data: jData,
async: true,
success: function (data, textStatus, jqXHR) {
console.log(textStatus + " in pushJsonData: " + data + " " + jqXHR);
//ko.cleanNode($('loadJson-custom')[0]);
loadJsonData();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus + " in pushJsonData: " + errorThrown + " " + jqXHR);
}
});
}
function loadAccordion() {
$("#accordion > div").livequery(function () {
if (typeof $("#accordion").data("ui-accordion") == "undefined")
{
$("#accordion").accordion({ event: "mouseover" });
}
else
{
$("#accordion").accordion("destroy").accordion({ event: "mouseover" });
}
});
}
$(function () {
isBound = false;
loadJsonData();
$("#addProduct").click(function () {
pushJsonData($("#productName").val());
});
});
</script>
}
Here is a complete solution for your question.
I have just implemented and checked.
Please have a look.
I have created a class for getting some records ie: Records.cs.
public static class Records
{
public static IList<Student> Stud(int size)
{
IList<Student> stud = new List<Student>();
for (int i = 0; i < size; i++)
{
Student stu = new Student()
{
Name = "Name " + i,
Age = 20 + i
};
stud.Add(stu);
}
return stud;
}
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
Here is a controller for the respective view.
//
// GET: /HelpStack/
private static IList<Student> stud = Records.Stud(10);
public ActionResult HelpStactIndex()
{
return View();
}
[HttpGet]
public JsonResult GetRecord()
{
return Json(stud, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public void PostData(Student model)
{
//do the required code here as All data is in "model"
}
Here is a view as HTML, I have taken two section one for list and other to Add records
<div id="loadJson-custom">
<h4>Student</h4>
<table width="100%">
<tr>
<td style="width: 50%">
<div id="accordion" data-bind='template: { name: "product-template", foreach: Student }'>
</div>
</td>
<td valign="top">
<div id="NewStudent">
<input type="text" data-bind="value: Name" /><br />
<input type="number" data-bind="value: Age" /><br />
<input type="submit" data-bind="click: Save" value="AddNew" />
</div>
</td>
</tr>
</table>
Here is your scripts for Knockoutjs.
<script id="product-template" type="text/html">
<h3><a data-bind="attr: { href: '#', title: Name, class: 'product' }"><span data-bind=" text: Name"></span></a>
<br />
Age: <span data-bind="text: Age"></span>
</h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span></p>
</div>
</script>
<script type="text/javascript">
//Model for insert new record
var Model = {
Name: ko.observable(''),
Age: ko.observable(''),
};
var Student = ko.observableArray([]); // List of Students
function loadData() { //Get records
$.getJSON("/HelpStack/GetRecord", function (data) {
$.each(data, function (index, item) {
Student.push(item);
});
}, null);
}
function Save() { //Save records
$.post("/HelpStack/PostData", Model, function () { //Oncomplete i have just pushed the new record.
// Here you can also recall the LoadData() to reload all the records
//Student.push(Model);
Student.unshift(Model); // unshift , add new item at top
});
}
$(function () {
loadData();
ko.applyBindings(Model, $('#NewStudent')[0]);
});
</script>
You are declaring your model inside loadJsonData function success callback, & creating new object on every success callback, move the model outside that function, create an object & use it inside loadJsonData function, it will fix the issue.