Search function with a foreign API in MVC architechture - c#

I am trying to mess around with a foreign API, but i cant seem to get the last bit working. I have succesfully retrieved data from the API but i cannot get the search functionality to cooperate with the API. The search function needs an id, and from that an object is returned. Here is what i have so far:
Controller
[HttpGet]
public ActionResult GetCardsByID(string idNumber)
{
//idNumber = "c353618d9f76c03a0c7d549f2d877f9533112d0c";
ViewBag.Message = "Your GetCardsByID page.";
var client = new RestClient("https://api.magicthegathering.io");
var request = new RestRequest("v1/cards/{id}", Method.GET);
request.AddUrlSegment("id", idNumber);
IRestResponse response = client.Execute(request);
var content = response.Content;
CardContainer cards = JsonConvert.DeserializeObject<CardContainer>(content);
return View();
}
View
#{
ViewBag.Title = "GetCardsByID";
}
<h2>#ViewBag.Title.</h2>
<h3>#ViewBag.Message</h3>
<p>
In this tab we can retrieve a card by searching with an id
</p>
<form method="get" action="#Url.Action("GetCardsByID", "CardsController")">
<label for="idNumber">Search</label>
<input type="text" name="idNumber" id="idNumber" />
<button type="submit">Perform search</button>
</form>
Routing
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional }
);
}
}
The error i get is as follows: (Translated)
Server error in program'/'.
Resource not found.
Description: HTTP 404, the resource you are looking for, or one of its dependencies, has possible been removed and is not accesable at this moment. Check if the following URL-addresses are spelled correctly
Wanted URL address: /CardsController/GetCardsByID
Home page GetCardsByID page Search error

When you call a controller, don't put controller on the end of it.
Try this:
<form method="get" action="#Url.Action("GetCardsByID", "Cards")">
<label for="idNumber">Search</label>
<input type="text" name="idNumber" id="idNumber" />
<button type="submit">Perform search</button>
</form>
Note the Url.Action is Cards, not CardsController
Even though your controller is called CardsController.cs
You know you could probably do this easier entirely in javascript

Related

Server error in application '/'. HTTP 404. MVC ASP.NET

I am trying to show a view through the POST action method, but when calling this action it shows me the message "Server error in application '/'".
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) may have been removed, renamed, or temporarily unavailable. Please review the URL below and make sure it is spelled correctly.
I have already created my respective view for this method using the routes.MapMvcAttributeRoutes().
[Route("Home/AddPiloto")]
[Route("AddPiloto")]
public ActionResult AddPiloto()
{
return View();
}
Here is the POST action that I am calling from my html form, the method works and gets the data, only the view fails.
[HttpPost]
public ActionResult AddPiloto(PilotoClass pclass)
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:8080/AeronauticaDGAC/");
var request = httpClient.PostAsync("webresources/conndatabase.piloto/supCreatePost", pclass,
new JsonMediaTypeFormatter()).Result;
if (request.IsSuccessStatusCode)
{
var resultString = request.Content.ReadAsStringAsync().Result;
var succes = JsonConvert.DeserializeObject<bool>(resultString);
ViewBag.Mg = succes;
return RedirectToAction("AddPiloto");
}
ViewBag.Mg = request.StatusCode;
return RedirectToAction("Index",ViewBag);
}
Finally here I have a typical form that calls this method POST.
<form action="AddPiloto" method="post">
<div class="form-group">
<input class="form-control" type="number" name="id" value="" placeholder="Id" />
<input id="inp1" class="form-control" type="text" name="nombre" value="" placeholder="Nombre" />
<input id="inp1" class="form-control" type="text" name="apellido" value="" placeholder="Apellido" />
<input id="inp1" class="form-control" type="number" name="edad" value="" placeholder="Edad" />
<hr />
<input class="btn btn-primary" type="submit" name="button" value="Enviar" />
<input onclick="limpiarFormulario1()" class="btn btn-danger" type="button" name="button" value="Limpiar" />
</div>
</form>
I already have the view created, compile and recompile the solution, clear the browser cache, check if the file exists and restart the IIS server, but nothing works for me, if someone knows any possible solution I would greatly appreciate the answer.
Thanks in advance.
All code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Net.Http;
using Newtonsoft.Json;
using AeronauticaClient.Models;
using System.Net.Http.Formatting;
namespace AeronauticaClient.Controllers
{
[RoutePrefix("Home")]
[Route("{action}")]
public class HomeController : Controller
{
[Route("~/")]
[Route("")]
[Route("Index")]
[HttpGet]
public ActionResult Index()
{
System.Net.Http.HttpClient CHttp = new HttpClient();
CHttp.BaseAddress = new Uri("http://localhost:8080/AeronauticaDGAC/");
var request = CHttp.GetAsync("webresources/conndatabase.piloto/supFindAllGet").Result;
if (request.IsSuccessStatusCode)
{
var resultString = request.Content.ReadAsStringAsync().Result;
var listado = JsonConvert.DeserializeObject<List<PilotoClass>>(resultString);
ViewBag.Message = request;
return View(listado);
}
else
{
ViewBag.Message = request;
}
return View();
}
[Route("Home/AddPiloto")]
[Route("AddPiloto")]
public ActionResult AddPiloto()
{
return View();
}
[HttpPost]
public ActionResult AddPiloto(PilotoClass pclass)
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:8080/AeronauticaDGAC/");
var request = httpClient.PostAsync("webresources/conndatabase.piloto/supCreatePost", pclass,
new JsonMediaTypeFormatter()).Result;
if (request.IsSuccessStatusCode)
{
var resultString = request.Content.ReadAsStringAsync().Result;
var succes = JsonConvert.DeserializeObject<bool>(resultString);
ViewBag.Mg = succes;
return RedirectToAction("AddPiloto");
}
ViewBag.Mg = request.StatusCode;
return RedirectToAction("Index",ViewBag);
}
}
}
Routing code.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
When you redirect to index, you're passing ViewBag as an argument.
return RedirectToAction("Index",ViewBag);
But the server cannot find an index method receiving that parameter, so it raises an exception.
Remove ViewBag as an argument when you redirect.
return RedirectToAction("Index");
Before redirecting, replace ViewBag for TempData
if (request.IsSuccessStatusCode)
{
var resultString = request.Content.ReadAsStringAsync().Result;
var succes = JsonConvert.DeserializeObject<bool>(resultString);
TempData["Mg"] = succes;
return RedirectToAction("AddPiloto");
}
TempData["Mg"] = request.StatusCode;
return RedirectToAction("Index");
To retrieve the value you stored in previous step, use TempData["Mg"] further on.
You need TempData instead because after RedirectToAction you'll be in a new request. Since ViewBag is only available for same request, the values would be lost after redirecting.

MVC route URL not containing parameter

I'm attempting to wrap my head around .NET MVC5 routing.
I've got a form:
#using (Html.BeginForm("ProductsCheaperThan", "Home", FormMethod.Post))
{
<input type="text" name="comparisonPrice" />
<button type="submit">Search!</button>
}
And I've got a controller Home and an action ProductsCheaperThan which takes a parameter comparisonPrice
public ActionResult ProductsCheaperThan(decimal comparisonPrice)
{
ViewBag.FilterPrice = comparisonPrice;
var resultSet = new ProductService().GetProductsCheaperThan(comparisonPrice);
return View(resultSet);
}
This posts the value in the input (let's suppose that the value I'm posting is 20) back to my action, and correctly routes me to ~/Home/ProductsCheaperThan. The problem is, I'd like to be routed to ~/Home/ProductsCheaperThan/20
I'd like to do this so that if somebody bookmarks the page they don't end up getting an error when they revisit the page.
I thought that adding something like:
routes.MapRoute(
name: "ProductsCheaperThan",
url: "Home/ProductsCheaperThan/{comparisonPrice}",
defaults: new { controller = "Home", action = "ProductsCheaperThan", comparisonPrice = 20 }
);
might work, and I have one solution to my problem which changes the form to a GET
#using (Html.BeginForm("ProductsCheaperThan", "Home", FormMethod.Get))
and produces a URL of ~/Home/ProductsCheaperThan?comparisonPrice=20, but that uses a query string instead, and isn't exactly what I was aiming for.
Can anybody help me get my URL right?
You should add [HttpPost] attribute to your action
[HttpPost]
public ActionResult ProductsCheaperThan(decimal comparisonPrice)
{
ViewBag.FilterPrice = comparisonPrice;
var resultSet = new ProductService().GetProductsCheaperThan(comparisonPrice);
return View(resultSet);
}
One option is to use JQuery -
<div>
<input type="text" name="comparisonPrice" id="comparisonPrice" />
<button type="button" id="Search">Search!</button>
</div>
#section scripts{
<script>
$(function () {
$("#Search").click(function () {
window.location = "#Url.Action("PriceToCompare", "Home")" + "/" + $("#comparisonPrice").val();
});
});
</script>
}
Above script will result in - http://localhost:1655/PriceToCompare/Home/123
I think you can specify your route values using an overload:
#using (Html.BeginForm("Login", "Account", new { comparisonPrice= "20" }))
{
...
}

ASP.NET MVC 4 to Generate URL Formate as Controller/Action/ID

I have the default route defined as
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I want to generate a url like this in html -
<form action="/app/Request/c35d4520-ba0b-452f-837b-a00046f40647 method="post">
But if I code Razor page like -
#using (Html.BeginForm("Default", "Request", FormMethod.Post, new { id = ViewBag.AppId }))
The rendered html is -
<form action="/app/Request" id="c35d4520-ba0b-452f-837b-a00046f40647" method="post">
How can I force the razor generate the url as controller/action/ID format?
Thanks
Try using Html.BeginRouteForm
#using (Html.BeginRouteForm("Default", new { controller = "foo", action = "bar" }, FormMethod.Post, new { id="foo", enctype="multipart/form-data", accept_charset="utf-8" }))
{
}
the problem is in the way you arrange the parameters in the Html.BeginForm call. According to the parameters you feed in, you are currently calling
Html.BeginForm(actionName, controllerName, formMethod, htmlAttributes)
Therefore, new { id = ViewBag.AppId } is treated as htmlAttributes. And that is why the id is renedered as an attribute in the form tag.
Instead, you should swap the positions of method and the id as below
Html.BeginForm("Default", "Request", new { id = ViewBag.AppId }, FormMethod.Post))
Let me know if it works for you :)
The problem has been solved by a function -
protected ActionResult RedirectToAppAction(string controllerName)
{
return this.Redirect(string.Format("/App/{0}/{1}", controllerName, this.Id));
}

Routing Issue on asp.net mvc 5 GET

I am trying to get my product search URL to look like "Products/Search/{search term here}".
I am using attribute based routing and my controller action looks like this:
[HttpGet]
[Route("Products/Search/{searchTerm?}", Name="ProductSearch")]
public ActionResult Search(string searchTerm = "")
{
return View();
}
I have tried using the HTML Helper for BeginForm and BeginRouteForm (shown below) but have not had luck with either. The right action is being called, but my URL looks like "Products/Search?searchTerm"
BeginRouteForm
#using (Html.BeginRouteForm("ProductSearch", new { searchTerm = "" }, FormMethod.Get, new { Class = "navbar-form navbar-right", role = "search" }))
{
<div class="form-group">
#Html.TextBox("searchTerm", null, new { Class = "form-control", placeholder = "Item # or Name" })
</div>
<button type="submit" class="btn btn-default">Search</button>
}
BeginForm
#using (Html.BeginForm("Search", "Products", new { searchTerm = "" }, FormMethod.Get, new { Class = "navbar-form navbar-right", role = "search" }))
{
<div class="form-group">
#Html.TextBox("searchTerm", null, new { Class = "form-control", placeholder = "Item # or Name" })
</div>
<button type="submit" class="btn btn-default">Search</button>
}
I have gone through debugging and the right route is selected, the URL is just not displaying how I wanted it to. What am I missing?
Here is the solution I suggest -
You have the following controller Action -
[HttpGet]
public ActionResult Search(string searchTerm = "")
{
return View();
}
Let the view be -
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script>
$(function () {
$('#click').click(function (e) {
var name = $("#search").val();
var url = '#Url.Action("Search", "Action")' + '/' + name;
window.location.href = url;
});
});
</script>
<input type="text" name="searchText" id="search"/>
<input type="button" value="click" id="click"/>
And when you click the button -
Do not forget to have proper route to be added on to the route configuration -
routes.MapRoute(
name: "searchaction",
url: "{controller}/{action}/{searchTerm}",
defaults: new { controller = "Action", action = "Search" }
);
The problem you think you are experiencing isn't because of anything about ASP.Net MVC. All Html Forms that use the method GET will translate all input elements into QueryString parameters. This is just a W3C standard.
If you want this to work, you'll have to write jQuery to throw an event before the form is submitted, take the text value from the input store it temporarily, empty the input box, and then update the action by appending the temporary value.
I don't think that BeginRouteForm works the way that you're expecting it to. According to the documentation, all that the method does is insert a <form> using the arguments provided. If you had provided something other than an empty string for the route value such as , new { searchTerm = "somesearchterm" }, you would see that show up in the Url as "/product/search/somesearchterm". As it is now, however, the form will be processed as normal, putting the search term on the Url as a normal query parameter.

New MVC 4 Project. Default routes are getting ignored

I just created a new MVC 4 project, and added an EDO.NET Entity Data Model using Database First. I'm not sure exactly why, but things don't seem to be functioning correctly as they used to. I had to manually add the EF Code Generation item to generate the entity classes.
Anyway, the main problem I have is that the default routing seems to be ignored.
My route config is the default, which is as follows:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
However [LOCALHOST]/Properties/ doesn't find /Properties/Index, it merely returns a 404 Server Error in '/' Application.
The resource cannot be found.
I wouldn't put it past me to have made some silly mistake or forgotten something crucial, but I've searched StackOverflow and the interwebs for similar problems and none of the solutions are of any help. If anyone knows why, I'd be grateful for a prod in the right direction.
Requested Edits:
I have 3 Controllers:
Home - Untouched
Account - Untouched
Properties - w/ Default MVC CRUD Actions (Index, Details, Create, Edit)
It works fine when hosted on IIS but not on VS's internal debugging IIS.
#Html.ActionLink("Properties", "Index", "Properties") generates http://[localhost]:53909/Properties when run. However clicking the generated link gives me a "Server Error in '/' Application.
The resource cannot be found."
PropertiesController.cs (only Index action)
public class PropertiesController : Controller
{
private PropertyInfoEntities db = new PropertyInfoEntities();
//
// GET: /Properties/
public ActionResult Index()
{
//Mapper.CreateMap<Property, PropertiesListViewModel>()
//.ForMember(vm => vm.MainImageURL, m => m.MapFrom(u => (u.MainImageURL != null) ? u.MainImageURL : "User" + u.ID.ToString()))
// ;
//List<PropertiesListViewModel> properties =
// Mapper.Map<List<Property>, List<PropertiesListViewModel>>(db.Properties.ToList());
return View(db.Properties.Include(p => p.Currency).Include(p => p.Type).Include(p => p.Province).Include(p => p.Region).Include(p => p.SaleType).Include(p => p.Source).Include(p => p.Town).ToList());
}
}
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<header>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title">#Html.ActionLink("your logo here", "Index", "Home")</p>
</div>
<div class="float-right">
<section id="login">
#Html.Partial("_LoginPartial")
</section>
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
<li>#Html.ActionLink("Properties", "Index", "Properties")</li>
<li>#Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
</nav>
</div>
</div>
</header>
....
Edit 2:
Even with a specific route it is still ignored
namespace ProjectName
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Properties",
"Properties/{action}/{id}",
new { controller = "Properties", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Cheers!
I tried changing the name of PropertiesController to Properties1Controller, and the routing worked for it completely fine. After some further digging I discovered that it's because Properties is a Windows Reserved Keyword.
Anyhow, the solution to the problem: Do not use reserved keywords as controller names.
Strangely routing for /Properties/Index works completely fine, and routing for /Properties/ works completely fine on production IIS, just not for development. This made it much harder to work out the problem but managed to get there in the end.
Thank-you all for your assistance.
In your Global.asax.cs file, have you registered the routes? For example:
RouteConfig.RegisterRoutes(RouteTable.Routes);
Visiting localhost/properties is explicitly saying that you want to invoke PropertiesController. If you mean you want that to be your default route, then you need to change your route config to the following:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Properties", action = "Index", id = UrlParameter.Optional }
);
That would allow you to invoke it directly from localhost. However, it sounds as though you are missing the .cshtml file. Have you made sure ~/Views/Properties/Index.cshtml exists?
Default route means that every [localhost]/foo/bar request is forwarded to FooController and its Bar action that must return some existing View. Probably you don't have some of them.
"defaults" parameter sets default controller and action names in case they are not specified in request (i.e. http://[localhost]/) so in your case this will search for HomeController and its Index action.
Does the namespace of the Properties controller match the "ProjectNamespace.Controllers" convention? If you copied the code from another source you may have forgotten to change the namespace of the controller class.

Categories

Resources