how to create charts in asp.net core - c#

what i want to do is creating charts from excuted data from a query in asp.net core but i face problem in usnig [httppost] in the controller when i use it gives me error 405 and when i don't use it the json data appear in the view and below are my codes.
Hello, what i want to do is creating charts from excuted data from a query in asp.net core but i face problem in usnig [httppost] in the controller when i use it gives me error 405 and when i don't use it the json data appear in the view and below are my codes.
public JsonResult Index()
{
string query = "select UserId, count(ServiceOrderNumber) as OrderNum from [dbo].[ServiceOrders] group by [UserId] order by count ([ServiceOrderNumber]) desc";
string constr = this._configuration.GetConnectionString("DefaultConnection");
List<object> chartData = new List<object>();
chartData.Add(new object[]
{
"UserId", "OrderNum"
});
SqlConnection con = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand(query);
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
con.Open();
SqlDataReader sdr = cmd.ExecuteReader();
while (sdr.Read())
{
chartData.Add(new object[]
{
sdr["UserId"], sdr["OrderNum"]
});
}
con.Close();
return Json(chartData);
}
and my view is
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);
function drawChart() {
$.ajax({
type: "POST",
url: "/Reports/Index/",
contentType: "application/json; charset=utf-8",
cache: false,
traditional: true,
dataType: "json",
success: function (r) {
var data = google.visualization.arrayToDataTable(r);
//Pie
var options = {
title: 'USA City Distribution'
};
var chart = new google.visualization.PieChart($("#chart")[0]);
chart.draw(data, options);
},
failure: function (r) {
alert(r.d);
},
error: function (r) {
alert(r.d);
}
});
}
</script>
<div id="chart" style="width: 500px; height: 400px;">
</div>
</body>
</html>

i face problem in usnig [httppost] in the controller when i use it
gives me error 405
The address bar of browser only support Get request.If you send the post request in browser address bar,it will get http 405 method not allowed error.
when i don't use it the json data appear in the
view and below are my codes.
If you remove HttpPost,it will be HttpGet by default.So when you enter the url in address bar,you will get the json string.
Also you may misunderstand ajax,ajax will be sent after your view has loaded.
You could check the document:
AJAX is a developer's dream, because you can:
Request data from a server - after the page has loaded
So,what you need do first is to send get request to backend to load the view and then it will hit the ajax you wrote. The whole principle you could check the gif below.
Here is a whole working demo:
Index.cshtml View in Views/Reports folder:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="~/lib/jquery/dist/jquery.min.js"></script> //be sure add jquery....
<script type="text/javascript">
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);
function drawChart() {
$.ajax({
type: "POST",
url: "/Reports/Index/",
//url:"/Reports/GetJson/" //if you do not use route attribute in action
contentType: "application/json; charset=utf-8",
cache: false,
traditional: true,
dataType: "json",
success: function (r) {
var data = google.visualization.arrayToDataTable(r);
//Pie
var options = {
title: 'USA City Distribution'
};
var chart = new google.visualization.PieChart($("#chart")[0]);
chart.draw(data, options);
},
failure: function (r) {
alert(r.d);
},
error: function (r) {
alert(r.d);
}
});
}
</script>
<div id="chart" style="width: 500px; height: 400px;">
</div>
</body>
</html>
Controller:
public class ReportsController : Controller
{
//default is httpget
public ActionResult Index()
{
return View(); //it is used to load the view..
}
//if your request url is the same with get method,you could add route attribute.
//Because the controller could not have two same name method with the same parameter although they are used in different http request
[Route("Reports/Index")]
[HttpPost]
public JsonResult GetJson()
{
List<object> chartData = new List<object>();
chartData.Add(new object[]
{
"UserId", "OrderNum"
});
chartData.Add(new object[]
{
"1", 3
});
chartData.Add(new object[]
{
"2", 4
});
chartData.Add(new object[]
{
"3", 6
});
return Json(chartData);
}
}
Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Result:

Related

MVC - display image from sqlite db

how can i export an image from DB - Sqlite and display this image in the view?
im using angular code, and the images byte stored now in x.img var.
i want to display the image in img tag.
i tried few ways...
please your help.
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://www.w3schools.com/lib/w3.css">
<link href="~/Content/productmenuStyle.css" rel="stylesheet" />
<script src="~/Scripts/angular.js"></script>
<script type="text/javascript">
var app = angular.module("myCode", []);
app.controller("CodeController", function ($scope, $http) {
$scope.Table = false;
$scope.showProduct = function (num) {
$scope.number = num;
$scope.getProduct(num);
}
$scope.getProduct = function (num) {
var list = $http({
method: 'post',
url: 'getProductjson',
params: {
prClass: num
}
});
list.then(function (list) {
$scope.Products = list.data;
}, function () {
alert("Inavalid data !!!");
});
}
$scope.sendProduct = function (num) {
var list = $http({
method: 'post',
url: 'sendProduct',
params: {
pid: num,
}
});
list.then(function (list) {
alert("The Product Addad To The Cart");
}, function () {
alert("Inavalid data !!!");
});
}
});
</script>
</head>

Pie chart using chart.js and asp.net web Service (asmx)

I have a static pie-chart created using chartJS and now I want to provide the data and labels from an asp.net webservice(asmx) to show the actual data that comes from the database but I don't know how to do that.
This is the Static Chart Code
<!doctype html>
<html>
<head>
<title>Pie Chart</title>
<script src="../../dist/Chart.min.js"></script>
<script src="../utils.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:40%">
<canvas id="chart-area"></canvas>
</div>
<script>
var config = {
type: 'pie',
data: {
datasets: [{
data: [420,576,812],
backgroundColor: [
"#3e95cd", "#8e5ea2", "#3cba9f"
],
label: 'Labels'
}],
labels: [
'iPhone',
'Windows Phone',
'Samsung'
]
},
options: {
responsive: true
}
};
window.onload = function () {
var ctx = document.getElementById('chart-area').getContext('2d');
window.myPie = new Chart(ctx, config);
};
</script>
</body>
</html>
The Data I want to Show
Phone as Chart Label and Amount as Chart-Data
-------------------------
-Phone - Amount-
-------------------------
-iPhone - 323 -
-Windows-Phone - 210 -
-Samsung - 860 -
-------------------------
The Web Service that fetch the data
[WebMethod]
public void GetTotalPhoneSales()
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
List<TotalSales> totalSales = new List<TotalSales>();
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spGetTotalPhoneSales", con)
{
CommandType = CommandType.StoredProcedure
};
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
TotalSales PhoneSale = new TotalSales
{
Amount = Convert.ToInt32(rdr["Amount"]),
Phone = rdr["Phone"].ToString()
};
totalSales.Add(PhoneSale);
}
}
JavaScriptSerializer js = new JavaScriptSerializer();
Context.Response.Write(js.Serialize(totalSales));
}
Expected output
You may call the web service method from Jquery Ajax function and return the values.
What you have to change is
1) Change the return type of your web method to string[][](Array of string Arrays:because we need to return two arrays)
2) Call this web method with the help of Jquery ajax function and in the success function assign the data and label options with respective arrays received from the jquery ajax call.
documentation of Jquery ajax function
Finally I solved it like this
<script>
//make an ajax call to the webservice
//then use `chartlabel` as label and `chartData` as Data
var chartLabel= [];
var chartData= [];
$.ajax({
url: 'TestService.asmx/GetTotalPhoneSales',
method: 'post',
dataType: 'json',
success: function (data) {
$(data).each(function (index, item) {
chartLabel.push(item.Phone);
chartData.push(item.Amount);
});
},
error: function (err) {
alert(err);
}
});
var config = {
type: 'pie',
data: {
datasets: [{
data: chartData,
backgroundColor: [
"#3e95cd", "#8e5ea2", "#3cba9f"
],
label: 'Labels'
}],
labels: chartLabel
},
options: {
responsive: true
}
};
window.onload = function () {
var ctx = document.getElementById('chart-area').getContext('2d');
window.myPie = new Chart(ctx, config);
};
</script>
Note: Its better to assign the backgroundColor programmatically, so that when new items are added to the database then those items will not show up with same color on the chart by default.
thanks for the hint #Gagan Deep

Example AJAX call back to an ASP.NET Core Razor Page

I've found examples of have multiple handlers on a page and the associated naming convention (ie OnPostXXX) and 'asp-post-hanlder' tag helper. But how can I call one of these methods from an AJAX call.
I have an older example with a typical MVC view and controller but how does this work with a Razor Page?
For example if I take the base application and modify the About.cshtml page to the following:
#page
#model AboutModel
#{
ViewData["Title"] = "About";
}
<h2>#ViewData["Title"]</h2>
<h3>#Model.Message</h3>
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
#section Scripts {
<script type="text/javascript">
function ajaxTest() {
console.log("Entered method");
$.ajax({
type: "POST",
url: '/About', // <-- Where should this point?
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function (xhr, status, errorThrown) {
var err = "Status: " + status + " " + errorThrown;
console.log(err);
}
}).done(function (data) {
console.log(data.result);
})
}
</script>
}
And on the model page About.cshtml.cs
public class AboutModel : PageModel
{
public string Message { get; set; }
public void OnGet()
{
Message = "Your application description page.";
}
public IActionResult OnPost() {
//throw new Exception("stop");
return new JsonResult("");
}
}
The OnPost is not called from the Ajax call.
Razor Pages automatically generates and validates Antiforgery tokens to prevent CSRF attacks. Since you aren't sending any token within your AJAX callback, the request fails.
To solve this problem you will have to:
Register the Antiforgery-Service
Add the token to your request
Add the antiforgery token to your page either by adding a <form> or by directly using the #Html.AntiForgeryToken HtmlHelper
1. Register the Antiforgery-Service in your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}
2. Modify your AJAX callback
In the AJAX callback we add additional code to send the XSRF-TOKEN with our request header.
$.ajax({
type: "POST",
url: '/?handler=YOUR_CUSTOM_HANDLER', // Replace YOUR_CUSTOM_HANDLER with your handler.
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
dataType: "json"
}).done(function (data) {
console.log(data.result);
})
3. Add the antiforgery token to your page
You can accomplish this by adding a <form>:
<form method="post">
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>
or by using the #Html.AntiForgeryToken:
#Html.AntiForgeryToken()
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
In both cases Razor Pages will automatically add a hidden input field which contains the antiforgery token once the page is loaded:
<input name="__RequestVerificationToken" type="hidden" value="THE_TOKEN_VALUE" />
Please see this related section of the documentation
https://learn.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio
The associations of URL paths to pages are determined by the page's location in the file system. The following table shows a Razor Page path and the matching URL
/Pages/Index.cshtml maps to / or /Index
/Pages/Contact.cshtml maps to /Contact
Everything works well, but some changes have to be made:
1)Open Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
services.AddMvc();
}
2)Open HomeController.cs:
[ValidateAntiForgeryToken]
public IActionResult OnPost()
{
return new JsonResult("Hello Response Back");
}
3)Open About.cshtml:
#{
ViewData["Title"] = "About";
}
<h2>#ViewData["Title"]</h2>
<h3>#ViewData["Message"]</h3>
<p>Use this area to provide additional information.</p>
<form method="post">
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script type="text/javascript">
function ajaxTest() {
$.ajax({
type: "POST",
url: 'onPost',
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
dataType: "json"
}).done(function (data) {
console.log(data.result);
})
}
</script>
It should be noted that "onPost" was added inside the controller, so in AJAX the correct "url" should be indicated. Then:
url: 'onPost',
After looking at the answers above I got JSON ajax to work with .NET Core 2.1 Razor pages using Visual Studio 2017 Preview 2:
Startup.cs
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
PostJson.cshtml
#page
#model myProj.Pages.PostJsonModel
#{
ViewData["Title"] = "PostJson";
}
<input type="button" value="Post Json" class="btn btn-default" onclick="postJson();" />
<script>
function ajaxRazorPostJson(o) {
return $.ajax({
type: "POST",
data: JSON.stringify(o),
url: 'postJson',
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); },
dataType: "json"
});
}
function postJson() {
ajaxRazorPostJson({ reqKey: "reqVal" }).done(data => alert(data));
}
</script>
PostJson.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json.Linq;
namespace myProj.Pages
{
public class PostJsonModel : PageModel
{
public IActionResult OnPost([FromBody] JObject jobject)
{
// request buffer in jobject
return new ContentResult { Content = "{ \"resKey\": \"resVal\" }", ContentType = "application/json" };
// or ie return new JsonResult(obj);
}
}
}
Browser
http://localhost:44322/postJson
Accepted solution worked in local developing machine, but failed then deployed in Debian server behind Nginx reverse proxy (not found 404 error).
This is a working example with payload data:
<script type="text/javascript">
$('#btnPost').on('click', function () {
var payloadData; /*asign payload data here */
$.post({ /* method name in code behind, and full path to my view*/
url: '#Url.Action("OnPostAsync", "/Turtas/Inventorius/InventoriausValdymas")',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: JSON.stringify({ payloadData }),
contentType: "application/json; charset=utf-8",
dataType: "json"
})
})
</script>
VS 2017; .Net Core 2.2 Razor Pages; jQuery 3.3.1
I'm adding this for posterity.
Wrangling the same problem, I discovered the following code which may be added to Startup.cs:
services.AddRazorPages().AddRazorPagesOptions(options =>
{
options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});
No more anti forgery tokens required.
The answer works for me. I would only add that if we have customized methods on the page like:
public IActionResult OnPostFilter1()
{
return new JsonResult("Hello Response Back");
}
Then we should specify the handler name in the url:
url: 'OnPost?handler=filter1',
The following works with ASP.NET Core MVC 3.1 using the headers setting:
$.ajax({
type: "POST",
url: '/Controller/Action',
data: {
id: 'value'
},
headers: {
RequestVerificationToken:
$('input:hidden[name="__RequestVerificationToken"]').val()
},
error: function (xhr, status, errorThrown) {
var err = "Error: " + status + " " + errorThrown;
console.log(err);
}
}).done(function (data) {
console.log(data.result);
});
Including the ValidateAntiForgeryToken attribute on the controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Action(string id)
{
var result = $"You sent '{id}'";
return Json(new { id, result });
}

The same autocomplete works in one solution, but not in the other one

I've tried everything and this is driving me mad.
I made an autocomplete which works in a solution, but when I export it (copy and paste) in my main solution it doesn't work anymore and I keep getting the following error: "Unable to get property 'length' of undefined or null reference".
It can't be the jquery version and stuff, cause it works in the other solution.
aspx:
CodiceFiscale.aspx
<link rel="Stylesheet" href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/them/redmond/jquery-ui.css" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.22/jquery-ui.js"></script>
<script type="text/javascript">
$(function () {
$("#MainContent_provatxt").autocomplete({
source: function (request, response) {
var param = { cityName: $('#MainContent_provatxt').val() };
$.ajax({
url: "CodiceFiscale.aspx/GetCities",
data: JSON.stringify(param),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
dataFilter: function (data) { return data; },
success: function (data) {
response($.map(data.d, function (item) {
return {
value: item
}
}))
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
},
minLength: 3
});
});
<asp:TextBox ID="provatxt" runat="server"></asp:TextBox>
Ah btw yea, I have to get the elements by #MainContent_ since the id of the textbox in the browser is different than the one in the project, but it works fine in the other solution.
code behind: CodiceFiscale.aspx.cs
[WebMethod]
public static List<string> GetCities(string cityName)
{
List<string> City = new List<string>();
string query = string.Format("SELECT DISTINCT nome_comune FROM comuni WHERE nome_comune LIKE '%{0}%'", cityName);
using (MySqlConnection conn = new MySqlConnection("server=localhost;Database=servizi; Uid=root; Pwd=root;"))
{
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
conn.Open();
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
City.Add(reader.GetString(0));
}
}
}
return City;
}
You can control your client id with ClientIDMode to make ID more predictable (post about that).
What does server return in your success function?

Search data in table using ajax in ASP.net MVC

I want to display data in a table based on the search criteria in a textbox. I have implemented it without using Ajax but do not know how to call controller method using jquery and update table data. Please try to solve my problem. Thanks...
Index.cshtml
#model IEnumerable<MvcApplication4.Models.tbl_product>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<title>Index</title>
<script type="text/javascript">
$(document).ready(function () {
$('#Button1').click(function () {
alert("button clicked");
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'Home/Index',
data: "{'searchString':'" + document.getElementById('searchString').value + "'}",
async: false,
Success: function (response) {
alert("Success");
window.location.reload();
},
error: function () { alert("error"); }
});
});
});
</script>
</head>
<body>
#* #using (#Html.BeginForm("Index", "Home"))
{*#
#Html.TextBox("searchString");
<input type="button" value="filter" id="Button1" />
#* }*#
<table id="showData">
#{Html.RenderPartial("SearchList");}
</table>
</body>
</html>
SearchList.cshtml(Partial View)
#foreach (var item in Model)
{
<tr>
<td>#item.ProductName</td>
<td>#item.ProductId</td>
<td>#item.ProductDesc</td>
</tr>
}
HomeController.cs
public class HomeController : Controller
{
//
// GET: /Home/
ProductEntities dbentity = new ProductEntities();
public ActionResult Index()
{
return View(dbentity.tbl_product.ToList());
}
[HttpPost]
public ActionResult Index(string searchString)
{
var query = dbentity.tbl_product.Where(c => c.ProductName.Contains(searchString));
return View(query.ToList());
}
}
$.ajax({
url: '/ControllerName/ActionName',
type: "POST",
data: {criteria: 'criteria'},
contentType: "application/json",
success: function (data) {
//Replace existing table with the new view (with the table).
}
});
//write ControllerName without the key controller.
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'Home/Index',
data: JSON.stringify({'searchString':document.getElementById('searchString').value }),
async: false,
Success: function (response) {
alert("Success");
//append the data in between table tbody like,
$('table tbody').html(response);
//No window.location.reload(); It will cause page reload initial data will appear in grid.
},
error: function () { alert("error"); }
});
return false
Hope this helps.
Your ajax request should look like:
$.ajax({
url: '/<ControllerName>/<MethodName>',
type: "POST",
data: requestData,
contentType: "application/json;charset=utf-8",
success: function (data, textStatus, XMLHTTPRequest) {
//Success callback handling
},
error: function (XMLHTTPRequest, textStatus, errorThrown) {
//Error callback handling
},
cache: false //whether you want to cache the response or not.
});
I'm not going to give you the exact answer, but to help you to get it.
There are two steps:
First you must get sure the request is being done, and the response is being get on the browser.
To do so, you can
do it on your way: leave only the alert("Success"); and check it's being run.
better than that, open the browser's developer console (I prefer Chrome, but you can also use IE or FireFox + FireBug add-on) using F12. Set breakpoints and inspect variable values and code flow. See thit tutorial for Chrome developer tools.
set a breakpoint on the server action, and check it's executed
Second Once you're sure the firs part is working fine, use your succes function to replace the table content with the data received in the response. You can do it in several ways with jQuery. For example
$('#showData').html(response);
Again, you can execute this code and inspect the contents of response from the developer's console in your browser. This makes things eaiser when you're starting to use javascript.
(If your action generated the whole table, you could use jQuery's replaceWith which replaces the target, instead of its content. Don't use this for this case).
FINAL NOTE: please, remove this code window.location.reload();!!! This reloads the whole page with the current URL, so whatever thing you do in advance will be lost.

Categories