WebAPI not found - asp.net-mvc

Sadly, I cannot get the most basic of things working with WebAPI
$.ajax({
url: "https://192.168.1.100/Api/Authentication/LogIn",
type: "POST",
contentType: "application/json",
data: "{ 'username': 'admin', 'password': 'MyPass' }",
error: function (r, s, e) { alert(e); },
success: function (d, s, r) { alert(s); }
});
I get "Not found"
API controller definition
public class AuthenticationController : ApiController
{
[HttpPost]
public bool LogIn(string username, string password)
{
return true;
}
}
If I remove HttpPost and replace it with HttpGet and then do
$.ajax({
url: "https://192.168.1.100/Api/Authentication/LogIn?username=admin&password=MyPass",
type: "GET",
error: function (r, s, e) { alert(e); },
success: function (d, s, r) { alert(s); }
});
That works fine.
What's wrong with WebAPI?

This article should help answer some of your questions.
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
I believe the thinking here is that, especially in a RESTful API, you’ll want to bind data to the single resource that a particular method deals with. So, pushing data into several loose parameters isn’t the sort of usage that Web API caters to.
When dealing with post data, you can tell your action method to bind its parameters correctly like this:
public class LoginDto {
public string Username { get; set; }
public string Password { get; set; }
}
[HttpPost]
public bool LogIn(LoginDto login) {
// authenticate, etc
return true;
}

A couple things. Yahia's change is valid. Also, POSTs need a little direction in WebAPI to know where to look for their data. It's pretty silly in my opinion. If you know it's a POST, look at the message body. At any rate, change your POST to this and things will work. The attribute tells WebAPI to look in the body and the model does binding.
The AuthModel is just a simple model containing your username and password properties. Because of the way WebApi wants to bind to the input, this will make your life easier.
Read here for more details:
http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1
Should be good to go with those changes.

Binding in WebAPI doesn't work if you use more than 1 parameter.
Though the same works in MVC controller.
In WebAPI use a class to bind two or more parameters. Read useful article:
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
You may solve it the following ways:
1. Do the same in MVC action (it works)
2. Stay parameterless Post and read request like this
[HttpPost]
[ActionName("login")]
public async Task<bool> Post()
{
var str= await Request.Content.ReadAsStringAsync();
//
3. Incapsulate parameters to class like gyus prompted
}
Hope it helps ;)

POST action can have only 1 body...
There is no way to send 2 bodies (in your case 2 strings).
Because of this, the WebAPI parser would expect to find it in URL and not in body.
You can solve it by putting attributes and set that one parameter will come from URL and another from body.
In general, When there is only one object parameter in method - there is no need for the attribute [FromBody].
Strings would be expected to be in URL.
So - you can try send them in the URL as parameters (much like you did in GET)
Or - build a class to wrap it.
I would strongly recommend to use POST for login action.

Related

DNN Cannot access POST method in DNN Api Controller

My GET method WORKS fine when I use the url logged in as SuperUser like this(I get the name of the first user pulled from the DB):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/GetMessage
But I cannot access the POST method in the same controller either using AJAX from view or just by entering the url (post method doesnt get hit/found):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage
And also this fails as well:
$('#sendChat').click(function (e) {
e.preventDefault();
var user = '#Model.CurrentUserInfo.DisplayName';
var message = $('#chatBoxReplyArea').val();
var url = '/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage';
$.post(url, { user: user, message: message }, function (data) {
}).done(function () {
});
});
The Error message is:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage'.
</Message>
<MessageDetail>
No action was found on the controller 'ChatApi' that matches the name 'SendMessage'.
</MessageDetail>
</Error>
And sometimes:
"The controller does not support GET method"
even though I do have both a GET and a POST there and the GET works. What am I missing?
I have made a routing class in my DNN project:
using DotNetNuke.Web.Api;
namespace AAAA.MyChatServer
{
public class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("MyChatServer", "default", "{controller}/{action}", new[] { "AAAA.MyChatServer.Services" });
}
}
}
I added a DNN Api Controller in folder Services of my project named AAAA.MyChatServer:
using DotNetNuke.Web.Api;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
namespace AAAA.MyChatServer.Services
{
[DnnAuthorize(StaticRoles = "SuperUser")]
public class ChatApiController : DnnApiController
{
[HttpGet]
public HttpResponseMessage GetMessage()
{
ChatServerManager csm = new ChatServerManager();
var users = csm.GetAllUsers();
var user = users.FirstOrDefault().Name;
return Request.CreateResponse(System.Net.HttpStatusCode.OK, user);
}
[System.Web.Http.HttpPost]
public HttpResponseMessage SendMessage(string toUser, string message)
{
return Request.CreateResponse(System.Net.HttpStatusCode.OK);
}
}
}
There are two ways to call a POST method in a DNN WebAPI: with parameters and with an object. If you use parameters, as you have in your SendMessage method, those parameter values need to be delivered via the Query String.
On the other hand, creating an object and sending that with your call to the WebAPI method can handle a great many more scenarios and is arguably a better way of handling any POST method (as it hides those values from prying eyes, making the call more difficult to counterfeit). To handle this, you can remove the parameters from your SendMessage method and instead interrogate the HttpContext.Current.Request object within your method. The object you created { user: user, message: message } will be nestled in there somewhere.
As it is written in your example, your object was sailing past your parameters like two ships in the night.
I've only just figured this out myself, and I don't have all the understanding I need yet, but hopefully this will help you along your way. Here are some articles I referenced in my quest to use cURL to upload a file to my DNN WebAPI:
https://www.dnnsoftware.com/community-blog/cid/134676/getting-started-with-dotnetnuke-services-framework
https://www.dnnsoftware.com/community-blog/cid/144400/webapi-tips
How To Accept a File POST
https://forums.asp.net/t/2104884.aspx?Uploading+a+file+using+webapi+C+
https://talkdotnet.wordpress.com/2014/03/18/dotnetnuke-webapi-helloworld-example-part-one/comment-page-1/
http://dnnmodule.com/Article/ArticleDetail/tabid/111/ArticleId/511/Dotnetnuke-7-0-WebAPI-Tips.aspx
How to post file using Curl in WebApi in Asp.Net MVC
Good luck!
Your Web Api for SendMessage contain 2 parameter, so it should POST in query string :
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage?touser=john&message=hello
if you want to POST it using data of object, you need to make the Web Service parameter as object model
Also your javascript parameter is different from the Web Service, as it use "toUser"

ASP.NET MVC Model binding doesn't work with AJAX GET but works with Post

I'm having a problem using the Jquery AJAX as a GET Request.
For some reason the ASP.NET MVC model binder doesn't seem to be able to bind to my filter item. What happens is the action result is called but an empty object is created.
However if I change from HTTP Get to HTTP Post then it works.
Why would that be?
From what I understand it would be better to use GET as no data is changing on the server.
Here's a stripped down version of my code:
AJAX:
$.ajax({
url: url,
contentType: 'application/json',
dataType: 'json',
type: "GET",
data: "{'filter':" + ko.toJSON(model.filter) + "}",
error: function (xhr, textStatus, errorThrown) {
},
success: function (returnedData) {
}
ActionResult:
[HttpGet]
public virtual ActionResult Index(IFilter filter)
{
ViewModel filteredViewModel = GetFilteredViewModel(filter);
if (Request.IsAjaxRequest())
{
return toJSON(filteredViewModel );
}
return View(filteredViewModel );
}
Filter:
public class Filter: IFilter
{
public Nullable<DateTime> LogDate { get; set; }
public Nullable<int> SpecificItem_ID { get; set; }
}
First, just to clear up misconceptions, POST doesn't mean change, necessarily. It's perfectly valid to request via POST when accessing a "function", for lack of a better word. For example:
# Request
POST /add-xy
{ "x": 2, "y": 2 }
# Response
200 OK
4
Nothing has "changed", but POST is still the most appropriate HTTP verb.
That said, there's a fundamental difference between GET and POST requests, namely the concept of a POST "body". A POST body can have a content type and therefore can be interpreted properly on the server-side as JSON, XML, etc. With GET, all you have is a querystring, which is just simply a string.
The problem you're having is that with GET, the filter "object" is just a string, and since a string does not implement IFilter the modelbinder can't bind it. However, via POST, the filter "object" is sent in the POST body with a proper content type. So, the modelbinder receives it as JSON, and maps the JSON object onto an implementation of IFilter.
The moral is that GET is only viable for simple requests -- with data that's pretty much only name-value pairs of simple types. If you need to transmit actual objects, you need to use POST.
I don't know why it was accepted, but the currently accepted answer is totally wrong.
ModelBinders don't bind the sent parameters if your object name is precisely filter. So change the name of the object and it will bind properly.

MVC4 not binding a list of basic types

I cannot, for the life of me, get this data to bind. Here's my JavaScript:
var params = { 'InvItemIDs': ["188475", "188490"]};
$.post("api/Orders/OrderFromInventory?" + $.param(params))
and the Controller action:
public HttpResponseMessage OrderFromInventory(IList<int> InvItemIDs)
{
return new HttpResponseMessage();
}
I've built the query string so that it's sending:
?InvItemIDs=188475&InvItemIDs=188490
as well as
?InvItemIDs[]=188475&InvItemIDs[]=188490
and even
?InvItemIDs[0]=188475&InvItemIDs[1]=188490
and none of them are binding. InvItemIDs is always null. What am I doing wrong?
EDIT:
So it turns out all this is a bug (or something) in the new Web API controller code in MVC4. As soon as I moved the exact same code over to a standard controller it started working.
I'm still interested if anyone has any insight as to why the Web API would break this binding.
The reason it doesn't work is because you are using [HttpPost] where it will be expecting the data to be posted in "post body" instead of URL.
You can either
1, remove httpPost
2. put the list in the post content
You would need to set the "traditional: true" for the array to work. Here is a sample code that I've tested on my local project, give that a try
var InvItemIDs = ["188475", "188490"];
$.ajax({ type: "POST",
url: "Home/TestIndex",
datatype: "json",
traditional: true,
data:
{
'InvItemIDs': InvItemIDs
}
});
This Haacked blog post may help. Specifically, looking at his first example, what happens if you change IList to ICollection?
Something like this "should" work
[HttpGet]
public HttpResponseMessage OrderFromInventory(IList<int> InvItemIDs)
{
return new HttpResponseMessage();
}
with the querystring
?InvItemIDs=188475&InvItemIDs=188490

Is it possible to implement X-HTTP-Method-Override in ASP.NET MVC?

I'm implementing a prototype of a RESTful API using ASP.NET MVC and apart from the odd bug here and there I've achieve all the requirements I set out at the start, apart from callers being able to use the X-HTTP-Method-Override custom header to override the HTTP method.
What I'd like is that the following request...
GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE
...would be dispatched to my controller method that implements the DELETE functionality rather than the GET functionality for that action (assuming that there are multiple methods implementing the action, and that they are marked with different [AcceptVerbs] attributes). So, given the following two methods, I would like the above request to be dispatched to the second one:
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }
Does anybody know if this is possible? And how much work would it be to do so...?
You won't be able to use the [AcceptVerbs] attribute as-is since it's tied to the request's actual HTTP verb. Fortunately the [AcceptVerbs] attribute is very simple; you can see the source for yourself at http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.
In short, subclass AcceptsVerbsAttribute and override the IsValidForRequest() method. The implementation would be something like the following:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
Levi's answer is great. Additionally, I added a check in the custom AcceptsVerbsAttribute that also examines the FORM collection, so you can simply put a hidden input to trigger the DELETE (similar to MVC 2's Html.HttpMethodOverride(HttpVerbs.Delete)).
<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />
Change the incomingVerb assignment to:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;
Be careful with this approach! See a related post by Stephen Walther.
Hopefully this helps someone.
Insert to Form:
<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
This conversation is a bit old, but I wanted to share what I have found using mvc 2:
Browsers support two HTTP verbs: GET and POST, but ASP.NET MVC 2 allows you to simulate Put, Get, and Delete using Html.HttpMethodOverride helper method. Internally, this works by sending the verb in an X-HTTP-Method-Override form field. The behavior of HttpMethodOverride is used by the [AcceptVerbs] attribute as well as the new shorter verb attributes:
For example, the action declaration:
[ActionName("someresource")]
[HttpDelete]
public ActionResult DeleteSomeResource()
should take responsibility for your get request that has the X-HTTP-Method-Override set to Delete.
I'm surprised that this hasn't been mentioned yet, but ASP.NET MVC natively supports X-HTTP-Method-Override and has been doing so from at least version 2. There's no need to write custom code to handle this.
It work in the following way:
Inside AcceptVerbsAttribute (also proxied by [HttpPut], [HttpPost], etc), there's an IsValidForRequest method. Inside that method, it checks with Request.GetHttpMethodOverride(), which returns the proper overriden HTTP method with the following conditions:
Overriding is only supported in POST requests. All others are ignored.
If the X-HTTP-Method-Override value is GET or POST, it's ignored. This makes sense, as you'd never need to override with these values.
It looks for X-HTTP-Method-Override in the following places in this priority:
1) HTTP Header
2) Form Body
3) Query String
If you're really curious, here's how GetHttpMethodOverride() looks (from MVC 3's source code):
public static class HttpRequestExtensions {
internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";
public static string GetHttpMethodOverride(this HttpRequestBase request) {
if (request == null) {
throw new ArgumentNullException("request");
}
string incomingVerb = request.HttpMethod;
if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
return incomingVerb;
}
string verbOverride = null;
string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(headerOverrideValue)) {
verbOverride = headerOverrideValue;
}
else {
string formOverrideValue = request.Form[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(formOverrideValue)) {
verbOverride = formOverrideValue;
}
else {
string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
verbOverride = queryStringOverrideValue;
}
}
}
if (verbOverride != null) {
if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
!String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
incomingVerb = verbOverride;
}
}
return incomingVerb;
}
}
Have you looked at Simply Restful Routing? It already does this.
Edited Feb 2010 to add: Method overrides are built into MVC 2.
The X-HTTP-Method-Override is a custom header and most likely isn't supported by your web container.
Are you calling this from a web page? If so, you should probably use XmlHttpRequest with DELETE (or whatever verb you want). Better yet, use a JS framework to do the heavy lifting for you.
You could create an ActionFilter that implements OnActionExecuting, which fires before the controller action is invoked. You could then interrogate the request headers, and redirect based on the value of the X-HTTP-Method-Override header, when present.

MVC User Controls + ViewData

Hi im new to MVC and I've fished around with no luck on how to build MVC User Controls that have ViewData returned to them. I was hoping someone would post a step by step solution on how to approach this problem. If you could make your solution very detailed that would help out greatly.
Sorry for being so discrete with my question, I would just like to clarify that what Im ultimatly trying to do is pass an id to a controller actionresult method and wanting to render it to a user control directly from the controller itself. Im unsure on how to begin with this approach and wondering if this is even possible. It will essentially in my mind look like this
public ActionResult RTest(int id){
RTestDataContext db = new RTestDataContext();
var table = db.GetTable<tRTest>();
var record = table.SingleOrDefault(m=> m.id = id);
return View("RTest", record);
}
and in my User Control I would like to render the objects of that record and thats my issue.
If I understand your question, you are trying to pass ViewData into the user control. A user control is essentially a partial view, so you would do this:
<% Html.RenderPartial("someUserControl.ascx", viewData); %>
Now in your usercontrol, ViewData will be whatever you passed in...
OK here it goes --
We use Json data
In the aspx page we have an ajax call that calls the controller. Look up the available option parameters for ajax calls.
url: This calls the function in the class.(obviously) Our class name is JobController, function name is updateJob and it takes no parameters. The url drops the controllerPortion from the classname. For example to call the updateJob function the url would be '/Job/UpdateJob/'.
var data = {x:1, y:2};
$.ajax({
data: data,
cache: false,
url: '/ClassName/functionName/parameter',
dataType: "json",
type: "post",
success: function(result) {
//do something
},
error: function(errorData) {
alert(errorData.responseText);
}
}
);
In the JobController Class:
public ActionResult UpdateJob(string id)
{
string x_Value_from_ajax = Request.Form["x"];
string y_Value_from_ajax = Request.Form["y"];
return Json(dataContextClass.UpdateJob(x_Value_from_ajax, y_Value_from_ajax));
}
We have a Global.asax.cs page that maps the ajax calls.
public class GlobalApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "EnterTime", action = "Index", id = "" } // Parameter defaults (EnterTime is our default controller class, index is our default function and it takes no parameters.)
);
}
}
I hope this gets you off to a good start.
Good luck
I am pretty sure view data is accessible inside user controls so long as you extend System.Web.Mvc.ViewUserControl and pass it in. I have a snippet of code:
<%Html.RenderPartial("~/UserControls/CategoryChooser.ascx", ViewData);%>
and from within my CategoryChooser ViewData is accessible.
Not sure if I understand your problem completely, but here's my answer to "How to add a User Control to your ASP.NET MVC Project".
In Visual Studio 2008, you can choose Add Item. In the categories at the left side, you can choose Visual C# > Web > MVC. There's an option MVC View User Control. Select it, choose a name, select the desired master page and you're good to go.

Resources