Error getting shortened URL using tinyurl API - c#

I am trying to make a URL shortener using TinyUrl. The problem is that I get the following error:
System.Net.WebException: 'Error on the remote server: (400) Incorrect request.
I have already tried reading in almost the entire site but I have not found the solution.
The controller code is:
namespace Prueba.Controllers
{
[HandleError]
public class TinyURLAPIController : Controller
{
// GET: TinyURLAPI
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View("Index");
}
[HttpPost]
public ActionResult MakeTinyUrl(string strURL)
{
var tinyUrl = WebRequest.Create("http: / tinyurl . com/api-create.php?url=" + strURL);
var shortUrl = tinyUrl.GetResponse();
using (var reader = new StreamReader(shortUrl.GetResponseStream())){
ViewData["tinyUrl"] = reader.ReadToEnd();
}
return PartialView("Index");
}
}
}
And this is the index code:
<Html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<#Ajax.BeginForm("MakeTinyUrl", new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "tinyUrl" }))>
#Html.TextBox("url")
<input id="btnMakeUrl" type="submit" value="Make tinyUrl" onclick="Index" />
</body>
</Html>
I need to enter the long URL in a textbox and pressing the button shows the short URL in a label

Can't comment so i'll just write it as an answer!
Your problem isn't the api request.
Your strURL is probably null as it was for me with your code.
Try making the following change in your view:
from
#Html.TextBox("url")
to
#Html.TextBox("strURL")
and also your html isn't quite valid where you defined the form.
try:
#using (Ajax.BeginForm("MakeTinyUrl", new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "tinyUrl" }))
{
#Html.TextBox("strURL")
<input id="btnMakeUrl" type="submit" value="Make tinyUrl" onclick="Index" />
}

It' possible you may have to UrlEncode the value before passing it to the view:
https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.urlencode?view=netframework-4.8

I understand you've altered the api link in your post due to restrictions.
firstly i'd manually call the api in your preferred browser using the URL you're trying to shorten...make sure that is ok.
e.g. [redacted]tinyurl.com/api-create.php?url=http://www.yoururltest.com
Next, run a test with a breakpoint, stepping through your code to see exactly where the error happens and view the data your controller receives and uses in the request.
I bet you'll find an issue with that somewhere along the way

Related

C# ASP.NET MVC : update view dynamically

I am learning C# using DotNetFiddle to code.
I have a web with a bunch of radio buttons and when I click them I want to update the view, for example: delete one button.
Also I need to do the delete logic in the backend and from the view I have to call a POST method to pass data.
So I'm trying to call the POST method with ajax and return RedirectToAction to display the new view, but somehow is not working.
You can check and test my current code here: dotnetfiddle
Controller
using System;
using System.Web.Mvc;
using System.Collections.Generic;
namespace HelloWorldMvcApp
{
public class HomeController : Controller
{
public SampleViewModel sampleViewModel = new SampleViewModel();
[HttpGet]
public ActionResult Index()
{
return View(sampleViewModel);
}
[HttpPost]
public ActionResult UpdateList(string id)
{
sampleViewModel.deleteElement();
return RedirectToAction("Index");
}
}
}
Model
using System;
using System.ComponentModel.DataAnnotations;
namespace HelloWorldMvcApp
{
public class SampleViewModel
{
public List<string> list = new List<string> { "a", "b", "c", "d", "e"} ;
}
}
View
#model HelloWorldMvcApp.SampleViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<!-- template from http://getbootstrap.com/getting-started -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- CSS Includes -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
</head>
<body>
<br/>
<div class="container">
<br></br>
<ul>
#foreach (var c in Model.arr)
{
<li>
<input type="radio" name="option" id="#c">#c
</li>
}
</ul>
</div>
<!-- JS includes -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
$('input[type=radio]').click(function() {
var elemId = $(this).attr("id");
$.ajax({
url: '#Url.RouteUrl(new{ action="UpdateList", controller="Home"})',
data: { id : elemId },
type: "POST"
});
});
</script>
</body>
</html>
UPDATE
I've edited your Fiddle into this: https://dotnetfiddle.net/zQq3aR
It does exactly what I describe below in the original answer, but uses the main view. Note that this is NOT what I would recommmend... we're rendering the entire view again, and then replacing the entire page contents with the new content, but I'm not too familiar with DotNetFiddle and don't know how to add more views (can you?).
C#:
[HttpPost]
public ActionResult PostToMe(string id)
{
// TODO: Do some stuff here, then return the updated view
return ButRenderMe(id);
}
[HttpPost]
public ActionResult ButRenderMe(string id)
{
// Remove some content from the model
sampleViewModel.arr = new [] { "a", "b", "c", "all of the above" };
return View(sampleViewModel);
}
JavaScript:
$.ajax({
url: '#Url.RouteUrl(new{ action="PostToMe", controller="Home"})',
data: { id : elemId },
type: "POST",
success: function(data) {
document.open();
document.write(data);
document.close();
}
});
The better way to do this in a normal MVC project would be to have a PartialView used for rendering the content you want to replace... in this case the list. In your "update" action you would update your data, and then re-render just that PartialView and return it. Then replace just that section with the new content.
With the code above, from my Fiddle, we may as well be making a normal page post instead of an AJAX call.
There are a lot of factors here, but hopefully this helps.
ORIGINAL ANSWER
So this is a bit confusing, given that your question doesn't match your code in either the DotNetFiddle or the question itself, but let's see if this helps.
I'm pretty sure that returning a RedirectToAction Result doesn't return the content from the other action your redirecting to. I think in this case, since it's an AJAX request, MVC knows that this isn't the proper usage, and returns a 200 OK status with the following example content. So with this Controller Action:
[HttpPost]
public ActionResult RedirectMe()
{
return RedirectToAction("UpdateList");
}
We get this Response:
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
So again, I don't think that will work the way you want.
I think what you want is to Render the other action, and return that content back. And that should be as simple as calling that other action:
[HttpPost]
public ActionResult PostToMe(string id)
{
return ButRenderMe(id);
}
[HttpPost]
public ActionResult ButRenderMe(string id)
{
return Content("Test");
}
That returns the content "test". I think that you should be able to render a normal view in that other action if you want.
I looked at your DotNetFiddle as well...
In your DotNetFiddle your JavaScript is calling into UpdateList which doesn't seem to exist... not sure why it would even return a 200 OK... The Actions you have are Index and UpdateFlights. If you open the F12 Developer Tools in Chrome you should see that the POST returns no Content.
So I added a Controller Action called UpdateList:
[HttpPost]
public ActionResult UpdateList(string id)
{
sampleViewModel.deleteElement();
return Content("Test");
}
And I can see that "test" is returned as the Response content in the F12 Tools.

Pass Data from View to Controller - with model

I need to pass some information from the View to the Controller.
Currently, I am doing something like the following:
var url = '#Url.Action((object)#ViewBag.CompID, "Print", "DataRecords")' + '?location=' + model.Location + '&startDate=' + model.StartDateTime + '&endDate=' + model.EndDateTime;
window.location.href = url;
I wanted to hide the location, startdate and end date from showing up in the browser url.
I was thinking about creating a model as shown below and sending the model to the Controller but not sure how to.
var model = {
Location: $('#Location :selected').val(),
StartDateTime: $("#StartDate").val(),
EndDateTime: $("#EndDate").val()
};
Note that in my case, I do not need to retrieve any data back as the Print method will do the printing.
I am open to accomplishing this besides using
window.location.href
How can this be done using AJAX as I do not need to return back to the view with any data as the Print method action will print the the appropriate view.
If you want to pass data from the front end to the back-end controller, you have two ways:
through a GET(passing parameters on the URL)
with a POST that you can do it via AJAX or simply putting your information inside a form with POST action to the method you want to hit in the controller
MVC will do the binding for you, all the information using the POST, for example, should be inside the form, then on the controller, you can create your model as the input and use the default MVC bindings.
My suggestion if you want to hide that information from the url is to do it via a post(inside a form with a submit), but anyways if you click on the Network tab of the browser in both cases you should see the parameters you are passing to your controller.
There are other ways to achieve the same thing as the use of the TempData dictionary, which keeps information for a roundtrip operation between the controller and the view, but I don't recommend to proceed this way, every time I use that as a backdoor to patch my problems I feel guilty
You can do this.
Controller
public class HomeController : Controller
{
public ActionResult HideQueryString()
{
return View("Tut143");
}
public ActionResult Print(string location, string startDate, string endDate)
{
//print here
return RedirectToAction("HideQueryString");
}
public ActionResult Tut143()
{
return View();
}
View:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Tut143</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function () {
$("#theButton").click(function () {
var model = {
Location: $('#Location :selected').val(),
StartDateTime: $("#StartDate").val(),
EndDateTime: $("#EndDate").val()
};
var url = '#Url.Action("Print", "Home")' + '?location=' + model.Location + '&startDate=' + model.StartDateTime + '&endDate=' + model.EndDateTime;
window.location.href = url;
})
})
</script>
</head>
<body>
<div>
<select id="Location">
<option value="Arizona">Arizona</option>
<option value="California">California</option>
<option value="Wyoming">Wyoming</option>
<option value="Delaware">Delaware</option>
</select>
<input id="StartDate" type="text" value="default startdate value" />
<input id="EndDate" type="text" value="default enddate value" />
<input id="theButton" type="button" value="Go" />
</div>
</body>
</html>

Need to pass the Rowdata to another view on link click

Here is my JQGrid Code:
click: function (e) {
debugger;
var id = $(e.target).closest("tr.jqgrow").attr("id");
rowdata = jQuery("#EmpTable").getRowData(id);
Data = { Id: rowdata.Id, Name: rowdata.Name, Designation: rowdata.Designation };
var url = 'http://localhost:50428/Script/Edit/';
return $.post(url, Data);
}
here is my controller code where the data is collecting
[HttpPost]
public ActionResult Edit(FormCollection form)
{
gridmodel properties = new gridmodel();
properties.Id = Convert.ToInt32(form["id"]);
properties.Name = form["Name"];
properties.Designation = form["Designation"];
ViewBag.id = properties.Id;
ViewBag.name = properties.Name;
ViewBag.designation = properties.Designation;
return View();
}
Now here is my View code
the data that is passing from the controller to the view
#model MVC5_JQGrid.Models.gridmodel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Edit</title>
</head>
<body>
<div>
Id:#ViewBag.id
<br />
Name:#ViewBag.name
<br />
Designation:#ViewBag.designation
</div>
</body>
</html>
But i am unable to load this page but in network ---> Response body i can see that these values are assigned
Update
Hello Venkata thanks for the answer i will keep the points which you mentioned and +1 from my side for the observation ,coming to the problem. it was resolved from oleg suggestion:(Here is the answer given by Oleg) The reason of your problem is the usage of $.post(url, Data); which just send data with respect of $.ajax({url: "/Script/Edit", data: Data, type: "POST"});. You need to do $.submit instead. If you would use HTTP GET then you can just assign new URL which includes parameters to location.href (something like location.href = "/Script/Edit?" + $.param(Data)). In case of HTTP POST one need to build with elements which contains (or just have on the page hidden form with all required elements with required name attributes) and use $.submit.
Thanks for the help from oleg and Venkata
Few Changes required in your code:
Observation and Notes:
Before fixing, we should know few points here regarding architecture, control-flow and standards
jQuery AJAX requests get response to its success callback handler(in your code you've missed success call)
In success function We should build or append or set HTML to target placeholder tag in existing page (let us say you have div for Edit section like <div id='editSection'>...</div> in your jqGrid page. you should bind the responseView to editSection div)
When we send AJAX request: In Controller.Action Instead of return View(); we should have return PartialView();
In your view.cshtml give preference to bind elements with Model rather than ViewData. You can get model to view if you do return PartialView(model); in the Action.
Try to reduce usage of ViewData or ViewBag in view.cshtml. Also business logic not recommended in Views.
Try to Follow best practices: Capitalization Conventions (in your code change gridmodel class name to GridModel)
By default routing url template will have {controller}/{action} (from your url Script is controller and Edit is action)
Make sure that you're passing correct Controller and Action names (Is Edit action located in the Controller with name ScriptController?)
Changes in JavaScript JQGrid Code:
url = '/Script/Edit/';
return $.post(url, Data).success(function(response){
//response datatype can be JSON or XML or HTML or text (In your case HTML Edit.cshtml View)
//update you target html tag with response view.
$('#editSection').html(responseView);
});
Changes in Controller:
[HttpPost]
public ActionResult Edit(FormCollection form)
{
var properties = new gridmodel();
properties.Id = Convert.ToInt32(form["id"]);
properties.Name = form["Name"];
properties.Designation = form["Designation"];
ViewBag.id = properties.Id;
ViewBag.name = properties.Name;
ViewBag.designation = properties.Designation;
return PartialView();
}
You can change above Edit Action like below if action require input parameters only id, name & designation
[HttpPost]
public ActionResult Edit(int id, string name, string designation)
{
var gridModel = new GridModel();
gridModel.Id = id;
gridModel.Name = name;
gridModel.Designation = designation;
ViewBag.id = gridModel.Id;
ViewBag.name = gridModel.Name;
ViewBag.designation = gridModel.Designation;
return PartialView(gridModel);
}
Hello Venkata thanks for the answer i will keep the points which you mentioned and +1 from my side for the observation ,coming to the problem. it was resolved from oleg suggestion:(Here is the answer given by Oleg) The reason of your problem is the usage of $.post(url, Data); which just send data with respect of $.ajax({url: "/Script/Edit", data: Data, type: "POST"});. You need to do $.submit instead. If you would use HTTP GET then you can just assign new URL which includes parameters to location.href (something like location.href = "/Script/Edit?" + $.param(Data)). In case of HTTP POST one need to build with elements which contains (or just have on the page hidden form with all required elements with required name attributes) and use $.submit. Thanks for the help from oleg and Venkata

Updating layout part dynamically

C# asp.net MVC project: I have my index page with a button in it, I want to press it and update the same page with some results.
Here's some code:
The View: (with a button that calls the getConfig method in the controller)
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
<p>
#ViewBag.totalRecords
</p>
The controller:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public void getConfig()
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
I want to press the view's button and show the totalRecords on the same page.
How can I achieve this?
Edit: There might be other solutions, (if you don't mind updating your entire page) but this how I generally do it.
Ok, there are a couple of things that you need to change in order to make it work:
Create a new partial view that contains just the part that you would like to update (and wrap it an element with an id). In this example, let's call it 'Partial_TotalCount'.
This partial view will contain the following code:
<div id="updated">
<p>
#ViewBag.totalRecords
</p>
</div>
Now, change your original view so that it includes the partial view:
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
#Html.Partial("Partial_TotalCount", #Model)
Now, update your controller to work with an ajax request. This would make your controller looks like:
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
if (Request.IsAjaxRequest())
{
getconfig();
return PartialView("Partial_TotalCount");
}
return View();
}
Now, you need to be able to submit the page when you click the button. This can be done through javascript:
First your javascript function that will update the contents:
<script type="text/javascript">
function Refresh() {
$.ajax({
url: '/Home/Index',
type: "GET",
dataType: "html",
success: function(data) {
$("#updated").html(data);
},
error: function() { alert('Refreshing error.'); }
});
}
</script>
You just need to add an onclick on your button. And you can remove the form tags from around your form aswell.
Edit: As requested by the questioner, I provide a bit of explanation on the Javascript function itself:
$.ajax means that we are doing an Ajax request. It means that we are doing some asynchronous requests with the server.
Then a couple of parameters are passed:
Url: The url that should be executed. In your example, the code behind the url "Home/GetConfig" get's executed.
Type: The type of submit that you want to do (POST, GET, ...)
dataType: The type we are expecting back from the server.
Success: The piece of javascript that needs to execute when complete. (In this case, update the DIV element with the id "WithCss" with the contents that are received with the url "Home/Getconfig".
Error: A function that is executed when the request failed for some reason.
There are a lot of other parameters you can pass (for example if you need to pass an id, and others.
For more explanation, please look at the original documentation.
Also, consider marking this answer as accepted.
I hope it works.
Try This:
Replace your input button code with the following code :
<input type="submit" id="btnSave" name="BtnSave" value="Get Config WS" />
Then in controller change the whole code for this code:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public ActionResult getConfig()
{
return View();
}
[HttpPost]
public ActionResult getConfig(FormCollection Form)
{
if(Form["BtnSave"]!=null)
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
return View();
}
Hopefully it works...!

redirect to different view after loading partial view in Main view

I dint find answers to this and tried several ways. any help would be appreciated thanks !!
I have view which updates the page without reloading on each click using ajax scripts. Below is the code. but after entire partial views are generated, I want user to redirect complete different view on clicking a link which is not associated to controller user is in now.
my View
#model IMONLP.Models.Search
#{
ViewBag.Title = "Search";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#using (Ajax.BeginForm("Search", new AjaxOptions() { UpdateTargetId = "results"
}))
{
<br />
#Html.TextBoxFor(m => m.search_text, new { style = "width: 200px;" })
<input type="submit" value="search" />
}
#Ajax.ActionLink("Try Demo", "PLNHK", "PLNHK", new AjaxOptions { })
// this ajax link should redirect to different view,
<div id="results">
#if (!String.IsNullOrEmpty(#Model.search_text))
{
Html.RenderPartial("Searchprocess", Model);
}
</div>
My controller:
public ActionResult Search(Search s)
{
//do something
return PartialView("Searchprocess", s);
}
public ActionResult Selected(Search s)
{
//DO something
return PartialView("Selected", s);
}
The above "TryDEMO" "PLNHK" ajax action link will have to be redirected to new controller and new action and return view thats returned by that action. everytime I click on that, I found it moving to that controller and then to corresponding view but again its getting back to old page. I used #html.actionlink instead of Ajax, but now I get this error
The "RenderBody" method has not been called for layout page "~/Views/PLNHK/PLNHK.cshtml".
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
EDIT : I did create PLNHK.cshtml. while I'm trying to debug this, the control goes to PLNHK controller then to PLNHK view(PLNHK.cshtml) parses each and every step in that page, but finally I would get the output to be the older page. I was thinking may be the Ajax scripts on before page is the reason.

Categories