Call web API string parameter - ajax

I have this function
[System.Web.Http.HttpGet]
[System.Web.Http.ActionName("StartProcess")]
public object StartProcess(string items)
{
//do stuff
}
trying to call with
$.ajax({
url: '/api/Details/StartProcess',
type: 'get',
contentType: 'application/json',
data: items,
success: function() {
logger.log('Successful', "", "", true);
},
error: function(error) {
var jsonValue = jQuery.parseJSON(error.responseText);
});
Keep getting 404 error. The rest of my calls work but this is the first one that I need to send a parameter.
items is just a comma delimited string.
this is my route info.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id=Urlameter.Optional }
);
Any ideas what I am missing?

you are getting 404 error because your routing table is not able to resolve the url "/api/Details/StartProcess"
In order to make the WebAPI routing work you need to modify the "MapHttpRoute()" function of route collection and not the "MapRoute()"
So please change the API routing as below (assuming you are using default api) and it should work fine.
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = RouteParameter.Optional, id = RouteParameter.Optional }
);

The parameter in Web API needs to follow the parameter in routing config.
In your example the easiest would be to change string items to string id.
Alternatly you could add api/{controller}/{action}/{items} to the route config.

Also, if you don't fancy changing your API route config (which would lead to minor complications with calling simple Get and Put methods) you can change your controller action annotation from
[System.Web.Http.ActionName("StartProcess")]
to
[Route("StartProcess/{items}")]
Also, you'll need to annotate your controller with:
[RoutePrefix("api/details")]

Related

Invoking Action in Controller using ajax - not working. (ASP.Net MVC)

I've been wrestling this error for quiet a while now and tried all the suggestions found on the web, still no luck.
I'm doing a simple ajax call to a controller's action. The application is in EPiServer, but this seems to be a generic question regarding using Ajax in ASP.NET.
Index View:
<input id="btnAjax" type="button" value="Favorite" />
<script>
$('#btnAjax').click(function () {
$.ajax({
url: '#Url.Action("SetCookie", "Home")',
contentType: 'application/html; charset=utf-8',
type: 'POST',
dataType: 'html'
})
.success(function (result) {
alert("Success");
})
.error(function (xhr, status) {
alert(status);
})
});
</script>
Controller - HomeController:
[HttpPost]
public void SetCookie()
{
//Do stuff
}
What I've done/tried:
Referenced jquery correctly.
Added the [WebMethod] attribute to the action
Added a Http module in Web.config (ScriptModule, for EPiServer)
Added Reference to jquery.unobtrusive-ajax.js, after the reference to jquery.
When I run the webapplication and push the button the debugger in Developer tool tells me
which is strange, since there is an action/method called SetCookie() in the HomeController. And the alert box "Fail" shows, which indicated that at least the js function is invoked.
Either I'm blind and missing something or there is something else which needs to be done...
All suggestions are welcome and much appreciated.
/ChrisRun
EPiServer does not register the default route for MVC by default. This is because you could have a page called "Home" in your site that would confict with the Home route. You can register the route yourself in Global.asax by overriding the RegisterRoutes method:
protected override void RegisterRoutes(RouteCollection routes)
{
base.RegisterRoutes(routes);
// Register a route for Web API
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "webapi/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Register a route for classic MVC to use for API calls
routes.MapRoute(
name: "API",
url: "api/{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional });
}
I like to put MVC and Web API routes under a prefix such as "webapi" or "api" so that it's less likely to conflict with any content routing.
Simply change your method from this:
public void SetCookie()
{
//Do stuff
}
to this:
public ActionResult SetCookie()
{
//Do stuff
}

AJAX call can't find my WebAPI Controller

I have the following AJAX call:
var params = {
provider: "facebook"
};
$.ajax({
url: "http://localhost/taskpro/api/account/ExternalLogin",
data: JSON.stringify(params),
type: "POST",
contentType: 'application/json; charset=utf-8'
})
.done(function (response) {
alert("Success");
});
calling the following WebAPI controller:
public class AccountController : ApiController
{
[HttpPost]
[AllowAnonymous]
public bool ExternalLogin(string provider)
{
return true;
}
}
with the following routemap:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
When I execute this, fiddler is returning:
{"Message":"No HTTP resource was found that matches the request URI
'http://localhost/taskpro/api/account/ExternalLogin'.","MessageDetail":
"No action was found on the controller 'Account' that matches the request."}
I have several other calls being made to this controller that are working just fine. It's just THIS call that is giving me troubles.
Also, if I remove the parameter in the controller so it's just
public bool ExternalLogin()
and comment out the data line in the ajax, it works fine.
Any ideas why the routing is not working for this call?
I ran across this article:
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
Basically, WebAPI can't bind to primitive data types like string. You have to either create a model to bind to, or use the [FromBody] attribute. I modified my method to this:
public bool ExternalLogin([FromBody]string provider)
and it's working fine now.

WebApi call fails for other than the default route

I have an Mvc3 project that includes both Mvc and Api controllers. When I run the application without specifying the "controller/action", the "Default" route is selected and the "home/index" page is rendered. When that page runs, an Ajax call is made using url: "api/controller", returning json, which is then used to populate a table on the page.
<script type="text/javascript">
$(function () {
var $products = $("#products");
$.ajax({
url: "api/products",
contentType: "json",
success: function (data) {
$.each(data, function (index, item) {
$products.append("<tr><td>" + item.ProductCode + "</td>" +
"<td>" + item.Description + "</td>");
});
}
});
});
</script>
However, when a request is made to the same page specifying the "controller/action", as in "localhost/home/index", the Ajax call is translated to "/home/api/controller" and of course the request cannot complete or return any results, since the ApiController cannot be found.
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Considering that it must be a routing issue, I proceeded to resolve this by adding a route:
routes.MapHttpRoute(
"HomeApi",
"home/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
This was successful. As was my next change to:
routes.MapHttpRoute(
"AnyApi",
"{folder}/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
Which also works but leaves me somewhat skeptical as to whether it is the correct way to handle combining WebApi with Mvc.
Is this the correct way to handle this? Or are there better alternatives?
Considering that it must be a routing issue, I proceeded to resolve this by adding a route:
No, that's not a routing issue at all. Your routes are perfectly fine:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Your issue stems from the fact that you have hardcoded the url in your javascript instead of using url helpers to generate it. You should absolutely never hardcode an url inside an ASP.NET MVC application. You should always use url helpers.
So:
<script type="text/javascript">
$(function () {
var $products = $("#products");
var url = '#Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" })';
$.ajax({
url: url,
success: function (data) {
$.each(data, function (index, item) {
$products.append("<tr><td>" + item.ProductCode + "</td>" +
"<td>" + item.Description + "</td>");
});
}
});
});
</script>
Also notice that I have removed the contentType: 'json' from your AJAX call because first the correct content type is contentType: 'application/json' and second in this case you are not sending any data in the request, so you shouldn't be setting it to application/json.
There's no need to add a route there -- you can specify the API URL so that it will always work:
/api/controller
In some cases you may need to use the Url.RouteUrl helper to create URLs explicitly based on the route (by route name and/or route values). For example, this would specify the route named "DefaultApi" with controller=products:
#Url.RouteUrl("DefaultApi", new { controller = "products" })

Ajax Post: 405 Method Not Allowed

Within my API Controller called Payment, I have the following method:
[HttpPost]
public HttpResponseMessage Charge(Payment payment)
{
var processedPayment = _paymentProcessor.Charge(payment);
var response = Request.CreateResponse(processedPayment.Status != "PAID" ? HttpStatusCode.ExpectationFailed : HttpStatusCode.OK, processedPayment);
return response;
}
In my HTML page I have:
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "http://localhost:65396/api/payment/charge",
data: $('#addPayment').serialize(),
dataType: "json",
success: function (data) {
alert(data);
}
});
Whenever I fire the POST, I get
"NetworkError: 405 Method Not Allowed - http://localhost:65396/api/payment/charge"
What am I missing?
Thank you.
UPDATE
Here's the routing information (default)
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Most likely your routing is not configured for the action to be invoked. Hence the request ends up in nowhere and ASP.NET Web API sends a blank-out message "method not allowed".
Can you please update the question with your routing?
UPDATE
As I thought! You are sending to http://localhost:65396/api/payment/charge while you need to send to http://localhost:65396/api/payment - assuming your controller is called PaymentController.
Note that route does not have action.
Turns out I needed to implement CORS support. http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/20/implementing-cors-support-in-asp-net-web-apis.aspx
I had the same problem with my controller.
The only thing which is different is the ending of the URL.
Add "/" to "http://localhost:65396/api/payment/charge" at the end, that helped me

Calling the home controller action using ajax

I have an 'Index' action within my home controller which responds to the url '/'. The action also has an optional 'id' parameter...
[HttpGet]
public ViewResultBase Index(int id = -1)
{
....
}
the routing for this is...
routes.MapRoute("Home",
"",
new { controller = "Home", action = "Index", id = -1 } );
If I try to call this action using ajax...
$.get(
'#Url.Action("Index", "Home")',
{ id: 20 },
function (response) {
});
the call fails as the url is /?id=20
Is it possible to force the Url.Action to include the controller and action names, as when I do this...
'#Url.Action("Index", "Home")' + 'Home/Index'
all works fine, or do I need to correct my routing?
You dont need to make a special route for your Action method like so. The default route:
{controller}/{action}/{id},
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
Handles that case already; when you request '/' on your server, you should get sent to your Home/Index action method. You should remove the custom route you have specified and let the default route send you to the correct destination.

Resources