I'm finishing my first project where I POST data to a server and then retrieve it in the form of a list on a separate page. I have gotten to the point where I can now post and retrieve the data, however I'm getting this error:
Uncaught RangeError: Maximum call stack size exceeded
at renderSearchResults (menu.js:8)
at renderSearchResults (menu.js:38)
My code is below. Any help would be appreciated.
var userInfo = JSON.parse(sessionStorage.getItem('user'));
function search() {
/* var userInfo = JSON.parse(sessionStorage.getItem('user')); */
var xhr = new XMLHttpRequest();
xhr.open('GET', (`https://ict4510.herokuapp.com/api/menus?api_key=${userInfo.user.api_key}` ));
xhr.onload = function renderSearchResults() {
if (this.status == 200) {
var menuInfo = JSON.parse(this.responseText);
var output = '';
for (var i in menuInfo.menu) {
output +=
'<div class="foodItems">' +
'<ul>' +
'<li>Food Item: ' + menuInfo.menu[i].item + '</li>' +
'<li>Description: ' + menuInfo.menu[i].description + '</li>' +
'<li> Price: ' + menuInfo.menu[i].price + '</li>' +
'</ul>' +
+
'</div>';
}
console.log(output);
document.getElementById('foods').innerHTML = output;
}
renderSearchResults();
}
xhr.send();
}
search();
Related
I have Highcharts chart rendered on yAxis[0] and whenever the user selects an indicator like Aroon Oscillator, MACD etc. it is added as a new yAxis in the rendering container. Example:
The above snapshot is with the Aroon Oscillator. All good.
When i select Slow Stochastic though i get the following:
First of all both SS$K and SS$D have the same value as you can see in the tooltip which is clearly wrong and both lines have the same color for a reason when they should not because:
I tried to log the p.series.yData[p.point.index] (the currently hovered point yData value) in my console and for my surprise I get the following:
It returns an array (but why) of 2 values, and both plots access the first value, instead of SS%D accessing the second value. This is a Slow Stochastic problem from Highcharts since the Aroon Oscillator which has the same philosophy of many plots on the same yAxis, still works fine as you can see in the first picture (where the lines have the correct color and correct values assigned).
Lastly as you can see with another indicators MACD (which has the same issue as mentioned before with Slow Stochastic) - and VPT which works as intended, when i go full range, those have a gap at start. Why is that happening?
Has anyone come across a similar indicator problem from Highcharts and if so, could anyone give me his/her lights on how to solve the problem?
Thanks in advance, Christopher.
P.S. Those are my tooltip options for highcharts:
tooltip: {
formatter: function() {
let finalDate = '';
let tooltipString = '';
$.each(this.points, function(i, p) {
// console.log(p.series.name, p.series.yData[p.point.index]);
//Starting date
let dateTo = new Date(p.x),
month = '' + (dateTo.getMonth() + 1),
day = '' + dateTo.getDate(),
year = dateTo.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
let intradayTime = '';
if (p.point.isIntradayData) {
let hours = dateTo.getHours();
let minutes = ('0' + dateTo.getMinutes()).slice(-2);
intradayTime += ' ' + hours + ':' + minutes;
}
dateTo = [day, month, year].join('.');
//If we wanna display previous date too:
let dateFrom = '';
if (p.point.previousDate) {
dateFrom = new Date(p.point.previousDate);
month = '' + (dateFrom.getMonth() + 1);
day = '' + dateFrom.getDate();
year = dateFrom.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
dateFrom = [day, month, year].join('.');
dateFrom += ' - ';
}
finalDate = dateFrom + dateTo + intradayTime;
if (p.series.userOptions.compare == 'percent') {
tooltipString +=
'<br>' +
`<span style="color:${p.color}; font-size:10px; font-family:\'Arial\'">` +
p.series.name +
': </span>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
' ' +
p.point.percentageDifference +
`%(${p.y})`;
('</span>');
} else if (
p.series.type == 'candlestick' ||
p.series.type == 'ohlc'
) {
tooltipString +=
'<br>' +
`<span style="color:${p.color}; font-size:10px; font-family:\'Arial\'">` +
p.series.name +
': </span>' +
'<br>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
'Open: ' +
p.point.open +
'<br>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
'High: ' +
p.point.high +
'<br>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
'Low: ' +
p.point.low +
'<br>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
'Close: ' +
p.point.close +
'</span> <br>';
} else {
let pointValueFormatted = p.y.toFixed(2);
tooltipString +=
'<br>' +
`<span style="color:${p.color}; font-size:10px; font-family:\'Arial\'">` +
p.series.name +
': </span>' +
'<span style="font-size:10px; font-family:\'Arial\'">' +
' ' +
pointValueFormatted +
'</span>';
}
});
return (
'<span style=" font-size:10px; font-family:\'Arial\'">' +
finalDate +
'</span>' +
tooltipString
);
},
borderColor: '#7fb7f0',
shared: true,
},
INDICATORS LOGIC
It's impossible to reproduce it in jsfiddle due to the size, the complexity and for security reasons due to policies. So a user can select indicators from a tabmenu like:
and they way the indicators are sorted:
//Sorting indicators.
sortIndicators() {
console.log(`Function Call: sortIndicators()`);
this.cleanIndicators(); // Just clearing the chart yaxises and the indicators array list to iterate over indicators again.
let counter = 0;
//For every indicator
for (let indicator of this.indicators) {
//If it is chart indicator we render it on yAxis[0] with our prices
if (toolsManager.isChartIndicator(indicator)) {
//some indicators have multiple arrays of data instead of one saved in an array called arrayOfObj
if (indicator.arrayOfObj) {
for (let arg of indicator.arrayOfObj) {
this.highchartOptions.series.push(arg);
}
} else {
this.highchartOptions.series.push(indicator);
}
} else {
//If it not chart indicator
this.highchartOptions.chart.height +=
2 * this.yAxisMargin + this.yAxisHeight;
let topCalculation =
456 + (counter + 1) * this.yAxisMargin + counter * this.yAxisHeight;
//yAxis to add
let addedAxis = {
title: {
enabled: false,
},
opposite: true,
min: null,
height: this.yAxisHeight,
top: topCalculation + this.yAxisMargin,
showLastLabel: false,
labels: {
enabled: true,
x: -30,
y: 0,
style: {
fontSize: '10px',
fontFamily: 'Arial',
color: '#999999',
},
},
};
this.highchartOptions.yAxis.push(addedAxis);
if (indicator.arrayOfObj) {
//some indicators have multiple arrays of data instead of one saved in an array called arrayOfObj
for (let arg of indicator.arrayOfObj) {
//for every array of that arrayOfObj
arg.yAxis = counter + 1;
this.highchartOptions.series.push(arg); //push it to series
}
} else {
indicator.yAxis = counter + 1;
if (indicator.id === 'volume') {
indicator.data = this.volumeSeries;
}
this.highchartOptions.series.push(indicator);
}
counter++;
}
}
},
the part where the magic happens is here:
if (indicator.arrayOfObj) {
//some indicators have multiple arrays of data instead of one saved in an array called arrayOfObj
for (let arg of indicator.arrayOfObj) {
//for every array of that arrayOfObj
arg.yAxis = counter + 1;
this.highchartOptions.series.push(arg); //push it to series
}
} else {
indicator.yAxis = counter + 1;
if (indicator.id === 'volume') {
indicator.data = this.volumeSeries;
}
the reason it is implemented like this is because when an indicator is selected an object is returned from the server which may have one of the two following structures:
data structure 1:
data structure 2:
And after sorting out what type of structure I am dealing with, I am pushing it into the series to display. counter variable is just used for the y-axis's. Arron Oscillator and Slow Stochastic both fulfill the first part of the conditional, because both return an object which contains and arrayOfObj (for the line colors etc as you can see in the photo uploaded).
I'm writing a script that does the following :
send an email with an attachment (eg proof of payment) to people that register for our event when two criteria are met: payment has been processed, and if they have not yet received their proof of payment
make a copy of an existing file, using some variables in the new copy (this works fine) to personalize the proof of payment.
The copy of the file gets a new name (personalized).
I seem to be unable to make the script check correctly if the file already exists or not.
Who can help me out ?
function createDocument(e) {
var headers = Sheets.Spreadsheets.Values.get('SHEET ID', 'Lijst!A1:G');
var lid = Sheets.Spreadsheets.Values.get('SHEET ID', 'Lijst!A2:G');
var templateId = 'TEMPLATE ID';
for (var j = 0; j < lid.values.length; j++) {
if (lid.values[j][6] == 'ok' && lid.values[j][7] != 'Bewijs Verzonden') {
//collect the data from the member
var voornaam = lid.values[j][0];
var familienaam = lid.values[j][1];
var email = lid.values[j][2];
var aantal = lid.values[j][3];
var betaaldop = lid.values[j][5];
//Make a copy of the template file
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
var doc = DriveApp.getFileById(documentId);
var docname = 'Betalingsbewijs Reunie 2019 voor ' + familienaam + ' ' + voornaam + '.pdf';
//var filecheck = DriveApp.getFolderById('FOLDER ID');
var filecheck = DriveApp.getFilesByName(docname);
if (filecheck.hasNext()) {
Logger.log("No File Found");
} else {
//Get the document body as a variable
var body = DocumentApp.openById(documentId).getBody();
//Insert the data from spreadsheet
body.replaceText('<<Voornaam>>', voornaam)
body.replaceText('<<Naam>>', familienaam)
body.replaceText('<<Aantal deelnemers>>', aantal)
body.replaceText('<<Betaald op>>', betaaldop)
DocumentApp.openById(documentId).saveAndClose();
//move file to new folder and remove from parent folder
var file = DriveApp.getFileById(documentId);
file.getParents().next().removeFile(file);
DriveApp.getFolderById('FOLDER ID').addFile(file);
var pdfname = file.setName('Betalingsbewijs Reunie 2019 voor ' + familienaam + ' ' + voornaam + '.pdf');
var steil = "email#gmail.com";
var blob = pdfname.getBlob().getAs('application/pdf');
var subject = 'Betalingsbewijs Reunie 2019 voor ' + familienaam + ' ' + voornaam + ' met ' + aantal + 'deelnemer(s)';
var htmlBody =
"Beste " + voornaam + ", " +
"<br/>" +
"<br/>" +
"<br/>Bedankt voor uw inschrijving voor de Steil reünie op zaterdag 26 januari 2019." +
"<br/>Wij hebben uw betaling goed ontvangen." +
"<br/>Uw deelname aan de reünie is nu definitief in orde." +
"<br/>In bijlage kan u uw betalingsbewijs terugvinden in pdf." +
"<br/><br/>Indien u nog vragen heeft kan u ons steeds bereiken via reunie.steil#gmail.com." +
"<br/>Met verplegende groeten," +
"<br/>Het Steil Reünie team";
var optAdvancedArgs = {
name: "Steil Reünie 2019",
htmlBody: htmlBody,
replyTo: email,
cc: steil,
attachments: [blob]
};
GmailApp.sendEmail(email, subject, body, optAdvancedArgs);
var ConfirmationRange = "Lijst!H" + [j + 2];
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(ConfirmationRange).setValue('Bewijs Verzonden');
}
}
}
}
I have the following highcharts graph
https://jsfiddle.net/deemgfay/
and I am trying to display the "Consum Test" values in the tooltip but without adding them to the series. I just want to add Consum (l/100km)
Total Consum (l) to the series. Is that possible with hightcharts? Please see the screenshot below.
You can set the extra series to be hidden and ignored in legend:
visible: false,
showInLegend: false
Then use tooltip formatter function (useHTML must be enabled) to display points from all series in the shared tooltip regardless of their visibility:
formatter: function() {
var html,
originalPoint = this.points[0];
// header
html = "<span style='font-size: 10px'>" + originalPoint.x + "</span><br/>";
// points
originalPoint.series.chart.series.forEach(function(series) {
var point = series.points.find((p) => p.x === originalPoint.point.x);
html += "<span style='color: " + series.color + "'>\u25CF</span> " + series.name + ": <b>" + point.y + "</b><br/>"
});
return html;
}
Live demo: https://jsfiddle.net/kkulig/1oggzsx0/
API references:
http://api.highcharts.com/highcharts/tooltip.formatter
http://api.highcharts.com/highcharts/tooltip.useHTML
This can be done by using tooltip.formatter. Here I append to tooltip info based on index of current series from index of required extra array.
formatter: function() {
var s = '<b>' + this.x + '</b>';
var reqpoint = 0;
$.each(this.points, function() {
var reqpoint = this.point.index
s += '<br/>' + this.series.name + ': ' +
this.y.toFixed(2) + 'm';
if (this.series.index == 1) {
s += '<br/>Test Consum (l): ' + extraData[reqpoint] + 'm';
}
});
return s;
},
Fiddle demo
I want to get all videos of a single channel that i have its Id. The problem that I am getting only the channel informations.
this is the link that I am using:
https://gdata.youtube.com/feeds/api/users/UCdCiB_pNQpR0M_KkDG4Dz5A?v=2&alt=json&q=goal&orderby=published&max-results=10
That link is for the now-retired V2 API, so it will not return any data. Instead, you'll want to use V3 of the API. The first thing you'll need to do is register for an API key -- you can do this by creating a project at console.developers.google.com, setting the YouTube data API to "on," and creating a public access key.
Since you have your user channel ID already, you can jump right into getting the videos from it; note, however, that if you ever don't know the channel ID, you can get it this way:
https://www.googleapis.com/youtube/v3/channels?part=snippet&forUsername={username}&key={YOUR_API_KEY}
With the channel ID, you can get all the videos from the channel with the search endpoint, like this:
https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId={channel id here}&maxResults=25&key={YOUR_API_KEY}
In this case, ordering by date is the same as the old V2 parameter for ordering by "published."
There are also a lot of other parameters you can use to retrieve videos while searching a channel; see https://developers.google.com/youtube/v3/docs/search/list for more details.
I thought I would share my final result using JavaScript. It uses the Google YouTube API key and UserName to get the channel ID, then pulls the videos and displays in a list to a given div tag.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>YouTube Channel Listing</title>
<script type="text/javascript">
function getJSONData(yourUrl) {
var Httpreq = new XMLHttpRequest();
try {
Httpreq.open("GET", yourUrl, false);
Httpreq.send(null);
} catch (ex) {
alert(ex.message);
}
return Httpreq.responseText;
}
function showVideoList(username, writediv, maxnumbervideos, apikey) {
try {
document.getElementById(writediv).innerHTML = "";
var keyinfo = JSON.parse(getJSONData("https://www.googleapis.com/youtube/v3/channels?part=snippet&forUsername=" + username + "&key=" + apikey));
var userid = keyinfo.items[0].id;
var channeltitle = keyinfo.items[0].snippet.title;
var channeldescription = keyinfo.items[0].snippet.description;
var channelthumbnail = keyinfo.items[0].snippet.thumbnails.default.url; // default, medium or high
//channel header
document.getElementById(writediv).innerHTML += "<div style='width:100%;min-height:90px;'>"
+ "<a href='https://www.youtube.com/user/" + username + "' target='_blank'>"
+ "<img src='" + channelthumbnail + "' style='border:none;float:left;margin-right:10px;' alt='" + channeltitle + "' title='" + channeltitle + "' /></a>"
+ "<div style='width:100%;text-align:center;'><h1><a href='https://www.youtube.com/user/" + username + "' target='_blank'>" + channeltitle + "</a></h1>" + channeldescription + "</div>"
+ "</div>";
var videoinfo = JSON.parse(getJSONData("https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId=" + userid + "&maxResults=" + maxnumbervideos + "&key=" + apikey));
var videos = videoinfo.items;
var videocount = videoinfo.pageInfo.totalResults;
// video listing
for (var i = 0; i < videos.length; i++) {
var videoid = videos[i].id.videoId;
var videotitle = videos[i].snippet.title;
var videodescription = videos[i].snippet.description;
var videodate = videos[i].snippet.publishedAt; // date time published
var videothumbnail = videos[i].snippet.thumbnails.default.url; // default, medium or high
document.getElementById(writediv).innerHTML += "<hr /><div style='width:100%;min-height:90px;'>"
+ "<a href='https://www.youtube.com/watch?v=" + videoid + "' target='_blank'>"
+ "<img src='" + videothumbnail + "' style='border:none;float:left;margin-right:10px;' alt='" + videotitle + "' title='" + videotitle + "' /></a>"
+ "<h3><a href='https://www.youtube.com/watch?v=" + videoid + "' target='_blank'>" + videotitle + "</a></h3>" + videodescription + ""
+ "</div>";
}
} catch (ex) {
alert(ex.message);
}
}
</script>
</head>
<body>
<div id="videos"></div>
<script type="text/javascript">
showVideoList("USER_NAME", "videos", 25, "YOUR_API_KEY");
</script>
</body>
</html>
ADDITION - I also wrote a function to handle if you are using a channel ID instead of a UserName based account.
Here is that code:
function showVideoListChannel(channelid, writediv, maxnumbervideos, apikey) {
try {
document.getElementById(writediv).innerHTML = "";
var vid = getJSONData("https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId=" + channelid + "&maxResults=" + (maxnumbervideos + 1) + "&key=" + apikey);
var videoinfo = JSON.parse(vid);
var videos = videoinfo.items;
var videocount = videoinfo.pageInfo.totalResults;
var content = "<div style='height:600px;overflow-y:auto;'>";
for (var i = 0; i < videos.length - 1; i++) {
var videoid = videos[i].id.videoId;
var videotitle = videos[i].snippet.title;
var videodescription = videos[i].snippet.description;
var videodate = videos[i].snippet.publishedAt; // date time published
var newdate = new Date(Date.parse((videodate + " (ISO 8601)").replace(/ *\(.*\)/, "")));
var min = newdate.getMinutes();
if (min < 10) {
min = "0" + min;
}
if (newdate.getHours() > 12) {
newdate = newdate.getMonth() + 1 + "/" + newdate.getDate() + "/" + newdate.getFullYear() + " " + (newdate.getHours() - 12) + ":" + min + " PM";
} else if (newdate.getHours() == 12) {
newdate = newdate.getMonth() + 1 + "/" + newdate.getDate() + "/" + newdate.getFullYear() + " " + newdate.getHours() + ":" + min + " PM";
} else {
newdate = newdate.getMonth() + 1 + "/" + newdate.getDate() + "/" + newdate.getFullYear() + " " + newdate.getHours() + ":" + min + " AM";
}
var videothumbnail = videos[i].snippet.thumbnails.default.url; // default, medium or high
content += "<hr /><div style='width:100%;min-height:90px;'>"
+ "<a href='https://www.youtube.com/watch?v=" + videoid + "' target='_blank'>"
+ "<img src='" + videothumbnail + "' style='border:none;float:left;margin-right:10px;' alt='" + videotitle + "' title='" + videotitle + "' /></a>"
+ "<h3><a href='https://www.youtube.com/watch?v=" + videoid + "' target='_blank'>" + videotitle + "</a></h3>" + videodescription + "<br />"
+ "<span style='color:#738AAD;font-size:Small;'>" + newdate + "</span>"
+ "</div>";
}
content += "</div>";
document.getElementById(writediv).innerHTML = content;
} catch (ex) {
alert(ex.message);
}
}
It is very easy method to get channel videos using your channel API key:
Step 1: You must have an YouTube account.
Step 2: Create your YouTube channel API key
Step 3: Create project console.developers.google.com,
<?php
$API_key = 'Your API key'; //my API key dei;
$channelID = 'Your Channel ID'; //my channel ID
$maxResults = 5;
$video_list =
json_decode(file_get_contents('https://www.googleapis.com/youtube/v3/search?
order=date&part=snippet&channelId='.$channelID.
'&maxResults='.$maxResults.'&key='.$API_key.''));
?>
Example : https://www.googleapis.com/youtube/v3/channelspart=snippet&forUsername=
{username}&key={YOUR_API_KEY}
Here is the way to get all videos with only 2 quotas using YouTube Data API (v3)
First of all do a list on channels with part=contentDetails (1 quota) :
https://youtube.googleapis.com/youtube/v3/channels?part=contentDetails&id=[CHANNEL_ID]&key=[YOUR_API_KEY]
You will get this result :
{
...
"items": [
{
...
"contentDetails": {
"relatedPlaylists": {
"likes": "",
"uploads": "UPLOADS_PLAYLIST_ID"
}
}
}
]
}
Then take UPLOADS_PLAYLIST_ID and do a list on playlistItems with part=contentDetails (1 quota):
https://youtube.googleapis.com/youtube/v3/playlistItems?part=contentDetails&playlistId=[UPLOADS_PLAYLIST_ID]&key=[YOUR_API_KEY]
You will get this result:
{
...
"items": [
{
...
"contentDetails": {
"videoId": "VIDEO_ID",
"videoPublishedAt": "2022-10-27T16:00:08Z"
}
},
...
],
"pageInfo": {
"totalResults": 5648,
"resultsPerPage": 5
}
}
You got the list of the videos under items
You can of course change the size of this list by adding maxResults=50 (max value is 50)
I use partialview like
<td style="vertical-align: top;">#Html.Action("_HavaDurumuPartial")
And It is working on server now. But sometimes It gives error. Erros is below:
This error not occur allways.
I cant find any reason for this problem.And I cant understand why does it sometimes give this error.
If it is neccesary, I write the content of partialview and controller action.
action
public ActionResult _HavaDurumuPartial(string il)
{
il = "Izmir";
HttpWebRequest GoogleRequest;
HttpWebResponse GoogleResponse = null;
XmlDocument GoogleXMLdoc = null;
try
{
GoogleRequest = (HttpWebRequest)WebRequest.Create("http://www.google.com/ig/api?weather=" + il + "&hl=tr&ie=utf-8&oe=utf-8");
GoogleResponse = (HttpWebResponse)GoogleRequest.GetResponse();
GoogleXMLdoc = new XmlDocument();
GoogleXMLdoc.Load(GoogleResponse.GetResponseStream());
XmlNode root = GoogleXMLdoc.DocumentElement;
XmlNodeList nodeList1 = root.SelectNodes("weather/forecast_information");
//ViewBag.HavaDurumu = ViewBag.HavaDurumu + "<b>Şehir : " + nodeList1.Item(0).SelectSingleNode("city").Attributes["data"].InnerText + "</b>";
XmlNodeList nodeList = root.SelectNodes("weather/current_conditions");
ViewBag.HavaDurumu = ViewBag.HavaDurumu + "<table cellpadding=\"5\"><tbody><tr><td style=\"width:50%;\"><b><big><nobr>" + nodeList.Item(0).SelectSingleNode("temp_c").Attributes["data"].InnerText + " °C | " + nodeList.Item(0).SelectSingleNode("temp_f").Attributes["data"].InnerText + " °F</nobr></big></b></br>";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + "<b>Şuan:</b> " + nodeList.Item(0).SelectSingleNode("condition").Attributes["data"].InnerText + "";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + " " + nodeList.Item(0).SelectSingleNode("wind_condition").Attributes["data"].InnerText + "</br>" + "";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + " " + nodeList.Item(0).SelectSingleNode("humidity").Attributes["data"].InnerText;
nodeList = root.SelectNodes("descendant::weather/forecast_conditions");
int i = 0;
foreach (XmlNode nod in nodeList)
{
if (i == 0)
{
i++;
continue;
}
ViewBag.HavaDurumu = ViewBag.HavaDurumu + "</td><td align=\"center\">" + nod.SelectSingleNode("day_of_week").Attributes["data"].InnerText + "</br>" + "";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + "<img src=\"http://www.google.com" + nod.SelectSingleNode("icon").Attributes["data"].InnerText + "\" alt=\"" + nod.SelectSingleNode("condition").Attributes["data"].InnerText + "\">" + "</br>";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + nod.SelectSingleNode("low").Attributes["data"].InnerText + "°C" + "</br>";
ViewBag.HavaDurumu = ViewBag.HavaDurumu + nod.SelectSingleNode("high").Attributes["data"].InnerText + "°C" + "</br>";
}
ViewBag.HavaDurumu = ViewBag.HavaDurumu + "</td></tr></tbody></table>";
}
catch (System.Exception ex)
{
ViewBag.HavaDurumu = ex.Message;
}
finally
{
GoogleResponse.Close();
}
return PartialView();
}
I get the weather for specific location from google with this action.
Thanks.
There is currently an intermittent 403 Forbidden response to the Google Weather API that you are using. See Google Weather API 403 Error
The reason for the intermittent 403 response is not known but has been a problem since the 7th of August 2012.
Add a null reference check in your finally. Initializing GoogleResponse could fail, so it would still be null. Then you'll hit your finally block and get a null reference exception since GoogleResponse is null when you try to call .Close().
finally
{
if (GoogleResponse != null)
{
GoogleResponse.Close();
}
}