I have a controller called "UploadsController". I have a GET action like so:
public string GetUpload([FromUri]string action)
{
return "hey " + action;
}
If I navigate to the following API URL in my browser, I get a successful response.
http://localhost:52841/MySite/api/uploads?action=testaction
However, when I try calling the API from code-behind in my WebForms app, I get a 404 response.
Here's what I have in my Global.aspx file (even though I believe the first should do it):
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
RouteTable.Routes.MapHttpRoute(
name: "Default2Api",
routeTemplate: "api/{controller}/{action}",
defaults: new { controller = "Uploads", action = "GetUpload" });
Here's how I'm calling the API:
// Send a request asynchronously continue when complete
client.GetAsync("http://localhost:52841/MySite/api/uploads?action=testaction").ContinueWith(
(requestTask) =>
{
// Get HTTP response from completed task.
HttpResponseMessage response = requestTask.Result;
// Check that response was successful or throw exception
response.EnsureSuccessStatusCode();
// Read response asynchronously as JsonValue
response.Content.ReadAsAsync<string>().ContinueWith(
(readTask) =>
{
var result = readTask.Result;
//Do something with the result
});
});
I thought I've done this before (with the RC version, using RTM now), but I can't seem to get this one.
As a side note, the request isn't showing in fiddler for some reason, which is kind of annoying when you're trying to debug these kind of stuff.
Any help is appreciated.
Try naming your query string parameter to something else (Right now it is "action"). I think that's one reason it's causing problems. Since MVC is convention-based, that might be causing problems.
Also in your route declaration, try adding the query string parameter (Let me call it custAction).
And declare custom route before default route.
Code sample:
RouteTable.Routes.MapHttpRoute(
name: "Default2Api",
routeTemplate: "api/{controller}/{action}",
defaults: new { controller = "Uploads", action = "GetUpload", custAction = RouteParameter.Optional});
Yes I have been through the same problem most likely your issue is that webapi doesnt allow cross domain calls by default or at least this is what I know about it.
You need to add a CORS support to your web api code, follow the link this guy has shown how to add CORS to your webapi
http://code.msdn.microsoft.com/CORS-support-in-ASPNET-Web-01e9980a
Good Luck.
Related
I am using ASP.NET FW 4.6.1; Microsft.AspNet.WebApi 5.2.7; EF 6.4.
I have the issue below when starting my project.
Method request.Files is not supported (please see image)
public static class WebApiConfig
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "<Pending>")]
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Enable cross domain request
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Filters.Add(new ErrorHandlers.AiHandleErrorAttribute());
**config.Filters.Add(new UploadFileFilterAttribute());**
config.MessageHandlers.Add(new RequestTabletMessageHandler());
config.MessageHandlers.Add(new RequestLoggingMessageHandler());
config.Services.Add(typeof(IExceptionLogger), new CustomExceptionLogger());
}
}
The reason it is not supported is because the file buffer stream has already been parsed (or parsing has started) at a previous point in the request pipeline. You should look at other filters/modules in your pipeline and see if any of them touch the files in the incoming request. You might find that simply commenting out other filters (such as ErrorHandlers.AiHandleErrorAttribute() for example) and rerunning could be used to quickly determine which filter/module is doing the parsing. Once you have figured that out, you need to decide how you are going to handle multiple parses of the files. One option is to only use one module, another would be to buffer it into a memory stream/block of memory and have both/all modules access that copy instead. Hope this helps.
Using C# web api, i created a web api that update the information.
// Update
// URI PUT + api/Gender/id
[HttpPut]
public IHttpActionResult PutGender(int id, [FromBody] Gender g)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var query = (from gen in genders
where gen.Id == id
select gen).FirstOrDefault();
if (query == null)
{
return BadRequest("wrong");
}
query.Description = g.Description;
query.LanguageId = g.LanguageId;
query.InternalCode = g.InternalCode;
query.isActive = g.isActive;
query.UpdatedAt = DateTime.Now;
return StatusCode(HttpStatusCode.OK);
}
I am testing through fiddler and this is how i ran the thing:
URL http://localhost:49625/API/PutGender
Action PUT
Request Header
Content-Type: application/json
User-Agent: Fiddler
Host: localhost:49625
Content-Length: 86
RequestBody
{"Id":1,"Description":"Undecided","LanguageId":null,"InternalCode":0,"isActive":false}
The URL is missing the name of the controller. For example, if your controller is called GenderController then the URL should be http://localhost:49625/API/Gender/PutGender
For other people that might run into this problem (myself included). Also check your route configuration. If you are using the default route configuration:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
There is no need to specify the "action part" of your url (PutGender), "PUT http://myhost/api/gender/1" should be fine. Also, if your method is named Put...Something, I am pretty sure you can omit the [HttpPut] attribute from the method signature aswell.
I've added this method to my web api controller:
[HttpPost]
public bool CreateTrening(int routineId)
{
try
{
var userId = User.Identity.GetUserId();
TreningService.CheckIfLastTrenigWasCompleted(userId);
TreningService.CreateTreningForUser(userId, routineId);
return true;
}
catch (Exception ex)
{
return false;
}
}
And I've added another route to my WebApiConfig file, so it looks like this now:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "CustomApi",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
But when I try to call my method:
/EditWorkout/CreateTrening/1
I get this error:
{"Message":"No HTTP resource was found that matches the request URI '/EditWorkout/CreateTrening/1'.","MessageDetail":"No action was found on the controller 'EditWorkout' that matches the request."}
How can I call my method which is in WebApi controller ?
Calling with that URL to a post method will not work because the post expects the values transmitted in the Http Message body. not in the URL so your controller is not finding the method.
Probably the best solution for this is to encode your posted value in the http message you send the controller, and call the URL with /EditWorkout/CreateTrening, this will work as a post.
Here is another SO thread where the question of how to do this was answered,
Specific post question answered
We are re-writing an old asp.net site into MVC4.
There are many links to our site that look like this (that we don't control but must support):
www.some.com/page.aspx?id=5
Is there a way to get a request for /page.aspx?id=5 into a Route so that we can handle the request, pass it to a controller/action and then handle it from there?
In the RouteConfig, add a route (before default route):
routes.MapRoute(
name: "DefaultAspx",
url: "page.aspx",
defaults: new { controller = "MyAspxPage", action = "Index", id = UrlParameter.Optional }
);
In the controller catch the page id:
(MyAspxPageController)
public ActionResult Index(int id)
{
// Do whatever needed
//return View();
}
Check out, you might also introduce "areas" to your app - it's helpful if your project is big enough. And if you use them, they will reflect on your routes.
I have a controller function which accepts a strongly typed model as parameter.
When i enter ANY url mapping to the controller but not on a specific action on the post request ,
then the controller executes this function instead of returning a 404 code.
When i Change the function's parameter to a primitive type variable then the problem does not occur. (i have tried using other strongly typed models as parameters and again the problem occurs)
Here's the function.
public class PhoneApiController : ApiController
{
[HttpPost]
public HttpResponseMessage RegisterApp(RegisterAppInfo appInfo)
{
var resp = Request.CreateResponse(HttpStatusCode.OK, new
{
Success = true,
AppId = 1000,
IdAlias = "QAUBC9",
appInfo = appInfo
});
return resp;
}
}
So when i enter for example
localhost:51464/Api/PhoneApi/Sajsdkasjdklajsasd
the function executes normally.!
I am using the default Route config
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I don't know if this is a bug or i am doing something wrong.
The URI /Api/PhoneApi/Sajsdkasjdklajsasd does match your route template api/{controller}/{id} with {controller} matching PhoneApi and {id} matching Sajsdkasjdklajsasd. I assume you are making a POST to this URI. So, Web API is mapping your request to the action method RegisterApp with [HttpPost] in the controller class PhoneApiController.
As far as the junk stuff in the URI, it gets mapped to {id}. But your parameter is RegisterAppInfo, which is a complex type and that gets bound from request body and not the URI. That's why it works when you have the complex type. The simple types are bound from URI, query string.
If you have the action method as public HttpResponseMessage RegisterApp(string id, Abc appInfo), you will see that this id parameter gets populated with "Sajsdkasjdklajsasd".
For MVC 4.5 this is the only thing that works
There is currently a bug about this.
Below is a work around in order to get the following route types work
api/{controller}/ //Get All
api/{controller}/{Id} //Get for id
api/{controller}/{Id}/{Action}/ //Get all for action for controller with Id
you need to do the following.
Change your routing over to. (Note the default action..)
config.Routes.MapHttpRoute(
name : "DefaultAPi",
routeTemplate : "api/{controller}/{id}/{action}",
defaults: new
{
id = RouteParameter.Optional,
action = "DefaultAction"
}
);
In your controller change the base methods over to
[ActionName("DefaultAction")]
public string Get()
{
}
[ActionName("DefaultAction")]
public string Get(int id)
{
}
[ActionName("SpaceTypes")]
public string GetSpaceTypes(int id)
{
}
Now everything should work as expected..
Thanks to Kip Streithorst full this, for a full explanation
The way routing works in Web API is:
First it matches the URI against route template. At this stage, it's not looking at your controller actions
Then it looks for a matching controller
Then it looks for a method where (a) the action matches (POST in this case) and (b) every simple parameter type is matched with a value from the URI.
If there is a complex parameter type, it tries to read that from the request body.
By default, Web API tries to bind "simple" parameter types (like int) from the URI, and tries to read complex types from the request body.
See here for details: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection